diff --git a/ProConPy/out_handler.py b/ProConPy/out_handler.py index 078521a..315c4b5 100644 --- a/ProConPy/out_handler.py +++ b/ProConPy/out_handler.py @@ -1,11 +1,37 @@ """ Logging Output Handler Module """ import logging +import sys import ipywidgets as widgets logger = logging.getLogger(__name__) +class _NameStrippingFormatter(logging.Formatter): + """Formatter that drops the whitespace some logger names are padded with.""" + + def format(self, record): + name = record.name + record.name = name.strip() + try: + return super().format(record) + finally: + record.name = name + + +def _console_handlers(): + """INFO and below to stdout, WARNING and above to stderr, so that notebooks + (which show stderr on a red background) only flag actual warnings.""" + formatter = _NameStrippingFormatter("%(levelname)s [%(name)s] %(message)s") + to_stdout = logging.StreamHandler(sys.stdout) + to_stdout.addFilter(lambda record: record.levelno < logging.WARNING) + to_stderr = logging.StreamHandler(sys.stderr) + to_stderr.setLevel(logging.WARNING) + for handler in (to_stdout, to_stderr): + handler.setFormatter(formatter) + return [to_stdout, to_stderr] + + class OutHandler(logging.Handler): """Custom logging handler sending logs to an output widget""" @@ -17,7 +43,7 @@ def __init__(self, *args, **kwargs): "border": "1px solid black" } self.out = widgets.Output(layout=layout) - logging.basicConfig(level=logging.DEBUG, datefmt="%I:%M:%S") + logging.basicConfig(level=logging.DEBUG, handlers=_console_handlers()) self.set_verbosity(verbose=False) def emit(self, record): diff --git a/external/mom6_forge b/external/mom6_forge index 83d40e2..89d8e67 160000 --- a/external/mom6_forge +++ b/external/mom6_forge @@ -1 +1 @@ -Subproject commit 83d40e2f63e1daaab3e007e14c3d1e27018209d4 +Subproject commit 89d8e67a76917a0d212da8db90517a7edc7ab24d diff --git a/visualCaseGen/custom_widget_types/case_creator.py b/visualCaseGen/custom_widget_types/case_creator.py index 892951b..cb6206e 100644 --- a/visualCaseGen/custom_widget_types/case_creator.py +++ b/visualCaseGen/custom_widget_types/case_creator.py @@ -521,6 +521,7 @@ def _run_create_newcase(self, caseroot, compset, resolution, do_exec): + f"--case {caseroot} " + f"--machine {machine} " + "--run-unsupported " + + "--handle-preexisting-dirs a " ) # append pecount if provided: @@ -549,7 +550,9 @@ def _run_create_newcase(self, caseroot, compset, resolution, do_exec): # Run the create_newcase command: if do_exec: - runout = subprocess.run(cmd, shell=True, capture_output=True) + runout = subprocess.run( + cmd, shell=True, capture_output=True, text=True, stdin=subprocess.DEVNULL + ) with self._out: if runout.returncode == 0: print(f"{COMMENT}The create_newcase command was successful.{RESET}\n") @@ -557,6 +560,12 @@ def _run_create_newcase(self, caseroot, compset, resolution, do_exec): print(f"{ERROR}Error creating case.{RESET}\n") print(f"{runout.stderr}\n") if runout.returncode != 0: + if "Aborting by user request" in runout.stderr: + raise RuntimeError( + "Error creating case: a previous case with the same name left its " + "build/run directories behind (see the message above). Remove them, " + "or choose a different case name." + ) raise RuntimeError("Error creating case.") def _apply_all_xmlchanges(self, do_exec): @@ -578,7 +587,6 @@ def _apply_all_xmlchanges(self, do_exec): self._apply_lnd_grid_xmlchanges(do_exec) self._apply_ocn_grid_xmlchanges(do_exec) self._apply_runoff_ocn_mapping_xmlchanges(do_exec) - self._apply_wav_coupling_xmlchanges(do_exec) def _apply_lnd_grid_xmlchanges(self, do_exec): @@ -642,16 +650,6 @@ def _wav_uses_custom_ocn_grid(self): ) return not picked_standard_wav_grid - def _apply_wav_coupling_xmlchanges(self, do_exec): - """Use the legacy MOM6-WW3 wave coupling method when the custom ocean grid is reused as - the wave grid.""" - - if cvars["COMP_WAV"].value == "ww3" and self._wav_uses_custom_ocn_grid(): - with self._out: - print(f"{COMMENT}Set wave coupling mode to legacy:{RESET}\n") - xmlchange("MOM6_WW3_CPL_METHOD", "legacy", do_exec, self._is_non_local(), self._out) - - @staticmethod def _calc_cores_based_on_grid( num_points, min_points_per_core = 32, max_points_per_core = 300, ideal_multiple_of_cores_used = 128): """Calculate the number of cores based on the grid size.""" @@ -946,6 +944,7 @@ def _update_component_grids_xml( if self._wav_uses_custom_ocn_grid(): comps_sharing_ocn_grid.append("WAV") for comp in comps_sharing_ocn_grid: + xmlchange(f"{comp}_GRID", ocn_grid, do_exec, self._is_non_local(), self._out) xmlchange(f"{comp}_NX", cvars["OCN_NX"].value, do_exec, self._is_non_local(), self._out) xmlchange(f"{comp}_NY", cvars["OCN_NY"].value, do_exec, self._is_non_local(), self._out) xmlchange(f"{comp}_DOMAIN_MESH", ocn_mesh.as_posix(), do_exec, self._is_non_local(), self._out) diff --git a/visualCaseGen/custom_widget_types/case_tools.py b/visualCaseGen/custom_widget_types/case_tools.py index cb5bfdb..b227dcc 100644 --- a/visualCaseGen/custom_widget_types/case_tools.py +++ b/visualCaseGen/custom_widget_types/case_tools.py @@ -126,7 +126,7 @@ def xmlchange(var, val, do_exec=True, is_non_local=False, out=None): out = DummyOutput() if out is None else out with out: - print(f"{cmd}\n") + print(cmd) if not do_exec: return