From 17074603d24e590eaf1c74cae5e64380698b34db Mon Sep 17 00:00:00 2001 From: Florian Deconinck Date: Tue, 24 Feb 2026 10:53:21 -0500 Subject: [PATCH 01/10] [TMP] Move NDSL to `NDSL_Backend` and update CI external trigger --- .github/workflows/main_unit_tests.yaml | 4 ++-- NDSL | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main_unit_tests.yaml b/.github/workflows/main_unit_tests.yaml index f8402a51..24835f7d 100644 --- a/.github/workflows/main_unit_tests.yaml +++ b/.github/workflows/main_unit_tests.yaml @@ -42,9 +42,9 @@ jobs: uses: actions/checkout@v6 with: submodules: 'recursive' - repository: NOAA-GFDL/pace + repository: FlorianDeconinck/pace + ref: update/2026.02.00 path: pace - ref: develop - name: 'Setup Python ${{ inputs.python_version && inputs.python_version || env.python_default }}' uses: actions/setup-python@v6 diff --git a/NDSL b/NDSL index 3d8fa05e..4cc245cd 160000 --- a/NDSL +++ b/NDSL @@ -1 +1 @@ -Subproject commit 3d8fa05ee7b78182afd2e749532582ffaa25b595 +Subproject commit 4cc245cd5847231bc46e7436342575aeac7f6803 From e8599551a47322d01f36c6731f58b219741ae4ff Mon Sep 17 00:00:00 2001 From: Florian Deconinck Date: Tue, 24 Feb 2026 12:20:17 -0500 Subject: [PATCH 02/10] [TMP] Move submodules to `update/2026.02.00` worthy branches --- NDSL | 2 +- pyFV3 | 2 +- pySHiELD | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NDSL b/NDSL index 4cc245cd..40f0a2dc 160000 --- a/NDSL +++ b/NDSL @@ -1 +1 @@ -Subproject commit 4cc245cd5847231bc46e7436342575aeac7f6803 +Subproject commit 40f0a2dcc3a0784930d0400561a307c55563ec6f diff --git a/pyFV3 b/pyFV3 index 64ddc3a6..e96ebc64 160000 --- a/pyFV3 +++ b/pyFV3 @@ -1 +1 @@ -Subproject commit 64ddc3a6c12d216ce46393c414754d4651ccebda +Subproject commit e96ebc6475ee5bc93e0eb85ad87bbdbe471891ac diff --git a/pySHiELD b/pySHiELD index 66df9db1..9d1e5a60 160000 --- a/pySHiELD +++ b/pySHiELD @@ -1 +1 @@ -Subproject commit 66df9db174aef33a2702961299c890fc75e347dc +Subproject commit 9d1e5a60c200c137d900e8bb8c6ef1b9bf6e3873 From abe8bb8ef62b3d34039204a329ab43242016ca36 Mon Sep 17 00:00:00 2001 From: Florian Deconinck Date: Tue, 24 Feb 2026 12:20:31 -0500 Subject: [PATCH 03/10] Move to `Backend` object --- .jenkins/driver_configs/baroclinic_c192_54ranks.yaml | 2 +- .jenkins/driver_configs/baroclinic_c192_6ranks.yaml | 2 +- .../driver_configs/baroclinic_c48_6ranks_dycore_only.yaml | 2 +- .../baroclinic_c48_6ranks_dycore_only_serialbox.yaml | 2 +- examples/configs/analytic_test.yaml | 2 +- examples/configs/baroclinic_c12.yaml | 2 +- examples/configs/baroclinic_c12_comm_read.yaml | 2 +- examples/configs/baroclinic_c12_comm_write.yaml | 2 +- examples/configs/baroclinic_c12_dp.yaml | 2 +- examples/configs/baroclinic_c12_explicit_physics.yaml | 2 +- examples/configs/baroclinic_c12_from_serialbox.yaml | 2 +- examples/configs/baroclinic_c12_null_comm.yaml | 7 ++++++- examples/configs/baroclinic_c12_orch_cpu.yaml | 2 +- examples/configs/baroclinic_c12_read_restart_fortran.yml | 2 +- examples/configs/baroclinic_c12_write_restart.yaml | 2 +- examples/configs/baroclinic_c48_6ranks_serialbox_test.yaml | 2 +- examples/configs/baroclinic_c48_no_out.yaml | 2 +- examples/configs/test_external_C12_1x1.yaml | 2 +- examples/configs/test_external_C12_2x2.yaml | 2 +- examples/configs/tropical_read_restart_fortran.yml | 2 +- examples/configs/tropicalcyclone_c128.yaml | 2 +- examples/notebooks/functions.py | 7 ++++--- pace/driver.py | 1 + pace/grid.py | 3 ++- pace/initialization.py | 3 ++- tests/main/conftest.py | 2 +- tests/main/driver/test_diagnostics_config.py | 5 +++-- tests/main/driver/test_restart_fortran.py | 3 ++- tests/main/driver/test_restart_serial.py | 3 ++- tests/main/driver/test_safety_checks.py | 5 +++-- tests/main/fv3core/test_cartesian_grid.py | 3 ++- tests/main/fv3core/test_dycore_baroclinic.py | 3 ++- tests/main/fv3core/test_dycore_call.py | 3 ++- tests/main/fv3core/test_init_from_geos.py | 5 +++-- tests/main/physics/test_integration.py | 5 +++-- tests/main/test_grid_init.py | 3 ++- tests/mpi/test_grid_init.py | 3 ++- tests/savepoint/conftest.py | 2 +- tests/savepoint/test_checkpoints.py | 3 ++- 39 files changed, 65 insertions(+), 44 deletions(-) diff --git a/.jenkins/driver_configs/baroclinic_c192_54ranks.yaml b/.jenkins/driver_configs/baroclinic_c192_54ranks.yaml index 111695d4..f627e90a 100644 --- a/.jenkins/driver_configs/baroclinic_c192_54ranks.yaml +++ b/.jenkins/driver_configs/baroclinic_c192_54ranks.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: dace:gpu + backend: st:dace:gpu:KJI rebuild: false validate_args: true format_source: false diff --git a/.jenkins/driver_configs/baroclinic_c192_6ranks.yaml b/.jenkins/driver_configs/baroclinic_c192_6ranks.yaml index 0bc52446..7a0db1c0 100644 --- a/.jenkins/driver_configs/baroclinic_c192_6ranks.yaml +++ b/.jenkins/driver_configs/baroclinic_c192_6ranks.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: dace:gpu + backend: st:dace:gpu:KJI rebuild: false validate_args: true format_source: false diff --git a/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only.yaml b/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only.yaml index 6d7f3d86..68eab391 100644 --- a/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only.yaml +++ b/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only.yaml @@ -2,7 +2,7 @@ dycore_only: true disable_step_physics: true stencil_config: compilation_config: - backend: gt:gpu + backend: st:gt:gpu:KJI rebuild: false validate_args: true format_source: false diff --git a/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only_serialbox.yaml b/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only_serialbox.yaml index 0c112346..2db6d3b6 100644 --- a/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only_serialbox.yaml +++ b/.jenkins/driver_configs/baroclinic_c48_6ranks_dycore_only_serialbox.yaml @@ -2,7 +2,7 @@ dycore_only: true disable_step_physics: true stencil_config: compilation_config: - backend: gt:gpu + backend: st:gt:gpu:KJI rebuild: false validate_args: true format_source: false diff --git a/examples/configs/analytic_test.yaml b/examples/configs/analytic_test.yaml index ce00af97..afcf2853 100644 --- a/examples/configs/analytic_test.yaml +++ b/examples/configs/analytic_test.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12.yaml b/examples/configs/baroclinic_c12.yaml index fc9418b1..43ee1951 100644 --- a/examples/configs/baroclinic_c12.yaml +++ b/examples/configs/baroclinic_c12.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_comm_read.yaml b/examples/configs/baroclinic_c12_comm_read.yaml index 8cfead55..37a97544 100644 --- a/examples/configs/baroclinic_c12_comm_read.yaml +++ b/examples/configs/baroclinic_c12_comm_read.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_comm_write.yaml b/examples/configs/baroclinic_c12_comm_write.yaml index 1c11655c..ecd47dfe 100644 --- a/examples/configs/baroclinic_c12_comm_write.yaml +++ b/examples/configs/baroclinic_c12_comm_write.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_dp.yaml b/examples/configs/baroclinic_c12_dp.yaml index e9819f1c..d95912a1 100644 --- a/examples/configs/baroclinic_c12_dp.yaml +++ b/examples/configs/baroclinic_c12_dp.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_explicit_physics.yaml b/examples/configs/baroclinic_c12_explicit_physics.yaml index b172888d..eb095ea0 100644 --- a/examples/configs/baroclinic_c12_explicit_physics.yaml +++ b/examples/configs/baroclinic_c12_explicit_physics.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_from_serialbox.yaml b/examples/configs/baroclinic_c12_from_serialbox.yaml index 0f05e7a0..b55d3225 100644 --- a/examples/configs/baroclinic_c12_from_serialbox.yaml +++ b/examples/configs/baroclinic_c12_from_serialbox.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: gtc:numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_null_comm.yaml b/examples/configs/baroclinic_c12_null_comm.yaml index 6625140a..31a2c723 100644 --- a/examples/configs/baroclinic_c12_null_comm.yaml +++ b/examples/configs/baroclinic_c12_null_comm.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false @@ -94,3 +94,8 @@ physics_config: hydrostatic: false nwat: 6 do_qa: true + +grid_config: + type: generated + config: + eta_file: './eta79.nc' \ No newline at end of file diff --git a/examples/configs/baroclinic_c12_orch_cpu.yaml b/examples/configs/baroclinic_c12_orch_cpu.yaml index 7cb6b3ed..15a58941 100644 --- a/examples/configs/baroclinic_c12_orch_cpu.yaml +++ b/examples/configs/baroclinic_c12_orch_cpu.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: dace:cpu + backend: st:dace:cpu:KIJ rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_read_restart_fortran.yml b/examples/configs/baroclinic_c12_read_restart_fortran.yml index a28f3129..616583e1 100644 --- a/examples/configs/baroclinic_c12_read_restart_fortran.yml +++ b/examples/configs/baroclinic_c12_read_restart_fortran.yml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c12_write_restart.yaml b/examples/configs/baroclinic_c12_write_restart.yaml index 58878441..d2dcacba 100644 --- a/examples/configs/baroclinic_c12_write_restart.yaml +++ b/examples/configs/baroclinic_c12_write_restart.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c48_6ranks_serialbox_test.yaml b/examples/configs/baroclinic_c48_6ranks_serialbox_test.yaml index cd240cd7..0f35b264 100644 --- a/examples/configs/baroclinic_c48_6ranks_serialbox_test.yaml +++ b/examples/configs/baroclinic_c48_6ranks_serialbox_test.yaml @@ -2,7 +2,7 @@ dycore_only: true disable_step_physics: true stencil_config: compilation_config: - backend: gt:gpu + backend: st:gt:gpu:KJI rebuild: false validate_args: true format_source: false diff --git a/examples/configs/baroclinic_c48_no_out.yaml b/examples/configs/baroclinic_c48_no_out.yaml index 24f3139e..6d5b0b1a 100644 --- a/examples/configs/baroclinic_c48_no_out.yaml +++ b/examples/configs/baroclinic_c48_no_out.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/test_external_C12_1x1.yaml b/examples/configs/test_external_C12_1x1.yaml index b26edbfe..8d7e0d14 100644 --- a/examples/configs/test_external_C12_1x1.yaml +++ b/examples/configs/test_external_C12_1x1.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/test_external_C12_2x2.yaml b/examples/configs/test_external_C12_2x2.yaml index fc84c85b..28ba4d5e 100644 --- a/examples/configs/test_external_C12_2x2.yaml +++ b/examples/configs/test_external_C12_2x2.yaml @@ -1,6 +1,6 @@ stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/tropical_read_restart_fortran.yml b/examples/configs/tropical_read_restart_fortran.yml index f0b55208..5a72c54a 100644 --- a/examples/configs/tropical_read_restart_fortran.yml +++ b/examples/configs/tropical_read_restart_fortran.yml @@ -2,7 +2,7 @@ dycore_only: true disable_step_physics: true stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/configs/tropicalcyclone_c128.yaml b/examples/configs/tropicalcyclone_c128.yaml index fe8d519b..2d466c4c 100644 --- a/examples/configs/tropicalcyclone_c128.yaml +++ b/examples/configs/tropicalcyclone_c128.yaml @@ -2,7 +2,7 @@ dycore_only: true disable_step_physics: true stencil_config: compilation_config: - backend: numpy + backend: st:numpy:cpu:IJK rebuild: false validate_args: true format_source: false diff --git a/examples/notebooks/functions.py b/examples/notebooks/functions.py index 4fe0887c..9ce246bd 100644 --- a/examples/notebooks/functions.py +++ b/examples/notebooks/functions.py @@ -25,6 +25,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import backend_python, Backend from ndsl.constants import RADIUS, X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM, Z_DIM from ndsl.grid import ( AngleGridData, @@ -62,7 +63,7 @@ def init_quantity( grid: VariableGrid, dims: VariableDims = VariableDims.XYZ, units: str = "", - backend: str = "numpy", + backend: Backend = backend_python, ) -> Quantity: """ Use: output = init_quantity(dimensions, grid, dims, units) @@ -310,13 +311,13 @@ def configure_domain( def configure_stencil( domain_configuration: Dict[str, Any], - backend: str = "numpy", + backend: Backend = backend_python, single_layer: bool = True, ) -> Dict[str, Any]: """ Use: stencil_configuration = configure_stencil( - domain_configuration, backend="numpy", single_layer=True) + domain_configuration, backend=Backend("st:numpy:cpu:IJK"), single_layer=True) Inputs: - domain configuration (Dict) from configure_domain() diff --git a/pace/driver.py b/pace/driver.py index f6f825d8..3289a1f8 100644 --- a/pace/driver.py +++ b/pace/driver.py @@ -338,6 +338,7 @@ def write_for_restart( if "case" in config_dict["initialization"]["config"].keys(): del config_dict["initialization"]["config"]["case"] with open(f"{restart_path}/restart.yaml", "w") as file: + print(config_dict) yaml.safe_dump(config_dict, file) diff --git a/pace/grid.py b/pace/grid.py index 2e681334..d235ef98 100644 --- a/pace/grid.py +++ b/pace/grid.py @@ -8,6 +8,7 @@ from ndsl import QuantityFactory, ndsl_log from ndsl.comm.partitioner import get_tile_index +from ndsl.config import Backend from ndsl.constants import X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM from ndsl.grid import ( AngleGridData, @@ -168,7 +169,7 @@ def _serializer(self, communicator: Communicator): def _get_serialized_grid( self, communicator: Communicator, - backend: str, + backend: Backend, ) -> grid.Grid: # type: ignore ser = self._serializer(communicator) grid = TranslateGrid.new_from_serialized_data( diff --git a/pace/initialization.py b/pace/initialization.py index f4eff622..47b583fc 100644 --- a/pace/initialization.py +++ b/pace/initialization.py @@ -15,6 +15,7 @@ StencilConfig, StencilFactory, ) +from ndsl.config import Backend from ndsl.constants import X_DIM, Y_DIM from ndsl.grid import DampingCoefficients, DriverGridData, GridData from ndsl.stencils.testing import TranslateGrid, grid @@ -259,7 +260,7 @@ def _grid_params(self) -> dict: def _get_serialized_grid( self, communicator: Communicator, - backend: str, + backend: Backend, ) -> grid.Grid: # type: ignore ser = self._serializer(communicator) grid = TranslateGrid.new_from_serialized_data( diff --git a/tests/main/conftest.py b/tests/main/conftest.py index 4680742f..f3e91b54 100644 --- a/tests/main/conftest.py +++ b/tests/main/conftest.py @@ -8,4 +8,4 @@ def backend(pytestconfig): def pytest_addoption(parser): - parser.addoption("--backend", action="store", default="numpy") + parser.addoption("--backend", action="store", default="st:numpy:cpu:IJK") diff --git a/tests/main/driver/test_diagnostics_config.py b/tests/main/driver/test_diagnostics_config.py index 55e43cc2..565eba7f 100644 --- a/tests/main/driver/test_diagnostics_config.py +++ b/tests/main/driver/test_diagnostics_config.py @@ -3,6 +3,7 @@ import pytest from ndsl import QuantityFactory, SubtileGridSizer +from ndsl.config import Backend from ndsl.constants import X_DIM, Y_DIM, Z_DIM from pace import DiagnosticsConfig from pace.diagnostics import MonitorDiagnostics, NullDiagnostics, ZSelect @@ -43,7 +44,7 @@ def test_zselect_raises_error_if_not_3d(tmpdir): z_select=[ZSelect(level=0, names=["phis"])], ) result = config.diagnostics_factory(unittest.mock.MagicMock()) - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") quantity_factory = QuantityFactory( sizer=SubtileGridSizer.from_tile_params( nx_tile=12, @@ -66,7 +67,7 @@ def test_zselect_raises_error_if_3rd_dim_not_z(tmpdir): z_select=[ZSelect(level=0, names=["foo"])], ) result = config.diagnostics_factory(unittest.mock.MagicMock()) - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") quantity_factory = QuantityFactory( sizer=SubtileGridSizer.from_tile_params( nx_tile=12, diff --git a/tests/main/driver/test_restart_fortran.py b/tests/main/driver/test_restart_fortran.py index cdb7c524..cc5aebf9 100644 --- a/tests/main/driver/test_restart_fortran.py +++ b/tests/main/driver/test_restart_fortran.py @@ -9,6 +9,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import Backend from pace import FortranRestartInit, GeneratedGridConfig, NullComm from pyshield import PHYSICS_PACKAGES from tests.paths import REPO_ROOT @@ -16,7 +17,7 @@ def test_state_from_fortran_restart(): layout = (1, 1) - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") partitioner = CubedSpherePartitioner(TilePartitioner(layout)) # need a local communicator to mock "scatter" for the restart data, # but need null communicator to handle grid initialization diff --git a/tests/main/driver/test_restart_serial.py b/tests/main/driver/test_restart_serial.py index 52600f2b..da679451 100644 --- a/tests/main/driver/test_restart_serial.py +++ b/tests/main/driver/test_restart_serial.py @@ -15,6 +15,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import Backend from pace import ( AnalyticInit, DriverConfig, @@ -38,7 +39,7 @@ def test_restart_save_to_disk(): try: with open(EXAMPLE_CONFIGS_DIR / "baroclinic_c12_write_restart.yaml", "r") as f: driver_config = DriverConfig.from_dict(yaml.safe_load(f)) - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") mpi_comm = NullComm(rank=0, total_ranks=6, fill_value=0.0) partitioner = CubedSpherePartitioner(TilePartitioner((1, 1))) communicator = CubedSphereCommunicator(mpi_comm, partitioner) diff --git a/tests/main/driver/test_safety_checks.py b/tests/main/driver/test_safety_checks.py index 4fa3d6be..fd88da76 100644 --- a/tests/main/driver/test_safety_checks.py +++ b/tests/main/driver/test_safety_checks.py @@ -4,6 +4,7 @@ import pytest from ndsl import Quantity +from ndsl.config import Backend from ndsl.constants import X_DIM, Y_DIM, Z_DIM from pace import SafetyChecker @@ -66,7 +67,7 @@ def test_check_state_domain_only(): "unknown", origin=(1, 1, 0), extent=(3, 3, 2), - backend="numpy", + backend=Backend("st:numpy:cpu:IJK"), ) dycore_state = unittest.mock.MagicMock(u=u_quantity) checker.check_state(dycore_state) @@ -84,7 +85,7 @@ def test_check_nan_value(): "unknown", origin=(0, 0, 0), extent=(4, 4, 2), - backend="numpy", + backend=Backend("st:numpy:cpu:IJK"), ) dycore_state = unittest.mock.MagicMock(u=u_quantity) with pytest.raises(RuntimeError): diff --git a/tests/main/fv3core/test_cartesian_grid.py b/tests/main/fv3core/test_cartesian_grid.py index 6e1d940b..003f79a6 100644 --- a/tests/main/fv3core/test_cartesian_grid.py +++ b/tests/main/fv3core/test_cartesian_grid.py @@ -4,6 +4,7 @@ import pytest from ndsl import TileCommunicator, TilePartitioner +from ndsl.config import Backend from ndsl.constants import PI from ndsl.grid import MetricTerms from pace import NullComm @@ -15,7 +16,7 @@ @pytest.mark.parametrize("dx_const", [1e2, 1e3]) @pytest.mark.parametrize("dy_const", [2e2, 3e3]) @pytest.mark.parametrize("deglat", [0.0, 15.0]) -@pytest.mark.parametrize("backend", ["numpy"]) +@pytest.mark.parametrize("backend", [Backend("st:numpy:cpu:IJK")]) def test_cartesian_grid_generation( npx: int, npy: int, diff --git a/tests/main/fv3core/test_dycore_baroclinic.py b/tests/main/fv3core/test_dycore_baroclinic.py index 533b12a6..838a8fad 100644 --- a/tests/main/fv3core/test_dycore_baroclinic.py +++ b/tests/main/fv3core/test_dycore_baroclinic.py @@ -21,6 +21,7 @@ TileCommunicator, TilePartitioner, ) +from ndsl.config import Backend from ndsl.grid import DampingCoefficients, GridData, MetricTerms from ndsl.performance.timer import NullTimer from pace import NullComm @@ -81,7 +82,7 @@ def setup_dycore( ) -> DycoreState: """Sets up Dycore state for analytic initialization""" - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") config = setup_dycore_config() mpi_comm = NullComm( rank=rank, total_ranks=6 * config.layout[0] * config.layout[1], fill_value=0.0 diff --git a/tests/main/fv3core/test_dycore_call.py b/tests/main/fv3core/test_dycore_call.py index 9fa95184..7cc9552f 100644 --- a/tests/main/fv3core/test_dycore_call.py +++ b/tests/main/fv3core/test_dycore_call.py @@ -18,6 +18,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import Backend from ndsl.grid import DampingCoefficients, GridData, MetricTerms from ndsl.performance.timer import NullTimer, Timer from ndsl.stencils.testing import assert_same_temporaries, copy_temporaries @@ -27,7 +28,7 @@ def setup_dycore() -> Tuple[DynamicalCore, DycoreState, Timer]: - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") config = DynamicalCoreConfig( layout=(1, 1), npx=13, diff --git a/tests/main/fv3core/test_init_from_geos.py b/tests/main/fv3core/test_init_from_geos.py index b1c05a67..1d9ca447 100644 --- a/tests/main/fv3core/test_init_from_geos.py +++ b/tests/main/fv3core/test_init_from_geos.py @@ -3,6 +3,7 @@ import pytest # noqa from pace import NullComm +from ndsl.config import Backend from pyfv3 import DynamicalCore from pyfv3.wrappers import GeosDycoreWrapper @@ -11,7 +12,7 @@ def test_geos_wrapper(): namelist_dict = { "stencil_config": { "compilation_config": { - "backend": "numpy", + "backend": "st:numpy:cpu:IJK", "rebuild": False, "validate_args": True, "format_source": False, @@ -83,7 +84,7 @@ def test_geos_wrapper(): namelist = f90nml.namelist.Namelist(namelist_dict) comm = NullComm(rank=0, total_ranks=6, fill_value=0.0) - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") wrapper = GeosDycoreWrapper( namelist=namelist, diff --git a/tests/main/physics/test_integration.py b/tests/main/physics/test_integration.py index dc5ba816..af932144 100644 --- a/tests/main/physics/test_integration.py +++ b/tests/main/physics/test_integration.py @@ -17,6 +17,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import Backend from ndsl.grid import GridData, MetricTerms from ndsl.stencils.testing import assert_same_temporaries, copy_temporaries from pace import NullComm @@ -30,7 +31,7 @@ def setup_physics(): - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") layout = (1, 1) physics_config = PhysicsConfig( dt_atmos=225, hydrostatic=False, npx=13, npy=13, npz=79, nwat=6, do_qa=True @@ -55,7 +56,7 @@ def setup_physics(): dace_config = DaceConfig( communicator=communicator, backend=backend, - orchestration=DaCeOrchestration.Python, + orchestration=DaCeOrchestration.BuildAndRun, ) stencil_config = StencilConfig( compilation_config=CompilationConfig( diff --git a/tests/main/test_grid_init.py b/tests/main/test_grid_init.py index 00624436..4fb6a80a 100644 --- a/tests/main/test_grid_init.py +++ b/tests/main/test_grid_init.py @@ -11,6 +11,7 @@ SubtileGridSizer, TilePartitioner, ) +from ndsl.config import Backend from ndsl.grid import MetricTerms from pace import NullComm @@ -25,7 +26,7 @@ def get_cube_comm(layout, rank: int): def get_quantity_factory(layout, nx_tile, ny_tile, nz): nx = nx_tile // layout[0] ny = ny_tile // layout[1] - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") return QuantityFactory( sizer=SubtileGridSizer.from_tile_params( diff --git a/tests/mpi/test_grid_init.py b/tests/mpi/test_grid_init.py index 337ae6ee..16cc7c00 100644 --- a/tests/mpi/test_grid_init.py +++ b/tests/mpi/test_grid_init.py @@ -12,6 +12,7 @@ TileCommunicator, TilePartitioner, ) +from ndsl.config import Backend from ndsl.grid import GridData, MetricTerms from pyfv3 import DycoreState from pyfv3.initialization.test_cases.initialize_baroclinic import init_baroclinic_state @@ -27,7 +28,7 @@ def get_cube_comm(layout, comm: MPIComm): def get_quantity_factory(layout, nx_tile, ny_tile, nz): nx = nx_tile // layout[0] ny = ny_tile // layout[1] - backend = "numpy" + backend = Backend("st:numpy:cpu:IJK") return QuantityFactory( sizer=SubtileGridSizer.from_tile_params( diff --git a/tests/savepoint/conftest.py b/tests/savepoint/conftest.py index b7ebdb7a..ad45ec4e 100644 --- a/tests/savepoint/conftest.py +++ b/tests/savepoint/conftest.py @@ -37,7 +37,7 @@ def dperiodic(pytestconfig): def pytest_addoption(parser): parser.addoption( - "--backend", action="store", default="numpy", help="gt4py backend name" + "--backend", action="store", default="st:numpy:cpu:IJK", help="gt4py backend name" ) parser.addoption( "--data_path", action="store", default="./", help="location of reference data" diff --git a/tests/savepoint/test_checkpoints.py b/tests/savepoint/test_checkpoints.py index f4c36847..4db3d5d7 100644 --- a/tests/savepoint/test_checkpoints.py +++ b/tests/savepoint/test_checkpoints.py @@ -28,6 +28,7 @@ ThresholdCalibrationCheckpointer, ValidationCheckpointer, ) +from ndsl.config import Backend from ndsl.grid import DampingCoefficients, GridData from ndsl.stencils.testing import Grid, TranslateGrid, dataset_to_dict from ndsl.testing import perturb @@ -35,7 +36,7 @@ from pyfv3.testing import TranslateFVDynamics -def get_grid(data_path: Path, rank: int, layout: Tuple[int, int], backend: str) -> Grid: +def get_grid(data_path: Path, rank: int, layout: Tuple[int, int], backend: Backend) -> Grid: ds_grid: xr.Dataset = xr.open_dataset(data_path / "Grid-Info.nc").isel(savepoint=0) grid = TranslateGrid( dataset_to_dict(ds_grid.isel(rank=rank)), From 5c4fcc810da7c22bc4fe47b37987d5e5340b11f4 Mon Sep 17 00:00:00 2001 From: Florian Deconinck Date: Tue, 24 Feb 2026 12:50:25 -0500 Subject: [PATCH 04/10] Lint --- examples/configs/baroclinic_c12_null_comm.yaml | 4 ++-- examples/notebooks/functions.py | 2 +- pace/initialization.py | 2 +- tests/main/fv3core/test_init_from_geos.py | 2 +- tests/savepoint/conftest.py | 5 ++++- tests/savepoint/test_checkpoints.py | 4 +++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/configs/baroclinic_c12_null_comm.yaml b/examples/configs/baroclinic_c12_null_comm.yaml index 31a2c723..c5460e27 100644 --- a/examples/configs/baroclinic_c12_null_comm.yaml +++ b/examples/configs/baroclinic_c12_null_comm.yaml @@ -96,6 +96,6 @@ physics_config: do_qa: true grid_config: - type: generated + type: generated config: - eta_file: './eta79.nc' \ No newline at end of file + eta_file: './eta79.nc' diff --git a/examples/notebooks/functions.py b/examples/notebooks/functions.py index 9ce246bd..60bb2768 100644 --- a/examples/notebooks/functions.py +++ b/examples/notebooks/functions.py @@ -25,7 +25,7 @@ SubtileGridSizer, TilePartitioner, ) -from ndsl.config import backend_python, Backend +from ndsl.config import Backend, backend_python from ndsl.constants import RADIUS, X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM, Z_DIM from ndsl.grid import ( AngleGridData, diff --git a/pace/initialization.py b/pace/initialization.py index 47b583fc..35eaa36b 100644 --- a/pace/initialization.py +++ b/pace/initialization.py @@ -308,7 +308,7 @@ def get_driver_state( def _initialize_dycore_state( self, communicator: Communicator, - backend: str, + backend: Backend, ) -> DycoreState: grid = self._get_serialized_grid(communicator=communicator, backend=backend) diff --git a/tests/main/fv3core/test_init_from_geos.py b/tests/main/fv3core/test_init_from_geos.py index 1d9ca447..3947ddd9 100644 --- a/tests/main/fv3core/test_init_from_geos.py +++ b/tests/main/fv3core/test_init_from_geos.py @@ -2,8 +2,8 @@ import numpy as np import pytest # noqa -from pace import NullComm from ndsl.config import Backend +from pace import NullComm from pyfv3 import DynamicalCore from pyfv3.wrappers import GeosDycoreWrapper diff --git a/tests/savepoint/conftest.py b/tests/savepoint/conftest.py index ad45ec4e..9a62e96c 100644 --- a/tests/savepoint/conftest.py +++ b/tests/savepoint/conftest.py @@ -37,7 +37,10 @@ def dperiodic(pytestconfig): def pytest_addoption(parser): parser.addoption( - "--backend", action="store", default="st:numpy:cpu:IJK", help="gt4py backend name" + "--backend", + action="store", + default="st:numpy:cpu:IJK", + help="gt4py backend name", ) parser.addoption( "--data_path", action="store", default="./", help="location of reference data" diff --git a/tests/savepoint/test_checkpoints.py b/tests/savepoint/test_checkpoints.py index 4db3d5d7..2a80abd3 100644 --- a/tests/savepoint/test_checkpoints.py +++ b/tests/savepoint/test_checkpoints.py @@ -36,7 +36,9 @@ from pyfv3.testing import TranslateFVDynamics -def get_grid(data_path: Path, rank: int, layout: Tuple[int, int], backend: Backend) -> Grid: +def get_grid( + data_path: Path, rank: int, layout: Tuple[int, int], backend: Backend +) -> Grid: ds_grid: xr.Dataset = xr.open_dataset(data_path / "Grid-Info.nc").isel(savepoint=0) grid = TranslateGrid( dataset_to_dict(ds_grid.isel(rank=rank)), From 2b13ebc61336002d23ca3cbefedf551489de42c0 Mon Sep 17 00:00:00 2001 From: Florian Deconinck Date: Tue, 24 Feb 2026 13:15:21 -0500 Subject: [PATCH 05/10] X/Y/Z_DIM -> I/J/K_DIM --- docs/util/communication.rst | 2 +- examples/notebooks/functions.py | 22 +- examples/notebooks/serial_debugging.ipynb | 950 +++--- examples/notebooks/stencil_definition.ipynb | 3152 +++++++++--------- pace/diagnostics.py | 15 +- pace/grid.py | 4 +- pace/initialization.py | 2 +- pace/state.py | 8 +- tests/main/driver/test_diagnostics_config.py | 4 +- tests/main/driver/test_safety_checks.py | 6 +- tests/main/fv3core/test_grid.py | 64 +- tests/mpi/ext_grid/test_external_grid.py | 4 +- 12 files changed, 2115 insertions(+), 2118 deletions(-) diff --git a/docs/util/communication.rst b/docs/util/communication.rst index 9b36eb3d..ac561bc4 100644 --- a/docs/util/communication.rst +++ b/docs/util/communication.rst @@ -68,7 +68,7 @@ To see how the boundary and other objects operate, we will need some data to ope >>> import numpy as np >>> quantity = pace.util.Quantity( ... data=np.zeros((6, 6)), - ... dims=[pace.util.X_DIM, pace.util.Y_DIM], + ... dims=[pace.util.I_DIM, pace.util.J_DIM], ... units="m", ... origin=(1, 1), ... extent=(4, 4), diff --git a/examples/notebooks/functions.py b/examples/notebooks/functions.py index 60bb2768..9d1a684a 100644 --- a/examples/notebooks/functions.py +++ b/examples/notebooks/functions.py @@ -26,7 +26,7 @@ TilePartitioner, ) from ndsl.config import Backend, backend_python -from ndsl.constants import RADIUS, X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM, Z_DIM +from ndsl.constants import I_DIM, I_INTERFACE_DIM, J_DIM, J_INTERFACE_DIM, K_DIM, RADIUS from ndsl.grid import ( AngleGridData, ContravariantGridData, @@ -103,7 +103,7 @@ def init_quantity( if grid == VariableGrid.CellCenters: variable = Quantity( data=empty, - dims=(X_DIM, Y_DIM, Z_DIM)[:skip_z], + dims=(I_DIM, J_DIM, K_DIM)[:skip_z], units=units, origin=(nhalo, nhalo, 0)[:skip_z], extent=(nx, ny, nz)[:skip_z], @@ -113,7 +113,7 @@ def init_quantity( if grid == VariableGrid.CellCorners: variable = Quantity( data=empty, - dims=(X_INTERFACE_DIM, Y_INTERFACE_DIM, Z_DIM)[:skip_z], + dims=(I_INTERFACE_DIM, J_INTERFACE_DIM, K_DIM)[:skip_z], units=units, origin=(nhalo, nhalo, 0)[:skip_z], extent=(nx + 1, ny + 1, nz)[:skip_z], @@ -123,7 +123,7 @@ def init_quantity( elif grid == VariableGrid.StaggeredInX: variable = Quantity( data=empty, - dims=(X_INTERFACE_DIM, Y_DIM, Z_DIM)[:skip_z], + dims=(I_INTERFACE_DIM, J_DIM, K_DIM)[:skip_z], units=units, origin=(nhalo, nhalo, 0)[:skip_z], extent=(nx + 1, ny, nz)[:skip_z], @@ -133,7 +133,7 @@ def init_quantity( elif grid == VariableGrid.StaggeredInY: variable = Quantity( data=empty, - dims=(X_DIM, Y_INTERFACE_DIM, Z_DIM)[:skip_z], + dims=(I_DIM, J_INTERFACE_DIM, K_DIM)[:skip_z], units=units, origin=(nhalo, nhalo, 0)[:skip_z], extent=(nx, ny + 1, nz)[:skip_z], @@ -647,20 +647,20 @@ def calculate_winds_from_streamfunction_grid( if isinstance(u_grid.data, np.ndarray) and isinstance(v_grid.data, np.ndarray): if grid == GridType.AGrid: if not ( - u_grid.metadata.dims == (X_DIM, Y_DIM, Z_DIM) - and v_grid.metadata.dims == (X_DIM, Y_DIM, Z_DIM) + u_grid.metadata.dims == (I_DIM, J_DIM, K_DIM) + and v_grid.metadata.dims == (I_DIM, J_DIM, K_DIM) ): print("Incorrect wind input dimensions for A-grid.") elif grid == GridType.CGrid: if not ( - u_grid.metadata.dims == (X_DIM, Y_INTERFACE_DIM, Z_DIM) - and v_grid.metadata.dims == (X_INTERFACE_DIM, Y_DIM, Z_DIM) + u_grid.metadata.dims == (I_DIM, J_INTERFACE_DIM, K_DIM) + and v_grid.metadata.dims == (I_INTERFACE_DIM, J_DIM, K_DIM) ): print("Incorrect wind input dimensions for C-grid.") elif grid == GridType.DGrid: if not ( - u_grid.metadata.dims == (X_INTERFACE_DIM, Y_DIM, Z_DIM) - and v_grid.metadata.dims == (X_DIM, Y_INTERFACE_DIM, Z_DIM) + u_grid.metadata.dims == (I_INTERFACE_DIM, J_DIM, K_DIM) + and v_grid.metadata.dims == (I_DIM, J_INTERFACE_DIM, K_DIM) ): print("Incorrect wind input dimensions for D-grid.") else: diff --git a/examples/notebooks/serial_debugging.ipynb b/examples/notebooks/serial_debugging.ipynb index ace1a5b4..02a41dea 100644 --- a/examples/notebooks/serial_debugging.ipynb +++ b/examples/notebooks/serial_debugging.ipynb @@ -1,477 +1,477 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "6c0756ec", - "metadata": {}, - "source": [ - "# Serial debugging example\n", - "\n", - "This example shows how you can use write and read comm configurations to save communication data from a mpi-enabled run to disk, and then debug that run in serial inside a jupyter notebook.\n", - "\n", - "This example is being run on April 22nd, 2022. It uses internal, unstable APIs and may not work for future versions of the code." - ] - }, - { - "cell_type": "markdown", - "id": "47acc297", - "metadata": {}, - "source": [ - "First let's import the packages we will use below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee1201d3", - "metadata": {}, - "outputs": [], - "source": [ - "from ndsl.constants import X_DIM, Y_DIM, Z_DIM\n", - "from pace import Driver, DriverConfig\n", - "from pyfv3.stencils import DGrid2AGrid2CGridVectors\n", - "import yaml\n", - "import dacite\n", - "import copy\n", - "import subprocess\n", - "import matplotlib.pyplot as plt # pip install matplotlib" - ] - }, - { - "cell_type": "markdown", - "id": "3f567c84", - "metadata": {}, - "source": [ - "We will base this example on a baroclinic c12 configuration using 6 ranks, but this same code can run with any configuration, even one that was run at scale on an HPC system." - ] - }, - { - "cell_type": "markdown", - "id": "82621ab9", - "metadata": {}, - "source": [ - "## Step 1: writing communication data\n", - "\n", - "First we modify the configuration into one that will write all communications on rank 0 into a directory called \"comm\". This could be modified to write communications for more ranks by adding them to the \"ranks\" list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9ed813d4", - "metadata": {}, - "outputs": [], - "source": [ - "with open(\"../configs/baroclinic_c12.yaml\", \"r\") as f:\n", - " base_config = yaml.safe_load(f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fcfc5d4", - "metadata": {}, - "outputs": [], - "source": [ - "write_config = copy.deepcopy(base_config)\n", - "write_config[\"comm_config\"] = {\n", - " \"type\": \"write\",\n", - " \"config\": {\n", - " \"path\": \"comm\",\n", - " \"ranks\": [0]\n", - " }\n", - "}\n", - "# diagnostics involve communication that interacts with the disk, must be disabled\n", - "write_config.pop(\"diagnostics_config\")\n", - "with open(\"driver_write_config.yaml\", \"w\") as f:\n", - " yaml.dump(write_config, f)" - ] - }, - { - "cell_type": "markdown", - "id": "c798f50c", - "metadata": {}, - "source": [ - "With this configuration written to disk, we run:\n", - "\n", - "```bash\n", - "mpirun -n 6 python3 -m pace.driver.run driver_write_config.yaml\n", - "```\n", - "\n", - "This produces output files in a \"comm\" directory. You could instead run a \"write\" configuration through another method like submitting a batch job to an HPC system. The important part is to recover the \"comm\" directory that gets written by this configuration, so it can be referenced in our read configuration below. Here we see it includes data for rank 0 only." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e428f254", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "ls comm" - ] - }, - { - "cell_type": "markdown", - "id": "b56dfc04", - "metadata": {}, - "source": [ - "## Step 2: reading communication data into a Driver object\n", - "\n", - "We can take the \"write\" configuration and modify its comm config to create a \"read\" configuration. The rank used can be any rank which has data inside the communication cache indicated by the path." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9bd52cf2", - "metadata": {}, - "outputs": [], - "source": [ - "read_config = copy.deepcopy(write_config)\n", - "read_config[\"comm_config\"] = {\n", - " \"type\": \"read\",\n", - " \"config\": {\n", - " \"path\": \"comm\",\n", - " \"rank\": 0\n", - " }\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "7348f957", - "metadata": {}, - "source": [ - "From this configuration, we can create a driver object, and start inspecting its state. Let's take a look at the evolution of the wind and pressure fields over the first two timesteps.\n", - "\n", - "Keep in mind that we will be looking at rank 0, whose y-axis exactly follows latitude lines and x-axis approximately follows longitude lines." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59ada075", - "metadata": {}, - "outputs": [], - "source": [ - "driver = Driver(config=DriverConfig.from_dict(read_config))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7c05df92", - "metadata": {}, - "outputs": [], - "source": [ - "dycore_state = driver.state.dycore_state\n", - "# make a copy of the initial state to do experiments with later\n", - "initial_state = copy.deepcopy(dycore_state)" - ] - }, - { - "cell_type": "markdown", - "id": "3c5e4822", - "metadata": {}, - "source": [ - "We'll also define a plot helper routine to make it easier to quickly inspect different variables, without copying code. We'll look at level 50 of the models' 79 levels, which lies somewhere in the middle of the troposphere." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7600cdee", - "metadata": {}, - "outputs": [], - "source": [ - "def plot(state, varname):\n", - " data = getattr(state, varname)\n", - " # temporary workaround for bug where view goes out-of-sync with storage\n", - " data.view._data = data.storage.data\n", - " plt.figure(figsize=(5, 5))\n", - " # imshow by default puts x on the left and y on the bottom axis, so we transpose\n", - " # view by default selects the compute domain, ignoring halos\n", - " im = plt.imshow(data.view[:, :, 50].T)\n", - " plt.xlabel(\"x\")\n", - " plt.ylabel(\"y\")\n", - " plt.colorbar(im)\n", - " plt.title(f\"{varname} ({data.units})\")" - ] - }, - { - "cell_type": "markdown", - "id": "21cf07ca", - "metadata": {}, - "source": [ - "First we'll look at the initial winds. Notice that for the winds only `u` and `v`, which contain the d-grid covariant winds, have data - this is intentional, as it is the prognostic variable used by the model. The C-grid winds in `uc`/`vc` will be diagnosed from these and then marched forward by half a timestep, before being used to advect the d-grid variables.\n", - "\n", - "This initialization case involves zonally uniform zonal winds with no meridional winds, so it makes sense that `v` is initialized with near-zero values." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "00d9d714", - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "plot(dycore_state, \"u\")\n", - "plot(dycore_state, \"v\")\n", - "plot(dycore_state, \"ua\")\n", - "plot(dycore_state, \"va\")\n", - "plot(dycore_state, \"uc\")\n", - "plot(dycore_state, \"vc\")\n", - "plot(dycore_state, \"delp\")" - ] - }, - { - "cell_type": "markdown", - "id": "46a473bc", - "metadata": {}, - "source": [ - "We can step the model forward by one timestep, and see how this affects the evolution of the model state." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fd1bda0b", - "metadata": {}, - "outputs": [], - "source": [ - "driver.step(timestep=driver.config.timestep)" - ] - }, - { - "cell_type": "markdown", - "id": "1da919ba", - "metadata": {}, - "source": [ - "`u` appears mostly unchanged, since its initial values are quite significant and are most of the signal in the plot. The changes to `v` are quite small." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3ec20047", - "metadata": {}, - "outputs": [], - "source": [ - "plot(dycore_state, \"u\")\n", - "plot(dycore_state, \"v\")" - ] - }, - { - "cell_type": "markdown", - "id": "0a12d6b9", - "metadata": {}, - "source": [ - "The other wind variables now contain their intermediate values used to evolve the model forward. `ua` and `va` contain the contravariant winds defined on the a-grid, in other words the winds in directions perpendicular to finite volume gridcell faces defined on cell centers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d912f43", - "metadata": {}, - "outputs": [], - "source": [ - "plot(dycore_state, \"ua\")\n", - "plot(dycore_state, \"va\")" - ] - }, - { - "cell_type": "markdown", - "id": "7adfb3b2", - "metadata": {}, - "source": [ - "`uc` and `vc` do not make much sense, comparing with the winds above. Note the very small magnitudes (1e-29 scaling on the colorbar). I don't have an explanation - it's likely these variables have been repurposed for a secondary use after they are no longer needed in the model, for memory efficiency reasons. In gt4py and dace we do not need this kind of manual memory optimization, and we are slowly refactoring re-usage of variables over time." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "aabd448a", - "metadata": {}, - "outputs": [], - "source": [ - "plot(dycore_state, \"uc\")\n", - "plot(dycore_state, \"vc\")" - ] - }, - { - "cell_type": "markdown", - "id": "5aa4fcb0", - "metadata": {}, - "source": [ - "And finally, we can see the evolved pressure thickness field." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "77084f49", - "metadata": {}, - "outputs": [], - "source": [ - "plot(dycore_state, \"delp\")" - ] - }, - { - "cell_type": "markdown", - "id": "dfedd87f", - "metadata": {}, - "source": [ - "## Inspecting behavior of an internal component" - ] - }, - { - "cell_type": "markdown", - "id": "c5297e4d", - "metadata": {}, - "source": [ - "The reader-comm driver will play back communications exactly as they occurred when the reference data was created, so we cannot run communication code different from what happened at that time. But we can run code that does not rely on communications. For example, let's look at how the d-grid winds (`u` and `v`) are remapped to a-grid and c-grid winds by `DGrid2AGrid2CGridVectors`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "401fdab2", - "metadata": {}, - "outputs": [], - "source": [ - "d2a2c = DGrid2AGrid2CGridVectors(\n", - " stencil_factory=driver.stencil_factory,\n", - " grid_data=driver.state.grid_data,\n", - " nested=False,\n", - " grid_type=0,\n", - " dord4=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0d5cf970", - "metadata": {}, - "outputs": [], - "source": [ - "remap_state = copy.deepcopy(initial_state)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "61d20a45", - "metadata": {}, - "outputs": [], - "source": [ - "# need temporaries for c-grid contravariant wind multiplied by timestep\n", - "utc = driver.quantity_factory.zeros(dims=[X_DIM, Y_DIM, Z_DIM], units=\"m/s\")\n", - "vtc = driver.quantity_factory.zeros(dims=[X_DIM, Y_DIM, Z_DIM], units=\"m/s\")\n", - "d2a2c(\n", - " uc=remap_state.uc,\n", - " vc=remap_state.vc,\n", - " u=remap_state.u,\n", - " v=remap_state.v,\n", - " ua=remap_state.ua,\n", - " va=remap_state.va,\n", - " utc=utc,\n", - " vtc=vtc\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ff396d96", - "metadata": {}, - "source": [ - "`u`, `ua`, and `uc` all look quite similar, since the magnitude of `u` is large and there is no component from `v` to factor in when converting between covariant and contravariant winds." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a645e6d7", - "metadata": {}, - "outputs": [], - "source": [ - "plot(remap_state, \"u\")\n", - "plot(remap_state, \"ua\")\n", - "plot(remap_state, \"uc\")" - ] - }, - { - "cell_type": "markdown", - "id": "59cc76ff", - "metadata": {}, - "source": [ - "`v` is more interesting. While the initial wind has no projection onto the meridional direction (no covariant component in the meridional direction), it does have a contravariant component along this direction, as we see in `va`, the contravariant y-wind on the a-grid." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e579390", - "metadata": {}, - "outputs": [], - "source": [ - "plot(remap_state, \"v\")\n", - "plot(remap_state, \"va\")" - ] - }, - { - "cell_type": "markdown", - "id": "4361238f", - "metadata": {}, - "source": [ - "`vc` is even more interesting, as it contains the covariant wind on the c-grid, which at y-edges lies on the boundary of two tile faces. At this location, the wind borders on two different coordinate systems, and the covariant wind is not well-defined. Despite the covariant y-wind being zero on the entire tile (including the edge, if we considered only rank 0's coordinate system), it contains non-zero values at the tile edge where it has to consider the coordinate systems of neighboring tiles.\n", - "\n", - "This is one of many examples where the FV3 code contains special logic for handling advection at tile edges." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a2f575f", - "metadata": {}, - "outputs": [], - "source": [ - "plot(remap_state, \"vc\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "91857b67", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 + "cells": [ + { + "cell_type": "markdown", + "id": "6c0756ec", + "metadata": {}, + "source": [ + "# Serial debugging example\n", + "\n", + "This example shows how you can use write and read comm configurations to save communication data from a mpi-enabled run to disk, and then debug that run in serial inside a jupyter notebook.\n", + "\n", + "This example is being run on April 22nd, 2022. It uses internal, unstable APIs and may not work for future versions of the code." + ] + }, + { + "cell_type": "markdown", + "id": "47acc297", + "metadata": {}, + "source": [ + "First let's import the packages we will use below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee1201d3", + "metadata": {}, + "outputs": [], + "source": [ + "from ndsl.constants import I_DIM, J_DIM, K_DIM\n", + "from pace import Driver, DriverConfig\n", + "from pyfv3.stencils import DGrid2AGrid2CGridVectors\n", + "import yaml\n", + "import dacite\n", + "import copy\n", + "import subprocess\n", + "import matplotlib.pyplot as plt # pip install matplotlib" + ] + }, + { + "cell_type": "markdown", + "id": "3f567c84", + "metadata": {}, + "source": [ + "We will base this example on a baroclinic c12 configuration using 6 ranks, but this same code can run with any configuration, even one that was run at scale on an HPC system." + ] + }, + { + "cell_type": "markdown", + "id": "82621ab9", + "metadata": {}, + "source": [ + "## Step 1: writing communication data\n", + "\n", + "First we modify the configuration into one that will write all communications on rank 0 into a directory called \"comm\". This could be modified to write communications for more ranks by adding them to the \"ranks\" list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ed813d4", + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"../configs/baroclinic_c12.yaml\", \"r\") as f:\n", + " base_config = yaml.safe_load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fcfc5d4", + "metadata": {}, + "outputs": [], + "source": [ + "write_config = copy.deepcopy(base_config)\n", + "write_config[\"comm_config\"] = {\n", + " \"type\": \"write\",\n", + " \"config\": {\n", + " \"path\": \"comm\",\n", + " \"ranks\": [0]\n", + " }\n", + "}\n", + "# diagnostics involve communication that interacts with the disk, must be disabled\n", + "write_config.pop(\"diagnostics_config\")\n", + "with open(\"driver_write_config.yaml\", \"w\") as f:\n", + " yaml.dump(write_config, f)" + ] + }, + { + "cell_type": "markdown", + "id": "c798f50c", + "metadata": {}, + "source": [ + "With this configuration written to disk, we run:\n", + "\n", + "```bash\n", + "mpirun -n 6 python3 -m pace.driver.run driver_write_config.yaml\n", + "```\n", + "\n", + "This produces output files in a \"comm\" directory. You could instead run a \"write\" configuration through another method like submitting a batch job to an HPC system. The important part is to recover the \"comm\" directory that gets written by this configuration, so it can be referenced in our read configuration below. Here we see it includes data for rank 0 only." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e428f254", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "ls comm" + ] + }, + { + "cell_type": "markdown", + "id": "b56dfc04", + "metadata": {}, + "source": [ + "## Step 2: reading communication data into a Driver object\n", + "\n", + "We can take the \"write\" configuration and modify its comm config to create a \"read\" configuration. The rank used can be any rank which has data inside the communication cache indicated by the path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bd52cf2", + "metadata": {}, + "outputs": [], + "source": [ + "read_config = copy.deepcopy(write_config)\n", + "read_config[\"comm_config\"] = {\n", + " \"type\": \"read\",\n", + " \"config\": {\n", + " \"path\": \"comm\",\n", + " \"rank\": 0\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "7348f957", + "metadata": {}, + "source": [ + "From this configuration, we can create a driver object, and start inspecting its state. Let's take a look at the evolution of the wind and pressure fields over the first two timesteps.\n", + "\n", + "Keep in mind that we will be looking at rank 0, whose y-axis exactly follows latitude lines and x-axis approximately follows longitude lines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59ada075", + "metadata": {}, + "outputs": [], + "source": [ + "driver = Driver(config=DriverConfig.from_dict(read_config))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c05df92", + "metadata": {}, + "outputs": [], + "source": [ + "dycore_state = driver.state.dycore_state\n", + "# make a copy of the initial state to do experiments with later\n", + "initial_state = copy.deepcopy(dycore_state)" + ] + }, + { + "cell_type": "markdown", + "id": "3c5e4822", + "metadata": {}, + "source": [ + "We'll also define a plot helper routine to make it easier to quickly inspect different variables, without copying code. We'll look at level 50 of the models' 79 levels, which lies somewhere in the middle of the troposphere." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7600cdee", + "metadata": {}, + "outputs": [], + "source": [ + "def plot(state, varname):\n", + " data = getattr(state, varname)\n", + " # temporary workaround for bug where view goes out-of-sync with storage\n", + " data.view._data = data.storage.data\n", + " plt.figure(figsize=(5, 5))\n", + " # imshow by default puts x on the left and y on the bottom axis, so we transpose\n", + " # view by default selects the compute domain, ignoring halos\n", + " im = plt.imshow(data.view[:, :, 50].T)\n", + " plt.xlabel(\"x\")\n", + " plt.ylabel(\"y\")\n", + " plt.colorbar(im)\n", + " plt.title(f\"{varname} ({data.units})\")" + ] + }, + { + "cell_type": "markdown", + "id": "21cf07ca", + "metadata": {}, + "source": [ + "First we'll look at the initial winds. Notice that for the winds only `u` and `v`, which contain the d-grid covariant winds, have data - this is intentional, as it is the prognostic variable used by the model. The C-grid winds in `uc`/`vc` will be diagnosed from these and then marched forward by half a timestep, before being used to advect the d-grid variables.\n", + "\n", + "This initialization case involves zonally uniform zonal winds with no meridional winds, so it makes sense that `v` is initialized with near-zero values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00d9d714", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "plot(dycore_state, \"u\")\n", + "plot(dycore_state, \"v\")\n", + "plot(dycore_state, \"ua\")\n", + "plot(dycore_state, \"va\")\n", + "plot(dycore_state, \"uc\")\n", + "plot(dycore_state, \"vc\")\n", + "plot(dycore_state, \"delp\")" + ] + }, + { + "cell_type": "markdown", + "id": "46a473bc", + "metadata": {}, + "source": [ + "We can step the model forward by one timestep, and see how this affects the evolution of the model state." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd1bda0b", + "metadata": {}, + "outputs": [], + "source": [ + "driver.step(timestep=driver.config.timestep)" + ] + }, + { + "cell_type": "markdown", + "id": "1da919ba", + "metadata": {}, + "source": [ + "`u` appears mostly unchanged, since its initial values are quite significant and are most of the signal in the plot. The changes to `v` are quite small." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ec20047", + "metadata": {}, + "outputs": [], + "source": [ + "plot(dycore_state, \"u\")\n", + "plot(dycore_state, \"v\")" + ] + }, + { + "cell_type": "markdown", + "id": "0a12d6b9", + "metadata": {}, + "source": [ + "The other wind variables now contain their intermediate values used to evolve the model forward. `ua` and `va` contain the contravariant winds defined on the a-grid, in other words the winds in directions perpendicular to finite volume gridcell faces defined on cell centers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d912f43", + "metadata": {}, + "outputs": [], + "source": [ + "plot(dycore_state, \"ua\")\n", + "plot(dycore_state, \"va\")" + ] + }, + { + "cell_type": "markdown", + "id": "7adfb3b2", + "metadata": {}, + "source": [ + "`uc` and `vc` do not make much sense, comparing with the winds above. Note the very small magnitudes (1e-29 scaling on the colorbar). I don't have an explanation - it's likely these variables have been repurposed for a secondary use after they are no longer needed in the model, for memory efficiency reasons. In gt4py and dace we do not need this kind of manual memory optimization, and we are slowly refactoring re-usage of variables over time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aabd448a", + "metadata": {}, + "outputs": [], + "source": [ + "plot(dycore_state, \"uc\")\n", + "plot(dycore_state, \"vc\")" + ] + }, + { + "cell_type": "markdown", + "id": "5aa4fcb0", + "metadata": {}, + "source": [ + "And finally, we can see the evolved pressure thickness field." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77084f49", + "metadata": {}, + "outputs": [], + "source": [ + "plot(dycore_state, \"delp\")" + ] + }, + { + "cell_type": "markdown", + "id": "dfedd87f", + "metadata": {}, + "source": [ + "## Inspecting behavior of an internal component" + ] + }, + { + "cell_type": "markdown", + "id": "c5297e4d", + "metadata": {}, + "source": [ + "The reader-comm driver will play back communications exactly as they occurred when the reference data was created, so we cannot run communication code different from what happened at that time. But we can run code that does not rely on communications. For example, let's look at how the d-grid winds (`u` and `v`) are remapped to a-grid and c-grid winds by `DGrid2AGrid2CGridVectors`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "401fdab2", + "metadata": {}, + "outputs": [], + "source": [ + "d2a2c = DGrid2AGrid2CGridVectors(\n", + " stencil_factory=driver.stencil_factory,\n", + " grid_data=driver.state.grid_data,\n", + " nested=False,\n", + " grid_type=0,\n", + " dord4=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d5cf970", + "metadata": {}, + "outputs": [], + "source": [ + "remap_state = copy.deepcopy(initial_state)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61d20a45", + "metadata": {}, + "outputs": [], + "source": [ + "# need temporaries for c-grid contravariant wind multiplied by timestep\n", + "utc = driver.quantity_factory.zeros(dims=[I_DIM, J_DIM, K_DIM], units=\"m/s\")\n", + "vtc = driver.quantity_factory.zeros(dims=[I_DIM, J_DIM, K_DIM], units=\"m/s\")\n", + "d2a2c(\n", + " uc=remap_state.uc,\n", + " vc=remap_state.vc,\n", + " u=remap_state.u,\n", + " v=remap_state.v,\n", + " ua=remap_state.ua,\n", + " va=remap_state.va,\n", + " utc=utc,\n", + " vtc=vtc\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ff396d96", + "metadata": {}, + "source": [ + "`u`, `ua`, and `uc` all look quite similar, since the magnitude of `u` is large and there is no component from `v` to factor in when converting between covariant and contravariant winds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a645e6d7", + "metadata": {}, + "outputs": [], + "source": [ + "plot(remap_state, \"u\")\n", + "plot(remap_state, \"ua\")\n", + "plot(remap_state, \"uc\")" + ] + }, + { + "cell_type": "markdown", + "id": "59cc76ff", + "metadata": {}, + "source": [ + "`v` is more interesting. While the initial wind has no projection onto the meridional direction (no covariant component in the meridional direction), it does have a contravariant component along this direction, as we see in `va`, the contravariant y-wind on the a-grid." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e579390", + "metadata": {}, + "outputs": [], + "source": [ + "plot(remap_state, \"v\")\n", + "plot(remap_state, \"va\")" + ] + }, + { + "cell_type": "markdown", + "id": "4361238f", + "metadata": {}, + "source": [ + "`vc` is even more interesting, as it contains the covariant wind on the c-grid, which at y-edges lies on the boundary of two tile faces. At this location, the wind borders on two different coordinate systems, and the covariant wind is not well-defined. Despite the covariant y-wind being zero on the entire tile (including the edge, if we considered only rank 0's coordinate system), it contains non-zero values at the tile edge where it has to consider the coordinate systems of neighboring tiles.\n", + "\n", + "This is one of many examples where the FV3 code contains special logic for handling advection at tile edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a2f575f", + "metadata": {}, + "outputs": [], + "source": [ + "plot(remap_state, \"vc\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91857b67", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/examples/notebooks/stencil_definition.ipynb b/examples/notebooks/stencil_definition.ipynb index 1e48b14f..5b71caa6 100644 --- a/examples/notebooks/stencil_definition.ipynb +++ b/examples/notebooks/stencil_definition.ipynb @@ -1,1579 +1,1579 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "559427b6-c6c4-4e98-9ab4-f321f8c4999d", - "metadata": { - "tags": [] - }, - "source": [ - "# Defining, compiling, and running stencils\n", - "\n", - "This notebook demonstrates how stencils can be defined, compiled and executed." - ] - }, - { - "cell_type": "markdown", - "id": "777c9dae-cb6f-49a8-963a-a85031d169af", - "metadata": {}, - "source": [ - "## Configuration\n", - "\n", - "First, let's define the configuration such as the size of the computational domain as well as the number of halo points and the GT4Py backend we are using." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "5e09b7ff-ead1-40da-a79f-9929fd7c9e93", - "metadata": {}, - "outputs": [], - "source": [ - "nx = 20\n", - "ny = 20\n", - "nz = 79\n", - "nhalo = 3\n", - "backend = \"numpy\"" - ] - }, - { - "cell_type": "markdown", - "id": "3acf8ab8-73b5-45f3-9605-6f5929ebdbb3", - "metadata": {}, - "source": [ - "## Stencil definition using GT4Py\n", - "\n", - "Next, we'll define the actual stencil that we want to compile and run. We use the GT4Py domain-specific language (GTScripts) for this. For demonstration purposes, we start with a very simple stencil that simply sets a field to a constant value at every grid cell." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c9d04aed-9513-447a-bae8-3c9719a60d9a", - "metadata": {}, - "outputs": [], - "source": [ - "from ndsl.dsl.gt4py import PARALLEL, computation\n", - "from ndsl.dsl.typing import FloatField\n", - "\n", - "def set_field_to_value_def(f: FloatField, value: float):\n", - " with computation(PARALLEL), interval(...):\n", - " f = value" - ] - }, - { - "cell_type": "markdown", - "id": "e3ff42c6-2fcb-4cbf-af4e-a41d5bbb0c95", - "metadata": { - "tags": [] - }, - "source": [ - "## Setup helpers for building stencils\n", - "\n", - "The `ndsl` package contains provides a helper class for compiling stencils. The helper class is called a stencil factory. In order to setup a stencil factory, several configuration objects have to be defined and passed in.\n", - "\n", - "- `DaceConfig`: configuration of DaCe backend\n", - "- `CompilationConfig`: specification of how to compile\n", - "- `StencilConfig`: wrapper to carry DaCe and compilation configuration\n", - "- `GridIndexing`: helper class which provides indexing (e.g. compute domain and origin)\n", - "- `StencilFactory`: helper class to build stencils from GT4Py stencil definitions" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "108a7b90-178d-461c-b313-cf0f1dcb4b94", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from ndsl import DaceConfig, DaCeOrchestration, GridIndexing, StencilConfig, StencilFactory, CompilationConfig, RunMode\n", - "\n", - "dace_config = DaceConfig(\n", - " communicator=None, backend=backend, orchestration=DaCeOrchestration.Python\n", - ")\n", - "\n", - "compilation_config = CompilationConfig(\n", - " backend=backend,\n", - " rebuild=True,\n", - " validate_args=True,\n", - " format_source=False,\n", - " device_sync=False,\n", - " run_mode=RunMode.BuildAndRun,\n", - " use_minimal_caching=False,\n", - ")\n", - "\n", - "stencil_config = StencilConfig(\n", - " compare_to_numpy=False,\n", - " compilation_config=compilation_config,\n", - " dace_config=dace_config,\n", - ")\n", - "\n", - "grid_indexing = GridIndexing(\n", - " domain=(nx, ny, nz),\n", - " n_halo=nhalo,\n", - " south_edge=True,\n", - " north_edge=True,\n", - " west_edge=True,\n", - " east_edge=True,\n", - ")\n", - "\n", - "stencil_factory = StencilFactory(config=stencil_config, grid_indexing=grid_indexing)" - ] - }, - { - "cell_type": "markdown", - "id": "7d5797e0-b80a-4b27-be30-5d138deda105", - "metadata": {}, - "source": [ - "## Wrap stencil into a Python class\n", - "\n", - "Using the stencil factory we can now wrap the compiled GT4Py stencil into a Python class. The init section is responsible for compiling the stencil, the call section will simply execute the compiled stencil with the arguments passed." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "51a5b99a-3cfc-437d-bf10-a1203499f28c", - "metadata": {}, - "outputs": [], - "source": [ - "from ndsl import StencilFactory\n", - "from ndsl.dsl.typing import FloatField\n", - "\n", - "\n", - "class SetFieldToValue:\n", - " def __init__(self, stencil_factory: StencilFactory):\n", - " grid_indexing = stencil_factory.grid_indexing\n", - " self._set_field_to_value_stencil = stencil_factory.from_origin_domain(\n", - " set_field_to_value_def,\n", - " origin=grid_indexing.origin_compute(),\n", - " domain=grid_indexing.domain_compute(),\n", - " )\n", - "\n", - " def __call__(\n", - " self,\n", - " f: FloatField,\n", - " value: float,\n", - " ):\n", - " self._set_field_to_value_stencil(f, value)" - ] - }, - { - "cell_type": "markdown", - "id": "cb397fe7-9ae0-46c0-8056-d35cde629a4b", - "metadata": {}, - "source": [ - "## Compiling and running the stencil\n", - "\n", - "To compile and run the stencil we first have to instanciate the wrapper class. This will compile the stencil and return a callable object. Next we have to define a GT4Py data storage (field). This could also be done using the `ndsl.quantity.Quantity` class, but here we use plain GT4Py data storages for simplicity. Finally, we can call the stencil and pass in the field and value." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "c27da0c5-bf57-4196-83be-65b32cfccbf9", - "metadata": {}, - "outputs": [], - "source": [ - "set_field_to_value = SetFieldToValue(stencil_factory)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "b545d4e6-a98f-440f-ab46-be2f9c182c31", - "metadata": {}, - "outputs": [], - "source": [ - "import gt4py.storage as gt_storage\n", - "\n", - "field = gt_storage.zeros(\n", - " backend=backend,\n", - " dtype=float,\n", - " shape=(nx + 2 * nhalo, ny + 2 * nhalo, nz),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "e993525f-fe88-42e0-823a-9712539621a5", - "metadata": {}, - "outputs": [], - "source": [ - "value = 42.0\n", - "set_field_to_value(field, value)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "a8ddf9b5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Min and max values: 42.0 0.0\n" - ] + "cells": [ + { + "cell_type": "markdown", + "id": "559427b6-c6c4-4e98-9ab4-f321f8c4999d", + "metadata": { + "tags": [] + }, + "source": [ + "# Defining, compiling, and running stencils\n", + "\n", + "This notebook demonstrates how stencils can be defined, compiled and executed." + ] + }, + { + "cell_type": "markdown", + "id": "777c9dae-cb6f-49a8-963a-a85031d169af", + "metadata": {}, + "source": [ + "## Configuration\n", + "\n", + "First, let's define the configuration such as the size of the computational domain as well as the number of halo points and the GT4Py backend we are using." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5e09b7ff-ead1-40da-a79f-9929fd7c9e93", + "metadata": {}, + "outputs": [], + "source": [ + "nx = 20\n", + "ny = 20\n", + "nz = 79\n", + "nhalo = 3\n", + "backend = \"numpy\"" + ] + }, + { + "cell_type": "markdown", + "id": "3acf8ab8-73b5-45f3-9605-6f5929ebdbb3", + "metadata": {}, + "source": [ + "## Stencil definition using GT4Py\n", + "\n", + "Next, we'll define the actual stencil that we want to compile and run. We use the GT4Py domain-specific language (GTScripts) for this. For demonstration purposes, we start with a very simple stencil that simply sets a field to a constant value at every grid cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9d04aed-9513-447a-bae8-3c9719a60d9a", + "metadata": {}, + "outputs": [], + "source": [ + "from ndsl.dsl.gt4py import PARALLEL, computation\n", + "from ndsl.dsl.typing import FloatField\n", + "\n", + "def set_field_to_value_def(f: FloatField, value: float):\n", + " with computation(PARALLEL), interval(...):\n", + " f = value" + ] + }, + { + "cell_type": "markdown", + "id": "e3ff42c6-2fcb-4cbf-af4e-a41d5bbb0c95", + "metadata": { + "tags": [] + }, + "source": [ + "## Setup helpers for building stencils\n", + "\n", + "The `ndsl` package contains provides a helper class for compiling stencils. The helper class is called a stencil factory. In order to setup a stencil factory, several configuration objects have to be defined and passed in.\n", + "\n", + "- `DaceConfig`: configuration of DaCe backend\n", + "- `CompilationConfig`: specification of how to compile\n", + "- `StencilConfig`: wrapper to carry DaCe and compilation configuration\n", + "- `GridIndexing`: helper class which provides indexing (e.g. compute domain and origin)\n", + "- `StencilFactory`: helper class to build stencils from GT4Py stencil definitions" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "108a7b90-178d-461c-b313-cf0f1dcb4b94", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from ndsl import DaceConfig, DaCeOrchestration, GridIndexing, StencilConfig, StencilFactory, CompilationConfig, RunMode\n", + "\n", + "dace_config = DaceConfig(\n", + " communicator=None, backend=backend, orchestration=DaCeOrchestration.Python\n", + ")\n", + "\n", + "compilation_config = CompilationConfig(\n", + " backend=backend,\n", + " rebuild=True,\n", + " validate_args=True,\n", + " format_source=False,\n", + " device_sync=False,\n", + " run_mode=RunMode.BuildAndRun,\n", + " use_minimal_caching=False,\n", + ")\n", + "\n", + "stencil_config = StencilConfig(\n", + " compare_to_numpy=False,\n", + " compilation_config=compilation_config,\n", + " dace_config=dace_config,\n", + ")\n", + "\n", + "grid_indexing = GridIndexing(\n", + " domain=(nx, ny, nz),\n", + " n_halo=nhalo,\n", + " south_edge=True,\n", + " north_edge=True,\n", + " west_edge=True,\n", + " east_edge=True,\n", + ")\n", + "\n", + "stencil_factory = StencilFactory(config=stencil_config, grid_indexing=grid_indexing)" + ] + }, + { + "cell_type": "markdown", + "id": "7d5797e0-b80a-4b27-be30-5d138deda105", + "metadata": {}, + "source": [ + "## Wrap stencil into a Python class\n", + "\n", + "Using the stencil factory we can now wrap the compiled GT4Py stencil into a Python class. The init section is responsible for compiling the stencil, the call section will simply execute the compiled stencil with the arguments passed." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "51a5b99a-3cfc-437d-bf10-a1203499f28c", + "metadata": {}, + "outputs": [], + "source": [ + "from ndsl import StencilFactory\n", + "from ndsl.dsl.typing import FloatField\n", + "\n", + "\n", + "class SetFieldToValue:\n", + " def __init__(self, stencil_factory: StencilFactory):\n", + " grid_indexing = stencil_factory.grid_indexing\n", + " self._set_field_to_value_stencil = stencil_factory.from_origin_domain(\n", + " set_field_to_value_def,\n", + " origin=grid_indexing.origin_compute(),\n", + " domain=grid_indexing.domain_compute(),\n", + " )\n", + "\n", + " def __call__(\n", + " self,\n", + " f: FloatField,\n", + " value: float,\n", + " ):\n", + " self._set_field_to_value_stencil(f, value)" + ] + }, + { + "cell_type": "markdown", + "id": "cb397fe7-9ae0-46c0-8056-d35cde629a4b", + "metadata": {}, + "source": [ + "## Compiling and running the stencil\n", + "\n", + "To compile and run the stencil we first have to instanciate the wrapper class. This will compile the stencil and return a callable object. Next we have to define a GT4Py data storage (field). This could also be done using the `ndsl.quantity.Quantity` class, but here we use plain GT4Py data storages for simplicity. Finally, we can call the stencil and pass in the field and value." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c27da0c5-bf57-4196-83be-65b32cfccbf9", + "metadata": {}, + "outputs": [], + "source": [ + "set_field_to_value = SetFieldToValue(stencil_factory)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b545d4e6-a98f-440f-ab46-be2f9c182c31", + "metadata": {}, + "outputs": [], + "source": [ + "import gt4py.storage as gt_storage\n", + "\n", + "field = gt_storage.zeros(\n", + " backend=backend,\n", + " dtype=float,\n", + " shape=(nx + 2 * nhalo, ny + 2 * nhalo, nz),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e993525f-fe88-42e0-823a-9712539621a5", + "metadata": {}, + "outputs": [], + "source": [ + "value = 42.0\n", + "set_field_to_value(field, value)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a8ddf9b5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Min and max values: 42.0 0.0\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgIAAAGzCAYAAABdO3+BAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA4KklEQVR4nO3df1zV9d3/8edR4YAKxwD5lUj4I/EXdl3+INKMxERqTpOaWtvUmc6FXVPXLLby11qUu1auXYhtc5AVpbbU5a50aopzE690c9ZWTLkoMQWXuwDFQMb5fP9wnG8nUD6Hc4DjOY/77fa+jfP+/Hqfz06e13m9f3wshmEYAgAAfqlLZzcAAAB0HgIBAAD8GIEAAAB+jEAAAAA/RiAAAIAfIxAAAMCPEQgAAODHCAQAAPBjBAIAAPgxAgG0u48++kgWi0UFBQUuH7t//35ZLBbt37+/1X1TU1OVmprq8jXgzJV7DuD6RyAAtxUUFMhisbRYHn/88c5uXrt6+umntW3bNlP7njlzRitXrtSxY8fatU2+5K677pLFYtGiRYuc6svLy7Vq1SqNGTNGN9xwgyIiIpSamqo9e/aYPrfdbteaNWuUkJCgoKAgJSUl6bXXXvP0WwC8XrfObgB8x+rVq5WQkOBUN2zYMMXHx+uzzz5TQEBAJ7Ws/Tz99NO67777NG3atFb3PXPmjFatWqWbbrpJt9xyS7u37Xr35ptv6tChQy1u2759u5599llNmzZNs2fP1j//+U9t3LhRd911l375y19q7ty5rZ7/+9//vp555hnNnz9fo0eP1vbt2/XAAw/IYrFo5syZnn47gNciEIDHZGRkaNSoUS1uCwoK6uDW4HpWV1en73znO3rssce0fPnyZtvvvPNOnTp1ShEREY66hQsX6pZbbtHy5ctbDQQ++eQT/fjHP1ZWVpb+67/+S5L00EMP6Y477tB3v/td3X///eratatn3xTgpegaQLu72hiBDz/8UPfdd5/CwsIUFBSkUaNG6de//rWpc/7sZz9T//79FRwcrDFjxuh3v/ud6fbs3r1b48aNU69evdSzZ08NGjRI3/ve95z2qa+v14oVKzRgwABZrVbFxcVp2bJlqq+vd+xjsVhUW1url156ydEVMmfOnBavuX//fo0ePVqSNHfuXMf+n78nW7Zs0ciRIxUcHKyIiAh99atf1SeffHLN93LkyBFZLBa99NJLzbbt2rVLFotFO3bskCR9/PHHevjhhzVo0CAFBwcrPDxc999/vz766KNW79lNN93U4ntraVyGmXvXmjVr1shut+vRRx9tcfvQoUOdggBJslqtuvvuu3X69GlduHDhmuffvn27Ghoa9PDDDzvqLBaLvvWtb+n06dNXzUQAvoiMADymurpan376qVPdF/+xbvKXv/xFY8eO1Y033qjHH39cPXr00ObNmzVt2jT96le/0r333nvV62zYsEHf/OY3ddttt2nx4sX63//9X335y19WWFiY4uLirtnGv/zlL/rSl76kpKQkrV69WlarVSdPntTvf/97xz52u11f/vKXdfDgQS1YsECDBw/We++9p+eff15/+9vfHGMCXn75ZT300EMaM2aMFixYIEnq379/i9cdPHiwVq9ereXLl2vBggW6/fbbJUm33XabpCvjLObOnavRo0crJydHlZWV+slPfqLf//73+tOf/qRevXq1eN5Ro0apX79+2rx5s2bPnu20bdOmTbrhhhuUnp4uSXr33Xf1hz/8QTNnzlSfPn300UcfKS8vT6mpqfrrX/+q7t27X/PemWH23l3LqVOn9Mwzz+iXv/ylgoODXbp+RUWFunfv3up7+dOf/qQePXpo8ODBTvVjxoxxbB83bpxL1wauWwbgpvz8fENSi8UwDKOsrMyQZOTn5zuOSUtLM4YPH27U1dU56ux2u3HbbbcZAwcOdNTt27fPkGTs27fPMAzDuHz5shEZGWnccsstRn19vWO/n/3sZ4Yk44477rhmW59//nlDkvH3v//9qvu8/PLLRpcuXYzf/e53TvXr1683JBm///3vHXU9evQwZs+efc1rNnn33Xeb3YfPv6dhw4YZn332maN+x44dhiRj+fLl1zxvdna2ERAQYPzjH/9w1NXX1xu9evUyvvGNbzjqLl261OzYQ4cOGZKMjRs3Ouq+eM8NwzDi4+NbfJ933HGH0z135d5dzX333WfcdtttjteSjKysrFaPO3HihBEUFGR87Wtfa3Xfe+65x+jXr1+z+traWkOS8fjjj7d6DsBX0DUAj8nNzdXu3budSkv+8Y9/6J133tFXvvIVXbhwQZ9++qk+/fRTnT9/Xunp6Tpx4sRVU+JHjhzRuXPntHDhQgUGBjrq58yZI5vN1mobm35Zb9++XXa7vcV9tmzZosGDBysxMdHRtk8//VQTJkyQJO3bt6/V67ii6T09/PDDTmMp7rnnHiUmJuo3v/nNNY+fMWOGGhoa9Oabbzrqfvvb36qqqkozZsxw1H3+13VDQ4POnz+vAQMGqFevXvrjH//okffi7r3bt2+ffvWrX2nt2rUuXffSpUu6//77FRwcrGeeeabV/T/77DNZrdZm9U33/7PPPnPp+sD1jK4BeMyYMWOuOljw806ePCnDMPTkk0/qySefbHGfc+fO6cYbb2xW//HHH0uSBg4c6FQfEBCgfv36tXrtGTNm6Be/+IUeeughPf7440pLS9P06dN13333qUuXK3HxiRMn9MEHH6h3795XbZsnNb2nQYMGNduWmJiogwcPXvP4ESNGKDExUZs2bdK8efMkXekWiIiIcHwBS1e+3HJycpSfn69PPvlEhmE4tlVXV3virbh17/75z3/qP/7jP/S1r33NMZ7CjMbGRs2cOVN//etf9fbbbys2NrbVY4KDg1scs1BXV+fYDvgLAgF0uKZf4o8++qij//qLBgwY0C7XDg4O1oEDB7Rv3z795je/0c6dO7Vp0yZNmDBBv/3tb9W1a1fZ7XYNHz5czz33XIvnaG0cQmeYMWOGfvjDH+rTTz9VSEiIfv3rX2vWrFnq1u3//yf+yCOPKD8/X4sXL1ZKSopsNptjqtzVsiNNLBZLi/WNjY1Oo+vduXcbN25USUmJXnzxxWYDGC9cuKCPPvpIkZGRzfr/58+frx07dujVV191CnyuJSYmRvv27ZNhGE7v7ezZs5JkKpgAfAWBADpc0y/3gIAATZw40aVj4+PjJV355fn5f/QbGhpUVlamESNGtHqOLl26KC0tTWlpaXruuef09NNP6/vf/7727duniRMnqn///vrzn/+stLS0q34BNmltu5l9m95TSUlJsy+ykpISx/ZrmTFjhlatWqVf/epXioqKUk1NTbO58G+88YZmz56tH//4x466uro6VVVVtXr+G264ocX9Pv74Y6dMjCv37otOnTqlhoYGjR07ttm2jRs3auPGjdq6davTmg3f/e53lZ+fr7Vr12rWrFmmr3XLLbfoF7/4hT744AMNGTLEUX/48GHHdsBfMEYAHS4yMlKpqal68cUXHb/APu/vf//7VY8dNWqUevfurfXr1+vy5cuO+oKCAlNfaP/4xz+a1TX9o9+UKv7KV76iTz75RD//+c+b7fvZZ5+ptrbW8bpHjx6mrtu0r6Rm+48aNUqRkZFav369U7r67bff1gcffKB77rmn1XMPHjxYw4cP16ZNm7Rp0ybFxMRo/PjxTvt07drVqTtAkn7605+qsbGx1fP3799fxcXFTvd8x44dKi8vd9rPlXv3RTNnztTWrVubFUm6++67tXXrViUnJzv2/9GPfqT//M//1Pe+9z19+9vfvup5q6ur9eGHHzp1f0ydOlUBAQFat26do84wDK1fv1433nijYzYH4A/ICKBT5Obmaty4cRo+fLjmz5+vfv36qbKyUocOHdLp06f15z//ucXjAgIC9NRTT+mb3/ymJkyYoBkzZqisrEz5+fmmxgisXr1aBw4c0D333KP4+HidO3dO69atU58+fRzTxb72ta9p8+bNWrhwofbt26exY8eqsbFRH374oTZv3qxdu3Y5xkKMHDlSe/bs0XPPPafY2FglJCQ4fVl9Xv/+/dWrVy+tX79eISEh6tGjh5KTk5WQkKBnn31Wc+fO1R133KFZs2Y5pg/edNNNWrJkial7OmPGDC1fvlxBQUGaN2+eY8xDky996Ut6+eWXZbPZNGTIEB06dEh79uxReHh4q+d+6KGH9MYbb2jy5Mn6yle+otLSUr3yyivNpku6cu++KDExUYmJiS1uS0hIcMoEbN26VcuWLdPAgQM1ePBgvfLKK07733XXXYqKinLsO3fuXOXn5zvWQujTp48WL16sH/3oR2poaNDo0aO1bds2/e53v9Orr77KYkLwL506ZwE+oWn64Lvvvtvi9pamDxqGYZSWlhpf//rXjejoaCMgIMC48cYbjS996UvGG2+84dinpalshmEY69atMxISEgyr1WqMGjXKOHDgQLOpbC3Zu3evMXXqVCM2NtYIDAw0YmNjjVmzZhl/+9vfnPa7fPmy8eyzzxpDhw41rFarccMNNxgjR440Vq1aZVRXVzv2+/DDD43x48cbwcHBhqRWpxJu377dGDJkiNGtW7dm92TTpk3Gv/3bvxlWq9UICwszHnzwQeP06dPXPN/nnThxwjFt8+DBg822/9///Z8xd+5cIyIiwujZs6eRnp5ufPjhh82mBl7tnv/4xz82brzxRsNqtRpjx441jhw50uI9N3vvzFIL0wdXrFhx1SmrX2x70+fzi5+/xsZG4+mnnzbi4+ONwMBAY+jQocYrr7zicvuA653FML6QKwQAAH6DMQIAAPgxAgEAAPwYgQAAAH6MQAAAAD9GIAAAgB8jEAAAwI953YJCdrtdZ86cUUhIiMtLlAIA/IthGLpw4YJiY2ObLaLlSXV1dU4ra7ZVYGCg01NGvYHXBQJnzpzxyoe6AAC8V3l5ufr06dMu566rq1NCfE9VnGt9Oe7WREdHq6yszKuCAa8LBEJCQiRJ43S3uimgk1sDAPBm/1SDDuq/Hd8d7eHy5cuqONeosqPxCg1pe9ah5oJdCSM/1uXLlwkErqWpO6CbAtTNQiAAALiGf62N2xFdyaEhXdwKBLyV1wUCAAB4o0bDrkY3FuVvNOyea4wHEQgAAGCCXYbsansk4M6x7YlAAAAAE+yyy53f9O4d3X58r7MDAACYRkYAAAATGg1DjUbb0/vuHNueCAQAADDBV8cI0DUAAIAfcykQyMnJ0ejRoxUSEqLIyEhNmzZNJSUlTvukpqbKYrE4lYULF3q00QAAdDS7DDW6UXwiI1BUVKSsrCwVFxdr9+7damho0KRJk1RbW+u03/z583X27FlHWbNmjUcbDQBAR2vqGnCneCOXxgjs3LnT6XVBQYEiIyN19OhRjR8/3lHfvXt3RUdHe6aFAACg3bg1RqC6ulqSFBYW5lT/6quvKiIiQsOGDVN2drYuXbp01XPU19erpqbGqQAA4G2aZg24U9zxzDPPyGKxaPHixY66uro6ZWVlKTw8XD179lRmZqYqKytdOm+bAwG73a7Fixdr7NixGjZsmKP+gQce0CuvvKJ9+/YpOztbL7/8sr761a9e9Tw5OTmy2WyOwpMHAQDeyO6B0lbvvvuuXnzxRSUlJTnVL1myRG+99Za2bNmioqIinTlzRtOnT3fp3G2ePpiVlaX3339fBw8edKpfsGCB4+/hw4crJiZGaWlpKi0tVf/+/ZudJzs7W0uXLnW8rqmpIRgAAOBfLl68qAcffFA///nP9dRTTznqq6urtWHDBhUWFmrChAmSpPz8fA0ePFjFxcW69dZbTZ2/TRmBRYsWaceOHdq3b1+rz39OTk6WJJ08ebLF7VarVaGhoU4FAABv486MgaYiqVl3eH19/TWvm5WVpXvuuUcTJ050qj969KgaGhqc6hMTE9W3b18dOnTI9PtyKRAwDEOLFi3S1q1b9c477yghIaHVY44dOyZJiomJceVSAAB4lUbD/SJJcXFxTl3iOTk5V73m66+/rj/+8Y8t7lNRUaHAwED16tXLqT4qKkoVFRWm35dLXQNZWVkqLCzU9u3bFRIS4riQzWZTcHCwSktLVVhYqLvvvlvh4eE6fvy4lixZovHjxzfr1wAA4Hribj9/07Hl5eVO2W+r1dri/uXl5fr2t7+t3bt3KygoyI0rX5tLGYG8vDxVV1crNTVVMTExjrJp0yZJUmBgoPbs2aNJkyYpMTFR3/nOd5SZmam33nqrXRoPAMD15ovd4VcLBI4ePapz587p3//939WtWzd169ZNRUVFeuGFF9StWzdFRUXp8uXLqqqqcjqusrLSpSn8LmUEjFamPsTFxamoqMiVUwIAcF2wy6JGWdw63hVpaWl67733nOrmzp2rxMREPfbYY4qLi1NAQID27t2rzMxMSVJJSYlOnTqllJQU09fhoUMAAJhgN64Ud453RUhIiNP0fEnq0aOHwsPDHfXz5s3T0qVLFRYWptDQUD3yyCNKSUkxPWNAIhAAAOC69fzzz6tLly7KzMxUfX290tPTtW7dOpfOQSAAAIAJjW52DbhzbJP9+/c7vQ4KClJubq5yc3PbfE4CAQAATPCGQKA9uPWsAQAAcH0jIwAAgAl2wyK74casATeObU8EAgAAmEDXAAAA8DlkBAAAMKFRXdToxu/nRg+2xZMIBAAAMMFwc4yAwRgBAACuX4wRAAAAPoeMAAAAJjQaXdRouDFGwI3nFLQnAgEAAEywyyK7G4l0u7wzEqBrAAAAP0ZGAAAAE3x1sCCBAAAAJrg/RoCuAQAA4GXICAAAYMKVwYJuPHSIrgEAAK5fdjeXGGbWAAAA8DpkBDxo15k/d3YTAKDN0mNHdHYTvJqvDhYkEAAAwAS7uvjkgkIEAgAAmNBoWNToxhME3Tm2PTFGAAAAP0ZGAAAAExrdnDXQSNcAAADXL7vRRXY3BgvavXSwIF0DAAD4MTICAACYQNcAAAB+zC73Rv7bPdcUj6JrAAAAP0ZGAAAAE9xfUMg7f3sTCAAAYIL7Swx7ZyDgna0CAAAdgowAAAAm2GWRXe4MFvTOJYYJBAAAMIGuAQAA/FjTOgLuFFfk5eUpKSlJoaGhCg0NVUpKit5++23H9tTUVFksFqeycOFCl98XGQEAALxQnz599Mwzz2jgwIEyDEMvvfSSpk6dqj/96U8aOnSoJGn+/PlavXq145ju3bu7fB0CAQAATLAbFtndWVDIxWOnTJni9PqHP/yh8vLyVFxc7AgEunfvrujo6Da3SaJrAAAAU+xudgs0rSNQU1PjVOrr61u9dmNjo15//XXV1tYqJSXFUf/qq68qIiJCw4YNU3Z2ti5duuTy+yIjAABAB4qLi3N6vWLFCq1cubLFfd977z2lpKSorq5OPXv21NatWzVkyBBJ0gMPPKD4+HjFxsbq+PHjeuyxx1RSUqI333zTpfYQCAAAYIL7jyG+cmx5eblCQ0Md9Var9arHDBo0SMeOHVN1dbXeeOMNzZ49W0VFRRoyZIgWLFjg2G/48OGKiYlRWlqaSktL1b9/f9PtIhAAAMCERlnU6MZaAE3HNs0CMCMwMFADBgyQJI0cOVLvvvuufvKTn+jFF19stm9ycrIk6eTJky4FAowRAADgOmG32686puDYsWOSpJiYGJfOSUYAAAATPNU1YFZ2drYyMjLUt29fXbhwQYWFhdq/f7927dql0tJSFRYW6u6771Z4eLiOHz+uJUuWaPz48UpKSnLpOgQCAACY0Ci52TXgmnPnzunrX/+6zp49K5vNpqSkJO3atUt33XWXysvLtWfPHq1du1a1tbWKi4tTZmamnnjiCZfbRSAAAIAX2rBhw1W3xcXFqaioyCPXIRAAAMCEju4a6CgEAgAAmOCrDx0iEAAAwATDzccQG176GGLvDE8AAECHICMAAIAJdA0AAODHOvrpgx3FO8MTAADQIcgIAABgQtPjhN053hsRCAAAYAJdAwAAwOeQEQAAwAS7usjuxu9nd45tTwQCAACY0GhY1OhGet+dY9uTd4YnAACgQ7gUCOTk5Gj06NEKCQlRZGSkpk2bppKSEqd96urqlJWVpfDwcPXs2VOZmZmqrKz0aKMBAOhoTYMF3SneyKVAoKioSFlZWSouLtbu3bvV0NCgSZMmqba21rHPkiVL9NZbb2nLli0qKirSmTNnNH36dI83HACAjmT86+mDbS2GL6wsuHPnTqfXBQUFioyM1NGjRzV+/HhVV1drw4YNKiws1IQJEyRJ+fn5Gjx4sIqLi3Xrrbd6ruUAAHSgRlnU6MaDg9w5tj25FZ5UV1dLksLCwiRJR48eVUNDgyZOnOjYJzExUX379tWhQ4daPEd9fb1qamqcCgAA6BhtDgTsdrsWL16ssWPHatiwYZKkiooKBQYGqlevXk77RkVFqaKiosXz5OTkyGazOUpcXFxbmwQAQLuxG+6OE+jsd9CyNgcCWVlZev/99/X666+71YDs7GxVV1c7Snl5uVvnAwCgPbgzPqCpeKM2rSOwaNEi7dixQwcOHFCfPn0c9dHR0bp8+bKqqqqcsgKVlZWKjo5u8VxWq1VWq7UtzQAAAG5yKTwxDEOLFi3S1q1b9c477yghIcFp+8iRIxUQEKC9e/c66kpKSnTq1CmlpKR4psUAAHQCuyxuF2/kUkYgKytLhYWF2r59u0JCQhz9/jabTcHBwbLZbJo3b56WLl2qsLAwhYaG6pFHHlFKSgozBgAA1zVfXVnQpUAgLy9PkpSamupUn5+frzlz5kiSnn/+eXXp0kWZmZmqr69Xenq61q1b55HGAgAAz3IpEDCM1oc8BgUFKTc3V7m5uW1uFAAA3sbdAX8+NVgQAAB/Y5d7ywR76xgB7wxPAABAhyAjAACACYabI/8NL80IEAgAAGCCu08Q9NanDxIIAABggq8OFvTOVgEAgA5BRgAAABPoGgAAwI+5u0ww0wcBAIDXIRAAAMCEpq4Bd4or8vLylJSUpNDQUIWGhiolJUVvv/22Y3tdXZ2ysrIUHh6unj17KjMzU5WVlS6/LwIBAABM6OhAoE+fPnrmmWd09OhRHTlyRBMmTNDUqVP1l7/8RZK0ZMkSvfXWW9qyZYuKiop05swZTZ8+3eX3xRgBAAC80JQpU5xe//CHP1ReXp6Ki4vVp08fbdiwQYWFhZowYYKkKw8AHDx4sIqLi1164i+BAAAAJnhq1kBNTY1TvdVqldVqveaxjY2N2rJli2pra5WSkqKjR4+qoaFBEydOdOyTmJiovn376tChQy4FAnQNAABggqe6BuLi4mSz2RwlJyfnqtd877331LNnT1mtVi1cuFBbt27VkCFDVFFRocDAQPXq1ctp/6ioKFVUVLj0vsgIAADQgcrLyxUaGup4fa1swKBBg3Ts2DFVV1frjTfe0OzZs1VUVOTR9hAIAABggiH31gIw/vW/TbMAzAgMDNSAAQMkSSNHjtS7776rn/zkJ5oxY4YuX76sqqoqp6xAZWWloqOjXWoXXQMAAJjQ0bMGWmyD3a76+nqNHDlSAQEB2rt3r2NbSUmJTp06pZSUFJfOSUYAAAATOnqJ4ezsbGVkZKhv3766cOGCCgsLtX//fu3atUs2m03z5s3T0qVLFRYWptDQUD3yyCNKSUlxaaCgRCAAAIBXOnfunL7+9a/r7NmzstlsSkpK0q5du3TXXXdJkp5//nl16dJFmZmZqq+vV3p6utatW+fydQgEAAAwoaMzAhs2bLjm9qCgIOXm5io3N7fNbZIIBAAAMMVXnz7IYEEAAPwYGQEAAEwwDIsMN37Vu3NseyIQAADABLssbq0j4M6x7YmuAQAA/BgZAQAATPDVwYIEAgAAmOCrYwToGgAAwI+REQAAwAS6BgAA8GO+2jVAIAAAgAmGmxkBbw0EGCMAAIAfIyMAAIAJhiTDcO94b0QgAACACXZZZGFlQQAA4EvICAAAYAKzBgAA8GN2wyKLD64jQNcAAAB+jIwAAAAmGIabswa8dNoAgQAAACb46hgBugYAAPBjZAQAADDBVzMCBAIAAJjgq7MGCAQAADDBVwcLMkYAAAA/RkYAAAATrmQE3Bkj4MHGeBCBAAAAJvjqYEG6BgAA8GNkBAAAMMH4V3HneG9EIAAAgAl0DQAAAJ9DRgAAADN8tG+AQAAAADPc7BoQXQMAAFy/mlYWdKe4IicnR6NHj1ZISIgiIyM1bdo0lZSUOO2Tmpoqi8XiVBYuXOjSdQgEAADwQkVFRcrKylJxcbF2796thoYGTZo0SbW1tU77zZ8/X2fPnnWUNWvWuHQdugYAADCho2cN7Ny50+l1QUGBIiMjdfToUY0fP95R3717d0VHR7e5XWQEAAAww7C4XyTV1NQ4lfr6elOXr66uliSFhYU51b/66quKiIjQsGHDlJ2drUuXLrn0tsgIAADQgeLi4pxer1ixQitXrrzmMXa7XYsXL9bYsWM1bNgwR/0DDzyg+Ph4xcbG6vjx43rsscdUUlKiN99803R7CAQAADDBU48hLi8vV2hoqKPearW2emxWVpbef/99HTx40Kl+wYIFjr+HDx+umJgYpaWlqbS0VP379zfVLgIBAADM8NA6AqGhoU6BQGsWLVqkHTt26MCBA+rTp881901OTpYknTx50nQg4PIYgQMHDmjKlCmKjY2VxWLRtm3bnLbPmTOn2VSGyZMnu3oZAAD8mmEYWrRokbZu3ap33nlHCQkJrR5z7NgxSVJMTIzp67icEaitrdWIESP0jW98Q9OnT29xn8mTJys/P9/x2kzaAwAAb9bRswaysrJUWFio7du3KyQkRBUVFZIkm82m4OBglZaWqrCwUHfffbfCw8N1/PhxLVmyROPHj1dSUpLp67gcCGRkZCgjI+Oa+1itVremMgAA4JU6cJngvLw8SVcWDfq8/Px8zZkzR4GBgdqzZ4/Wrl2r2tpaxcXFKTMzU0888YRL12mXMQL79+9XZGSkbrjhBk2YMEFPPfWUwsPDW9y3vr7eaepETU1NezQJAIDritHKyMS4uDgVFRW5fR2PryMwefJkbdy4UXv37tWzzz6roqIiZWRkqLGxscX9c3JyZLPZHOWL0yoAAPAGTV0D7hRv5PGMwMyZMx1/Dx8+XElJSerfv7/279+vtLS0ZvtnZ2dr6dKljtc1NTUEAwAA7+OjTx9s95UF+/Xrp4iICJ08ebLF7Var1TGVwtUpFQAAdByLB4r3afdA4PTp0zp//rxLUxkAAEDHcLlr4OLFi06/7svKynTs2DGFhYUpLCxMq1atUmZmpqKjo1VaWqply5ZpwIABSk9P92jDAQDoUD7aNeByIHDkyBHdeeedjtdN/fuzZ89WXl6ejh8/rpdeeklVVVWKjY3VpEmT9IMf/IC1BAAA1zcCgStSU1OvOaVh165dbjUIAAB0HJ41AACAGZ97lHCbj/dCBAIAAJjgqacPept2nzUAAAC8FxkBAADMYLAgAAB+zEfHCNA1AACAHyMjAACACRbjSnHneG9EIAAAgBmMEQAAwI8xRgAAAPgaMgIAAJhB1wAAAH7MRwMBugYAAPBjZAQAADDDRzMCBAIAAJjBrAEAAOBryAgAAGACKwsCAODPfHSMAF0DAAD4MQIBAAD8GF0DAACYYJGbYwQ81hLPIhAAAMAMpg8CAABfQ0YAAAAzfHTWAIEAAABm+GggQNcAAAB+jEAAAAATmlYWdKe4IicnR6NHj1ZISIgiIyM1bdo0lZSUOO1TV1enrKwshYeHq2fPnsrMzFRlZaVL1yEQAADADMMDxQVFRUXKyspScXGxdu/erYaGBk2aNEm1tbWOfZYsWaK33npLW7ZsUVFRkc6cOaPp06e7dB3GCAAA4IV27tzp9LqgoECRkZE6evSoxo8fr+rqam3YsEGFhYWaMGGCJCk/P1+DBw9WcXGxbr31VlPXISMAAIAZHsoI1NTUOJX6+npTl6+urpYkhYWFSZKOHj2qhoYGTZw40bFPYmKi+vbtq0OHDpl+WwQCAACY4KkxAnFxcbLZbI6Sk5PT6rXtdrsWL16ssWPHatiwYZKkiooKBQYGqlevXk77RkVFqaKiwvT7omsAAIAOVF5ertDQUMdrq9Xa6jFZWVl6//33dfDgQY+3h0AAAAAzPLTEcGhoqFMg0JpFixZpx44dOnDggPr06eOoj46O1uXLl1VVVeWUFaisrFR0dLTp89M1AACAGR08a8AwDC1atEhbt27VO++8o4SEBKftI0eOVEBAgPbu3euoKykp0alTp5SSkmL6OmQEAAAwoS1rAXzxeFdkZWWpsLBQ27dvV0hIiKPf32azKTg4WDabTfPmzdPSpUsVFham0NBQPfLII0pJSTE9Y0AiEAAAwCvl5eVJklJTU53q8/PzNWfOHEnS888/ry5duigzM1P19fVKT0/XunXrXLoOgQAAAGZ08LMGDKP1A4KCgpSbm6vc3Nw2NopAAAAAc9zsGuChQwAAwOuQEQAAwAwffQwxgQAAAGb4aCBA1wAAAH6MjAAAACZ09DoCHYWMAAAAfoxAAAAAP0bXAAAAZvjoYEECAQAATPDVMQIEAgAAmOWlX+buYIwAAAB+jIwAAABmMEYAAAD/5atjBOgaAADAj5ERAADADLoGAADwX3QNAAAAn0NGAAAAM+gaAADAj/loIEDXAAAAfoyMAAAAJvjqYEECAQAAzKBr4IoDBw5oypQpio2NlcVi0bZt25y2G4ah5cuXKyYmRsHBwZo4caJOnDjhqfYCANA5DA8UL+RyIFBbW6sRI0YoNze3xe1r1qzRCy+8oPXr1+vw4cPq0aOH0tPTVVdX53ZjAQCAZ7ncNZCRkaGMjIwWtxmGobVr1+qJJ57Q1KlTJUkbN25UVFSUtm3bppkzZ7rXWgAAOomvjhHw6KyBsrIyVVRUaOLEiY46m82m5ORkHTp0qMVj6uvrVVNT41QAAPA6dA20rqKiQpIUFRXlVB8VFeXY9kU5OTmy2WyOEhcX58kmAQCAa+j0dQSys7NVXV3tKOXl5Z3dJAAAmmnqGnCneCOPTh+Mjo6WJFVWViomJsZRX1lZqVtuuaXFY6xWq6xWqyebAQCA5zF9sHUJCQmKjo7W3r17HXU1NTU6fPiwUlJSPHkpAADgAS5nBC5evKiTJ086XpeVlenYsWMKCwtT3759tXjxYj311FMaOHCgEhIS9OSTTyo2NlbTpk3zZLsBAOhYPpoRcDkQOHLkiO68807H66VLl0qSZs+erYKCAi1btky1tbVasGCBqqqqNG7cOO3cuVNBQUGeazUAAB3M8q/izvHeyOWugdTUVBmG0awUFBRIkiwWi1avXq2KigrV1dVpz549uvnmmz3dbgAAfF5rq/nOmTNHFovFqUyePNmla3T6rAEAAK4LnbCOQGur+UrS5MmTdfbsWUd57bXXXLoGDx0CAMCEzlhZ8Fqr+TaxWq2OWXttQUYAAAAzPJQR+OJquvX19W41a//+/YqMjNSgQYP0rW99S+fPn3fpeAIBAAA6UFxcnNOKujk5OW0+1+TJk7Vx40bt3btXzz77rIqKipSRkaHGxkbT56BrAAAAszwwBbC8vFyhoaGO1+4sqvf5h/kNHz5cSUlJ6t+/v/bv36+0tDRT5yAjAACACZ5aYjg0NNSpeHJ13X79+ikiIsJpvZ/WEAgAAOAjTp8+rfPnzzst898augYAADCjE1YWvNZqvmFhYVq1apUyMzMVHR2t0tJSLVu2TAMGDFB6errpaxAIAABgQmdMH7zWar55eXk6fvy4XnrpJVVVVSk2NlaTJk3SD37wA5e6GwgEAADwUk2r+V7Nrl273L4GgQAAAGbw0CEAAPxXZ3QNdARmDQAA4MfICAAAYAZdAwAA+DECAQAA/BdjBAAAgM8hIwAAgBl0DQAA4L8shiHLNRb3MXO8N6JrAAAAP0ZGAAAAM+gaAADAfzFrAAAA+BwyAgAAmEHXAAAA/ouuAQAA4HPICAAAYAZdAwAA+C9f7RogEAAAwAwfzQgwRgAAAD9GRgAAAJO8Nb3vDgIBAADMMIwrxZ3jvRBdAwAA+DEyAgAAmMCsAQAA/BmzBgAAgK8hIwAAgAkW+5XizvHeiEAAAAAz6BoAAAC+howAAAAmMGsAAAB/5qMLChEIAABggq9mBBgjAACAHyMQAADADMMDxUUHDhzQlClTFBsbK4vFom3btjk3yTC0fPlyxcTEKDg4WBMnTtSJEydcugaBAAAAJjR1DbhTXFVbW6sRI0YoNze3xe1r1qzRCy+8oPXr1+vw4cPq0aOH0tPTVVdXZ/oajBEAAMBLZWRkKCMjo8VthmFo7dq1euKJJzR16lRJ0saNGxUVFaVt27Zp5syZpq5BRgAAADOaZg24UyTV1NQ4lfr6+jY1p6ysTBUVFZo4caKjzmazKTk5WYcOHTJ9HgIBAABM8FTXQFxcnGw2m6Pk5OS0qT0VFRWSpKioKKf6qKgoxzYz6BoAAKADlZeXKzQ01PHaarV2YmvICAAAYI6HZg2EhoY6lbYGAtHR0ZKkyspKp/rKykrHNjMIBAAAMKEzZg1cS0JCgqKjo7V3715HXU1NjQ4fPqyUlBTT56FrAAAAL3Xx4kWdPHnS8bqsrEzHjh1TWFiY+vbtq8WLF+upp57SwIEDlZCQoCeffFKxsbGaNm2a6WsQCAAAYIbduFLcOd5FR44c0Z133ul4vXTpUknS7NmzVVBQoGXLlqm2tlYLFixQVVWVxo0bp507dyooKMj0NQgEAAAwo42rAzod76LU1FQZ13hYkcVi0erVq7V69eo2N4tAAAAAEyxy86FDHmuJZzFYEAAAP0ZGAAAAMz63OmCbj/dCBAIAAJjg7hRAT08f9BS6BgAA8GNkBAAAMKMTZg10BI9nBFauXCmLxeJUEhMTPX0ZAAA6lMUw3C7eqF0yAkOHDtWePXv+/0W6kXgAAMAbtcs3dLdu3Vx64AEAAF7P/q/izvFeqF0GC544cUKxsbHq16+fHnzwQZ06deqq+9bX16umpsapAADgbXy1a8DjgUBycrIKCgq0c+dO5eXlqaysTLfffrsuXLjQ4v45OTmy2WyOEhcX5+kmAQCAq/B4IJCRkaH7779fSUlJSk9P13//93+rqqpKmzdvbnH/7OxsVVdXO0p5ebmnmwQAgPsMDxQv1O6j+Hr16qWbb77Z6TGKn2e1WmW1Wtu7GQAAuMdHVxZs9wWFLl68qNLSUsXExLT3pQAAaDdNKwu6U7yRxwOBRx99VEVFRfroo4/0hz/8Qffee6+6du2qWbNmefpSAADATR7vGjh9+rRmzZql8+fPq3fv3ho3bpyKi4vVu3dvT18KAICO46NdAx4PBF5//XVPnxIAgE5nsV8p7hzvjXjoEAAAfoy1fwEAMIOuAQAA/BhPHwQAAL6GjAAAACa4+7wAb33WAIEAAABm+OgYAboGAADwY2QEAAAww5DkzloA3pkQIBAAAMAMxggAAODPDLk5RsBjLfEoxggAAODHyAgAAGCGj84aIBAAAMAMuySLm8d7IboGAADwY2QEAAAwgVkDAAD4Mx8dI0DXAAAAXmjlypWyWCxOJTEx0ePXISMAAIAZnZARGDp0qPbs2eN43a2b57+2CQQAADCjEwKBbt26KTo6uu3XNIGuAQAAOlBNTY1Tqa+vv+q+J06cUGxsrPr166cHH3xQp06d8nh7CAQAADDD7oEiKS4uTjabzVFycnJavFxycrIKCgq0c+dO5eXlqaysTLfffrsuXLjg0bdF1wAAACZ4avpgeXm5QkNDHfVWq7XF/TMyMhx/JyUlKTk5WfHx8dq8ebPmzZvX5nZ8EYGAB6XHjujsJgAA2ouHxgiEhoY6BQJm9erVSzfffLNOnjzZ9ja0gK4BAACuAxcvXlRpaaliYmI8el4CAQAAzLAb7hcXPProoyoqKtJHH32kP/zhD7r33nvVtWtXzZo1y6Nvi64BAADM6ODpg6dPn9asWbN0/vx59e7dW+PGjVNxcbF69+7d9ja0gEAAAAAv9Prrr3fIdQgEAAAwxc2MgLzzWQMEAgAAmMFDhwAAgK8hIwAAgBl2Q26l912cNdBRCAQAADDDsF8p7hzvhegaAADAj5ERAADADB8dLEggAACAGYwRAADAj/loRoAxAgAA+DEyAgAAmGHIzYyAx1riUQQCAACYQdcAAADwNWQEAAAww26X5MaiQHbvXFCIQAAAADPoGgAAAL6GjAAAAGb4aEaAQAAAADN8dGVBugYAAPBjZAQAADDBMOwy3HiUsDvHticCAQAAzDAM99L7jBEAAOA6Zrg5RsBLAwHGCAAA4MfICAAAYIbdLlnc6OdnjAAAANcxugYAAICvISMAAIAJht0uw42uAaYPAgBwPaNrAAAA+BoyAgAAmGE3JIvvZQQIBAAAMMMwJLkzfdA7AwG6BgAA8GNkBAAAMMGwGzLc6Bow/C0jkJubq5tuuklBQUFKTk7W//zP/7TXpQAAaH+G3f3SBu39fdougcCmTZu0dOlSrVixQn/84x81YsQIpaen69y5c+1xOQAA2p1hN9wuruqI79N2CQSee+45zZ8/X3PnztWQIUO0fv16de/eXb/85S/b43IAAPikjvg+9fgYgcuXL+vo0aPKzs521HXp0kUTJ07UoUOHmu1fX1+v+vp6x+vq6mpJ0j/V4Na6DQAA3/dPNUjqmP73fxr1bj04qKmtNTU1TvVWq1VWq7XZ/q5+n7aVxwOBTz/9VI2NjYqKinKqj4qK0ocffths/5ycHK1atapZ/UH9t6ebBgDwURcuXJDNZmuXcwcGBio6OloHK9z/XurZs6fi4uKc6lasWKGVK1c229fV79O26vRZA9nZ2Vq6dKnjdVVVleLj43Xq1Kl2+z/V19TU1CguLk7l5eUKDQ3t7OZ4Pe6Xa7hfruOeucad+2UYhi5cuKDY2Nh2ap0UFBSksrIyXb582e1zGYYhi8XiVNdSNqAjeTwQiIiIUNeuXVVZWelUX1lZqejo6Gb7Xy0lYrPZ+A/IRaGhodwzF3C/XMP9ch33zDVtvV8d8aMxKChIQUFB7X6dz3P1+7StPD5YMDAwUCNHjtTevXsddXa7XXv37lVKSoqnLwcAgE/qqO/TdukaWLp0qWbPnq1Ro0ZpzJgxWrt2rWprazV37tz2uBwAAD6pI75P2yUQmDFjhv7+979r+fLlqqio0C233KKdO3c2G/DQEqvVqhUrVnR6n8n1hHvmGu6Xa7hfruOeuYb7dXXufJ+aZTG8dc1DAADQ7njoEAAAfoxAAAAAP0YgAACAHyMQAADAjxEIAADgx7wuEGjv5y77ipUrV8pisTiVxMTEzm6WVzlw4ICmTJmi2NhYWSwWbdu2zWm7YRhavny5YmJiFBwcrIkTJ+rEiROd01gv0Nr9mjNnTrPP3OTJkzunsV4gJydHo0ePVkhIiCIjIzVt2jSVlJQ47VNXV6esrCyFh4erZ8+eyszMbLZKnL8wc79SU1ObfcYWLlzYSS32H14VCHTEc5d9ydChQ3X27FlHOXjwYGc3yavU1tZqxIgRys3NbXH7mjVr9MILL2j9+vU6fPiwevToofT0dNXV1XVwS71Da/dLkiZPnuz0mXvttdc6sIXepaioSFlZWSouLtbu3bvV0NCgSZMmqba21rHPkiVL9NZbb2nLli0qKirSmTNnNH369E5sdecxc78kaf78+U6fsTVr1nRSi/2I4UXGjBljZGVlOV43NjYasbGxRk5OTie2yjutWLHCGDFiRGc347ohydi6davjtd1uN6Kjo40f/ehHjrqqqirDarUar732Wie00Lt88X4ZhmHMnj3bmDp1aqe053pw7tw5Q5JRVFRkGMaVz1NAQICxZcsWxz4ffPCBIck4dOhQZzXTa3zxfhmGYdxxxx3Gt7/97c5rlJ/ymoxA03OXJ06c6Khrj+cu+5ITJ04oNjZW/fr104MPPqhTp051dpOuG2VlZaqoqHD6vNlsNiUnJ/N5u4b9+/crMjJSgwYN0re+9S2dP3++s5vkNaqrqyVJYWFhkqSjR4+qoaHB6TOWmJiovn378hlT8/vV5NVXX1VERISGDRum7OxsXbp0qTOa51c6/THETTrqucu+Ijk5WQUFBRo0aJDOnj2rVatW6fbbb9f777+vkJCQzm6e16uoqJCkFj9vTdvgbPLkyZo+fboSEhJUWlqq733ve8rIyNChQ4fUtWvXzm5ep7Lb7Vq8eLHGjh2rYcOGSbryGQsMDFSvXr2c9uUz1vL9kqQHHnhA8fHxio2N1fHjx/XYY4+ppKREb775Zie21vd5TSAA12RkZDj+TkpKUnJysuLj47V582bNmzevE1sGXzVz5kzH38OHD1dSUpL69++v/fv3Ky0trRNb1vmysrL0/vvvM07HpKvdrwULFjj+Hj58uGJiYpSWlqbS0lL179+/o5vpN7yma6Cjnrvsq3r16qWbb75ZJ0+e7OymXBeaPlN83tquX79+ioiI8PvP3KJFi7Rjxw7t27dPffr0cdRHR0fr8uXLqqqqctrf3z9jV7tfLUlOTpYkv/+MtTevCQQ66rnLvurixYsqLS1VTExMZzflupCQkKDo6Ginz1tNTY0OHz7M582k06dP6/z58377mTMMQ4sWLdLWrVv1zjvvKCEhwWn7yJEjFRAQ4PQZKykp0alTp/zyM9ba/WrJsWPHJMlvP2Mdxau6Bjriucu+4tFHH9WUKVMUHx+vM2fOaMWKFeratatmzZrV2U3zGhcvXnT6JVFWVqZjx44pLCxMffv21eLFi/XUU09p4MCBSkhI0JNPPqnY2FhNmzat8xrdia51v8LCwrRq1SplZmYqOjpapaWlWrZsmQYMGKD09PRObHXnycrKUmFhobZv366QkBBHv7/NZlNwcLBsNpvmzZunpUuXKiwsTKGhoXrkkUeUkpKiW2+9tZNb3/Fau1+lpaUqLCzU3XffrfDwcB0/flxLlizR+PHjlZSU1Mmt93GdPW3hi376058affv2NQIDA40xY8YYxcXFnd0krzRjxgwjJibGCAwMNG688UZjxowZxsmTJzu7WV5l3759hqRmZfbs2YZhXJlC+OSTTxpRUVGG1Wo10tLSjJKSks5tdCe61v26dOmSMWnSJKN3795GQECAER8fb8yfP9+oqKjo7GZ3mpbulSQjPz/fsc9nn31mPPzww8YNN9xgdO/e3bj33nuNs2fPdl6jO1Fr9+vUqVPG+PHjjbCwMMNqtRoDBgwwvvvd7xrV1dWd23A/YDEMw+jIwAMAAHgPrxkjAAAAOh6BAAAAfoxAAAAAP0YgAACAHyMQAADAjxEIAADgxwgEAADwYwQCAAD4MQIBAAD8GIEAAAB+jEAAAAA/9v8Aor55y9Pt/D0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"Min and max values:\", field.max(), field.min())\n", + "\n", + "fig = plt.figure()\n", + "fig.patch.set_facecolor(\"white\")\n", + "ax = fig.add_subplot(111)\n", + "ax.set_facecolor(\".4\")\n", + "\n", + "f1 = ax.pcolormesh(field[:, :, 0])\n", + "\n", + "cbar = plt.colorbar(f1)\n", + "ax.set_title(\"Field set to value %.1f\" % value)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "6562a18e", + "metadata": {}, + "source": [ + "## Building and Running Pre-defined Stencils for Tracer Advection\n", + "\n", + "In this portion, we build and run the stencils required for calculating tracer advection. This will include:\n", + "- `FiniteVolumeFluxPrep`: calculates/updates Courant number and total mass flux fields based on input wind field.\n", + "- `FiniteVolumeTransport`: calculates tracer fluxes for horizontal finite volume flux transport.\n", + "- `TracerAdvection`: performs horizontal advection on tracers." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "a45c6f83", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting 6 engines with \n", + "100%|███████████████████████████████████████████████████████| 6/6 [00:05<00:00, 1.09engine/s]\n", + "%autopx enabled\n" + ] + } + ], + "source": [ + "import ipyparallel as ipp\n", + "\n", + "layout = (1, 1)\n", + "ntiles = 6\n", + "# spinup cluster of MPI-workers\n", + "num_ranks = ntiles * layout[0] * layout[1]\n", + "\n", + "tracer_center = (0, 0)\n", + "test_case = \"b\"\n", + "timestep = 900.0\n", + "\n", + "cluster = ipp.Cluster(engines=\"mpi\", n=num_ranks).start_and_connect_sync()\n", + "\n", + "# broadcast configuration to all workers\n", + "ar = cluster[:].push(\n", + " {\n", + " \"ntiles\": ntiles,\n", + " \"nx\": nx,\n", + " \"ny\": ny,\n", + " \"nz\": nz,\n", + " \"nhalo\": nhalo,\n", + " \"layout\": layout,\n", + " \"backend\": backend,\n", + " \"tracer_center\": tracer_center,\n", + " \"test_case\": test_case,\n", + " \"timestep\": timestep\n", + " }\n", + ")\n", + "\n", + "# start executing cells on the workers in parallel from here on\n", + "%autopx" + ] + }, + { + "cell_type": "markdown", + "id": "b5546849", + "metadata": {}, + "source": [ + "### Getting initial state\n", + "\n", + "Before we can build and run stencils associated with tracer advection, we need to have the grid configuration and initial fields for u- and v- winds on the C grid. \n", + "\n", + "More details on these processes are described in `grid_generation.ipynb` and `initial_condition_definition.ipynb`, and here they are shortened by using helper functions inside `functions.py`." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "d35b55bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[stderr:5] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", + " np.sum(p * q, axis=-1)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "[stderr:2] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", + " np.sum(p * q, axis=-1)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import functions as func\n", + "from mpi4py import MPI\n", + "import importlib\n", + "\n", + "importlib.reload(func)\n", + "\n", + "mpi_comm = MPI.COMM_WORLD\n", + "mpi_rank = mpi_comm.Get_rank()\n", + "\n", + "namelist_dict = func.store_namelist_variables(locals())\n", + "dimensions = func.define_dimensions(namelist_dict)\n", + "\n", + "domain_configuration = func.configure_domain(mpi_comm, dimensions)\n", + "\n", + "initial_state = func.create_initial_state_advection(\n", + " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9965c31a", + "metadata": {}, + "source": [ + "For the stencils used in the tracer advection process, we will need some additional classes, such as `DampingCoefficients` and `GridIndexing`.\n", + "\n", + "If we want to run tracer advection in a single layer instead of extending it to 79 identical conditions, we want to create `GridData` with the `single_layer=True`." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "3c865c63", + "metadata": {}, + "outputs": [], + "source": [ + "from ndsl import DaceConfig, DaCeOrchestration, GridIndexing, StencilConfig, StencilFactory, CompilationConfig, RunMode\n", + "from ndsl.grid import AngleGridData, ContravariantGridData, DampingCoefficients, GridData, HorizontalGridData, MetricTerms, VerticalGridData\n", + "\n", + "\n", + "if nz == 1:\n", + " single_layer = True\n", + "else:\n", + " single_layer = False\n", + "\n", + "if single_layer:\n", + " horizontal_grid_data = HorizontalGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", + " vertical_grid_data = VerticalGridData(ptop=0, ks=0, ak=[10], bk=[0], p_ref=0)\n", + " contravariant_grid_data = ContravariantGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", + " angle_grid_data = AngleGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", + "\n", + " grid_data = GridData(horizontal_grid_data, vertical_grid_data, contravariant_grid_data, angle_grid_data)\n", + " \n", + "else:\n", + " grid_data = GridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", + "\n", + "\n", + "damping_coefficients = DampingCoefficients.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", + "\n", + "dace_config = DaceConfig(\n", + " communicator=None, backend=backend, orchestration=DaCeOrchestration.Python\n", + ")\n", + "\n", + "compilation_config = CompilationConfig(\n", + " backend=backend,\n", + " rebuild=True,\n", + " validate_args=True,\n", + " format_source=False,\n", + " device_sync=False,\n", + " run_mode=RunMode.BuildAndRun,\n", + " use_minimal_caching=False,\n", + " communicator=domain_configuration[\"communicator\"],\n", + ")\n", + "\n", + "stencil_config = StencilConfig(\n", + " compare_to_numpy=False,\n", + " compilation_config=compilation_config,\n", + " dace_config=dace_config,\n", + ")\n", + "\n", + "grid_indexing = GridIndexing.from_sizer_and_communicator(\n", + " sizer=domain_configuration[\"sizer\"], comm=domain_configuration[\"communicator\"]\n", + ")\n", + "\n", + "stencil_factory = StencilFactory(config=stencil_config, grid_indexing=grid_indexing)\n" + ] + }, + { + "cell_type": "markdown", + "id": "6eea64a5", + "metadata": {}, + "source": [ + "### 1. Finite Volume Flux Prep\n", + "\n", + "In order to run the stencil, we first need to build it (initialize an instance of the class). \n", + "\n", + "For building the `FiniteVolumeFluxPrep` stencil, we need `stencil_factory` and `grid_data` from the configuration dictionary. \n", + "\n", + "For running the stencil, we require the following inputs:\n", + "- `uc (in)`: covariant x-velocity on the C-grid (stored in `initial_state` as `u_Cgrid`)\n", + "- `vc (in)`: covariant y-velocity on the C-grid (stored in `initial_state` as `v_Cgrid`)\n", + "- `crx (out)`: Courant number, x-direction\n", + "- `cry (out)`: Courant number, y-direction\n", + "- `x_area_flux (out)`: flux of area in x-direction, in units of m^2\n", + "- `y_area_flux (out)`: flux of area in y-direction, in units of m^2\n", + "- `uc_contra (out)`: contravariant x-velocity on C-grid\n", + "- `vc_contra (out)`: contravariant y-velocity on C-grid\n", + "- `dt (in)`: acoustic timestep in seconds\n", + "\n", + "We need to create empty storages or quantities to initialize the output variables, and their values get updated when we run the stencil.\n", + "We plot the empty storage of `crx` on the first (zeroth) rank, run `FiniteVolumeFluxPrep`, then plot the updated storage for comparison." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "886c8a20", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "%px: 83%|██████████████████████████████████████████▌ | 5/6 [00:00<00:00, 48.19tasks/s]" + ] + }, + { + "data": { + "text/plain": [ + "[output:0]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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de2DfX19MWbMGGRkZNg6ijdKT0+Hv78/7r//fgDAv//9bzz88MNo2bIlmjZtiv79+2Pr1q11bnNN11rcnEk37l/T0tLQoUMHNG3aFMOHD8f58+chhMBLL72Etm3bwtfXFw888AB++eWXavX+4x//wKBBg9CsWTP4+/tj1KhR+OGHH+pspwzZHFX72e/ZsyeCgoJs2WP9jbJ27Vq88MILaNOmDZo2bYrCwkIAcnlrbaM1PwICAtCqVSs8+eSTKC0tldr+/fv345577kGLFi3QrFkz9OrVC2+88Ybt70ePHsXkyZPRoUMH+Pj4IDQ0FI8++qjHDXdsDNxyJufixYvo168f8vPzkZSUhG7duuHChQv4+OOPUVJSYnek5oknnkBwcDAWLFiA4uJiTJkyBZ9++imSk5Nx9913IyIiAt9//z1SUlIwderUaqfHHTl58iTGjRuHxx9/HImJiVi1ahUefvhhbNu2DXfffTeAqlPUQ4YMwYULF/DHP/4R7dq1w969ezFv3jxcunQJS5cuRffu3fHBBx/gqaeeQtu2bW1DfIKDg/Hbb79h6NChOHXqFGbMmIGoqCisX78ekydPRn5+Pp588km7Nq1atQqlpaVISkqC2WxGy5Yt8cMPP+COO+5AmzZtMHfuXDRr1gwfffQREhIS8Mknn2D06NF1bmtpaSmuXLlit8zf37/WI2kvv/wyjEYjnnnmGRQUFGDx4sWYOHEi9u/f77B8cHAwli9fjmnTpmH06NEYM2YMANiGlclux8SJE5GSkoL09HTcdttttvorKyvx0UcfYdCgQWjXrp3i11aNr776Cp999hmmT58OAEhNTcW9996LZ599Fm+//TaeeOIJ/Prrr1i8eDEeffRR7Ny50/bcnTt3YuTIkejTpw8WLlwIo9GIVatW4a677sJXX32Ffv362a2roKCg2nvliqNrd911F5544gmkpqYiISEBt912Gy5duoSZM2ciLi6uziFoFRUVOH/+fLWhGq74zM6YMQPNmzfHokWLcOLECSxfvhxnz561hVlNjh49ikGDBqFJkyZISkpCZGQkTp8+jc2bN+PPf/4zAOC7777D3r17MX78eLRt2xZnzpzB8uXLMXToUPz4449o2rSpk68o6Y07M2v16tXw8/NDcnIy/Pz8sHPnTixYsACFhYV49dVXAQBLly7F+++/jw0bNtiGHvXs2RP9+/dXvV+uabvqUlJSUm1/FhgYWOsogJkzZ6JFixZYuHAhzpw5g6VLl2LGjBlYt26dw/Ldu3fHiy++iAULFiApKQmDBg0CAAwYMACA/D544sSJeO+99/DRRx9hxowZtvp/+eUXbN++HRMmTICvry9yc3MxYMAAlJSUYNasWWjVqhXee+893H///fj444+lMlnW3//+d5SXl2PmzJn45ZdfsHjxYowdOxZ33XUXMjMz8dxzz+HUqVNYtmwZnnnmGbuOxAcffIDExETEx8fjlVdeQUlJCZYvX46BAwfi8OHD1TooN3eSvLy80KJFC9XboPaz/+uvv+LXX3+1Db+0eumll2AymfDMM8+grKwMJpNJcd6OHTsWkZGRSE1Nxb59+/Dmm2/i119/xfvvv19rm3bs2IF7770XYWFhePLJJxEaGoqffvoJW7Zssf322LFjB/79739jypQpCA0NxQ8//ICVK1fihx9+wL59+2rNNnIx4QaTJk0SRqNRfPfdd9X+ZrFYhBBCrFq1SgAQAwcOFNevX7crc+nSJdGyZUtx9913i7KyMvG73/1OtGvXThQUFNS57vbt2wsA4pNPPrEtKygoEGFhYeJ3v/udbdlLL70kmjVrJv71r3/ZPX/u3LnCy8tLnDt3zq7OUaNG2ZVbunSpACA+/PBD27Ly8nIRGxsr/Pz8RGFhoRBCiOzsbAFABAQEiLy8PLs6hg0bJnr27ClKS0vtXp8BAwaIzp0717mtABw+Vq1aJYQQYsiQIWLIkCG28rt27RIARPfu3UVZWZlt+RtvvCEAiO+//962LDExUbRv397278uXLwsAYuHChdXaoWQ7+vbtK9q2bSsqKytty7Zt2yYAiHfeeUcIIf/aWl+DG9t0c7utFi5cKG7+OgAQZrNZZGdn25a98847AoAIDQ21W8+8efMEAFtZi8UiOnfuLOLj422faSGEKCkpEVFRUeLuu++2LbN+1h09btS+fXuRmJhYa5tvrO/GdhcXF4tOnTqJW2+9VZSWlopRo0aJgIAAcfbs2WrrGD58uLh8+bK4fPmy+Oc//ynGjx8vAIiZM2cKIVzzmbW2sU+fPqK8vNy2fPHixQKA2LRpU7XtutHgwYOFv79/tfbf/FrfLCsrSwAQ77//vm2Z9XO/a9cu27KaPiekT+7MLEef4z/+8Y+iadOmdt8z6/7g8uXLtmWu2C/Xtl2OWPcPjh7W79jN+zLrOuLi4uy+w0899ZTw8vIS+fn5tmU359Z3331nl2s3bovsPvj69esiLCxMxMbG2tWxYsUKAUBs375dCCHE7NmzBQDx1Vdf2cpcu3ZNREVFicjISFtuWV+DG9t0c7utbt7XWJ8bHBxst93WjOndu7eoqKiwLZ8wYYIwmUy29/HatWuiefPm4rHHHrNbT05OjggMDLRbbv3M3Py4ed+nJkdlP/sAxNSpU8Xly5dFXl6e2L9/vxg2bJgAIF577TUhxH/31R06dLD7Xih5r61tvP/+++3W/8QTTwgA4p///Ge17bK6fv26iIqKEu3btxe//vqr3d/qyp41a9YIAGLPnj22ZY6yuqbPCTmnwYerWSwWbNy4Effdd5/D6w9u7uE+9thj8PLyslsWGhqKtLQ07NixA4MGDcKRI0fw7rvvIiAgQKoN4eHhdkdcrMNkDh8+jJycHADA+vXrMWjQILRo0QJXrlyxPeLi4lBZWYk9e/bUuo7PP/8coaGhtuFVQNV1LLNmzUJRURF2795tV/7BBx+0DS0Aqo6s7Ny5E2PHjsW1a9ds67969Sri4+Nx8uRJXLhwoc5tfeCBB7Bjxw67R3x8fK3PmTJlit2RSevRsX//+991ru9mSrfjD3/4A37++We71zc9PR0mkwkPP/wwAOWvrRrDhg2zO+plvRjzwQcfhL+/f7Xl1tfoyJEjOHnyJH7/+9/j6tWrtu0uLi7GsGHDsGfPHruJGwDYPtM3PlyladOmWL16NX766ScMHjwYW7duxV//+le0a9euWtkvvvgCwcHBCA4ORu/evbF+/Xo88sgjeOWVV+zKueIzm5SUZHdkd9q0afD29q51GMPly5exZ88ePProo9Xaf+P+wzrBBlB1Nurq1avo1KkTmjdv7nBIJJEj7s6sGz/H1u/VoEGDUFJSguPHjzu1Tc58Vx1tV22SkpKq7c969+5d53NufD0HDRqEyspKnD17VtkGQtk+2MvLC+PHj0dWVpbdcNb09HSEhIRg2LBhAKqyp1+/fhg4cKCtjJ+fH5KSknDmzBnbkF1XePjhhxEYGGj7tzVj/vCHP8Db29tueXl5ue392rFjB/Lz8zFhwgS73y5eXl6IiYnBrl27qq3rk08+sXuf/v73v7tsO5R89v/v//4PwcHBaN26NWJiYmzDF2++LUdiYqLd98KZvLWOzrCaOXMmANSaPYcPH0Z2djZmz55d7dq3mrLHOprGOrMgs6dhNfhwtcuXL6OwsFB61qibZ5uyGj9+PD788ENs3boVSUlJtp2QjE6dOlULpi5dugCoGg8bGhqKkydP4ujRo3Y/4m7kaOzujc6ePYvOnTtXuxiue/futr/f6ObtPHXqFIQQmD9/PubPn19jG9q0aVNrO9q2bYu4uLhay9zs5h+O1tPWstdK3EjpdowfPx7JyclIT0/H0KFDUVpaig0bNmDkyJG2dih9bdW4+bWwhk5ERITD5dbX6OTJkwCqdsY1KSgosBsS0K9fv3qdeOCOO+7AtGnTkJaWhvj4eDz66KMOy8XExOBPf/oTDAYDmjZtiu7duzu8mNkVn9nOnTvb/d3Pzw9hYWG1Xjdj7UjWtQ/57bffkJqailWrVuHChQsQQtj+VlBQUOtziazcnVk//PADXnjhBezcudN27YGVs59jZ76rNW1XTTp37uzW7FG6D544cSL++te/Ij09Hc8//zx+/vlnfPXVV5g1a5atc3f27FmHs47dmD2umhFTbfbcddddDut11LkYPHhwvU48IPvZf+CBBzBjxgwYDAb4+/vj1ltvdTjBxc2fRWfy9ubs6dixI4xGY63Zc/r0aQB1Z88vv/yClJQUrF27ttpvRWZPw9L87Go39ohvdPXqVRw4cAAA8OOPP8Jisbh0dg2LxYK7774bzz77rMO/WztFrnLzdlqPOjzzzDM1nnm5eZyqq9R0tO7GH4mylG5H69atcffdd+OTTz5BWloaNm/ejGvXrrlsZpuaxsLeeBHvjWp6Lep6jazb/eqrr9Y4renNU3YqpXRbysrKbPccOH36NEpKShxelxIUFCT140RLn1lHZs6ciVWrVmH27NmIjY1FYGAgDAYDxo8fX+2oHpGruDKz8vPzMWTIEAQEBODFF19Ex44d4ePjg0OHDuG5555z+nPszHe1pu1ypfrIHtl9cJ8+fdCtWzesWbMGzz//PNasWQMhhEuzx9F21Ff2fPDBBw7viXfjWSBnKc0e2c++7EHZmrJHTd668jqZsWPHYu/evZgzZw6io6Ph5+cHi8WCESNGMHsaWIN3coKDgxEQEIBjx46pqmf69Om4du0aUlNTMW/ePCxduhTJyclSz7UexbrxQ/2vf/0LAGxDkzp27IiioiLFR6Ks2rdvj6NHj1b7MluHF7Rv377W53fo0AFA1TAsZ9vQkGraQTizHRMnTsS2bdvwj3/8A+np6QgICMB9991n+7ua17ZFixbIz8+vttyVZ3+Aqs8PUHXUrL7eP+tRqfz8fLszLTVty8KFC/HTTz9hyZIleO655zB37ly8+eabLmuPM+/1yZMnceedd9r+XVRUhEuXLtV6Qap1PXXtQz7++GMkJibitddesy0rLS11+P4T1cSdmZWZmYmrV6/i008/xeDBg23LrbNN1cWV+2WtqmkbndkHT5w4EfPnz8fRo0eRnp6Ozp0722ZvA6qy5cSJE9WeJ5s9joZ811f2tG7dul6zR0mOqvm9JsOZ9/rkyZN2Z4ROnToFi8XicNa4m9dz7NixGtfz66+/IiMjAykpKXYzmlrPNlHDavBrcoxGIxISErB582Zbz/5GMkdsPv74Y6xbtw4vv/wy5s6di/Hjx+OFF16wdVTqcvHiRbs7uBcWFuL9999HdHS07cjH2LFjkZWVhe3bt1d7fn5+Pq5fv17rOu655x7k5OTYzQpz/fp1LFu2DH5+fhgyZEitz2/dujWGDh2Kd955B5cuXar295un1XQ36xmBm3d8zmxHQkICmjZtirfffhv/+Mc/MGbMGPj4+Nj+rua17dixIwoKCnD06FHbskuXLtl9HlyhT58+6NixI5YsWYKioqJqf3fF+2fd4d54/VJxcbHDqbT379+PJUuWYPbs2Xj66acxZ84cvPXWWy69fsmZ93rlypWoqKiw/Xv58uW4fv16rTd+Cw4OxuDBg/Huu+/i3Llzdn+7cf/h5eVVbX+ybNmyGo82EjnizsyyHrW/cR3l5eV4++23pdruyv2yVlmHM928jc7sg61nbRYsWIAjR45UO4tzzz334Ntvv0VWVpZtWXFxMVauXInIyMha75fXsWNHHD9+3G69//znP112SwGr+Ph4BAQE4C9/+YvdvtXKVdkjm6Nqf6/JcOa9TktLs/v3smXLAKDW7LntttsQFRWFpUuXVvu8Wb+jjr6zQNUMiNTw3DJc7S9/+Qu++OILDBkyBElJSejevTsuXbqE9evX4+uvv671ZmZ5eXmYNm0a7rzzTttUj2+99RZ27dqFyZMn4+uvv65zCECXLl0wdepUfPfddwgJCcG7776L3NxcrFq1ylZmzpw5+Oyzz3Dvvfdi8uTJ6NOnD4qLi/H999/j448/xpkzZ2odw5qUlIR33nkHkydPxsGDBxEZGYmPP/4Y33zzDZYuXWp30XpN0tLSMHDgQPTs2ROPPfYYOnTogNzcXGRlZeHnn3/GP//5zzrraCi+vr645ZZbsG7dOnTp0gUtW7ZEjx490KNHD8Xb4efnh4SEBKSnpwNAtaBR89qOHz8ezz33HEaPHo1Zs2bZptbs0qWLSy8INBqN+N///V+MHDkSt956K6ZMmYI2bdrgwoUL2LVrFwICArB582ZV6xg+fDjatWuHqVOnYs6cOfDy8sK7776L4OBgux//paWlSExMROfOnW3TK6ekpGDz5s2YMmUKvv/+e5fdsFDpe11eXo5hw4Zh7NixOHHiBN5++20MHDjQdk+Kmrz55psYOHAgbrvtNiQlJSEqKgpnzpzB1q1bceTIEQDAvffeiw8++ACBgYG45ZZbkJWVhS+//NJj71pO9cddmTVgwAC0aNECiYmJmDVrFgwGAz744APp4Vuu3C9rVceOHdG8eXOsWLEC/v7+aNasGWJiYhAVFaV4HxwVFYUBAwZg06ZNAKpnz9y5c7FmzRqMHDkSs2bNQsuWLfHee+8hOzsbn3zySa2/PR599FG8/vrriI+Px9SpU5GXl4cVK1bg1ltvrXatlRoBAQFYvnw5HnnkEdx2220YP368LRO2bt2KO+64A2+99ZaqdcjmqCt+r8lwJm+zs7Nx//33Y8SIEcjKysKHH36I3//+97VOjmE0GrF8+XLcd999iI6OxpQpUxAWFobjx4/jhx9+wPbt2xEQEIDBgwdj8eLFqKioQJs2bfDFF19In30lF2vYydz+6+zZs2LSpEkiODhYmM1m0aFDBzF9+nTb1MXWqfVunrJzzJgxwt/fX5w5c8Zu+aZNmwQA8corr9S6Xut0z9u3bxe9evUSZrNZdOvWTaxfv75a2WvXrol58+aJTp06CZPJJIKCgsSAAQPEkiVL7Ka9dTSFtBBC5ObmiilTpoigoCBhMplEz549q01zaZ0u8tVXX3XY3tOnT4tJkyaJ0NBQ0aRJE9GmTRtx7733io8//rjW7RSiakrG6dOn1/j3mqaQvvm1cDQdpqMpJPfu3Sv69OkjTCZTtSknlW7H1q1bBQARFhZmN520lcxra30Nbp4+9YsvvhA9evQQJpNJdO3aVXz44Yc1TiF98+tX0/tV02t3+PBhMWbMGNGqVSthNptF+/btxdixY0VGRoatTE2f9ZvdPO2qEEIcPHhQxMTECJPJJNq1aydef/31atNSWqdh3b9/v91zDxw4ILy9vcW0adPs1uHosyzzGljJvNfWNu7evVskJSWJFi1aCD8/PzFx4kRx9erVWtdvdezYMTF69GjRvHlz4ePjI7p27Srmz59v+/uvv/5q+4z4+fmJ+Ph4cfz48WqvI6eQJhnuyqxvvvlG9O/fX/j6+orw8HDx7LPPiu3bt1f7zDqaQloI9ftl2f2TVV37ByFqnkL65nU4+m46mmJ306ZN4pZbbhHe3t7VskpmH3yjtLQ0AUD069fP4d9Pnz4tHnroIdt+p1+/fmLLli0OX4ObM+nDDz8UHTp0ECaTSURHR4vt27fXOIW0bMbU9trFx8eLwMBA4ePjIzp27CgmT54sDhw4YCtT02fmZs7mqJLPfl2/V2p7Daxk3mtrG3/88Ufx0EMPCX9/f9GiRQsxY8YM8dtvv9W6fquvv/5a3H333cLf3180a9ZM9OrVSyxbtsz2959//tmWTYGBgeLhhx8WFy9erPY6cgrp+mcQwokr+oiIVFi9ejWmTJmC7777rl5nlCMiIrJatGgRUlJScPny5XqdUY60ocGvySEiIiIiIqpP7OQQEREREZFHYSeHiIiIiIg8Cjs5RNTgJk+eDCEEr8dxQlpaGiIjI+Hj44OYmBh8++23NZb94Ycf8OCDDyIyMhIGg6HGaUyV1ElE1FgtWrQIQghej1MPtJhN7OQQETUS69atQ3JyMhYuXIhDhw6hd+/eiI+PR15ensPyJSUl6NChA15++WWHdz93pk4iIqIbaTWbOLsaEVEjERMTg759+9ruc2GxWBAREYGZM2di7ty5tT43MjISs2fPxuzZs11WJxERkVazyS03A62NxWLBxYsX4e/vD4PB4O7mEJEHEkLg2rVrCA8PV30zutLSUpSXlzvdjpv3c2azGWazuVrZ8vJyHDx4EPPmzbMtMxqNiIuLs7sDuxL1UaenYjYRUX1jNrm2Ts11ci5evIiIiAh3N4OIdOD8+fNo27at088vLS1FsK8filDp1PP9/PxQVFRkt2zhwoVYtGhRtbJXrlxBZWUlQkJC7JaHhITg+PHjTq2/Pur0VMwmImoozCbX1Km5To6/vz8A4Pz5rQgIaObm1hCRJyosLEZExCjb/sZZ5eXlKEIlnkYUzAovcSyDBa8VZeP8+fMICAiwLXd0pIzcj9lERPWN2eRamuvkWE+PBQQ0Q0CAn5tbQ0SezFXDjswwwgdeTj03ICDALkhqEhQUBC8vL+Tm5totz83NrfHCTXfU6amYTUTUUJhNrqmTs6sREalkdPKhhMlkQp8+fZCRkWFbZrFYkJGRgdjYWKfaXR91EhGRNug9mzR3JoeIqLFxJhicOcKUnJyMxMRE3H777ejXrx+WLl2K4uJiTJkyBQAwadIktGnTBqmpqQCqhiz8+OOPtv+/cOECjhw5Aj8/P3Tq1EmqTiIiapz0nk3s5BARqdRQQTJu3DhcvnwZCxYsQE5ODqKjo7Ft2zbbxZnnzp2zm5Hn4sWL+N3vfmf795IlS7BkyRIMGTIEmZmZUnUSEVHjpPds0tx9cgoLCxEYGIiCgkyOeyaielFYWITAwKEoKCiQGnNccz1V+6sX0VHxuOdSVGIBTqtuAzUMZhMR1Tdmk2vxTA4RkUqG/zyUPoeIiKi+6D2bOPEAERERERF5FJ7JISJSqaHGPRMREcnSezaxk0NEpJLeg4SIiLRH79nETg4RkUp6DxIiItIevWcTOzlERCoZoDwYPOniTiIi0h69Z5MnddiIiIiIiIh4JoeISC29DwkgIiLt0Xs2sZNDRKSS3oOEiIi0R+/ZxE4OEZFKeg8SIiLSHr1nEzs5REQq6T1IiIhIe/SeTezkEBGppPcgISIi7dF7NinaltTUVPTt2xf+/v5o3bo1EhIScOLECbsyQ4cOhcFgsHs8/vjjLm00ERGRFbOJiIhupqiTs3v3bkyfPh379u3Djh07UFFRgeHDh6O4uNiu3GOPPYZLly7ZHosXL3Zpo4mItMTo5INcg9lERFSd3rNJ0XC1bdu22f179erVaN26NQ4ePIjBgwfbljdt2hShoaGuaSERkcbpfUiAuzGbiIiq03s2qdqWgoICAEDLli3tlv/9739HUFAQevTogXnz5qGkpKTGOsrKylBYWGj3ICJqTAxOPqh+MJuIiJhNTk88YLFYMHv2bNxxxx3o0aOHbfnvf/97tG/fHuHh4Th69Ciee+45nDhxAp9++qnDelJTU5GSkuJsM4iI3M4A5UeMPClItITZRERURe/Z5HQnZ/r06Th27Bi+/vpru+VJSUm2/+/ZsyfCwsIwbNgwnD59Gh07dqxWz7x585CcnGz7d2FhISIiIpxtFhFRg9P7kAAtYTYREVXRezY51cmZMWMGtmzZgj179qBt27a1lo2JiQEAnDp1ymGQmM1mmM1mZ5pBRERkw2wiIiIrRZ0cIQRmzpyJDRs2IDMzE1FRUXU+58iRIwCAsLAwpxpIRKR1ej9a5m7MJiKi6vSeTYo6OdOnT0d6ejo2bdoEf39/5OTkAAACAwPh6+uL06dPIz09Hffccw9atWqFo0eP4qmnnsLgwYPRq1evetkAIiJ303uQuBuziYioOr1nk6JOzvLlywFU3VTtRqtWrcLkyZNhMpnw5ZdfYunSpSguLkZERAQefPBBvPDCCy5rMBGR1ug9SNyN2UREVJ3es0nxcLXaREREYPfu3aoaRETU2Og9SNyN2UREVJ3es8np2dWIiKiK3oOEiIi0R+/Z5EnbQkRERERExDM5RERq6f1oGRERaY/es4mdHCIilfQeJEREpD16zyZ2coiIVNJ7kBARkfboPZvYySEicgGDuxtADUL8eyuEv7nugkX5chUWFEgVu/zYHrn6AFwvtUiVqyiXrhIV1+U+4dct8t+ESsmysuXqmGTPqbKiHr7ZBsg31CC5etlyAOBllFu/bDlvyXIA0MRbrmwTk3SV8PaR+1ke/LfB8pUGBsqV82suVczQMUF+3S6m52xiJ4eISCW9Hy0jIiLt0Xs2edK2EBERERER8UwOEZFaej9aRkRE2qP3bGInh4hIJb0HCRERaY/es4mdHCIilQxQduEvABgUXCRNRESklN6ziZ0cIiKVjAYBo8JkMEJAwSRLREREiug9m9jJISJSyWBw4mgZ4DFBQkRE2qP3bPKkoXdEREREREQ8k0NEpJYBym+4pucbtBERUf3Tezaxk0NEpFLVkABl5/c9KUiIiEh79J5N7OQQEank9LhnanQMzaNg8Petu6BvgVR9omWpVLmLF7+WKgcAZ4vMUuVM0jUCPpIfWJO3RbpOk7fcj68mXnJ1NpGsDwC8jHJljfXwRbUo+M1ZaZFrQMV1+YaWVXhJlSuXrLP8uvyVD6WS214uXSPQ3q9Cqlxw1K3SdRq8fOQKmgOl63QHvWcTOzlERCrpPUiIiEh79J5N7OQQEank9DSdRERE9UTv2cTZ1YiIiIiIyKPwTA4RkUp6n8GGiIi0R+/ZxE4OEZFaTox7JiIiqlc6zyZ2coiIVNL7xZ1ERKQ9es8mdnKIiFQyGIQT9yLwnIs7iYhIe/SeTezkEBGpZDQov58GZ30hIqL6pPds8qRtISIiIiIi4pkcIiK19D7umYiItEfv2cRODhGRSgYIxeOYnR33nJaWhldffRU5OTno3bs3li1bhn79+tVYfv369Zg/fz7OnDmDzp0745VXXsE999xj+3tRURHmzp2LjRs34urVq4iKisKsWbPw+OOPO9U+j1dRBFRU1llMlBXK1Xe9RKpYK/8KufoACMmfKUo+g0bJcR/eRvk6vb3kynpJ1ilbDpDfnvq4PkH2/QEAi0WuXGUT+TorJSu9XilX53WL67dHyWsk/d0ozZeuU3g3lSpnMHpJ1+kOes8mDlcjIlLJerRM6UOpdevWITk5GQsXLsShQ4fQu3dvxMfHIy8vz2H5vXv3YsKECZg6dSoOHz6MhIQEJCQk4NixY7YyycnJ2LZtGz788EP89NNPmD17NmbMmIHPPvvM2ZeDiIg0QO/ZxE4OEZFKDRUkr7/+Oh577DFMmTIFt9xyC1asWIGmTZvi3XffdVj+jTfewIgRIzBnzhx0794dL730Em677Ta89dZbtjJ79+5FYmIihg4disjISCQlJaF379749ttvnX05iIhIA/SeTezkEBGpZDQIpx5KlJeX4+DBg4iLi/vveo1GxMXFISsry+FzsrKy7MoDQHx8vF35AQMG4LPPPsOFCxcghMCuXbvwr3/9C8OHD1fUPiIi0ha9ZxOvySEicqPCQvtrN8xmM8xmc7VyV65cQWVlJUJCQuyWh4SE4Pjx4w7rzsnJcVg+JyfH9u9ly5YhKSkJbdu2hbe3N4xGI/72t79h8ODBzm4SERE1cp6QTTyTQ0SkkpohAREREQgMDLQ9UlNTG7Tty5Ytw759+/DZZ5/h4MGDeO211zB9+nR8+eWXDdoOIiJyLb1nE8/kEBGpZIDyaTet5c+fP4+AgADbckdHygAgKCgIXl5eyM3NtVuem5uL0NBQh88JDQ2ttfxvv/2G559/Hhs2bMCoUaMAAL169cKRI0ewZMmSasMJiIio8dB7NvFMDhGRSgaDcOoBAAEBAXaPmoLEZDKhT58+yMjIsC2zWCzIyMhAbGysw+fExsbalQeAHTt22MpXVFSgoqICxpvm0/Xy8oJFdq5XIiLSJL1nE8/kEBGp1FA3XEtOTkZiYiJuv/129OvXD0uXLkVxcTGmTJkCAJg0aRLatGljG1bw5JNPYsiQIXjttdcwatQorF27FgcOHMDKlSsBVIXYkCFDMGfOHPj6+qJ9+/bYvXs33n//fbz++utOtJCIiLRC79nETg4RkUpGAEaFyaDgvoU248aNw+XLl7FgwQLk5OQgOjoa27Zts13Aee7cObsjXwMGDEB6ejpeeOEFPP/88+jcuTM2btyIHj162MqsXbsW8+bNw8SJE/HLL7+gffv2+POf/8ybgRIRNXJ6zyaDEML1t/NVobCwEIGBgSgoyERAgJ+7m0NEHqiwsAiBgUNRUFBgN+ZYeT1V+6uDLSLgJ3sL9f8osljQ59fzqttADcOWTf9ajAB/3zrLi99+lav4eolUsZ+HfChXH4Ar10xS5ZTc2Vz24+2t4BeSt5dcWS/JOmXLAfLb4+zd32sjFBwrlx2ZU2mRr1O27PVKyXIK1i27PUpeoyD/cqlybXf/QbpOeDeVKmbwbSFXX6jjYVs3Yza5Fs/kEBGpdOM4ZiXPISIiqi96zyZ2coiIXMCZcczU+IiK3yAqJH4EVBTJVVgsV84/3PFFv44Yc+WObAuL63/MGBSMjTHInk3xkqtT0bolL1SQbaMSQsGcHrKDbRTVWSlXWLZOd3+OmoVIfjeKCusuY6tU8jXyllu3O/NBz9nETg4RkUpOXdyp5+QhIqJ6p/dsYieHiEglvQ8JICIi7dF7NrGTQ0SkktHgxAw2HnS0jIiItEfv2cSbgRIRERERkUfhmRwiIpX0Pu6ZiIi0R+/ZxE4OEZFKeg8SIiLSHr1nk6Lhaqmpqejbty/8/f3RunVrJCQk4MSJE3ZlSktLMX36dLRq1Qp+fn548MEHkZub69JGExFpiQHCqQe5BrOJiKg6vWeTok7O7t27MX36dOzbtw87duxARUUFhg8fjuLiYluZp556Cps3b8b69euxe/duXLx4EWPGjHF5w4mItMJ6tEzpg1yD2UREVJ3es0nRcLVt27bZ/Xv16tVo3bo1Dh48iMGDB6OgoAD/93//h/T0dNx1110AgFWrVqF79+7Yt28f+vfv77qWExFphMFoUHTzOgAw6PoWba7FbCIiqk7v2aRqdrWCggIAQMuWLQEABw8eREVFBeLi4mxlunXrhnbt2iErK8thHWVlZSgsLLR7EBEROYvZRERETk88YLFYMHv2bNxxxx3o0aMHACAnJwcmkwnNmze3KxsSEoKcnByH9aSmpiIlJcXZZhARuZ3BWPVQ9Jz6aYru1Xs2XS8Drku8e6Wlcg0uLpIq5hdqkqsPgNFL7tNlqZQfey9d1uLG8fyedIMPpRrJ6y772ZQtBwBNg5vIFZT8rgEAvCR/Hjcpk6/TDfSeTU6fyZk+fTqOHTuGtWvXqmrAvHnzUFBQYHucP39eVX1ERA1N7+OetYTZRERURe/Z5NSZnBkzZmDLli3Ys2cP2rZta1seGhqK8vJy5Ofn2x0xy83NRWhoqMO6zGYzzGazM80gItIGZ24r7VHHy7SB2UREdAOdZ5OiMzlCCMyYMQMbNmzAzp07ERUVZff3Pn36oEmTJsjIyLAtO3HiBM6dO4fY2FjXtJiISGOsQwKUPsg1mE1ERNXpPZsUncmZPn060tPTsWnTJvj7+9vGMgcGBsLX1xeBgYGYOnUqkpOT0bJlSwQEBGDmzJmIjY3l7DVE5LEMBgMMCs/xKy1PNWM2ERFVp/dsUtTJWb58OQBg6NChdstXrVqFyZMnAwD++te/wmg04sEHH0RZWRni4+Px9ttvu6SxREREN2M2ERHRzRR1coSoe/YOHx8fpKWlIS0tzelGERE1JgaDEzPYeM5Npd2O2UREVJ3es8npKaSJiOg/nJmSxoOGBBARkQbpPJvYySEiUsmpexF40NEyIiLSHr1nEzs5REQqGYwGGBRO02kQnnO0jIiItEfv2eRBE8URERERERHxTA4RkWo6H/ZMREQapPdsYieHiEgtZ26g5kHjnnXFUgFYJN7s8jK5+kqKpYoZQs1y9QFoJjk85XqZRbpOy3W5D6xsOQCAxKx4ACAkmyks+v1SKRmSJL2vkvy1a/SWX7dsWW+zgh1qa5NcOcnvGgDAx1eunKVcvk530Hk2sZNDRKSW0VD1UMKDxj0TEZEG6Tyb2MkhIlJJ70MCiIhIe/SeTezkEBGppPcZbIiISHv0nk2cXY2IiIiIiDwKz+QQEamk9xuuERGR9ug9m9jJISJSyWAwwKBwILPS8kREREroPZvYySEiUssA5YN/5WfvJSIiUk7n2cRODhGRSnqfwYaIiLRH79nETg4RkUpV454VDgngtC9ERFSP9J5NHrQpREREREREPJNDRKSaUzPY8BBT4yQsVY+6VFTI1VdWJlXM0MokVx8A2cmRvEsqpetEqdxAfVEuP6DfUinXUiHZTGGRnxZKNJIZpGSHDik5Wm/wkitn9JKr02BSsDPzkSzbVLKRUPDdkPyuAZD//srsC9xI79nETg4RkVp6H/hMRETao/NsYieHiEglvR8tIyIi7dF7NrGTQ0SkksFocOLiTs85WkZERNqj92xiJ4eISCWdjwggIiIN0ns2edBJKSIiIiIiIp7JISJSTe9DAoiISHv0nk3s5BARqWX4z0Ppc4iIiOqLzrOJnRwiIpX0PoMNERFpj96ziZ0cIiKVDAYnhgR40tWdRESkOXrPJnZyiIhU0vsMNkREpD16zyZ2coiIiKRZAGGRKFYpV12FRF0A0Fw+rg0WIVVOmBWMS/lNbnsMpZLbA8CrXLJsudz2WCrlygGAkH2N5DdHmpLhQLJH4Y1eCn6ZmiTLmiQb6qNgg3y9pIoZmsqVAyD/3ZD9rgHy39/6+ICQy7CTQ0Skkt5nsCEiIu3Rezaxk0NEpJYRyu865kEXdxIRkQbpPJvYySEiUstoqHoofQ4REVF90Xk2sZNDRKSWzo+WERGRBuk8mzxoU4iI3MR6tEzpwwlpaWmIjIyEj48PYmJi8O2339Zafv369ejWrRt8fHzQs2dPfP7559XK/PTTT7j//vsRGBiIZs2aoW/fvjh37pxT7SMiIo3QeTaxk0NE1EisW7cOycnJWLhwIQ4dOoTevXsjPj4eeXl5Dsvv3bsXEyZMwNSpU3H48GEkJCQgISEBx44ds5U5ffo0Bg4ciG7duiEzMxNHjx7F/Pnz4ePj01CbRUREjZhWs8kghJCfc7EBFBYWIjAwEAUFmQgI8HN3c4jIAxUWFiEwcCgKCgoQEBCgop6q/dUvY7ojoImCKU8BFFZUouWnPylqQ0xMDPr27Yu33noLAGCxWBAREYGZM2di7ty51cqPGzcOxcXF2LJli21Z//79ER0djRUrVgAAxo8fjyZNmuCDDz5Q1H69sb7X+YeeQoCfue4n5F2Sqzj3slQxcSJfrj4A+KVCrs4SyWlyAekppKFgCmlwCmmJspxCuk4tm8jV2bW5fJ0hwXLlWofJrbvzQ1LlmE2uzSaeySEiUkvFkIDCwkK7R1lZmcNVlJeX4+DBg4iLi/vvao1GxMXFISsry+FzsrKy7MoDQHx8vK28xWLB1q1b0aVLF8THx6N169aIiYnBxo0bXfCiEBGRW+k8m9jJISJSS0WQREREIDAw0PZITU11uIorV66gsrISISEhdstDQkKQk5Pj8Dk5OTm1ls/Ly0NRURFefvlljBgxAl988QVGjx6NMWPGYPfu3WpfFSIiciedZxNnVyMiUssA5YeM/jNi5Pz583ZDAsxmiaFQLmKxVI3FeeCBB/DUU08BAKKjo7F3716sWLECQ4YMabC2EBGRi+k8m9jJISJSS8W9CAICAqTGPQcFBcHLywu5ubl2y3NzcxEaGurwOaGhobWWDwoKgre3N2655Ra7Mt27d8fXX38tvSlERKRBOs8mdnKIiBoBk8mEPn36ICMjAwkJCQCqjnZlZGRgxowZDp8TGxuLjIwMzJ4927Zsx44diI2NtdXZt29fnDhxwu55//rXv9C+fft62Q7dkJ3T57rkle2SF2wDAPzk6lTy08e9MxTJbY/xupIq5bZedoICJWQnEwAgfxTeW8nEAy6eUEDBZ1N6QgE/BZ932fXLftcA+e8vaTqb2MkhIlKrgW64lpycjMTERNx+++3o168fli5diuLiYkyZMgUAMGnSJLRp08Y2dvrJJ5/EkCFD8Nprr2HUqFFYu3YtDhw4gJUrV9rqnDNnDsaNG4fBgwfjzjvvxLZt27B582ZkZmYqbyAREWmHzrOJnRwiIrVUDAlQYty4cbh8+TIWLFiAnJwcREdHY9u2bbYLOM+dOwej8b8JNWDAAKSnp+OFF17A888/j86dO2Pjxo3o0aOHrczo0aOxYsUKpKamYtasWejatSs++eQTDBw4UHH7iIhIQ3SeTbxPDhHpjsvvRTCpJwJMCu9FUF6Jlu9/r7oN1DAU3ycn96JcxRcd3yzvZuJisVx9AFAgd58cFMnfJ0f6njqy99MB5O+pI3s/nesKfs5IVsnhahLcPVwtUPI+OeHN5OsMby1XLiRcbt3uuk+OzrOJZ3KIiNRqoKNlRERE0nSeTezkEBGppfMgISIiDdJ5NvFmoERERERE5FEUd3L27NmD++67D+Hh4TAYDNi4caPd3ydPngyDwWD3GDFihKvaS0SkPUYnH+QSzCUiIgd0nk2KN6W4uBi9e/dGWlpajWVGjBiBS5cu2R5r1qxR1UgiIk2zDglQ+iCXYC4RETmg82xSfE3OyJEjMXLkyFrLmM3mGu9ySkTkaQwGwKDwkJHBc3LE7ZhLRETV6T2b6uWkVGZmJlq3bo2uXbti2rRpuHr1ao1ly8rKUFhYaPcgImpUdH60rDFQkksAs4mIPIDOs8nls6uNGDECY8aMQVRUFE6fPo3nn38eI0eORFZWFry8qs/VnZqaipSUFFc3g4io4TTQXaXJOUpzCaglm4SoetRF9v4qsuW8FXxgfCTvi6HgvjIGybKiHu5VI/0aKSHZTgPq4Qefku++7P1v6uM+OU3kyhlk6wPk770j+xkG5L8bSj5HsmW1davJ6nSeTS7v5IwfP972/z179kSvXr3QsWNHZGZmYtiwYdXKz5s3D8nJybZ/FxYWIiIiwtXNIiIinVKaSwCziYiosav3/lqHDh0QFBSEU6dOOfy72WxGQECA3YOIqFHR+ZCAxqauXAKYTUTkAXSeTfV+M9Cff/4ZV69eRVhYWH2viojIPXR+w7XGhrlERLqg82xS3MkpKiqyO/qVnZ2NI0eOoGXLlmjZsiVSUlLw4IMPIjQ0FKdPn8azzz6LTp06IT4+3qUNJyLSDJ2Pe3Y35hIRkQM6zybFnZwDBw7gzjvvtP3bOmY5MTERy5cvx9GjR/Hee+8hPz8f4eHhGD58OF566SWYzWbXtZqISEuMcOJoWb20RJeYS0REDug8mxR3coYOHQpRy2wS27dvV9UgIqJGR+dHy9yNuURE5IDOs8mDNoWIiIiIiKgBJh4gIvJ4Or+4k4iINEjn2cRODhGRWgYoPy/uOTlCRERapPNsYieHiEgtnR8tIyIiDdJ5NrGTQ0Skls4v7iQiIg3SeTaxk0NEpJbOj5ZRA1Dyw0O2rJLPoDt/+Ei3s+YZ9jyeO/cnij6bku2sj8+7Huk8m/jRICIiIiIij8IzOUREaun8aBkREWmQzrOJnRwiIrV0Pu6ZiIg0SOfZxE4OEZFaOj9aRkREGqTzbGInh4hILZ0fLSMiIg3SeTaxk0NEpJbBUPVQ+hwiIqL6ovNs8qD+GhEREREREc/kEBGpZ/jPQ+lziIiI6ovOs4mdHCIitXQ+JICIiDRI59nETg4RkSt4Ti4QEZGn0HE2sZNDRKSWzo+WUQOw1EPZ60K+TtmyFgV1ypaVXrf8qmXLCiXbI8mg5FdnfbyX3i5+L+vlcyRfpaKyeqPzbGInh4hILZ1P00lERBqk82zyoE0hIiIiIiLimRwiIvV0PiSAiIg0SOfZxE4OEZFaOp+mk4iINEjn2cRODhGRWjo/WkZERBqk82xiJ4eISC2dHy0jIiIN0nk2ceIBIiIiIiLyKDyTQ0Skls6HBBARkQbpPJvYySEiUkvn9yIgIiIN0nk2sZNDRKSWzo+WERGRBuk8m9jJISJSS+cXd5IDRsk3WLbcdYv8uksrXVsOgCgXcgUrJMsBQLnkNkmWE9fl122plCsrFLzssgxG+XYaLXKfD4NkuapKZcvJ1Sn92QBgkP3MmRRsj1lyg2S/a0rLapnOs4mdHCIitXR+tIyIiDRI59nkQSPviIiIiIiIeCaHiEg1nR8sIyIiDdJ7NrGTQ0Sklt6ThIiItEfn2cRODhGRWjq/uJOIiDRI59nETg4RkVoGg/LZeDzoaBkREWmQzrOJnRwiIrV0frSMiIg0SOfZxNnViIiIiIjIo/BMDhGRWjq/uJOIiDRI59nEMzlERGoZnHw4IS0tDZGRkfDx8UFMTAy+/fbbWsuvX78e3bp1g4+PD3r27InPP/+8xrKPP/44DAYDli5d6lzjiIhIO3SeTezkEBGpZT1apvSh0Lp165CcnIyFCxfi0KFD6N27N+Lj45GXl+ew/N69ezFhwgRMnToVhw8fRkJCAhISEnDs2LFqZTds2IB9+/YhPDxccbuIiEiDdJ5NHK5GRKRWA13c+frrr+Oxxx7DlClTAAArVqzA1q1b8e6772Lu3LnVyr/xxhsYMWIE5syZAwB46aWXsGPHDrz11ltYsWKFrdyFCxcwc+ZMbN++HaNGjVLeMD2R/REg+0PBW/JY42+VcuUAoEiurJAsp2j9pRb5OiXLVlbIlRMKNkdYhFw5uWKKKPkNKbtNhkr5hnrJvkXS5eTXLSxeUuUMSmYEM0l+h2S/a4D8m6T1oV06zyaeySEiUsuIqmk6FT2qnlpYWGj3KCsrc7iK8vJyHDx4EHFxcf9drdGIuLg4ZGVlOXxOVlaWXXkAiI+PtytvsVjwyCOPYM6cObj11lvVvQ5ERKQdOs8mdnKIiNwoIiICgYGBtkdqaqrDcleuXEFlZSVCQkLsloeEhCAnJ8fhc3Jycuos/8orr8Db2xuzZs1SuSVEROQpPCGbOFyNiEgtFUMCzp8/j4CAANtis9nssmbV5eDBg3jjjTdw6NAhGLQ+7IKIiJTReTbxTA4RkVoqLu4MCAiwe9QUJEFBQfDy8kJubq7d8tzcXISGhjp8TmhoaK3lv/rqK+Tl5aFdu3bw9vaGt7c3zp49i6effhqRkZEqXxQiInIrnWcTOzlERGo1wDSdJpMJffr0QUZGhm2ZxWJBRkYGYmNjHT4nNjbWrjwA7Nixw1b+kUcewdGjR3HkyBHbIzw8HHPmzMH27duVNZCIiLRF59nE4WpERGo10A3XkpOTkZiYiNtvvx39+vXD0qVLUVxcbJvRZtKkSWjTpo1t7PSTTz6JIUOG4LXXXsOoUaOwdu1aHDhwACtXrgQAtGrVCq1atbJbR5MmTRAaGoquXbsqbh8REWmIzrNJ8ZmcPXv24L777kN4eDgMBgM2btxo93chBBYsWICwsDD4+voiLi4OJ0+eVLoaIqLGowGOlgHAuHHjsGTJEixYsADR0dE4cuQItm3bZruA89y5c7h06ZKt/IABA5Ceno6VK1eid+/e+Pjjj7Fx40b06NFDxcZqD3OJiMgBnWeT4jM5xcXF6N27Nx599FGMGTOm2t8XL16MN998E++99x6ioqIwf/58xMfH48cff4SPj49LGk1EpFczZszAjBkzHP4tMzOz2rKHH34YDz/8sHT9Z86ccbJl7sNcIiJyLy1mk+JOzsiRIzFy5EiHfxNCYOnSpXjhhRfwwAMPAADef/99hISEYOPGjRg/frziBhIRaZ71/gJKn0MuwVwiInJA59nk0okHsrOzkZOTY3eDn8DAQMTExNR4Q6CysrJqNxwiImpUVMxgQ/XLmVwCmE1E5AF0nk0unXjAehMfJTcESk1NRUpKiiubQUTUsBro4k5SzplcAmrLJiNgkDg+aPSSa2ATyWON+dflygEQv1bIFSySrxMlFqlilRVy5QDAUiEk65QrByFZDoCQbKawyNcpy6DgSLnMR62qoHydliZy22SUfC+9ShUcLy+Xq1NUyr/u0q+n7HcNkP/+Sr9BbqLzbHL7uzNv3jwUFBTYHufPn3d3k4iIlNH50TJPxGwiokZP59nk0jM51pv45ObmIiwszLY8NzcX0dHRDp9jNpsb9C6qREQuZ5A8un/zc6jeOZNLALOJiDyAzrPJpVsSFRWF0NBQuxv8FBYWYv/+/TXeEIiIiKi+MJeIiPRJ8ZmcoqIinDp1yvbv7OxsHDlyBC1btkS7du0we/Zs/OlPf0Lnzp1tU3WGh4cjISHBle0mItIOgxMz2HjQkAB3Yy4RETmg82xS3Mk5cOAA7rzzTtu/k5OTAQCJiYlYvXo1nn32WRQXFyMpKQn5+fkYOHAgtm3bxnsREJHn0vnFne7GXCIickDn2aS4kzN06FCIWmYwMRgMePHFF/Hiiy+qahgRUaOh83HP7sZcIiJyQOfZ5NKJB4iIdEnnR8uIiEiDdJ5N7OQQEaml87tKExGRBuk8mzznnBQRERERERF4JoeISD2dj3smIiIN0nk2sZNDRKSWzsc9ExGRBuk8m9jJISJSS+dBoiuyR0a9JePVbJYqJq6Wy9UHQOSUSZW7XmqRrrOyoubZ625kqZCvU1TKlbNUyq1bWOTKKVHLpH1Oq4+vvkHBdRSVXnJlDV5y9RmbyB/59yqRW7d3keSHQwGD5HetqgGS31+tn/XQeTaxk0NEpJbB4MSQAM8JEiIi0iCdZxM7OUREaul8BhsiItIgnWeTxs+zERERERERKcMzOUREaul83DMREWmQzrOJnRwiIrV0Pk0nERFpkM6ziZ0cIiK1dH60jIiINEjn2cRODhGRWjq/uJOIiDRI59nETg4RkWpODAngvC9ERFSv9J1NnrMlRERERERE4JkcIiL1dD7umYiINEjn2cRODhGRWjoPEl0xegFGieg0meTqa9pMqpjlUplcfQBKLpdLlasss0jXaamULHddSNcJoaAsNTzJfZTRW35fZvSSK+dllh9o1FTyY2SU/K4BkP/+yuwL3Enn2aTxd4eIqBHQeZAQEZEG6Tyb2MkhIlLLaKx6KH0OERFRfdF5NrGTQ0Skls6PlhERkQbpPJs8p7tGREREREQEnskhIlJP50fLiIhIg3SeTezkEBGpZTAov+GaBwUJERFpkM6ziZ0cIiK1jIaqh9LnEBER1RedZxM7OUREaul8SAAREWmQzrOJnRwiIrUMRieGBHDeFyIiqkc6zybP2RIiIiIiIiLwTA4RkXo6HxKgK94+VY+6+DaVq89ikSpWnFsuVx+AaxfL5FYt5D+DQkgXdTnZr4qSr5QBbtwgBQTkNkrJ+9MY3kujQb6RQu4rhMBmftJ1Sn9/ZfYF7qTzbGInh4hILZ0HCRERaZDOs4mdHCIitYzGqofS5xAREdUXnWcTOzlERKoZ/vNQ+hwiIqL6ou9sYieHiEgtnQ8JICIiDdJ5NnnOOSkiIiIiIiLwTA4RkQs4cS8CHmMiIqJ6pe9sYieHiEg1fY97JiIiLdJ3NrGTQ0Skls7HPRMRkQbpPJvYySEiUsvgxJAAxUMIiIiIFNB5NrGTQ0Skmr6HBBARkRbpO5s8p7tGREREREQEnskhIlLPACfGPddLS6ieGbx9YfD2qbOcaOInV6Gf3LHGwovlcvUByCswSZeVZZT8vCr5GhgNQqqct5dcOdn6APl2ym63Ehb5ZkJIlrUI+YZer5QrK1unbBur6pQvK0tA7rsR6BcgX6l3U6liBm9f+TrdQefZxE4OEZFqRig/Mc4T6UREVJ/0nU2esyVERO5incFG6cMJaWlpiIyMhI+PD2JiYvDtt9/WWn79+vXo1q0bfHx80LNnT3z++ee2v1VUVOC5555Dz5490axZM4SHh2PSpEm4ePGiU20jIiIN0Xk2sZNDRKRWAwXJunXrkJycjIULF+LQoUPo3bs34uPjkZeX57D83r17MWHCBEydOhWHDx9GQkICEhIScOzYMQBASUkJDh06hPnz5+PQoUP49NNPceLECdx///2qXg4iItIAnWeTQQgloynrX2FhIQIDA1FQkImAAMkxzUREChQWFiEwcCgKCgoQEKBgnHa1eqr2V/nfv4AA/7qv07B77rVSNO/5J0VtiImJQd++ffHWW28BACwWCyIiIjBz5kzMnTu3Wvlx48ahuLgYW7ZssS3r378/oqOjsWLFCofr+O6779CvXz+cPXsW7dq1U7RNnsyWTSdekXqvRWmBXMXXS6SKnR/yd7n6AOQVNJEuK4vX5LgOr8lxrdaBFVLlInZPlK9U9pocn0C5+sLukCrGbHJtNvFMDhGRagYnH/LKy8tx8OBBxMXF2ZYZjUbExcUhKyvL4XOysrLsygNAfHx8jeUBoKCgAAaDAc2bN1fUPiIi0hp9ZxMnHiAiUkvFDdcKCwvtFpvNZpjN5mrFr1y5gsrKSoSEhNgtDwkJwfHjxx2uIicnx2H5nJwch+VLS0vx3HPPYcKECaqOIhIRkQboPJtcfiZn0aJFMBgMdo9u3bq5ejVERNqhYtxzREQEAgMDbY/U1FS3bEJFRQXGjh0LIQSWL1/uljbUJ2YTEemOzrOpXs7k3Hrrrfjyyy//uxJvnjAiIk+m/BS/tfz58+ftjkw5OlIGAEFBQfDy8kJubq7d8tzcXISGhjp8TmhoqFR5a4icPXsWO3fu9NizOMwmItIXfWdTvVyT4+3tjdDQUNsjKCioPlZDRKQN1iEBSh8AAgIC7B41BYnJZEKfPn2QkZFhW2axWJCRkYHY2FiHz4mNjbUrDwA7duywK28NkZMnT+LLL79Eq1at1L4amsVsIiJd0Xk21cthrJMnTyI8PBw+Pj6IjY1FampqjTMhlJWVoayszPbvm8cAEhFRleTkZCQmJuL2229Hv379sHTpUhQXF2PKlCkAgEmTJqFNmza2YQVPPvkkhgwZgtdeew2jRo3C2rVrceDAAaxcuRJAVYg89NBDOHToELZs2YLKykrbmOiWLVvCZDK5Z0PrCbOJiMj1tJpNLu/kxMTEYPXq1ejatSsuXbqElJQUDBo0CMeOHYO/v3+18qmpqUhJSXF1M4iIGoz1Gg+lz1Fq3LhxuHz5MhYsWICcnBxER0dj27Zttgs4z507B6PxvyfoBwwYgPT0dLzwwgt4/vnn0blzZ2zcuBE9evQAAFy4cAGfffYZACA6OtpuXbt27cLQoUMVt1GrXJZNJn/A5Fvn+gzCItUu4SU33fPVa/LTQmeXyEW7kh8AspPQKpm82iQ5NbTsFNJNJMsBgJdRrqyT90WslZIplystcg2okJwWGpCfQrpcspzcBM5VSiXLXVdQp5fkmKQIs+R0zwAM3pKfeJO2h/bqPZvq/T45+fn5aN++PV5//XVMnTq12t8dHS2LiIjgfXKIqN64+l4EBT/92al7EQR2/x/VbSDnOJ1N2W8jwL/uTg7K8qXaIa7L/ew7cuvfpMoBwKkidnLqwk5O3RpLJ6eTn1zp6B8ek65TupNjbi5XrlVPqWLMJteq96sumzdvji5duuDUqVMO/17TlHRERI2Gimk6yT2YTUTk8XSeTfW+JUVFRTh9+jTCwsLqe1VERG5S/zdcI9diNhGR59N3Nrm8k/PMM89g9+7dOHPmDPbu3YvRo0fDy8sLEyZMcPWqiIi0QcW9CKhhMJuISHd0nk0uH672888/Y8KECbh69SqCg4MxcOBA7Nu3D8HBwa5eFRERkRRmExGRvri8k7N27VpXV0lEpG0GgxPjnj3naFljwGwiIt3ReTbxds9ERKo5f1dpIiKi+qHvbGInh4hILWfGMXvQ0TIiItIgnWcTOzlERGrpfJpOIiLSIJ1nEzs5RESq6XtIABERaZG+s8lzumtERERERETgmRwiIvV0Pu5ZT0R+NkSlue6CRflyFRYUSBVrE14pVx+AkNIKqXIV5dJVouK63Of1ukX+c10pWVa2nBDSq5YuK+rhqLbRIN9QL2+5suYm8uv3MsrVKVvOW7IcADSR3J4mJukq4e0jebz+zI/SdYrAQLmCfs2lihla9ZRet0vpPJvYySEiUs0I5SfGeSKdiIjqk76ziZ0cIiK1dH60jIiINEjn2cRODhGRWjoPEiIi0iCdZxM7OUREqul7SAAREWmRvrPJc7aEiIiIiIgIPJNDROQCTgwJ8KB7ERARkRbpO5vYySEiUk3fN1wjIiIt0nc2sZNDRKSWwVj1UPocIiKi+qLzbGInh4hILQOcmMGmXlpCRERURefZxE4OEZFq+h4SQEREWqTvbGInh4iISJKhwygYAvwafL2tTzzZ4OskImrM2MkhIlJL5+OeiYhIg3SeTezkEBGppu8hAUREpEX6ziZ2coiI1DI4cS8CxfcuICIiUkDn2cRODhGRasb/PJQ+h4iIqL7oO5vYySEiUkvnR8uIiEiDdJ5NntNdIyIiIiIiAs/kEBGpp/MZbIiISIN0nk3s5BARqabvGWyIiEiL9J1N7OQQEaml83HPRESkQTrPJnZyiIhU0/cMNkREpEX6ziZ2coiI1NL50TIiItIgnWeT53TXiIiIiIiIwDM5REQuoO8hAUREpEX6ziZ2coiI1NL5kAAiItIgnWcTOzlERGoZ4ESQ1EtLiIiIqug8m9jJISJSTd9DAoiISIv0nU3s5BARqaXzIQFERKRBOs8mz+muERERERERgWdyiIhcwADlA5k952gZERFpkb6ziZ0cIiK1DMaqh9LnEBER1RedZxM7OUREqun7aBkREWmRvrOJnRwiIrV0frSMiIg0SOfZxE4OEZFq+j5aRkREWqTvbPKc7hoRERERERF4JoeISD2d34uAiIg0SOfZxE4OEZFaOh/3TEREGqTzbGInh4hINX2PeyYiIi3Sdzaxk0NEpJbOhwQQEZEG6Tyb2MkhIlLNCOXzuHjOkAAiItIifWdTvW1JWloaIiMj4ePjg5iYGHz77bf1tSoiIt1Qum9dv349unXrBh8fH/Ts2ROff/653d+FEFiwYAHCwsLg6+uLuLg4nDx5sj43wW2YS0RE9UOL2VQvnZx169YhOTkZCxcuxKFDh9C7d2/Ex8cjLy+vPlZHROReBvx3WID0Q/lqlO5b9+7diwkTJmDq1Kk4fPgwEhISkJCQgGPHjtnKLF68GG+++SZWrFiB/fv3o1mzZoiPj0dpaamTL4Y2MZeISHd0nk0GIYRQvjm1i4mJQd++ffHWW28BACwWCyIiIjBz5kzMnTu31ucWFhYiMDAQBQWZCAjwc3XTiIhQWFiEwMChKCgoQEBAgIp6/rO/yt+leH9VWFiEwOZ3KmqD0n3ruHHjUFxcjC1bttiW9e/fH9HR0VixYgWEEAgPD8fTTz+NZ555BgBQUFCAkJAQrF69GuPHj1e0TVqmJpcAZhMR1T9mk2uzyeXX5JSXl+PgwYOYN2+ebZnRaERcXByysrKqlS8rK0NZWZnt3wUFBQCAwsJiVzeNiAjAf/cvrjrGU3itRPHFmoXXSv7TlkK75WazGWazuVp5pftWAMjKykJycrLdsvj4eGzcuBEAkJ2djZycHMTFxdn+HhgYiJiYGGRlZXlMJ8eZ147ZREQNjdm0EYDrssnlnZwrV66gsrISISEhdstDQkJw/PjxauVTU1ORkpJSbXlExChXN42IyM61a9cQGBjo9PNNJhNCQ0Od3l/5+fkhIiLCbtnChQuxaNGiamWV7lsBICcnx2H5nJwc29+ty2oq4wmcee2YTUTkLswm12ST22dXmzdvnl1vLj8/H+3bt8e5c+dUvcFaUlhYiIiICJw/f17V6Uet4PZoG7enbkIIXLt2DeHh4arq8fHxQXZ2NsrLy51uh+Gmo2yOjpRRw/P0bOJ+Qvs8bZu4PXVjNrmWyzs5QUFB8PLyQm5urt3y3NxchIaGVitf0+mvwMBAj/gS3CggIMCjtonbo23cntq56oeqj48PfHx8XFJXbZTuWwEgNDS01vLW/+bm5iIsLMyuTHR0tAtb717OvHZ6ySbuJ7TP07aJ21M7ZpPrssnls6uZTCb06dMHGRkZtmUWiwUZGRmIjY119eqIiHTBmX1rbGysXXkA2LFjh618VFQUQkND7coUFhZi//79HrW/Zi4REdUPTWeTqAdr164VZrNZrF69Wvz4448iKSlJNG/eXOTk5NT53IKCAgFAFBQU1EfT3MLTtonbo23cHs9V1771kUceEXPnzrWV/+abb4S3t7dYsmSJ+Omnn8TChQtFkyZNxPfff28r8/LLL4vmzZuLTZs2iaNHj4oHHnhAREVFid9++63Bt68+qcklITzvc8jt0T5P2yZuj+fSajbVSydHCCGWLVsm2rVrJ0wmk+jXr5/Yt2+f1PNKS0vFwoULRWlpaX01rcF52jZxe7SN2+PZatu3DhkyRCQmJtqV/+ijj0SXLl2EyWQSt956q9i6davd3y0Wi5g/f74ICQkRZrNZDBs2TJw4caIhNqXBOZtLQnje55Dbo32etk3cHs+mxWyql/vkEBERERERuYvLr8khIiIiIiJyJ3ZyiIiIiIjIo7CTQ0REREREHoWdHCIiIiIi8iia6+SkpaUhMjISPj4+iImJwbfffuvuJjll0aJFMBgMdo9u3bq5u1nS9uzZg/vuuw/h4eEwGAzYuHGj3d+FEFiwYAHCwsLg6+uLuLg4nDx50j2NlVTXNk2ePLnaezZixAj3NLYOqamp6Nu3L/z9/dG6dWskJCTgxIkTdmVKS0sxffp0tGrVCn5+fnjwwQer3XxLS2S2aejQodXeo8cff9xNLSY9YTZpg6dlkyflEuB52cRcatw01clZt24dkpOTsXDhQhw6dAi9e/dGfHw88vLy3N00p9x66624dOmS7fH111+7u0nSiouL0bt3b6SlpTn8++LFi/Hmm29ixYoV2L9/P5o1a4b4+HiUlpY2cEvl1bVNADBixAi792zNmjUN2EJ5u3fvxvTp07Fv3z7s2LEDFRUVGD58OIqLi21lnnrqKWzevBnr16/H7t27cfHiRYwZM8aNra6dzDYBwGOPPWb3Hi1evNhNLSa9YDZph6dlkyflEuB52cRcauScmgy7nvTr109Mnz7d9u/KykoRHh4uUlNT3dgq5yxcuFD07t3b3c1wCQBiw4YNtn9bLBYRGhoqXn31Vduy/Px8YTabxZo1a9zQQuVu3iYhhEhMTBQPPPCAW9qjVl5engAgdu/eLYSoej+aNGki1q9fbyvz008/CQAiKyvLXc1U5OZtEqJqrv0nn3zSfY0iXWI2aZOnZZOn5ZIQnpdNzKXGRTNncsrLy3Hw4EHExcXZlhmNRsTFxSErK8uNLXPeyZMnER4ejg4dOmDixIk4d+6cu5vkEtnZ2cjJybF7rwIDAxETE9No3yurzMxMtG7dGl27dsW0adNw9epVdzdJSkFBAQCgZcuWAICDBw+ioqLC7j3q1q0b2rVr12jeo5u3yervf/87goKC0KNHD8ybNw8lJSXuaB7pBLOp8fDUbGqsuQR4XjYxlxoXb3c3wOrKlSuorKxESEiI3fKQkBAcP37cTa1yXkxMDFavXo2uXbvi0qVLSElJwaBBg3Ds2DH4+/u7u3mq5OTkAIDD98r6t8ZoxIgRGDNmDKKionD69Gk8//zzGDlyJLKysuDl5eXu5tXIYrFg9uzZuOOOO9CjRw8AVe+RyWRC8+bN7co2lvfI0TYBwO9//3u0b98e4eHhOHr0KJ577jmcOHECn376qRtbS56M2dR4eGI2NdZcAjwvm5hLjY9mOjmeZuTIkbb/79WrF2JiYtC+fXt89NFHmDp1qhtbRjUZP3687f979uyJXr16oWPHjsjMzMSwYcPc2LLaTZ8+HceOHWtU4+rrUtM2JSUl2f6/Z8+eCAsLw7Bhw3D69Gl07NixoZtJ1OgwmxqXxppLgOdlE3Op8dHMcLWgoCB4eXlVm2EjNzcXoaGhbmqV6zRv3hxdunTBqVOn3N0U1azvh6e+V1YdOnRAUFCQpt+zGTNmYMuWLdi1axfatm1rWx4aGory8nLk5+fblW8M71FN2+RITEwMAGj6PaLGjdnUeOghmxpDLgGel03MpcZJM50ck8mEPn36ICMjw7bMYrEgIyMDsbGxbmyZaxQVFeH06dMICwtzd1NUi4qKQmhoqN17VVhYiP3793vEe2X1888/4+rVq5p8z4QQmDFjBjZs2ICdO3ciKirK7u99+vRBkyZN7N6jEydO4Ny5c5p9j+raJkeOHDkCAJp8j8gzMJsaDz1kk5ZzCfC8bGIuNXLunffA3tq1a4XZbBarV68WP/74o0hKShLNmzcXOTk57m6aYk8//bTIzMwU2dnZ4ptvvhFxcXEiKChI5OXlubtpUq5duyYOHz4sDh8+LACI119/XRw+fFicPXtWCCHEyy+/LJo3by42bdokjh49Kh544AERFRUlfvvtNze3vGa1bdO1a9fEM888I7KyskR2drb48ssvxW233SY6d+4sSktL3d30aqZNmyYCAwNFZmamuHTpku1RUlJiK/P444+Ldu3aiZ07d4oDBw6I2NhYERsb68ZW166ubTp16pR48cUXxYEDB0R2drbYtGmT6NChgxg8eLCbW06ejtmkHZ6WTZ6US0J4XjYxlxo3TXVyhBBi2bJlol27dsJkMol+/fqJffv2ubtJThk3bpwICwsTJpNJtGnTRowbN06cOnXK3c2StmvXLgGg2iMxMVEIUTVV5/z580VISIgwm81i2LBh4sSJE+5tdB1q26aSkhIxfPhwERwcLJo0aSLat28vHnvsMc3+iHG0HQDEqlWrbGV+++038cQTT4gWLVqIpk2bitGjR4tLly65r9F1qGubzp07JwYPHixatmwpzGaz6NSpk5gzZ44oKChwb8NJF5hN2uBp2eRJuSSE52UTc6lxMwghhOvPDxEREREREbmHZq7JISIiIiIicgV2coiIiIiIyKOwk0NERERERB6FnRwiIiIiIvIo7OQQEREREZFHYSeHiIiIiIg8Cjs5RERERETkUdjJISIiIiIij8JODhEREREReRR2coiIiIiIyKOwk0NERERERB6FnRwiIiIiIvIo/x8ND78JUUP2OwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": { + "engine": 0 + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "%px: 100%|███████████████████████████████████████████████████| 6/6 [00:00<00:00, 11.28tasks/s]\n" + ] + } + ], + "source": [ + "import copy as cp\n", + "import matplotlib.pyplot as plt\n", + "from pyfv3.stencils import FiniteVolumeFluxPrep\n", + "from units_config import units\n", + "\n", + "fvf_prep = FiniteVolumeFluxPrep(\n", + " stencil_factory, grid_data, grid_type=0\n", + ")\n", + "\n", + "crx = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"courant\"], dtype=\"float\"\n", + ")\n", + "cry = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"courant\"], dtype=\"float\"\n", + ")\n", + "\n", + "x_area_flux = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"area\"], dtype=\"float\"\n", + ")\n", + "y_area_flux = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"area\"], dtype=\"float\"\n", + ")\n", + "\n", + "uc_contra = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"wind\"], dtype=\"float\"\n", + ")\n", + "vc_contra = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"wind\"], dtype=\"float\"\n", + ")\n", + "\n", + "crx_before = cp.deepcopy(crx)\n", + "\n", + "fvf_prep(\n", + " initial_state[\"u_cgrid\"],\n", + " initial_state[\"v_cgrid\"],\n", + " crx,\n", + " cry,\n", + " x_area_flux,\n", + " y_area_flux,\n", + " uc_contra,\n", + " vc_contra,\n", + " timestep,\n", + ")\n", + "\n", + "if mpi_rank == 0:\n", + " fig = plt.figure(figsize=(10, 4))\n", + " fig.patch.set_facecolor(\"white\")\n", + " ax_before = fig.add_subplot(121)\n", + " ax_after = fig.add_subplot(122)\n", + "\n", + " f1 = ax_before.pcolormesh(\n", + " crx_before.data[:, :, 0], vmin=-0, vmax=0.1, cmap=\"YlOrRd\"\n", + " )\n", + " plt.colorbar(f1, ax=ax_before)\n", + " f2 = ax_after.pcolormesh(crx.data[:, :, 0], vmin=-0, vmax=0.1, cmap=\"YlOrRd\")\n", + " plt.colorbar(f2, ax=ax_after)\n", + "\n", + " ax_before.set_title(\"crx before FiniteVolumeFluxPrep call\")\n", + " ax_after.set_title(\"crx after FiniteVolumeFluxPrep call\")\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "aadc97e9", + "metadata": {}, + "source": [ + "Since our layer have thickness of delp Pa, we can use that information and the `x_area_flux` and `y_area_flux` variables provided by `FiniteVolumeFluxPrep` to calculate mass fluxes that are required as input to `TracerAdvection`.\n", + "\n", + "We are assuming that density is 1 (kg /m3)." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "4869723d", + "metadata": {}, + "outputs": [], + "source": [ + "mfxd = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"mass\"], dtype=\"float\"\n", + ")\n", + "mfyd = domain_configuration[\"quantity_factory\"].zeros(\n", + " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"mass\"], dtype=\"float\"\n", + ")\n", + "\n", + "density = 1.0\n", + "\n", + "mfxd.data[:] = x_area_flux.data[:] * initial_state[\"delp\"].data[:] * density\n", + "mfyd.data[:] = y_area_flux.data[:] * initial_state[\"delp\"].data[:] * density\n" + ] + }, + { + "cell_type": "markdown", + "id": "8cbf898b", + "metadata": {}, + "source": [ + "### 2. Tracer Advection and its Inputs\n", + "\n", + "In order to build the `TracerAdvection` stencil, it needs an input of a different stencil, `FiniteVolumeTransport`. \n", + "\n", + "For building the `FiniteVolumeTransport` stencil, we need `stencil_factory`, `grid_data`, and `damping_coefficients` from the configuration dictionary. We do not actually need to run it, as it get run within `TracerAdvection`, but if we did, we would get output tracer mass fluxes. \n", + "\n", + "For building `TracerAdvection`, we need `stencil_factory`, the pre-built `FiniteVolumeTransport` stencil, `grid_data`, and the cubed-sphere communicator stored under configuration as `communicator`. We also need a dictionary that includes all the tracers we want to follow at their initial state.\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4446b419", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "%px: 100%|███████████████████████████████████████████████████| 6/6 [00:20<00:00, 3.38s/tasks]\n" + ] + } + ], + "source": [ + "from pyfv3.stencils import FiniteVolumeTransport, TracerAdvection\n", + "\n", + "grid_type = 0 # cubed-sphere\n", + "hord = 6 # horizontal diffusion order\n", + "\n", + "tracers = {\"tracer\": initial_state[\"tracer\"]}\n", + "\n", + "fvtp_2d = FiniteVolumeTransport(\n", + " stencil_factory,\n", + " domain_configuration[\"quantity_factory\"],\n", + " grid_data,\n", + " damping_coefficients,\n", + " grid_type,\n", + " hord,\n", + ")\n", + "\n", + "tracer_advection = TracerAdvection(\n", + " stencil_factory,\n", + " domain_configuration[\"quantity_factory\"],\n", + " fvtp_2d,\n", + " grid_data,\n", + " domain_configuration[\"communicator\"],\n", + " tracers,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "de2681d7", + "metadata": {}, + "source": [ + "To run a single step of `TracerAdvection`, we need to provide it the following inputs:\n", + "- `tracers`: a dictionary of all tracers we want to advect\n", + "- `delp`: pressure thickness of layers\n", + "- `mfxd`: mass flux in the x-direction\n", + "- `mfyd`: mass flux in the y-direction\n", + "- `crx`: Courant number in the x-direction\n", + "- `cry`: Courant number in the y-direction\n", + "- `timestep`: the timestep that is applied. \n", + "\n", + "Within `TracerAdvection`, the time step is split into 3 equal sub-steps, and all fields are divided by three, then advection is calculated for each of the substeps. \n", + "\n", + "All fields but `delp` are updated. Mass fluxes and Courant numbers are divided by 3 and then returned. So if we want to continue advecting with the initial wind field, we actually need to re-set those fields to initial conditions after each step." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "8043021f", + "metadata": { + "jupyter": { + "outputs_hidden": true + }, + "tags": [] + }, + "outputs": [], + "source": [ + "tracer_initial = cp.deepcopy(tracers)\n", + "mfxd_initial = cp.deepcopy(mfxd)\n", + "mfyd_initial = cp.deepcopy(mfyd)\n", + "crx_initial = cp.deepcopy(crx)\n", + "cry_initial = cp.deepcopy(cry)\n", + "\n", + "tracer_state = [tracer_initial[\"tracer\"]]\n", + "\n", + "nSteps = 10\n", + "\n", + "for step in range(nSteps):\n", + " tracer_advection(tracers, initial_state[\"delp\"], mfxd, mfyd, crx, cry)\n", + "\n", + " tracer_state.append(tracers[\"tracer\"])\n", + "\n", + " mfxd = cp.deepcopy(mfxd_initial)\n", + " mfyd = cp.deepcopy(mfyd_initial)\n", + " crx = cp.deepcopy(crx_initial)\n", + " cry = cp.deepcopy(cry_initial)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "f1e2588c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[output:0]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFh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586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "engine": 0 + }, + "output_type": "display_data" + } + ], + "source": [ + "if mpi_rank == 0:\n", + " fig = plt.figure(figsize=(16, 4))\n", + " fig.patch.set_facecolor(\"white\")\n", + " ax_before = fig.add_subplot(131)\n", + " ax_after = fig.add_subplot(132)\n", + " ax_diff = fig.add_subplot(133)\n", + "\n", + " f1 = ax_before.pcolormesh(\n", + " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f1, ax=ax_before)\n", + " f2 = ax_after.pcolormesh(\n", + " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f2, ax=ax_after)\n", + " f3 = ax_diff.pcolormesh(\n", + " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", + " vmin=-0.5,\n", + " vmax=0.5,\n", + " cmap=\"bwr\",\n", + " )\n", + " plt.colorbar(f3, ax=ax_diff)\n", + "\n", + " ax_before.set_title(\"tracer concentration at t=0\")\n", + " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", + " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "d41c4b7b", + "metadata": {}, + "source": [ + "## Recreating this with functions.py\n", + "\n", + "You can reproduce the above steps in a more succinct manner by using the following syntax.\n", + "\n", + "In this case, we are using 79 layers, and things are not as fast as they could be - the same calculation is repeated at every vertical level." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "5d38b817", + "metadata": { + "jupyter": { + "outputs_hidden": true + }, + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[1:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", + "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", + "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", + "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", + "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", + "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 982\u001b[0m \n", + "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", + "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", + "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", + "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", + "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 1003\u001b[0m }\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", + "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 874\u001b[0m )\n", + "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", + "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 881\u001b[0m fvf_prep(\n", + "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 890\u001b[0m timestep,\n", + "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", + "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 895\u001b[0m )\n", + "\n", + "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n" + ] + }, + { + "data": { + "text/plain": [ + "[stderr:2] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", + " np.sum(p * q, axis=-1)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[4:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", + "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", + "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", + "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", + "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", + "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 982\u001b[0m \n", + "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", + "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", + "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", + "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", + "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 1003\u001b[0m }\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", + "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 874\u001b[0m )\n", + "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", + "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 881\u001b[0m fvf_prep(\n", + "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 890\u001b[0m timestep,\n", + "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", + "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 895\u001b[0m )\n", + "\n", + "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n" + ] + }, + { + "data": { + "text/plain": [ + "[stderr:5] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", + " np.sum(p * q, axis=-1)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[0:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", + "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", + "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", + "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", + "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", + "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 982\u001b[0m \n", + "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", + "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", + "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", + "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", + "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 1003\u001b[0m }\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", + "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 874\u001b[0m )\n", + "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", + "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 881\u001b[0m fvf_prep(\n", + "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 890\u001b[0m timestep,\n", + "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", + "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 895\u001b[0m )\n", + "\n", + "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n", + "[2:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", + "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", + "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", + "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", + "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", + "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 982\u001b[0m \n", + "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", + "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", + "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", + "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", + "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", + "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", + "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 1003\u001b[0m }\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", + "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 874\u001b[0m )\n", + "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", + "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 881\u001b[0m fvf_prep(\n", + "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 890\u001b[0m timestep,\n", + "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", + "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", + "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "\u001b[1;32m 895\u001b[0m )\n", + "\n", + "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n", + "[5:execute] TypeError: __init__() missing 1 required positional argument: 'grid_type'\n", + "[3:execute] TypeError: __init__() missing 1 required positional argument: 'grid_type'\n" + ] + }, + { + "ename": "AlreadyDisplayedError", + "evalue": "6 errors", + "output_type": "error", + "traceback": [ + "6 errors" + ] + } + ], + "source": [ + "mpi_comm = MPI.COMM_WORLD\n", + "mpi_rank = mpi_comm.Get_rank()\n", + "\n", + "nz = 79\n", + "if nz == 1:\n", + " single_layer = True\n", + "else:\n", + " single_layer = False\n", + "\n", + "namelist_dict = func.store_namelist_variables(locals())\n", + "dimensions = func.define_dimensions(namelist_dict)\n", + "\n", + "\n", + "domain_configuration = func.configure_domain(mpi_comm, dimensions, single_layer=single_layer)\n", + "\n", + "initial_state = func.create_initial_state_advection(\n", + " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", + ")\n", + "\n", + "stencil_configuration = func.configure_stencil(domain_configuration, backend=backend)\n", + "stencil_configuration[\"quantity_factory\"] = domain_configuration[\"quantity_factory\"]\n", + "\n", + "tracer_advection_data, tracer_advection = func.prepare_everything_for_advection(\n", + " stencil_configuration, initial_state, dimensions, timestep\n", + ")\n", + "\n", + "tracer_advection_data_initial = cp.deepcopy(tracer_advection_data)\n", + "\n", + "tracer_state = [cp.deepcopy(tracer_advection_data_initial[\"tracers\"][\"tracer\"])]\n", + "\n", + "nSteps = 10\n", + "for step in range(nSteps):\n", + " tracer_advection_data = func.run_advection_step_with_reset(\n", + " tracer_advection_data_initial, tracer_advection_data, tracer_advection\n", + " )\n", + "\n", + " tracer_state.append(cp.deepcopy(tracer_advection_data[\"tracers\"][\"tracer\"]))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "fe879468", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[output:0]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFh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586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "engine": 0 + }, + "output_type": "display_data" + } + ], + "source": [ + "if mpi_rank == 0:\n", + " fig = plt.figure(figsize=(16, 4))\n", + " fig.patch.set_facecolor(\"white\")\n", + " ax_before = fig.add_subplot(131)\n", + " ax_after = fig.add_subplot(132)\n", + " ax_diff = fig.add_subplot(133)\n", + "\n", + " f1 = ax_before.pcolormesh(\n", + " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f1, ax=ax_before)\n", + " f2 = ax_after.pcolormesh(\n", + " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f2, ax=ax_after)\n", + " f3 = ax_diff.pcolormesh(\n", + " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", + " vmin=-0.5,\n", + " vmax=0.5,\n", + " cmap=\"bwr\",\n", + " )\n", + " plt.colorbar(f3, ax=ax_diff)\n", + "\n", + " ax_before.set_title(\"tracer concentration at t=0\")\n", + " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", + " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "79388634", + "metadata": {}, + "source": [ + "For a faster calculation, we can set the number of vertical levels to 1. This will increase computation speed more significantly once we add more time steps, or more points in the x- and y- dimensions. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "ced9db5c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[0:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", + "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", + "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", + "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", + "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", + "\u001b[1;32m 18\u001b[0m )\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", + "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", + "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", + "\u001b[1;32m 265\u001b[0m )\n", + "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", + "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", + "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", + "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 299\u001b[0m (\n", + "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", + "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", + "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", + "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", + "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", + "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2163\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2166\u001b[0m )\n", + "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2168\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2171\u001b[0m )\n", + "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", + "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", + "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", + "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", + "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\n", + "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", + "[4:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", + "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", + "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", + "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", + "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", + "\u001b[1;32m 18\u001b[0m )\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", + "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", + "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", + "\u001b[1;32m 265\u001b[0m )\n", + "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", + "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", + "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", + "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 299\u001b[0m (\n", + "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", + "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", + "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", + "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", + "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", + "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2163\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2166\u001b[0m )\n", + "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2168\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2171\u001b[0m )\n", + "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", + "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", + "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", + "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", + "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\n", + "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", + "[5:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", + "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", + "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", + "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", + "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", + "\u001b[1;32m 18\u001b[0m )\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", + "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", + "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", + "\u001b[1;32m 265\u001b[0m )\n", + "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", + "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", + "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", + "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 299\u001b[0m (\n", + "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", + "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", + "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", + "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", + "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", + "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2163\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2166\u001b[0m )\n", + "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2168\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2171\u001b[0m )\n", + "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", + "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", + "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", + "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", + "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\n", + "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", + "[3:execute]\n", + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", + "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", + "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", + "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", + "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", + "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", + "\u001b[1;32m 18\u001b[0m )\n", + "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\n", + "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", + "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", + "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", + "\u001b[0;32m (...)\u001b[0m\n", + "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", + "\u001b[1;32m 265\u001b[0m )\n", + "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", + "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", + "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", + "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", + "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 299\u001b[0m (\n", + "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", + "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", + "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", + "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", + "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", + "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2163\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2166\u001b[0m )\n", + "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", + "\u001b[1;32m 2168\u001b[0m [K_INTERFACE_DIM],\n", + "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", + "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", + "\u001b[1;32m 2171\u001b[0m )\n", + "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", + "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", + "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", + "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", + "\n", + "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", + "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", + "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", + "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "\n", + "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", + "[1:execute] ValueError: size of ak array is not equal to km=1\n", + "[2:execute] ValueError: size of ak array is not equal to km=1\n" + ] + }, + { + "ename": "AlreadyDisplayedError", + "evalue": "6 errors", + "output_type": "error", + "traceback": [ + "6 errors" + ] + } + ], + "source": [ + "mpi_comm = MPI.COMM_WORLD\n", + "mpi_rank = mpi_comm.Get_rank()\n", + "\n", + "nz = 1\n", + "if nz == 1:\n", + " single_layer = True\n", + "else:\n", + " single_layer = False\n", + "\n", + "namelist_dict = func.store_namelist_variables(locals())\n", + "dimensions = func.define_dimensions(namelist_dict)\n", + "\n", + "\n", + "domain_configuration = func.configure_domain(mpi_comm, dimensions, single_layer=single_layer)\n", + "\n", + "initial_state = func.create_initial_state_advection(\n", + " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", + ")\n", + "\n", + "stencil_configuration = func.configure_stencil(domain_configuration, backend=backend)\n", + "stencil_configuration[\"quantity_factory\"] = domain_configuration[\"quantity_factory\"]\n", + "\n", + "tracer_advection_data, tracer_advection = func.prepare_everything_for_advection(\n", + " stencil_configuration, initial_state, dimensions, timestep\n", + ")\n", + "\n", + "tracer_advection_data_initial = cp.deepcopy(tracer_advection_data)\n", + "\n", + "tracer_state = [cp.deepcopy(tracer_advection_data_initial[\"tracers\"][\"tracer\"])]\n", + "\n", + "nSteps = 10\n", + "for step in range(nSteps):\n", + " tracer_advection_data = func.run_advection_step_with_reset(\n", + " tracer_advection_data_initial, tracer_advection_data, tracer_advection\n", + " )\n", + "\n", + " tracer_state.append(cp.deepcopy(tracer_advection_data[\"tracers\"][\"tracer\"]))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "783a781e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[output:0]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFh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586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "engine": 0 + }, + "output_type": "display_data" + } + ], + "source": [ + "if mpi_rank == 0:\n", + " fig = plt.figure(figsize=(16, 4))\n", + " fig.patch.set_facecolor(\"white\")\n", + " ax_before = fig.add_subplot(131)\n", + " ax_after = fig.add_subplot(132)\n", + " ax_diff = fig.add_subplot(133)\n", + "\n", + " f1 = ax_before.pcolormesh(\n", + " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f1, ax=ax_before)\n", + " f2 = ax_after.pcolormesh(\n", + " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", + " )\n", + " plt.colorbar(f2, ax=ax_after)\n", + " f3 = ax_diff.pcolormesh(\n", + " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", + " vmin=-0.5,\n", + " vmax=0.5,\n", + " cmap=\"bwr\",\n", + " )\n", + " plt.colorbar(f3, ax=ax_diff)\n", + "\n", + " ax_before.set_title(\"tracer concentration at t=0\")\n", + " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", + " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b0cc550-95f0-4b79-9916-6d5859cb8420", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "vscode": { + "interpreter": { + "hash": "5aaa1d64d2aec5fc9d71d95fe114c55e361597d915cf108c460e747a228aecec" + } + } }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgIAAAGzCAYAAABdO3+BAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA4KklEQVR4nO3df1zV9d3/8edR4YAKxwD5lUj4I/EXdl3+INKMxERqTpOaWtvUmc6FXVPXLLby11qUu1auXYhtc5AVpbbU5a50aopzE690c9ZWTLkoMQWXuwDFQMb5fP9wnG8nUD6Hc4DjOY/77fa+jfP+/Hqfz06e13m9f3wshmEYAgAAfqlLZzcAAAB0HgIBAAD8GIEAAAB+jEAAAAA/RiAAAIAfIxAAAMCPEQgAAODHCAQAAPBjBAIAAPgxAgG0u48++kgWi0UFBQUuH7t//35ZLBbt37+/1X1TU1OVmprq8jXgzJV7DuD6RyAAtxUUFMhisbRYHn/88c5uXrt6+umntW3bNlP7njlzRitXrtSxY8fatU2+5K677pLFYtGiRYuc6svLy7Vq1SqNGTNGN9xwgyIiIpSamqo9e/aYPrfdbteaNWuUkJCgoKAgJSUl6bXXXvP0WwC8XrfObgB8x+rVq5WQkOBUN2zYMMXHx+uzzz5TQEBAJ7Ws/Tz99NO67777NG3atFb3PXPmjFatWqWbbrpJt9xyS7u37Xr35ptv6tChQy1u2759u5599llNmzZNs2fP1j//+U9t3LhRd911l375y19q7ty5rZ7/+9//vp555hnNnz9fo0eP1vbt2/XAAw/IYrFo5syZnn47gNciEIDHZGRkaNSoUS1uCwoK6uDW4HpWV1en73znO3rssce0fPnyZtvvvPNOnTp1ShEREY66hQsX6pZbbtHy5ctbDQQ++eQT/fjHP1ZWVpb+67/+S5L00EMP6Y477tB3v/td3X///eratatn3xTgpegaQLu72hiBDz/8UPfdd5/CwsIUFBSkUaNG6de//rWpc/7sZz9T//79FRwcrDFjxuh3v/ud6fbs3r1b48aNU69evdSzZ08NGjRI3/ve95z2qa+v14oVKzRgwABZrVbFxcVp2bJlqq+vd+xjsVhUW1url156ydEVMmfOnBavuX//fo0ePVqSNHfuXMf+n78nW7Zs0ciRIxUcHKyIiAh99atf1SeffHLN93LkyBFZLBa99NJLzbbt2rVLFotFO3bskCR9/PHHevjhhzVo0CAFBwcrPDxc999/vz766KNW79lNN93U4ntraVyGmXvXmjVr1shut+vRRx9tcfvQoUOdggBJslqtuvvuu3X69GlduHDhmuffvn27Ghoa9PDDDzvqLBaLvvWtb+n06dNXzUQAvoiMADymurpan376qVPdF/+xbvKXv/xFY8eO1Y033qjHH39cPXr00ObNmzVt2jT96le/0r333nvV62zYsEHf/OY3ddttt2nx4sX63//9X335y19WWFiY4uLirtnGv/zlL/rSl76kpKQkrV69WlarVSdPntTvf/97xz52u11f/vKXdfDgQS1YsECDBw/We++9p+eff15/+9vfHGMCXn75ZT300EMaM2aMFixYIEnq379/i9cdPHiwVq9ereXLl2vBggW6/fbbJUm33XabpCvjLObOnavRo0crJydHlZWV+slPfqLf//73+tOf/qRevXq1eN5Ro0apX79+2rx5s2bPnu20bdOmTbrhhhuUnp4uSXr33Xf1hz/8QTNnzlSfPn300UcfKS8vT6mpqfrrX/+q7t27X/PemWH23l3LqVOn9Mwzz+iXv/ylgoODXbp+RUWFunfv3up7+dOf/qQePXpo8ODBTvVjxoxxbB83bpxL1wauWwbgpvz8fENSi8UwDKOsrMyQZOTn5zuOSUtLM4YPH27U1dU56ux2u3HbbbcZAwcOdNTt27fPkGTs27fPMAzDuHz5shEZGWnccsstRn19vWO/n/3sZ4Yk44477rhmW59//nlDkvH3v//9qvu8/PLLRpcuXYzf/e53TvXr1683JBm///3vHXU9evQwZs+efc1rNnn33Xeb3YfPv6dhw4YZn332maN+x44dhiRj+fLl1zxvdna2ERAQYPzjH/9w1NXX1xu9evUyvvGNbzjqLl261OzYQ4cOGZKMjRs3Ouq+eM8NwzDi4+NbfJ933HGH0z135d5dzX333WfcdtttjteSjKysrFaPO3HihBEUFGR87Wtfa3Xfe+65x+jXr1+z+traWkOS8fjjj7d6DsBX0DUAj8nNzdXu3budSkv+8Y9/6J133tFXvvIVXbhwQZ9++qk+/fRTnT9/Xunp6Tpx4sRVU+JHjhzRuXPntHDhQgUGBjrq58yZI5vN1mobm35Zb9++XXa7vcV9tmzZosGDBysxMdHRtk8//VQTJkyQJO3bt6/V67ii6T09/PDDTmMp7rnnHiUmJuo3v/nNNY+fMWOGGhoa9Oabbzrqfvvb36qqqkozZsxw1H3+13VDQ4POnz+vAQMGqFevXvrjH//okffi7r3bt2+ffvWrX2nt2rUuXffSpUu6//77FRwcrGeeeabV/T/77DNZrdZm9U33/7PPPnPp+sD1jK4BeMyYMWOuOljw806ePCnDMPTkk0/qySefbHGfc+fO6cYbb2xW//HHH0uSBg4c6FQfEBCgfv36tXrtGTNm6Be/+IUeeughPf7440pLS9P06dN13333qUuXK3HxiRMn9MEHH6h3795XbZsnNb2nQYMGNduWmJiogwcPXvP4ESNGKDExUZs2bdK8efMkXekWiIiIcHwBS1e+3HJycpSfn69PPvlEhmE4tlVXV3virbh17/75z3/qP/7jP/S1r33NMZ7CjMbGRs2cOVN//etf9fbbbys2NrbVY4KDg1scs1BXV+fYDvgLAgF0uKZf4o8++qij//qLBgwY0C7XDg4O1oEDB7Rv3z795je/0c6dO7Vp0yZNmDBBv/3tb9W1a1fZ7XYNHz5czz33XIvnaG0cQmeYMWOGfvjDH+rTTz9VSEiIfv3rX2vWrFnq1u3//yf+yCOPKD8/X4sXL1ZKSopsNptjqtzVsiNNLBZLi/WNjY1Oo+vduXcbN25USUmJXnzxxWYDGC9cuKCPPvpIkZGRzfr/58+frx07dujVV191CnyuJSYmRvv27ZNhGE7v7ezZs5JkKpgAfAWBADpc0y/3gIAATZw40aVj4+PjJV355fn5f/QbGhpUVlamESNGtHqOLl26KC0tTWlpaXruuef09NNP6/vf/7727duniRMnqn///vrzn/+stLS0q34BNmltu5l9m95TSUlJsy+ykpISx/ZrmTFjhlatWqVf/epXioqKUk1NTbO58G+88YZmz56tH//4x466uro6VVVVtXr+G264ocX9Pv74Y6dMjCv37otOnTqlhoYGjR07ttm2jRs3auPGjdq6davTmg3f/e53lZ+fr7Vr12rWrFmmr3XLLbfoF7/4hT744AMNGTLEUX/48GHHdsBfMEYAHS4yMlKpqal68cUXHb/APu/vf//7VY8dNWqUevfurfXr1+vy5cuO+oKCAlNfaP/4xz+a1TX9o9+UKv7KV76iTz75RD//+c+b7fvZZ5+ptrbW8bpHjx6mrtu0r6Rm+48aNUqRkZFav369U7r67bff1gcffKB77rmn1XMPHjxYw4cP16ZNm7Rp0ybFxMRo/PjxTvt07drVqTtAkn7605+qsbGx1fP3799fxcXFTvd8x44dKi8vd9rPlXv3RTNnztTWrVubFUm6++67tXXrViUnJzv2/9GPfqT//M//1Pe+9z19+9vfvup5q6ur9eGHHzp1f0ydOlUBAQFat26do84wDK1fv1433nijYzYH4A/ICKBT5Obmaty4cRo+fLjmz5+vfv36qbKyUocOHdLp06f15z//ucXjAgIC9NRTT+mb3/ymJkyYoBkzZqisrEz5+fmmxgisXr1aBw4c0D333KP4+HidO3dO69atU58+fRzTxb72ta9p8+bNWrhwofbt26exY8eqsbFRH374oTZv3qxdu3Y5xkKMHDlSe/bs0XPPPafY2FglJCQ4fVl9Xv/+/dWrVy+tX79eISEh6tGjh5KTk5WQkKBnn31Wc+fO1R133KFZs2Y5pg/edNNNWrJkial7OmPGDC1fvlxBQUGaN2+eY8xDky996Ut6+eWXZbPZNGTIEB06dEh79uxReHh4q+d+6KGH9MYbb2jy5Mn6yle+otLSUr3yyivNpku6cu++KDExUYmJiS1uS0hIcMoEbN26VcuWLdPAgQM1ePBgvfLKK07733XXXYqKinLsO3fuXOXn5zvWQujTp48WL16sH/3oR2poaNDo0aO1bds2/e53v9Orr77KYkLwL506ZwE+oWn64Lvvvtvi9pamDxqGYZSWlhpf//rXjejoaCMgIMC48cYbjS996UvGG2+84dinpalshmEY69atMxISEgyr1WqMGjXKOHDgQLOpbC3Zu3evMXXqVCM2NtYIDAw0YmNjjVmzZhl/+9vfnPa7fPmy8eyzzxpDhw41rFarccMNNxgjR440Vq1aZVRXVzv2+/DDD43x48cbwcHBhqRWpxJu377dGDJkiNGtW7dm92TTpk3Gv/3bvxlWq9UICwszHnzwQeP06dPXPN/nnThxwjFt8+DBg822/9///Z8xd+5cIyIiwujZs6eRnp5ufPjhh82mBl7tnv/4xz82brzxRsNqtRpjx441jhw50uI9N3vvzFIL0wdXrFhx1SmrX2x70+fzi5+/xsZG4+mnnzbi4+ONwMBAY+jQocYr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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "print(\"Min and max values:\", field.max(), field.min())\n", - "\n", - "fig = plt.figure()\n", - "fig.patch.set_facecolor(\"white\")\n", - "ax = fig.add_subplot(111)\n", - "ax.set_facecolor(\".4\")\n", - "\n", - "f1 = ax.pcolormesh(field[:, :, 0])\n", - "\n", - "cbar = plt.colorbar(f1)\n", - "ax.set_title(\"Field set to value %.1f\" % value)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "6562a18e", - "metadata": {}, - "source": [ - "## Building and Running Pre-defined Stencils for Tracer Advection\n", - "\n", - "In this portion, we build and run the stencils required for calculating tracer advection. This will include:\n", - "- `FiniteVolumeFluxPrep`: calculates/updates Courant number and total mass flux fields based on input wind field.\n", - "- `FiniteVolumeTransport`: calculates tracer fluxes for horizontal finite volume flux transport.\n", - "- `TracerAdvection`: performs horizontal advection on tracers." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "a45c6f83", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting 6 engines with \n", - "100%|███████████████████████████████████████████████████████| 6/6 [00:05<00:00, 1.09engine/s]\n", - "%autopx enabled\n" - ] - } - ], - "source": [ - "import ipyparallel as ipp\n", - "\n", - "layout = (1, 1)\n", - "ntiles = 6\n", - "# spinup cluster of MPI-workers\n", - "num_ranks = ntiles * layout[0] * layout[1]\n", - "\n", - "tracer_center = (0, 0)\n", - "test_case = \"b\"\n", - "timestep = 900.0\n", - "\n", - "cluster = ipp.Cluster(engines=\"mpi\", n=num_ranks).start_and_connect_sync()\n", - "\n", - "# broadcast configuration to all workers\n", - "ar = cluster[:].push(\n", - " {\n", - " \"ntiles\": ntiles,\n", - " \"nx\": nx,\n", - " \"ny\": ny,\n", - " \"nz\": nz,\n", - " \"nhalo\": nhalo,\n", - " \"layout\": layout,\n", - " \"backend\": backend,\n", - " \"tracer_center\": tracer_center,\n", - " \"test_case\": test_case,\n", - " \"timestep\": timestep\n", - " }\n", - ")\n", - "\n", - "# start executing cells on the workers in parallel from here on\n", - "%autopx" - ] - }, - { - "cell_type": "markdown", - "id": "b5546849", - "metadata": {}, - "source": [ - "### Getting initial state\n", - "\n", - "Before we can build and run stencils associated with tracer advection, we need to have the grid configuration and initial fields for u- and v- winds on the C grid. \n", - "\n", - "More details on these processes are described in `grid_generation.ipynb` and `initial_condition_definition.ipynb`, and here they are shortened by using helper functions inside `functions.py`." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "d35b55bb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[stderr:5] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", - " np.sum(p * q, axis=-1)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[stderr:2] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", - " np.sum(p * q, axis=-1)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import functions as func\n", - "from mpi4py import MPI\n", - "import importlib\n", - "\n", - "importlib.reload(func)\n", - "\n", - "mpi_comm = MPI.COMM_WORLD\n", - "mpi_rank = mpi_comm.Get_rank()\n", - "\n", - "namelist_dict = func.store_namelist_variables(locals())\n", - "dimensions = func.define_dimensions(namelist_dict)\n", - "\n", - "domain_configuration = func.configure_domain(mpi_comm, dimensions)\n", - "\n", - "initial_state = func.create_initial_state_advection(\n", - " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "9965c31a", - "metadata": {}, - "source": [ - "For the stencils used in the tracer advection process, we will need some additional classes, such as `DampingCoefficients` and `GridIndexing`.\n", - "\n", - "If we want to run tracer advection in a single layer instead of extending it to 79 identical conditions, we want to create `GridData` with the `single_layer=True`." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "3c865c63", - "metadata": {}, - "outputs": [], - "source": [ - "from ndsl import DaceConfig, DaCeOrchestration, GridIndexing, StencilConfig, StencilFactory, CompilationConfig, RunMode\n", - "from ndsl.grid import AngleGridData, ContravariantGridData, DampingCoefficients, GridData, HorizontalGridData, MetricTerms, VerticalGridData\n", - "\n", - "\n", - "if nz == 1:\n", - " single_layer = True\n", - "else:\n", - " single_layer = False\n", - "\n", - "if single_layer:\n", - " horizontal_grid_data = HorizontalGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", - " vertical_grid_data = VerticalGridData(ptop=0, ks=0, ak=[10], bk=[0], p_ref=0)\n", - " contravariant_grid_data = ContravariantGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", - " angle_grid_data = AngleGridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", - "\n", - " grid_data = GridData(horizontal_grid_data, vertical_grid_data, contravariant_grid_data, angle_grid_data)\n", - " \n", - "else:\n", - " grid_data = GridData.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", - "\n", - "\n", - "damping_coefficients = DampingCoefficients.new_from_metric_terms(domain_configuration[\"metric_terms\"])\n", - "\n", - "dace_config = DaceConfig(\n", - " communicator=None, backend=backend, orchestration=DaCeOrchestration.Python\n", - ")\n", - "\n", - "compilation_config = CompilationConfig(\n", - " backend=backend,\n", - " rebuild=True,\n", - " validate_args=True,\n", - " format_source=False,\n", - " device_sync=False,\n", - " run_mode=RunMode.BuildAndRun,\n", - " use_minimal_caching=False,\n", - " communicator=domain_configuration[\"communicator\"],\n", - ")\n", - "\n", - "stencil_config = StencilConfig(\n", - " compare_to_numpy=False,\n", - " compilation_config=compilation_config,\n", - " dace_config=dace_config,\n", - ")\n", - "\n", - "grid_indexing = GridIndexing.from_sizer_and_communicator(\n", - " sizer=domain_configuration[\"sizer\"], comm=domain_configuration[\"communicator\"]\n", - ")\n", - "\n", - "stencil_factory = StencilFactory(config=stencil_config, grid_indexing=grid_indexing)\n" - ] - }, - { - "cell_type": "markdown", - "id": "6eea64a5", - "metadata": {}, - "source": [ - "### 1. Finite Volume Flux Prep\n", - "\n", - "In order to run the stencil, we first need to build it (initialize an instance of the class). \n", - "\n", - "For building the `FiniteVolumeFluxPrep` stencil, we need `stencil_factory` and `grid_data` from the configuration dictionary. \n", - "\n", - "For running the stencil, we require the following inputs:\n", - "- `uc (in)`: covariant x-velocity on the C-grid (stored in `initial_state` as `u_Cgrid`)\n", - "- `vc (in)`: covariant y-velocity on the C-grid (stored in `initial_state` as `v_Cgrid`)\n", - "- `crx (out)`: Courant number, x-direction\n", - "- `cry (out)`: Courant number, y-direction\n", - "- `x_area_flux (out)`: flux of area in x-direction, in units of m^2\n", - "- `y_area_flux (out)`: flux of area in y-direction, in units of m^2\n", - "- `uc_contra (out)`: contravariant x-velocity on C-grid\n", - "- `vc_contra (out)`: contravariant y-velocity on C-grid\n", - "- `dt (in)`: acoustic timestep in seconds\n", - "\n", - "We need to create empty storages or quantities to initialize the output variables, and their values get updated when we run the stencil.\n", - "We plot the empty storage of `crx` on the first (zeroth) rank, run `FiniteVolumeFluxPrep`, then plot the updated storage for comparison." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "886c8a20", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%px: 83%|██████████████████████████████████████████▌ | 5/6 [00:00<00:00, 48.19tasks/s]" - ] - }, - { - "data": { - "text/plain": [ - "[output:0]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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de2DfX19MWbMGGRkZNg6ijdKT0+Hv78/7r//fgDAv//9bzz88MNo2bIlmjZtiv79+2Pr1q11bnNN11rcnEk37l/T0tLQoUMHNG3aFMOHD8f58+chhMBLL72Etm3bwtfXFw888AB++eWXavX+4x//wKBBg9CsWTP4+/tj1KhR+OGHH+pspwzZHFX72e/ZsyeCgoJs2WP9jbJ27Vq88MILaNOmDZo2bYrCwkIAcnlrbaM1PwICAtCqVSs8+eSTKC0tldr+/fv345577kGLFi3QrFkz9OrVC2+88Ybt70ePHsXkyZPRoUMH+Pj4IDQ0FI8++qjHDXdsDNxyJufixYvo168f8vPzkZSUhG7duuHChQv4+OOPUVJSYnek5oknnkBwcDAWLFiA4uJiTJkyBZ9++imSk5Nx9913IyIiAt9//z1SUlIwderUaqfHHTl58iTGjRuHxx9/HImJiVi1ahUefvhhbNu2DXfffTeAqlPUQ4YMwYULF/DHP/4R7dq1w969ezFv3jxcunQJS5cuRffu3fHBBx/gqaeeQtu2bW1DfIKDg/Hbb79h6NChOHXqFGbMmIGoqCisX78ekydPRn5+Pp588km7Nq1atQqlpaVISkqC2WxGy5Yt8cMPP+COO+5AmzZtMHfuXDRr1gwfffQREhIS8Mknn2D06NF1bmtpaSmuXLlit8zf37/WI2kvv/wyjEYjnnnmGRQUFGDx4sWYOHEi9u/f77B8cHAwli9fjmnTpmH06NEYM2YMANiGlclux8SJE5GSkoL09HTcdttttvorKyvx0UcfYdCgQWjXrp3i11aNr776Cp999hmmT58OAEhNTcW9996LZ599Fm+//TaeeOIJ/Prrr1i8eDEeffRR7Ny50/bcnTt3YuTIkejTpw8WLlwIo9GIVatW4a677sJXX32Ffv362a2roKCg2nvliqNrd911F5544gmkpqYiISEBt912Gy5duoSZM2ciLi6uziFoFRUVOH/+fLWhGq74zM6YMQPNmzfHokWLcOLECSxfvhxnz561hVlNjh49ikGDBqFJkyZISkpCZGQkTp8+jc2bN+PPf/4zAOC7777D3r17MX78eLRt2xZnzpzB8uXLMXToUPz4449o2rSpk68o6Y07M2v16tXw8/NDcnIy/Pz8sHPnTixYsACFhYV49dVXAQBLly7F+++/jw0bNtiGHvXs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AIDD98r6t8ZoxIgRGDNmDKKionD69Gk8//zzGDlyJLKysuDl5eXu5tXIYrFg9uzZuOOOO9CjRw8AVe+RyWRC8+bN7co2lvfI0TYBwO9//3u0b98e4eHhOHr0KJ577jmcOHECn376qRtbS56M2dR4eGI2NdZcAjwvm5hLjY9mOjmeZuTIkbb/79WrF2JiYtC+fXt89NFHmDp1qhtbRjUZP3687f979uyJXr16oWPHjsjMzMSwYcPc2LLaTZ8+HceOHWtU4+rrUtM2JSUl2f6/Z8+eCAsLw7Bhw3D69Gl07NixoZtJ1OgwmxqXxppLgOdlE3Op8dHMcLWgoCB4eXlVm2EjNzcXoaGhbmqV6zRv3hxdunTBqVOn3N0U1azvh6e+V1YdOnRAUFCQpt+zGTNmYMuWLdi1axfatm1rWx4aGory8nLk5+fblW8M71FN2+RITEwMAGj6PaLGjdnUeOghmxpDLgGel03MpcZJM50ck8mEPn36ICMjw7bMYrEgIyMDsbGxbmyZaxQVFeH06dMICwtzd1NUi4qKQmhoqN17VVhYiP3793vEe2X1888/4+rVq5p8z4QQmDFjBjZs2ICdO3ciKirK7u99+vRBkyZN7N6jEydO4Ny5c5p9j+raJkeOHDkCAJp8j8gzMJsaDz1kk5ZzCfC8bGIuNXLunffA3tq1a4XZbBarV68WP/74o0hKShLNmzcXOTk57m6aYk8//bTIzMwU2dnZ4ptvvhFxcXEiKChI5OXlubtpUq5duyYOHz4sDh8+LACI119/XRw+fFicPXtWCCHEyy+/LJo3by42bdokjh49Kh544AERFRUlfvvtNze3vGa1bdO1a9fEM888I7KyskR2drb48ssvxW233SY6d+4sSktL3d30aqZNmyYCAwNFZmamuHTpku1RUlJiK/P444+Ldu3aiZ07d4oDBw6I2NhYERsb68ZW166ubTp16pR48cUXxYEDB0R2drbYtGmT6NChgxg8eLCbW06ejtmkHZ6WTZ6US0J4XjYxlxo3TXVyhBBi2bJlol27dsJkMol+/fqJffv2ubtJThk3bpwICwsTJpNJtGnTRowbN06cOnXK3c2StmvXLgGg2iMxMVEIUTVV5/z580VISIgwm81i2LBh4sSJE+5tdB1q26aSkhIxfPhwERwcLJo0aSLat28vHnvsMc3+iHG0HQDEqlWrbGV+++038cQTT4gWLVqIpk2bitGjR4tLly65r9F1qGubzp07JwYPHixatmwpzGaz6NSpk5gzZ44oKChwb8NJF5hN2uBp2eRJuSSE52UTc6lxMwghhOvPDxEREREREbmHZq7JISIiIiIicgV2coiIiIiIyKOwk0NERERERB6FnRwiIiIiIvIo7OQQEREREZFHYSeHiIiIiIg8Cjs5RERERETkUdjJISIiIiIij8JODhEREREReRR2coiIiIiIyKOwk0NERERERB6FnRwiIiIiIvIo/x8ND78JUUP2OwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": { - "engine": 0 - }, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%px: 100%|███████████████████████████████████████████████████| 6/6 [00:00<00:00, 11.28tasks/s]\n" - ] - } - ], - "source": [ - "import copy as cp\n", - "import matplotlib.pyplot as plt\n", - "from pyfv3.stencils import FiniteVolumeFluxPrep\n", - "from units_config import units\n", - "\n", - "fvf_prep = FiniteVolumeFluxPrep(\n", - " stencil_factory, grid_data, grid_type=0\n", - ")\n", - "\n", - "crx = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"courant\"], dtype=\"float\"\n", - ")\n", - "cry = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"courant\"], dtype=\"float\"\n", - ")\n", - "\n", - "x_area_flux = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"area\"], dtype=\"float\"\n", - ")\n", - "y_area_flux = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"area\"], dtype=\"float\"\n", - ")\n", - "\n", - "uc_contra = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"wind\"], dtype=\"float\"\n", - ")\n", - "vc_contra = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"wind\"], dtype=\"float\"\n", - ")\n", - "\n", - "crx_before = cp.deepcopy(crx)\n", - "\n", - "fvf_prep(\n", - " initial_state[\"u_cgrid\"],\n", - " initial_state[\"v_cgrid\"],\n", - " crx,\n", - " cry,\n", - " x_area_flux,\n", - " y_area_flux,\n", - " uc_contra,\n", - " vc_contra,\n", - " timestep,\n", - ")\n", - "\n", - "if mpi_rank == 0:\n", - " fig = plt.figure(figsize=(10, 4))\n", - " fig.patch.set_facecolor(\"white\")\n", - " ax_before = fig.add_subplot(121)\n", - " ax_after = fig.add_subplot(122)\n", - "\n", - " f1 = ax_before.pcolormesh(\n", - " crx_before.data[:, :, 0], vmin=-0, vmax=0.1, cmap=\"YlOrRd\"\n", - " )\n", - " plt.colorbar(f1, ax=ax_before)\n", - " f2 = ax_after.pcolormesh(crx.data[:, :, 0], vmin=-0, vmax=0.1, cmap=\"YlOrRd\")\n", - " plt.colorbar(f2, ax=ax_after)\n", - "\n", - " ax_before.set_title(\"crx before FiniteVolumeFluxPrep call\")\n", - " ax_after.set_title(\"crx after FiniteVolumeFluxPrep call\")\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "aadc97e9", - "metadata": {}, - "source": [ - "Since our layer have thickness of delp Pa, we can use that information and the `x_area_flux` and `y_area_flux` variables provided by `FiniteVolumeFluxPrep` to calculate mass fluxes that are required as input to `TracerAdvection`.\n", - "\n", - "We are assuming that density is 1 (kg /m3)." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "4869723d", - "metadata": {}, - "outputs": [], - "source": [ - "mfxd = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x_interface\", \"y\", \"z\"), units=units[\"mass\"], dtype=\"float\"\n", - ")\n", - "mfyd = domain_configuration[\"quantity_factory\"].zeros(\n", - " dims=(\"x\", \"y_interface\", \"z\"), units=units[\"mass\"], dtype=\"float\"\n", - ")\n", - "\n", - "density = 1.0\n", - "\n", - "mfxd.data[:] = x_area_flux.data[:] * initial_state[\"delp\"].data[:] * density\n", - "mfyd.data[:] = y_area_flux.data[:] * initial_state[\"delp\"].data[:] * density\n" - ] - }, - { - "cell_type": "markdown", - "id": "8cbf898b", - "metadata": {}, - "source": [ - "### 2. Tracer Advection and its Inputs\n", - "\n", - "In order to build the `TracerAdvection` stencil, it needs an input of a different stencil, `FiniteVolumeTransport`. \n", - "\n", - "For building the `FiniteVolumeTransport` stencil, we need `stencil_factory`, `grid_data`, and `damping_coefficients` from the configuration dictionary. We do not actually need to run it, as it get run within `TracerAdvection`, but if we did, we would get output tracer mass fluxes. \n", - "\n", - "For building `TracerAdvection`, we need `stencil_factory`, the pre-built `FiniteVolumeTransport` stencil, `grid_data`, and the cubed-sphere communicator stored under configuration as `communicator`. We also need a dictionary that includes all the tracers we want to follow at their initial state.\n", - "\n", - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4446b419", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%px: 100%|███████████████████████████████████████████████████| 6/6 [00:20<00:00, 3.38s/tasks]\n" - ] - } - ], - "source": [ - "from pyfv3.stencils import FiniteVolumeTransport, TracerAdvection\n", - "\n", - "grid_type = 0 # cubed-sphere\n", - "hord = 6 # horizontal diffusion order\n", - "\n", - "tracers = {\"tracer\": initial_state[\"tracer\"]}\n", - "\n", - "fvtp_2d = FiniteVolumeTransport(\n", - " stencil_factory,\n", - " domain_configuration[\"quantity_factory\"],\n", - " grid_data,\n", - " damping_coefficients,\n", - " grid_type,\n", - " hord,\n", - ")\n", - "\n", - "tracer_advection = TracerAdvection(\n", - " stencil_factory,\n", - " domain_configuration[\"quantity_factory\"],\n", - " fvtp_2d,\n", - " grid_data,\n", - " domain_configuration[\"communicator\"],\n", - " tracers,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "de2681d7", - "metadata": {}, - "source": [ - "To run a single step of `TracerAdvection`, we need to provide it the following inputs:\n", - "- `tracers`: a dictionary of all tracers we want to advect\n", - "- `delp`: pressure thickness of layers\n", - "- `mfxd`: mass flux in the x-direction\n", - "- `mfyd`: mass flux in the y-direction\n", - "- `crx`: Courant number in the x-direction\n", - "- `cry`: Courant number in the y-direction\n", - "- `timestep`: the timestep that is applied. \n", - "\n", - "Within `TracerAdvection`, the time step is split into 3 equal sub-steps, and all fields are divided by three, then advection is calculated for each of the substeps. \n", - "\n", - "All fields but `delp` are updated. Mass fluxes and Courant numbers are divided by 3 and then returned. So if we want to continue advecting with the initial wind field, we actually need to re-set those fields to initial conditions after each step." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "8043021f", - "metadata": { - "jupyter": { - "outputs_hidden": true - }, - "tags": [] - }, - "outputs": [], - "source": [ - "tracer_initial = cp.deepcopy(tracers)\n", - "mfxd_initial = cp.deepcopy(mfxd)\n", - "mfyd_initial = cp.deepcopy(mfyd)\n", - "crx_initial = cp.deepcopy(crx)\n", - "cry_initial = cp.deepcopy(cry)\n", - "\n", - "tracer_state = [tracer_initial[\"tracer\"]]\n", - "\n", - "nSteps = 10\n", - "\n", - "for step in range(nSteps):\n", - " tracer_advection(tracers, initial_state[\"delp\"], mfxd, mfyd, crx, cry)\n", - "\n", - " tracer_state.append(tracers[\"tracer\"])\n", - "\n", - " mfxd = cp.deepcopy(mfxd_initial)\n", - " mfyd = cp.deepcopy(mfyd_initial)\n", - " crx = cp.deepcopy(crx_initial)\n", - " cry = cp.deepcopy(cry_initial)" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "f1e2588c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[output:0]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFhjDFm6tSppnXr1iYqKspIMlu2bDHGHL8leU23Gn/llVfMmWeeadxut+ncubOZPXu2mTRpUrW3YX/11VfNz372M+N2u81pp51mBgwYYJYtW+bT5oMPPjDZ2dkmPj7exMbGmo4dO5obb7zR53boo0ePNs2aNQvo3LZt22ZGjRplWrZsadxut+nQoYMZP368KS0t9bbZvHmzueqqq0xCQoKJjY01ffr0Me+8806V/kkyCxYs8Fm/ZcsWI8nMnj3bZ/3HH39sfv7zn5sWLVqYZs2amR49epjnn3/ep83mzZvNqFGjTGpqqmncuLFp3bq1+cUvfmHefPNNb5vZs2cbSeaLL76otj8ffPCBd11+fr4ZOnSoadGihZFkBgwYUOs+jDHmv//9rxkzZoxJSkoyzZs3N9nZ2WbDhg2mbdu2ZvTo0T5tX375ZdOhQwcTHR3tc+wBAwZ4j1WhoKDAu9+YmBjTvXv3Ks9RxXP31FNPVemXJDNp0qQq60905MgR85vf/Ma0atXKNGnSxJx//vkmLy+v2v68/fbbpmvXrqZRo0bVvl4nq+l3IhgLFy40vXr1Mm6325xxxhnmwQcfNGVlZUHvF4hE5Aq54vRcqe7f8rFjx8ztt99uWrZsaVwuV5V/uy+99JLJyMgwTZo0MS1atDDdu3c3v/vd78zOnTu9bdq2bWuGDh1aaz+rO+fqlrZt21ZpbzWLHnnkEdOnTx+TkJBgmjRpYjp37mweffRRn21Def5Lly41PXr08L4fnPx74k9/gIZq5cqVJiMjw8TExJgOHTqYWbNmVZunJ78v1/QeWlNeGRNc7py4f6t5Xd15HTt2zDz11FOmc+fOJiYmxrRs2dIMGTLErFmzxqfdW2+9ZS644ALTrFkz06xZM9O5c2czfvx4s3Hjxmr7WcHfnKvp+Tx48KC57rrrTEJCQpX36rKyMvPEE0+Yc845x/s3TkZGhpkyZYopKirytqvt76nqVLyG1S0n55sxx9+vzz77bBMTE2M6duxonn32WePxeGo9Rmlpqfntb39revbs6f1bpWfPnubFF18M2/n/9a9/9f7t+LOf/cznbxh/+wO4jAlgxm4AAAAAtmrXrp26deumd955p667AgCIUC6XS+PHj7d8pQhwIuYsBAAAAAAAACCJYiEAAAAAAACAn1AsBAAAAAAAACCJYiEAOM6HH36oYcOGKS0tTS6XS4sWLTrlNitWrNC5554rt9utTp06ac6cOWHvJwDAP1u3bm3Q8xWSawBwasYY5itEyFAsBACHKSkpUc+ePTVjxgy/2m/ZskVDhw7VRRddpHXr1umuu+7SzTffrKVLl4a5pwAAnBq5BgCAvbgbMgA4mMvl0sKFCzV8+PAa29x7771699139c0333jXjRw5UoWFhVqyZIkNvQQAwD/kGgAA4deorjtwMo/Ho507d6pFixZyuVx13R0ADZgxRgcOHFBaWpqiooIbiH3kyBGVlZUF1ZeT3xPdbrfcbndQ/ZKkvLw8ZWVl+azLzs7WXXfdFfS+Qa4BiByRkmvhzDSJXAs3cg1AJAhlpknB5VpMTIxiY2OD7kMkibhi4c6dO5Wenl7X3QAArx07duiMM86wvP2RI0fUvm1z5e8ut7yP5s2b6+DBgz7rJk2apMmTJ1veZ4X8/HylpKT4rEtJSVFxcbEOHz6sJk2aBH2MhoxcAxBp6jrXwplpErkWbuQagEgSbKZJP+VakybKt7h9amqqtmzZ4qiCYcQVC1u0aCFJukCXqpEa13FvADRkx3RUH2ux933JqrKyMuXvLteWNW0V1yLwb72KD3jUPmObduzYobi4OO/6UI3AQHiRawAiRSTkGplW/1X8+9mxfbvPawgAdiouLlZ6mzZBZ5r0U65J2uFyKdB3tWJJ6fn5Kisro1gYThVD2RupsRq5+FAFoA79NKNrqC6xiWsRZalY6N0+Li4sf5SnpqaqoKDAZ11BQYHi4uIYfREC5BqAiBFBuRauTJPItXCr+PcTztcQAPwVyukQ4iTFBbo/h94GJOKKhQDgVOXGo3ILWVJuPKHvzAn69u2rxYsX+6xbtmyZ+vbtG9bjAgDqNyu5Fu5Mk8g1AIBFUVGSlWJhufXppiJV8LNAAgD84pGxvATi4MGDWrdundatWydJ2rJli9atW6ft27dLku6//36NGjXK2/6WW27Rf/7zH/3ud7/Thg0b9OKLL+qNN97Q3XffHbJzBwA4jx2ZJpFrAACbREVZWxyIkYUAYBOPPLIyniLQrVavXq2LLrrI+/OECRMkSaNHj9acOXO0a9cu7wcsSWrfvr3effdd3X333Xruued0xhln6E9/+pOys7Mt9BYA0FBYyTUrSUiuAQBsYXVkoQNRLAQAm5Qbo3ILYRLoNgMHDpSpZZs5c+ZUu83atWsD7RoAoAGzkmtWcpBcAwDYgmKhF8VCALCJ1cuvrGwDAEC4Wck1Mg0AELEoFno58+JqAAAAAAAAAAFjZCEA2MQjo3JGFgIAHMJKrpFpAICIxchCL4qFAGATLkMGADgJlyEDAByFYqEXxUIAsIldNzgBAMAOdt3gBAAAW1As9KJYCAA28fy0WNkOAIBIYyXXyDQAQMRyuY4XDAPhcWaycYMTAAAAAAAAAJIYWQgAtim3eIMTK9sAABBuVnKNTAMARKyoqMBHFjoUxUIAsEm5Ob5Y2Q4AgEhjJdfINABAxKJY6EWxEABswpyFAAAnYc5CAICjUCz0olgIADbxyKVyBXh3rZ+2AwAg0ljJNTINABCxKBZ6USwEAJt4zPHFynYAAEQaK7lGpgEAIhbFQq+AnoXc3Fydd955atGihZKTkzV8+HBt3LjRp83AgQPlcrl8lltuuSWknQYAIBTINQCAU5BpAIBQCahYuHLlSo0fP16fffaZli1bpqNHj2rQoEEqKSnxaTd27Fjt2rXLuzz55JMh7TQA1EflP12uZWVBeJBrAGAdmRZZyDQACFLFyMJAFwcK6DLkJUuW+Pw8Z84cJScna82aNbrwwgu965s2barU1NTQ9BAAHMLqhyQ+WIUPuQYA1lnJNTItfMg0AAiSg4t/gQrqWSgqKpIkJSYm+qx/7bXXlJSUpG7duun+++/XoUOHatxHaWmpiouLfRYAcCKPcVleYA9yDQD8R6ZFtlBkmkSuAWhAGFnoZfkGJx6PR3fddZfOP/98devWzbv+uuuuU9u2bZWWlqavvvpK9957rzZu3Ki///3v1e4nNzdXU6ZMsdoNAKg3GFkY2cg1AAgMIwsjV6gyTSLXADQgLlfgxT/jzDt3uYyxdma33nqr/u///k8ff/yxzjjjjBrbvf/++7rkkkv0/fffq2PHjlUeLy0tVWlpqffn4uJipaena6AuVyNXYytdA4CQOGaOaoXeVlFRkeLi4izvp7i4WPHx8Xr/m3Q1bxH4N08HD3h0cbcdQfcDtSPXADhdJOQamWaPUGWaVHOuFRUW8hoCqDPFxcWKT0gISZ5U5FrRmWcqLjo6sG3LyxW/aZPjcs3SyMKcnBy98847+vDDD2sNH0nKzMyUpBoDyO12y+12W+kGAAAhQa4BAJwilJkmkWsA0BAFVCw0xuj222/XwoULtWLFCrVv3/6U26xbt06S1KpVK0sdBACnMBbnajLM7xQ25BoAWGcl18i08CHTACBIVuYgdOhlyAE9C+PHj9df//pXzZs3Ty1atFB+fr7y8/N1+PBhSdLmzZs1depUrVmzRlu3btU//vEPjRo1ShdeeKF69OgRlhMAgPqiYm4nKwvCg1wDAOvItMhCpgFAkGy8wcmMGTPUrl07xcbGKjMzU6tWrfJru9dff10ul0vDhw+3dFx/BTSycObMmZKkgQMH+qyfPXu2brzxRsXExOi9997T9OnTVVJSovT0dF155ZV68MEHQ9ZhAKivyk2Uyk3gYVLuzC+rIgK5BgDWWck1Mi18yDQACJJNIwvnz5+vCRMmaNasWcrMzNT06dOVnZ2tjRs3Kjk5ucbttm7dqnvuuUf9+/cP+JiBCvgy5Nqkp6dr5cqVQXUIAJzKI5c8gQ3o/mk7PlmFC7kGANZZyTUyLXzINAAIkk3FwmnTpmns2LEaM2aMJGnWrFl699139eqrr+q+++6rdpvy8nJdf/31mjJlij766CMVFhYGfNxAWBsvCQAIGJchAwCchEwDADhKEJchFxcX+ywn3kX+RGVlZVqzZo2ysrJOOGyUsrKylJeXV2PXHn74YSUnJ+umm24K7TnXgGIhAAAAAAAAYFF6erri4+O9S25ubrXt9u7dq/LycqWkpPisT0lJUX5+frXbfPzxx3rllVf08ssvh7zfNQnoMmQAgHXW5yzkki0AQOSxNmchmQYAiFBBXIa8Y8cOxcXFeVe73e6QdOnAgQO64YYb9PLLLyspKSkk+/QHxUIAsMnxuZ0Cv/zKyjYAAISblVwj0wAAESuIYmFcXJxPsbAmSUlJio6OVkFBgc/6goICpaamVmm/efNmbd26VcOGDfOu83g8kqRGjRpp48aN6tixY2B99gPFQgCwiUdRKucGJwAAh7CSa2QaACBiuVyBFwt/Ktz5KyYmRhkZGVq+fLmGDx/+0y48Wr58uXJycqq079y5s77++mufdQ8++KAOHDig5557Tunp6YH1108UCwHAJlyGDABwEi5DBhBqJoDRxy6+fAiLBv0aWBlZGGh7SRMmTNDo0aPVu3dv9enTR9OnT1dJSYn37sijRo1S69atlZubq9jYWHXr1s1n+4SEBEmqsj6UKBYCgE08ipKHkYUAAIewkmtkGgAgYtlULBwxYoT27NmjiRMnKj8/X7169dKSJUu8Nz3Zvn27oizsN5QoFgIAAAAAAAA2ycnJqfayY0lasWJFrdvOmTMn9B06CcVCALBJuXGp3AQ+sbuVbQAACDcruUamAQAilk0jC+sDioUAYJNyizc4KeeSLQBABLKSa2QaACBiUSz0olgIADbxmCh5LNzgxMNk8ACACGQl18g0AEDEoljoRbEQAGzCyEIAgJMwshAA4CgUC70oFgKATTyyNleTJ/RdAQAgaFZyjUwDAEQsioVezjwrAAAAAAAAAAFjZCEA2MSjKHksfEdjZRsAAMLNSq6RaQCAiMXIQi+KhQBgk3ITpXILNzixsg0AAOFmJdfINABAxHK5Ai/+uQKfZqo+oFgIADbxyCWPrMxZ6MwAAgDUb1ZyjUwDGh7D7z3qC0YWelEsBACbMLIQAOAkjCwEADgKxUIvioUAYJNyRancwlxNVrYBACDcrOQamQYAiFgUC72ceVYAAAAAAAAAAsbIQgCwice45DEW5iy0sA0AAOFmJdfINABAxGJkoRfFQgCwicfiZcgeBoEDACKQlVwj0wAAEYtioRfFQgCwicdEyWNhYncr2wAAEG5Wco1MAwBELIqFXhQLAcAm5XKpXIFffmVlGwAAws1KrpFpAICIRbHQi2IhANiEkYUAACdhZCEAwFEoFno586wAAAAAAAAABIyRhQBgk3JZu/yqPPRdAQAgaFZyjUwDAEQslyvwkYIuZ06vwchCALBJxeVaVpZAzZgxQ+3atVNsbKwyMzO1atWqWttPnz5dZ599tpo0aaL09HTdfffdOnLkiNVTBQA0AHZlmkSuAQ2FS8bvBeHRoF+DisuQA10ciJGFAGCTchOlcgsfkgLdZv78+ZowYYJmzZqlzMxMTZ8+XdnZ2dq4caOSk5OrtJ83b57uu+8+vfrqq+rXr5++++473XjjjXK5XJo2bVrA/QUANAxWcs1KDpJrAABbMGehlzPPCgAikJFLHguLCfASr2nTpmns2LEaM2aMunbtqlmzZqlp06Z69dVXq23/6aef6vzzz9d1112ndu3aadCgQbr22mtPOWoDANCwWcm1QDNNItcAADZhZKGXM88KACJQxQgMK4u/ysrKtGbNGmVlZXnXRUVFKSsrS3l5edVu069fP61Zs8b7Ieo///mPFi9erEsvvTS4EwYAOFq4M00i1wAANqJY6MVlyABQTxQXF/v87Ha75Xa7fdbt3btX5eXlSklJ8VmfkpKiDRs2VLvf6667Tnv37tUFF1wgY4yOHTumW265Rb///e9DewIAAPzEn0yTyDUAAOqCM0ugABCBPMZleZGk9PR0xcfHe5fc3NyQ9GvFihV67LHH9OKLL+rLL7/U3//+d7377ruaOnVqSPYPAHCmSMw0iVwDAFjEyEIvRhYCgE3KFaVyC9/RVGyzY8cOxcXFeddXNwIjKSlJ0dHRKigo8FlfUFCg1NTUavf/0EMP6YYbbtDNN98sSerevbtKSko0btw4PfDAA4pyaAACAIJjJdcCyTSJXAMA2IgbnHg586wAIAIFO7IwLi7OZ6nug1VMTIwyMjK0fPnyyuN6PFq+fLn69u1bbb8OHTpU5YNTdHS0JMkYE6rTBwA4TLgzTSLXAAA2YmShFyMLAcAmHkXJY+E7mkC3mTBhgkaPHq3evXurT58+mj59ukpKSjRmzBhJ0qhRo9S6dWvvJV/Dhg3TtGnT9LOf/UyZmZn6/vvv9dBDD2nYsGHeD1cAAJzMSq5ZyUFyDQBgC0YWelEsBACblBuXyn8aURHodoEYMWKE9uzZo4kTJyo/P1+9evXSkiVLvJPDb9++3WfExYMPPiiXy6UHH3xQP/74o1q2bKlhw4bp0UcfDbivAICGw0quWclBcg0AYAuXK/DinyvwXKsPKBYCgAPl5OQoJyen2sdWrFjh83OjRo00adIkTZo0yYaeAQAQOHINAAD7UCwEAJucOFdToNsBABBprOQamQYAiFhchuxFsRAAbGJMlDwm8DAxFrYBACDcrOQamQYAiFgUC70oFgKATcrlUrkszFloYRsAAMLNSq6RaQCAiEWx0ItiIQDYxGOsXX7lMWHoDAAAQbKSa2QaACBiUSz0olgIADbxWLwM2co2AACEm5VcI9MAABGLYqGXM88KAAAAAAAAQMAYWQgANvHIJY+FuZqsbAMAQLhZyTUyDQAQsRhZ6EWxEABsUm5cKrcwZ6GVbQAACDcruUamAQAiFsVCr4DOKjc3V+edd55atGih5ORkDR8+XBs3bvRpc+TIEY0fP16nn366mjdvriuvvFIFBQUh7TQA1EcVcztZWRAe5BoAWEemRRYyDQCCVFEsDHRxoIDOauXKlRo/frw+++wzLVu2TEePHtWgQYNUUlLibXP33Xfrn//8pxYsWKCVK1dq586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "engine": 0 - }, - "output_type": "display_data" - } - ], - "source": [ - "if mpi_rank == 0:\n", - " fig = plt.figure(figsize=(16, 4))\n", - " fig.patch.set_facecolor(\"white\")\n", - " ax_before = fig.add_subplot(131)\n", - " ax_after = fig.add_subplot(132)\n", - " ax_diff = fig.add_subplot(133)\n", - "\n", - " f1 = ax_before.pcolormesh(\n", - " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f1, ax=ax_before)\n", - " f2 = ax_after.pcolormesh(\n", - " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f2, ax=ax_after)\n", - " f3 = ax_diff.pcolormesh(\n", - " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", - " vmin=-0.5,\n", - " vmax=0.5,\n", - " cmap=\"bwr\",\n", - " )\n", - " plt.colorbar(f3, ax=ax_diff)\n", - "\n", - " ax_before.set_title(\"tracer concentration at t=0\")\n", - " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", - " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "d41c4b7b", - "metadata": {}, - "source": [ - "## Recreating this with functions.py\n", - "\n", - "You can reproduce the above steps in a more succinct manner by using the following syntax.\n", - "\n", - "In this case, we are using 79 layers, and things are not as fast as they could be - the same calculation is repeated at every vertical level." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "5d38b817", - "metadata": { - "jupyter": { - "outputs_hidden": true - }, - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[1:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", - "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", - "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", - "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", - "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", - "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 982\u001b[0m \n", - "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", - "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", - "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", - "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", - "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 1003\u001b[0m }\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", - "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 874\u001b[0m )\n", - "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", - "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", - "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 881\u001b[0m fvf_prep(\n", - "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 890\u001b[0m timestep,\n", - "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", - "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 895\u001b[0m )\n", - "\n", - "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n" - ] - }, - { - "data": { - "text/plain": [ - "[stderr:2] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", - " np.sum(p * q, axis=-1)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[4:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", - "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", - "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", - "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", - "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", - "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 982\u001b[0m \n", - "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", - "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", - "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", - "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", - "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 1003\u001b[0m }\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", - "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 874\u001b[0m )\n", - "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", - "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", - "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 881\u001b[0m fvf_prep(\n", - "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 890\u001b[0m timestep,\n", - "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", - "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 895\u001b[0m )\n", - "\n", - "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n" - ] - }, - { - "data": { - "text/plain": [ - "[stderr:5] /pace/NDSL/ndsl/grid/gnomonic.py:681: RuntimeWarning: invalid value encountered in true_divide\n", - " np.sum(p * q, axis=-1)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[0:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", - "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", - "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", - "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", - "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", - "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 982\u001b[0m \n", - "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", - "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", - "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", - "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", - "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 1003\u001b[0m }\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", - "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 874\u001b[0m )\n", - "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", - "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", - "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 881\u001b[0m fvf_prep(\n", - "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 890\u001b[0m timestep,\n", - "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", - "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 895\u001b[0m )\n", - "\n", - "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n", - "[2:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [15], line 23\u001b[0m\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[1;32m 21\u001b[0m stencil_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantity_factory\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[0;32m---> 23\u001b[0m tracer_advection_data, tracer_advection \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprepare_everything_for_advection\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 24\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\n", - "\u001b[1;32m 25\u001b[0m \u001b[43m)\u001b[49m\n", - "\u001b[1;32m 27\u001b[0m tracer_advection_data_initial \u001b[38;5;241m=\u001b[39m cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data)\n", - "\u001b[1;32m 29\u001b[0m tracer_state \u001b[38;5;241m=\u001b[39m [cp\u001b[38;5;241m.\u001b[39mdeepcopy(tracer_advection_data_initial[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:987\u001b[0m, in \u001b[0;36mprepare_everything_for_advection\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep)\u001b[0m\n", - "\u001b[1;32m 962\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 963\u001b[0m \u001b[38;5;124;03mUse: tracer_advection_data, tracer_advection =\u001b[39;00m\n", - "\u001b[1;32m 964\u001b[0m \u001b[38;5;124;03m prepare_everything_for_advection(stencil_configuration, initial_state,\u001b[39;00m\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 982\u001b[0m \n", - "\u001b[1;32m 983\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n", - "\u001b[1;32m 985\u001b[0m tracers \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracer\u001b[39m\u001b[38;5;124m\"\u001b[39m]}\n", - "\u001b[0;32m--> 987\u001b[0m flux_prep \u001b[38;5;241m=\u001b[39m \u001b[43mrun_finite_volume_fluxprep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 988\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 989\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 990\u001b[0m \u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 991\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep\u001b[49m\u001b[43m,\u001b[49m\n", - "\u001b[1;32m 992\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 994\u001b[0m tracer_advection \u001b[38;5;241m=\u001b[39m build_tracer_advection(stencil_configuration, tracers)\n", - "\u001b[1;32m 996\u001b[0m tracer_advection_data \u001b[38;5;241m=\u001b[39m {\n", - "\u001b[1;32m 997\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtracers\u001b[39m\u001b[38;5;124m\"\u001b[39m: tracers,\n", - "\u001b[1;32m 998\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m: initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdelp\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 1002\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m: flux_prep[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcry\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 1003\u001b[0m }\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:877\u001b[0m, in \u001b[0;36mrun_finite_volume_fluxprep\u001b[0;34m(stencil_configuration, initial_state, dimensions, timestep, density)\u001b[0m\n", - "\u001b[1;32m 872\u001b[0m vc_contra \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 873\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInY, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 874\u001b[0m )\n", - "\u001b[1;32m 876\u001b[0m \u001b[38;5;66;03m# intialize and run\u001b[39;00m\n", - "\u001b[0;32m--> 877\u001b[0m fvf_prep \u001b[38;5;241m=\u001b[39m \u001b[43mFiniteVolumeFluxPrep\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 878\u001b[0m \u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mstencil_factory\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstencil_configuration\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mgrid_data\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", - "\u001b[1;32m 879\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 881\u001b[0m fvf_prep(\n", - "\u001b[1;32m 882\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 883\u001b[0m initial_state[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mv_cgrid\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 890\u001b[0m timestep,\n", - "\u001b[1;32m 891\u001b[0m ) \u001b[38;5;66;03m# this will modify empty quantities, but not change uc, vc\u001b[39;00m\n", - "\u001b[1;32m 893\u001b[0m mfxd \u001b[38;5;241m=\u001b[39m init_quantity(\n", - "\u001b[1;32m 894\u001b[0m dimensions, VariableGrid\u001b[38;5;241m.\u001b[39mStaggeredInX, VariableDims\u001b[38;5;241m.\u001b[39mXYZ, units\u001b[38;5;241m=\u001b[39munits[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124marea\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", - "\u001b[1;32m 895\u001b[0m )\n", - "\n", - "\u001b[0;31mTypeError\u001b[0m: __init__() missing 1 required positional argument: 'grid_type'\n", - "[5:execute] TypeError: __init__() missing 1 required positional argument: 'grid_type'\n", - "[3:execute] TypeError: __init__() missing 1 required positional argument: 'grid_type'\n" - ] - }, - { - "ename": "AlreadyDisplayedError", - "evalue": "6 errors", - "output_type": "error", - "traceback": [ - "6 errors" - ] - } - ], - "source": [ - "mpi_comm = MPI.COMM_WORLD\n", - "mpi_rank = mpi_comm.Get_rank()\n", - "\n", - "nz = 79\n", - "if nz == 1:\n", - " single_layer = True\n", - "else:\n", - " single_layer = False\n", - "\n", - "namelist_dict = func.store_namelist_variables(locals())\n", - "dimensions = func.define_dimensions(namelist_dict)\n", - "\n", - "\n", - "domain_configuration = func.configure_domain(mpi_comm, dimensions, single_layer=single_layer)\n", - "\n", - "initial_state = func.create_initial_state_advection(\n", - " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", - ")\n", - "\n", - "stencil_configuration = func.configure_stencil(domain_configuration, backend=backend)\n", - "stencil_configuration[\"quantity_factory\"] = domain_configuration[\"quantity_factory\"]\n", - "\n", - "tracer_advection_data, tracer_advection = func.prepare_everything_for_advection(\n", - " stencil_configuration, initial_state, dimensions, timestep\n", - ")\n", - "\n", - "tracer_advection_data_initial = cp.deepcopy(tracer_advection_data)\n", - "\n", - "tracer_state = [cp.deepcopy(tracer_advection_data_initial[\"tracers\"][\"tracer\"])]\n", - "\n", - "nSteps = 10\n", - "for step in range(nSteps):\n", - " tracer_advection_data = func.run_advection_step_with_reset(\n", - " tracer_advection_data_initial, tracer_advection_data, tracer_advection\n", - " )\n", - "\n", - " tracer_state.append(cp.deepcopy(tracer_advection_data[\"tracers\"][\"tracer\"]))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "fe879468", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[output:0]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFh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586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "engine": 0 - }, - "output_type": "display_data" - } - ], - "source": [ - "if mpi_rank == 0:\n", - " fig = plt.figure(figsize=(16, 4))\n", - " fig.patch.set_facecolor(\"white\")\n", - " ax_before = fig.add_subplot(131)\n", - " ax_after = fig.add_subplot(132)\n", - " ax_diff = fig.add_subplot(133)\n", - "\n", - " f1 = ax_before.pcolormesh(\n", - " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f1, ax=ax_before)\n", - " f2 = ax_after.pcolormesh(\n", - " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f2, ax=ax_after)\n", - " f3 = ax_diff.pcolormesh(\n", - " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", - " vmin=-0.5,\n", - " vmax=0.5,\n", - " cmap=\"bwr\",\n", - " )\n", - " plt.colorbar(f3, ax=ax_diff)\n", - "\n", - " ax_before.set_title(\"tracer concentration at t=0\")\n", - " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", - " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "79388634", - "metadata": {}, - "source": [ - "For a faster calculation, we can set the number of vertical levels to 1. This will increase computation speed more significantly once we add more time steps, or more points in the x- and y- dimensions. " - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "ced9db5c", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[0:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", - "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", - "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", - "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", - "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", - "\u001b[1;32m 18\u001b[0m )\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", - "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", - "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", - "\u001b[1;32m 265\u001b[0m )\n", - "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", - "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", - "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", - "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 299\u001b[0m (\n", - "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", - "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", - "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", - "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", - "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", - "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2163\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2166\u001b[0m )\n", - "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2168\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2171\u001b[0m )\n", - "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", - "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", - "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", - "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", - "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\n", - "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", - "[4:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", - "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", - "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", - "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", - "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", - "\u001b[1;32m 18\u001b[0m )\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", - "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", - "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", - "\u001b[1;32m 265\u001b[0m )\n", - "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", - "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", - "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", - "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 299\u001b[0m (\n", - "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", - "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", - "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", - "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", - "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", - "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2163\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2166\u001b[0m )\n", - "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2168\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2171\u001b[0m )\n", - "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", - "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", - "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", - "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", - "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\n", - "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", - "[5:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", - "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", - "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", - "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", - "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", - "\u001b[1;32m 18\u001b[0m )\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", - "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", - "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", - "\u001b[1;32m 265\u001b[0m )\n", - "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", - "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", - "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", - "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 299\u001b[0m (\n", - "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", - "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", - "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", - "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", - "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", - "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2163\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2166\u001b[0m )\n", - "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2168\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2171\u001b[0m )\n", - "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", - "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", - "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", - "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", - "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\n", - "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", - "[3:execute]\n", - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)\n", - "Cell \u001b[0;32mIn [17], line 14\u001b[0m\n", - "\u001b[1;32m 10\u001b[0m namelist_dict \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mstore_namelist_variables(\u001b[38;5;28mlocals\u001b[39m())\n", - "\u001b[1;32m 11\u001b[0m dimensions \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mdefine_dimensions(namelist_dict)\n", - "\u001b[0;32m---> 14\u001b[0m domain_configuration \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigure_domain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmpi_comm\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdimensions\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msingle_layer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msingle_layer\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 16\u001b[0m initial_state \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mcreate_initial_state_advection(\n", - "\u001b[1;32m 17\u001b[0m domain_configuration[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetric_terms\u001b[39m\u001b[38;5;124m\"\u001b[39m], dimensions, tracer_center, test_case\n", - "\u001b[1;32m 18\u001b[0m )\n", - "\u001b[1;32m 20\u001b[0m stencil_configuration \u001b[38;5;241m=\u001b[39m func\u001b[38;5;241m.\u001b[39mconfigure_stencil(domain_configuration, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\n", - "File \u001b[0;32m/pace/examples/notebooks/functions.py:269\u001b[0m, in \u001b[0;36mconfigure_domain\u001b[0;34m(mpi_comm, dimensions, single_layer, backend)\u001b[0m\n", - "\u001b[1;32m 256\u001b[0m sizer \u001b[38;5;241m=\u001b[39m SubtileGridSizer\u001b[38;5;241m.\u001b[39mfrom_tile_params(\n", - "\u001b[1;32m 257\u001b[0m nx_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnx\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[1;32m 258\u001b[0m ny_tile\u001b[38;5;241m=\u001b[39mdimensions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mny\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n", - "\u001b[0;32m (...)\u001b[0m\n", - "\u001b[1;32m 264\u001b[0m tile_rank\u001b[38;5;241m=\u001b[39mcommunicator\u001b[38;5;241m.\u001b[39mtile\u001b[38;5;241m.\u001b[39mrank,\n", - "\u001b[1;32m 265\u001b[0m )\n", - "\u001b[1;32m 267\u001b[0m quantity_factory \u001b[38;5;241m=\u001b[39m QuantityFactory\u001b[38;5;241m.\u001b[39mfrom_backend(sizer\u001b[38;5;241m=\u001b[39msizer, backend\u001b[38;5;241m=\u001b[39mbackend)\n", - "\u001b[0;32m--> 269\u001b[0m metric_terms \u001b[38;5;241m=\u001b[39m \u001b[43mMetricTerms\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 270\u001b[0m \u001b[43m \u001b[49m\u001b[43mquantity_factory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquantity_factory\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcommunicator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcommunicator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43meta79.nc\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n", - "\u001b[1;32m 271\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 273\u001b[0m \u001b[38;5;66;03m# workaround for single layer\u001b[39;00m\n", - "\u001b[1;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m single_layer:\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:304\u001b[0m, in \u001b[0;36mMetricTerms.__init__\u001b[0;34m(self, quantity_factory, communicator, grid_type, dx_const, dy_const, deglat, extdgrid, eta_file)\u001b[0m\n", - "\u001b[1;32m 297\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 298\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_area_c \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 299\u001b[0m (\n", - "\u001b[1;32m 300\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ks,\n", - "\u001b[1;32m 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ptop,\n", - "\u001b[1;32m 302\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ak,\n", - "\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_bk,\n", - "\u001b[0;32m--> 304\u001b[0m ) \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\u001b[43meta_file\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 305\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\u001b[1;32m 306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ec2 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/generation.py:2172\u001b[0m, in \u001b[0;36mMetricTerms._set_hybrid_pressure_coefficients\u001b[0;34m(self, eta_file)\u001b[0m\n", - "\u001b[1;32m 2162\u001b[0m ak \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2163\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2164\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPa\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2165\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2166\u001b[0m )\n", - "\u001b[1;32m 2167\u001b[0m bk \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mquantity_factory\u001b[38;5;241m.\u001b[39mzeros(\n", - "\u001b[1;32m 2168\u001b[0m [Z_INTERFACE_DIM],\n", - "\u001b[1;32m 2169\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n", - "\u001b[1;32m 2170\u001b[0m dtype\u001b[38;5;241m=\u001b[39mFloat,\n", - "\u001b[1;32m 2171\u001b[0m )\n", - "\u001b[0;32m-> 2172\u001b[0m pressure_coefficients \u001b[38;5;241m=\u001b[39m \u001b[43meta\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_hybrid_pressure_coefficients\u001b[49m\u001b[43m(\u001b[49m\n", - "\u001b[1;32m 2173\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_npz\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meta_file\u001b[49m\n", - "\u001b[1;32m 2174\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[1;32m 2175\u001b[0m ks \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mks\n", - "\u001b[1;32m 2176\u001b[0m ptop \u001b[38;5;241m=\u001b[39m pressure_coefficients\u001b[38;5;241m.\u001b[39mptop\n", - "\n", - "File \u001b[0;32m/pace/NDSL/ndsl/grid/eta.py:60\u001b[0m, in \u001b[0;36mset_hybrid_pressure_coefficients\u001b[0;34m(km, eta_file)\u001b[0m\n", - "\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# check size of ak and bk array is km+1\u001b[39;00m\n", - "\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ak\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of ak array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bk\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m!=\u001b[39m km:\n", - "\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msize of bk array is not equal to km=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkm\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\n", - "\u001b[0;31mValueError\u001b[0m: size of ak array is not equal to km=1\n", - "[1:execute] ValueError: size of ak array is not equal to km=1\n", - "[2:execute] ValueError: size of ak array is not equal to km=1\n" - ] - }, - { - "ename": "AlreadyDisplayedError", - "evalue": "6 errors", - "output_type": "error", - "traceback": [ - "6 errors" - ] - } - ], - "source": [ - "mpi_comm = MPI.COMM_WORLD\n", - "mpi_rank = mpi_comm.Get_rank()\n", - "\n", - "nz = 1\n", - "if nz == 1:\n", - " single_layer = True\n", - "else:\n", - " single_layer = False\n", - "\n", - "namelist_dict = func.store_namelist_variables(locals())\n", - "dimensions = func.define_dimensions(namelist_dict)\n", - "\n", - "\n", - "domain_configuration = func.configure_domain(mpi_comm, dimensions, single_layer=single_layer)\n", - "\n", - "initial_state = func.create_initial_state_advection(\n", - " domain_configuration[\"metric_terms\"], dimensions, tracer_center, test_case\n", - ")\n", - "\n", - "stencil_configuration = func.configure_stencil(domain_configuration, backend=backend)\n", - "stencil_configuration[\"quantity_factory\"] = domain_configuration[\"quantity_factory\"]\n", - "\n", - "tracer_advection_data, tracer_advection = func.prepare_everything_for_advection(\n", - " stencil_configuration, initial_state, dimensions, timestep\n", - ")\n", - "\n", - "tracer_advection_data_initial = cp.deepcopy(tracer_advection_data)\n", - "\n", - "tracer_state = [cp.deepcopy(tracer_advection_data_initial[\"tracers\"][\"tracer\"])]\n", - "\n", - "nSteps = 10\n", - "for step in range(nSteps):\n", - " tracer_advection_data = func.run_advection_step_with_reset(\n", - " tracer_advection_data_initial, tracer_advection_data, tracer_advection\n", - " )\n", - "\n", - " tracer_state.append(cp.deepcopy(tracer_advection_data[\"tracers\"][\"tracer\"]))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "783a781e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[output:0]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABQsAAAF2CAYAAADJMM7PAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqNUlEQVR4nO3deXxU1f3/8fckkAlbEmNIQjDsKiBbDZIvKIKaEpCi1A3UryBVqErcqK1alUXUuCJWEapVaKlURAu2yheKKLhFEYSfWgGRsikkbE0CARLInN8fmAlDFmbuzNxMbl7Px+M+NHfOvffcGTLvzGfOPddljDECAAAAAAAA0OBF1XUHAAAAAAAAAEQGioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioUAAAAAAAAAJFEsBAAAAAAAAPATioVAmAwcOFADBw6s624AAByiPuRKQUGBrrrqKp1++ulyuVyaPn16XXcJAGo0efJkuVwun3Xt2rXTjTfe6LNu06ZNGjRokOLj4+VyubRo0SJJ0hdffKF+/fqpWbNmcrlcWrdunT0dr+dqej4BRA6KhTX49NNPNXnyZBUWFtZ1VxCkF198UXPmzAnLvr/99ltNnjxZW7duDcv+w2nnzp2aPHmy33/UhOt34h//+IfOPfdcxcbGqk2bNpo0aZKOHTsW0mMAkYBccQ5ypWZ33323li5dqvvvv19z587V4MGDtXjxYk2ePNnWfmzcuFF33323+vXrp9jYWLlcrlqf03BmUV2cP4DQGj16tL7++ms9+uijmjt3rnr37q2jR4/q6quv1v79+/Xss89q7ty5atu2bV13tV6o7vmcN2+e7V8wrVq1SrfddpsyMjLUuHHjKoXjk73yyivq0qWLYmNjdeaZZ+r5558PWV/q4vyBWhlU66mnnjKSzJYtW+q6KwjSOeecYwYMGBCWfS9YsMBIMh988EGVx0pLS01paWlYjhsKX3zxhZFkZs+e7Vf7cPxOLF682LhcLnPRRReZl156ydx+++0mKirK3HLLLSE7BhApyBXnIFdqlpKSYq6//nqfdePHjzd2/8k5e/ZsExUVZbp162Z69epV6+9euLOoLs4fgH8mTZpU5ffzyJEjpqyszPvzoUOHjCTzwAMP+LRbv369kWRefvllW/rqFDU9n0OHDjVt27a1tS+TJk0yjRs3NhkZGeass86q9b161qxZRpK58sorzUsvvWRuuOEGI8k8/vjjIelLXZw/UJtG9pcnncfj8aisrEyxsbF13RWvkpISNWvWrK67Ue+E8nmLiYkJyX6c7J577lGPHj30r3/9S40aHX87iouL02OPPaY777xTnTt3ruMeAnWDXHGOhpYru3fvVkJCQtiPY4zRkSNH1KRJk2ofv+yyy1RYWKgWLVro6aefrnUUPVkE4ERut9vn5z179khSlfe23bt3V7s+GA0ha2t6PsPhVH9P3Xrrrbr33nvVpEkT5eTk6Lvvvqu23eHDh/XAAw9o6NChevPNNyVJY8eOlcfj0dSpUzVu3DiddtppYTsPoE7UdbUyElV8w3TyUvGNtCQzfvx489e//tV07drVNGrUyCxcuNAYc3zkSN++fU1iYqKJjY015557rlmwYEG1x5k7d64577zzTJMmTUxCQoLp37+/Wbp0qU+bxYsXmwsuuMA0bdrUNG/e3Fx66aXmm2++8WkzevRo06xZM/P999+bIUOGmObNm5vLL7+81nP84YcfzK9+9SvTqlUrExMTY9q1a2duueUWnxELmzdvNldddZU57bTTTJMmTUxmZqZ55513fPbzwQcfGElm/vz55pFHHjGtW7c2brfbXHzxxWbTpk1VjvvZZ5+ZIUOGmISEBNO0aVPTvXt3M336dJ8269evN1deeaU57bTTjNvtNhkZGebtt9/2aTN79mwjyXz88cfm7rvvNklJSaZp06Zm+PDhZvfu3d52bdu2rfI6VowGqdjHihUrzK233mpatmxpEhISjDHGbN261dx6663mrLPOMrGxsSYxMdFcddVVPqMSKrY/eakYDTJgwIAqI08KCgrMr371K5OcnGzcbrfp0aOHmTNnjk+bLVu2GEnmqaeeMn/84x9Nhw4dTExMjOndu7dZtWpVzS/qT/bt22d+85vfmG7duplmzZqZFi1amMGDB5t169ZVed1OXmoaZXiq3wkr/v3vfxtJZsaMGT7rf/zxRyPJTJ061fK+gUhDrhxHrjg3V2rq++jRo6tdX6G8vNw8++yzpmvXrsbtdpvk5GQzbtw4s3//fp8+tG3b1gwdOtQsWbLEZGRkGLfbbZ599tlT9t2Y2kf1BptFZWVlZvLkyaZTp07G7XabxMREc/7555t//etfxhgT8vNfunSp6dmzp3G73aZLly7mrbfeCqg/QEP20Ucfmd69exu32206dOhgZs2aVe3IwrZt25rRo0cbY6rP74rHa8oCYwLLneoyw5jA8vqHH34wl19+uWnWrJlJSkoyv/nNb8yxY8d82paXl5vp06ebbt26GbfbbZKSkkx2drb54osvfNrNnTvXnHvuuSY2NtacdtppZsSIEWb79u2nfH79ybmans8BAwZUu77CkSNHzMSJE03Hjh1NTEyMOeOMM8xvf/tbc+TIEZ8+1Pb31KnUNgr83XffNZLMu+++67P+008/NZLM3Llza913cXGxufPOO03btm1NTEyMadmypcnKyjJr1qwxxpiwnP9ZZ51l3G63Offcc83KlSsD6g9gDCMLq3XFFVfou+++09/+9jc9++yzSkpKkiS1bNnS2+b999/XG2+8oZycHCUlJaldu3aSpOeee06XXXaZrr/+epWVlen111/X1VdfrXfeeUdDhw71bj9lyhRNnjxZ/fr108MPP6yYmBh9/vnnev/99zVo0CBJ0ty5czV69GhlZ2friSee0KFDhzRz5kxdcMEFWrt2rfeYknTs2DFlZ2frggsu0NNPP62mTZvWeH47d+5Unz59VFhYqHHjxqlz58768ccf9eabb+rQoUOKiYlRQUGB+vXrp0OHDumOO+7Q6aefrj//+c+67LLL9Oabb+qXv/ylzz4ff/xxRUVF6Z577lFRUZGefPJJXX/99fr888+9bZYtW6Zf/OIXatWqle68806lpqZq/fr1euedd3TnnXdKkv7973/r/PPPV+vWrXXfffepWbNmeuONNzR8+HC99dZbVY57++2367TTTtOkSZO0detWTZ8+XTk5OZo/f74kafr06br99tvVvHlzPfDAA5KklJQUn33cdtttatmypSZOnKiSkhJJxycr/vTTTzVy5EidccYZ2rp1q2bOnKmBAwfq22+/VdOmTXXhhRfqjjvu0B/+8Af9/ve/V5cuXSTJ+9+THT58WAMHDtT333+vnJwctW/fXgsWLNCNN96owsJC73NQYd68eTpw4IB+/etfy+Vy6cknn9QVV1yh//znP2rcuHGNr+9//vMfLVq0SFdffbXat2+vgoIC/fGPf9SAAQP07bffKi0tTV26dNHDDz+siRMnaty4cerfv78kqV+/ftXu81S/E0VFRTp69GiNfaoQGxur5s2bS5LWrl0rSerdu7dPm7S0NJ1xxhnexwEnIFfIFafnyoUXXqi5c+fqhhtu0M9//nONGjVKktSxY0ft3LlTy5Yt09y5c6vs+9e//rXmzJmjMWPG6I477tCWLVv0wgsvaO3atfrkk098+rVx40Zde+21+vWvf62xY8fq7LPPrrHP/go2iyZPnqzc3FzdfPPN6tOnj4qLi7V69Wp9+eWX+vnPf65f//rXITv/TZs2acSIEbrllls0evRozZ49W1dffbWWLFmin//85371B2iovv76aw0aNEgtW7bU5MmTdezYMU2aNKnK+/fJrrjiCiUkJOjuu+/Wtddeq0svvVTNmzdXSkqKWrdurccee0x33HGHzjvvPO++As2d6jIjkLwuLy9Xdna2MjMz9fTTT+u9997TM888o44dO+rWW2/1trvppps0Z84cDRkyRDfffLOOHTumjz76SJ999pn3PfDRRx/VQw89pGuuuUY333yz9uzZo+eff14XXnih1q5dW+toQH9yrqbns1mzZioqKtIPP/ygZ599VpK8nxk8Ho8uu+wyffzxxxo3bpy6dOmir7/+Ws8++6y+++67KjdHqenvqWDUlBUZGRmKiorS2rVr9b//+781bn/LLbfozTffVE5Ojrp27ap9+/bp448/1vr163XuuefqgQceCNn5r1y5UvPnz9cdd9wht9utF198UYMHD9aqVavUrVs3v/oDSGJkYU1q+xZakomKijL//ve/qzx26NAhn5/LyspMt27dzMUXX+xdt2nTJhMVFWV++ctfmvLycp/2Ho/HGGPMgQMHTEJCghk7dqzP4/n5+SY+Pt5nfcU3W/fdd59f5zZq1CgTFRVV5VukE49/1113GUnmo48+8j524MAB0759e9OuXTtvvytGgHTp0sVn9Mhzzz1nJJmvv/7aGGPMsWPHTPv27U3btm3Nf//732qPaYwxl1xyienevbvPtyQej8f069fPnHnmmd51Fd/EZWVl+Wx/9913m+joaFNYWOhdV9PcUhX7uOCCC6p883by62iMMXl5eUaS+ctf/uJdV9vcUiePAJk+fbqRZP76179615WVlZm+ffua5s2bm+LiYmNM5QiQ008/3Wdkwdtvv20kmX/+859VjnWiI0eOVPl3tWXLFuN2u83DDz/sXRfKOQur+zasuqXiW9oT91fdN5XnnXee+Z//+R+/+gXUF+QKuXIyp+WKMZWjGk5U02iNjz76yEgyr732ms/6JUuWVFlfMaJzyZIltfa1OrX97gWbRT179jRDhw6ttU0oz//EkYRFRUWmVatW5mc/+1lA/QEaouHDh5vY2Fizbds277pvv/3WREdH1zqy0Bjf0dknqsirk0f7B5o7J2eGlbw++b34Zz/7mcnIyPD+/P777xtJ5o477qjy3FRk3tatW010dLR59NFHfR7/+uuvTaNGjaqsP5m/OVfT81nTnH1z5841UVFRPn8/GFM5h+Ann3ziXVfb31OnUtvIwvHjx5vo6OhqH2vZsqUZOXJkrfuOj4+vko0nC9X5SzKrV6/2rtu2bZuJjY01v/zlLwPqD8DdkC0aMGCAunbtWmX9iXPn/Pe//1VRUZH69++vL7/80rt+0aJF8ng8mjhxoqKifF+CijswLVu2TIWFhbr22mu1d+9e7xIdHa3MzEx98MEHVY594jdHNfF4PFq0aJGGDRtW5ZuRE4+/ePFi9enTRxdccIH3sebNm2vcuHHaunWrvv32W5/txowZ4zOXUsVItf/85z+Sjn8bs2XLFt11111VvpGqOOb+/fv1/vvv65prrtGBAwe857xv3z5lZ2dr06ZN+vHHH322HTdunM9dq/r376/y8nJt27btlM9FhbFjxyo6Otpn3Ymv49GjR7Vv3z516tRJCQkJPq9lIBYvXqzU1FRde+213nWNGzfWHXfcoYMHD2rlypU+7UeMGOEz98XJz2lN3G63999VeXm59u3bp+bNm+vss8+23PdTeeaZZ7Rs2bJTLr/73e+82xw+fNjb35PFxsZ6HwcaCnKFXAlUfc+VBQsWKD4+Xj//+c99/k1mZGSoefPmVf5Ntm/fXtnZ2ZaPV51gsyghIUH//ve/tWnTpoCPHej5p6Wl+YxIiouL06hRo7R27Vrl5+cH3R/AqcrLy7V06VINHz5cbdq08a7v0qVLyN9TrOTOyZlhJa9vueUWn5/79+/v897+1ltvyeVyadKkSVW2rci8v//97/J4PLrmmmt8jpuamqozzzyz2uOeKBw5Jx1/r+zSpYs6d+7s06+LL75Ykqr0q6a/p4Jx+PDhGucN9jcrPv/8c+3cuTPgYwd6/n379lVGRob35zZt2ujyyy/X0qVLVV5eHnR/0HBwGbJF7du3r3b9O++8o0ceeUTr1q1TaWmpd/2JHzw2b96sqKioWt/EKv7Iq3gTOFlcXJzPz40aNdIZZ5xxyn7v2bNHxcXF3iHINdm2bZsyMzOrrK+4FGrbtm0++zgxeCV5P4z897//lXT8nCXVetzvv/9exhg99NBDeuihh6pts3v3brVu3drv4/qjutfy8OHDys3N1ezZs/Xjjz/KGON9rKioyO99n2jbtm0688wzq3yQP/E5PZHVc/N4PHruuef04osvasuWLd5QkKTTTz/dUt9P5cRA8lfFHxQn/p5UqG3SesCpyBVyJVD1PVc2bdqkoqIiJScnV/t4xc0DKtT0OxKMYLPo4Ycf1uWXX66zzjpL3bp10+DBg3XDDTeoR48epzx2oOffqVMnn997STrrrLMkSVu3blVqampQ/QGcas+ePTp8+LDOPPPMKo+dffbZWrx4cciOZSV3Tn5vCzSvY2NjfaY1kY6/v5/43r5582alpaUpMTGxxr5v2rRJxphqnydJtU5XIYUn5yr6tX79+irnWMGurCgrK6v2MX+y4sknn9To0aOVnp6ujIwMXXrppRo1apQ6dOhwymMHev7VvX5nnXWWDh06pD179ig1NTWo/qDhoFhoUXVvCB999JEuu+wyXXjhhXrxxRfVqlUrNW7cWLNnz9a8efMC2r/H45F0fL6K1NTUKo9X3K2vwonf+teFk0dQVDgxJE6l4pzvueeeGr/l69SpU8iPW91refvtt2v27Nm666671LdvX8XHx8vlcmnkyJHefoab1XN77LHH9NBDD+lXv/qVpk6dqsTEREVFRemuu+4KW9/3799fY4CeqEmTJoqPj5cktWrVSpK0a9cupaen+7TbtWuX+vTpE/qOAhGMXPFFroRepOWKx+NRcnKyXnvttWofP/mDUTi+RAo2iy688EJt3rxZb7/9tv71r3/pT3/6k5599lnNmjVLN998c63bBnr+/gimPwCCZyV3Tn5vCzSva3pvD5TH45HL5dL//d//VbvPijn0ahKunPN4POrevbumTZtW7eMnv3eHKyvKy8u1e/duny94ysrKtG/fPqWlpdW6/TXXXKP+/ftr4cKF+te//qWnnnpKTzzxhP7+979ryJAhtW4b6Pn7I5j+oOGgWFiDk7+59cdbb72l2NhYLV261OdyltmzZ/u069ixozwej7799lv16tWr2n117NhRkpScnKysrKyA+1KTli1bKi4uTt98802t7dq2bauNGzdWWb9hwwbv44GoOJ9vvvmmxvOp+CajcePGIT1nK6/lm2++qdGjR+uZZ57xrjty5IgKCwst77tt27b66quv5PF4fD6AW31Oa/Lmm2/qoosu0iuvvOKzvrCw0HtTBSnw56W29ldccUWVy92qM3r0aM2ZM0eSvP/2V69e7fNhbOfOnfrhhx80bty4gPoHRDpyhVxxeq7UpKZz6tixo9577z2df/75dTaaPBRZlJiYqDFjxmjMmDE6ePCgLrzwQk2ePNlbnAvV+VeMWDpxf999950k+Uzgf6r+AA1Ny5Yt1aRJk2ovz68ul4IRitwJR1537NhRS5cu1f79+2scXdixY0cZY9S+fXvvqOVA+JtzNantvfL//b//p0suucRS/obCiVlx6aWXetevXr1aHo+nxr+9TtSqVSvddtttuu2227R7926de+65evTRR73FuVCdf3X/zr/77js1bdrU50uoU/UHYM7CGjRr1kyS/H5zk45/q+NyuXwuz9m6dWuVOxQNHz5cUVFRevjhh6t8y1Lx7X52drbi4uL02GOPVXuX2T179vjdrxNFRUVp+PDh+uc//6nVq1dXebzi+JdeeqlWrVqlvLw872MlJSV66aWX1K5du4DngTj33HPVvn17TZ8+vcpzWnHM5ORkDRw4UH/84x+1a9euKvuwes7NmjUL6HWUjr+WJ4+0eP75531e24p9S/79O7n00kuVn5/vvaOmdPxuo88//7yaN2+uAQMGBNTHmlTX9wULFlSZHyXQf+O1tbcyZ+E555yjzp0766WXXvJ5XmfOnCmXy6WrrrrKr34B9QW5Qq44PVdqUtM5XXPNNSovL9fUqVOrbHPs2LGAn2Mrgs2iffv2+fzcvHlzderUyeey5lCd/86dO7Vw4ULvz8XFxfrLX/6iXr16eUcf+dMfoKGJjo5Wdna2Fi1apO3bt3vXr1+/XkuXLg3psUKRO+HI6yuvvFLGGE2ZMqXKYxXv71dccYWio6M1ZcqUKu/5xpgq7y8n8zfnalJxR+STXXPNNfrxxx/18ssvV3ns8OHD3jtIh9PFF1+sxMREzZw502f9zJkz1bRpUw0dOrTGbcvLy6ucV3JystLS0qpkRSjOPy8vz2eOyB07dujtt9/WoEGDFB0d7Xd/AEYW1qBiDrYHHnhAI0eOVOPGjTVs2DDvH3zVGTp0qKZNm6bBgwfruuuu0+7duzVjxgx16tRJX331lbddp06d9MADD2jq1Knq37+/rrjiCrndbn3xxRdKS0tTbm6u4uLiNHPmTN1www0699xzNXLkSLVs2VLbt2/Xu+++q/PPP18vvPCCpXN77LHH9K9//UsDBgzw3n59165dWrBggT7++GMlJCTovvvu09/+9jcNGTJEd9xxhxITE/XnP/9ZW7Zs0VtvvRXwpWlRUVGaOXOmhg0bpl69emnMmDFq1aqVNmzYoH//+9/eoJ4xY4YuuOACde/eXWPHjlWHDh1UUFCgvLw8/fDDD/p//+//BXy+GRkZmjlzph555BF16tRJycnJNc4BUuEXv/iF5s6dq/j4eHXt2lV5eXl67733qszN1KtXL0VHR+uJJ55QUVGR3G63Lr744mrnHxo3bpz++Mc/6sYbb9SaNWvUrl07vfnmm/rkk080ffp0tWjRIuBzq6nvDz/8sMaMGaN+/frp66+/1muvvVZlDoqOHTsqISFBs2bNUosWLdSsWTNlZmbWOM9Hbb8TVuYslKSnnnpKl112mQYNGqSRI0fqm2++0QsvvKCbb77ZO+cW4BTkCrni9FypScW//TvuuEPZ2dmKjo7WyJEjNWDAAP36179Wbm6u1q1bp0GDBqlx48batGmTFixYoOeee87yF0dFRUV6/vnnJUmffPKJJOmFF15QQkKCEhISlJOT420bTBZ17dpVAwcOVEZGhhITE7V69Wq9+eabPvsP1fmfddZZuummm/TFF18oJSVFr776qgoKCnxGGvvTH6AhmjJlipYsWaL+/fvrtttu836xcs455/jkaSgEmzvhyOuLLrpIN9xwg/7whz9o06ZNGjx4sDwejz766CNddNFFysnJUceOHfXII4/o/vvv19atWzV8+HC1aNFCW7Zs0cKFCzVu3Djdc889NR7D35yrSUZGhubPn68JEybovPPOU/PmzTVs2DDdcMMNeuONN3TLLbfogw8+0Pnnn6/y8nJt2LBBb7zxhpYuXVrtDdb8sW3bNs2dO1eSvF94PvLII5KOj86/4YYbJB2/tHnq1KkaP368rr76amVnZ+ujjz7SX//6Vz366KO1zgV54MABnXHGGbrqqqvUs2dPNW/eXO+9956++OILn1GYoTr/bt26KTs7W3fccYfcbrdefPFFSfIWiv3tD1D9vcFh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586duuKKK0LecQCobzxyyWMsLFyyFTbkGgBYZynXyLSwIdMAIEguV+CFQpczcy2gy5CXLFni8/OcOXOUnJysNWvW6MILL1RRUZFeeeUVzZs3TxdffLEkafbs2erSpYs+++wz/c///E/oeg4A9YyxOGeh4YNV2JBrAGCdlVwj08KHTAOAIHEZsldQZ1VUVCRJSkxMlCStWbNGR48eVVZWlrdN586d1aZNG+Xl5VW7j9LSUhUXF/ssAADUBXINAOAUocg0iVwDgIbIcrHQ4/Horrvu0vnnn69u3bpJkvLz8xUTE6OEhASftikpKcrPz692P7m5uYqPj/cu6enpVrsEABHN0iXIPy0IP3INAAJDpkWuUGWaRK4BaECYs9DL8lmNHz9e33zzjV5//fWgOnD//ferqKjIu+zYsSOo/QFApOIGJ5GNXAOAwJBpkStUmSaRawAaEIqFXgHNWVghJydH77zzjj788EOdccYZ3vWpqakqKytTYWGhzzdWBQUFSk1NrXZfbrdbbrfbSjcAoF6xOqKCURjhR64BQOCs5BqZFn6hzDSJXAPQgDBnoVdAZ2WMUU5OjhYuXKj3339f7du393k8IyNDjRs31vLly73rNm7cqO3bt6tv376h6TEA1FOenyaCt7IgPMg1ALCOTIssZBoABImRhV4BjSwcP3685s2bp7ffflstWrTwzm0RHx+vJk2aKD4+XjfddJMmTJigxMRExcXF6fbbb1ffvn25uxaABo+RhZGHXAMA6xhZGFnINAAIEiMLvQIqFs6cOVOSNHDgQJ/1s2fP1o033ihJevbZZxUVFaUrr7xSpaWlys7O1osvvhiSzgIAEErkGgDAKcg0AECoBFQsNMacsk1sbKxmzJihGTNmWO4UADgRIwsjD7kGANYxsjCykGkAECRGFnpZusEJACBwFAsBAE5CsRAA4CgUC72ceVYAEIEqPlRZWQAAiDRkGgDAUVyuwG9u4rKWazNmzFC7du0UGxurzMxMrVq1qsa2L7/8svr376/TTjtNp512mrKysmptHwoUCwHAJkbW7hx56ouKAACwn5VcI9MAABHLprshz58/XxMmTNCkSZP05ZdfqmfPnsrOztbu3burbb9ixQpde+21+uCDD5SXl6f09HQNGjRIP/74Y7BnXCOKhQAAAAAAAIANpk2bprFjx2rMmDHq2rWrZs2apaZN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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "engine": 0 - }, - "output_type": "display_data" - } - ], - "source": [ - "if mpi_rank == 0:\n", - " fig = plt.figure(figsize=(16, 4))\n", - " fig.patch.set_facecolor(\"white\")\n", - " ax_before = fig.add_subplot(131)\n", - " ax_after = fig.add_subplot(132)\n", - " ax_diff = fig.add_subplot(133)\n", - "\n", - " f1 = ax_before.pcolormesh(\n", - " tracer_state[0].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f1, ax=ax_before)\n", - " f2 = ax_after.pcolormesh(\n", - " tracer_state[-1].data[:, :, 0].T, vmin=-0, vmax=1, cmap=\"viridis\"\n", - " )\n", - " plt.colorbar(f2, ax=ax_after)\n", - " f3 = ax_diff.pcolormesh(\n", - " (tracer_state[-1].data[:, :, 0] - tracer_state[0].data[:, :, 0]).T,\n", - " vmin=-0.5,\n", - " vmax=0.5,\n", - " cmap=\"bwr\",\n", - " )\n", - " plt.colorbar(f3, ax=ax_diff)\n", - "\n", - " ax_before.set_title(\"tracer concentration at t=0\")\n", - " ax_after.set_title(\"tracer concentration after %s steps\" % nSteps)\n", - " ax_diff.set_title(\"difference after %s steps\" % nSteps)\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b0cc550-95f0-4b79-9916-6d5859cb8420", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "vscode": { - "interpreter": { - "hash": "5aaa1d64d2aec5fc9d71d95fe114c55e361597d915cf108c460e747a228aecec" - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/pace/diagnostics.py b/pace/diagnostics.py index 6afdc768..5a4b9d54 100644 --- a/pace/diagnostics.py +++ b/pace/diagnostics.py @@ -7,7 +7,7 @@ import numpy as np from ndsl import Quantity -from ndsl.constants import RGRAV, Z_DIM, Z_INTERFACE_DIM +from ndsl.constants import K_DIM, K_INTERFACE_DIM, RGRAV from ndsl.dsl.dace.orchestration import dace_inhibitor from ndsl.dsl.typing import Float from ndsl.grid import GridData @@ -46,7 +46,7 @@ def select_data(self, state: DycoreState): if name not in state.__dict__.keys(): raise ValueError(f"Invalid state variable {name} for level select") assert len(getattr(state, name).dims) > 2 - if getattr(state, name).dims[2] != (Z_DIM or Z_INTERFACE_DIM): + if getattr(state, name).dims[2] != (K_DIM or K_INTERFACE_DIM): raise ValueError( f"z_select only works for state variables with dimension (x, y, z). \ \n {name} has dimension {getattr(state, name).dims}" @@ -95,13 +95,11 @@ def __post_init__(self): ) if self.output_format not in ["zarr", "netcdf"]: raise ValueError( - "output_format must be one of 'zarr' or 'netcdf', " - f"got {self.output_format}" + f"output_format must be one of 'zarr' or 'netcdf', got {self.output_format}" ) if self.precision not in ["Float", "float32", "float64"]: raise ValueError( - "precision must be one of 'Float', 'float32', or 'float64" - f"got {self.precision}" + f"precision must be one of 'Float', 'float32', or 'float64got {self.precision}" ) def diagnostics_factory(self, communicator: Communicator) -> Diagnostics: @@ -140,8 +138,7 @@ def diagnostics_factory(self, communicator: Communicator) -> Diagnostics: ) else: raise ValueError( - "output_format must be one of 'zarr' or 'netcdf', " - f"got {self.output_format}" + f"output_format must be one of 'zarr' or 'netcdf', got {self.output_format}" ) return MonitorDiagnostics( @@ -251,7 +248,7 @@ def _compute_column_integral(name: str, q_in: Quantity, delp: Quantity) -> Quant if len(q_in.dims) <= 2: raise RuntimeError("This function assumes that q_in is at least 3-dimensional.") - if q_in.dims[2] != Z_DIM: + if q_in.dims[2] != K_DIM: raise RuntimeError( "This function assumes the z-dimension is the third dimension" ) diff --git a/pace/grid.py b/pace/grid.py index d235ef98..5419f99f 100644 --- a/pace/grid.py +++ b/pace/grid.py @@ -9,7 +9,7 @@ from ndsl import QuantityFactory, ndsl_log from ndsl.comm.partitioner import get_tile_index from ndsl.config import Backend -from ndsl.constants import X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM +from ndsl.constants import I_DIM, I_INTERFACE_DIM, J_DIM, J_INTERFACE_DIM from ndsl.grid import ( AngleGridData, ContravariantGridData, @@ -257,7 +257,7 @@ def get_grid( subtile_slice_grid = communicator.partitioner.tile.subtile_slice( rank=communicator.rank, - global_dims=[X_INTERFACE_DIM, Y_INTERFACE_DIM], + global_dims=[I_INTERFACE_DIM, J_INTERFACE_DIM], global_extent=(npx, npy), overlap=True, ) diff --git a/pace/initialization.py b/pace/initialization.py index 35eaa36b..eaab682d 100644 --- a/pace/initialization.py +++ b/pace/initialization.py @@ -16,7 +16,7 @@ StencilFactory, ) from ndsl.config import Backend -from ndsl.constants import X_DIM, Y_DIM +from ndsl.constants import I_DIM, J_DIM from ndsl.grid import DampingCoefficients, DriverGridData, GridData from ndsl.stencils.testing import TranslateGrid, grid from ndsl.typing import Communicator diff --git a/pace/state.py b/pace/state.py index 45c20560..ff36e9dc 100644 --- a/pace/state.py +++ b/pace/state.py @@ -6,7 +6,7 @@ import ndsl.dsl.gt4py_utils as gt_utils from ndsl import Quantity, QuantityFactory, SubtileGridSizer -from ndsl.constants import N_HALO_DEFAULT, X_DIM, Y_DIM, Z_DIM +from ndsl.constants import I_DIM, J_DIM, K_DIM, N_HALO_DEFAULT from ndsl.dsl.typing import Float from ndsl.grid import DampingCoefficients, DriverGridData, GridData from ndsl.typing import Communicator @@ -24,7 +24,7 @@ class TendencyState: u_dt: Quantity = dataclasses.field( metadata={ "name": "eastward_wind_tendency_due_to_physics", - "dims": [X_DIM, Y_DIM, Z_DIM], + "dims": [I_DIM, J_DIM, K_DIM], "units": "m/s**2", "intent": "inout", } @@ -32,7 +32,7 @@ class TendencyState: v_dt: Quantity = dataclasses.field( metadata={ "name": "northward_wind_tendency_due_to_physics", - "dims": [X_DIM, Y_DIM, Z_DIM], + "dims": [I_DIM, J_DIM, K_DIM], "units": "m/s**2", "intent": "inout", } @@ -40,7 +40,7 @@ class TendencyState: pt_dt: Quantity = dataclasses.field( metadata={ "name": "temperature_tendency_due_to_physics", - "dims": [X_DIM, Y_DIM, Z_DIM], + "dims": [I_DIM, J_DIM, K_DIM], "units": "K/s", "intent": "inout", } diff --git a/tests/main/driver/test_diagnostics_config.py b/tests/main/driver/test_diagnostics_config.py index 565eba7f..1f1ead4b 100644 --- a/tests/main/driver/test_diagnostics_config.py +++ b/tests/main/driver/test_diagnostics_config.py @@ -4,7 +4,7 @@ from ndsl import QuantityFactory, SubtileGridSizer from ndsl.config import Backend -from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.constants import I_DIM, J_DIM, K_DIM from pace import DiagnosticsConfig from pace.diagnostics import MonitorDiagnostics, NullDiagnostics, ZSelect from pyfv3 import DycoreState @@ -80,6 +80,6 @@ def test_zselect_raises_error_if_3rd_dim_not_z(tmpdir): backend=backend, ) state = DycoreState.init_zeros(quantity_factory) - foo = quantity_factory.zeros(dims=[Z_DIM, X_DIM, Y_DIM], units="-") + foo = quantity_factory.zeros(dims=[K_DIM, I_DIM, J_DIM], units="-") state.foo = foo result.z_select[0].select_data(state) diff --git a/tests/main/driver/test_safety_checks.py b/tests/main/driver/test_safety_checks.py index fd88da76..e17c93b7 100644 --- a/tests/main/driver/test_safety_checks.py +++ b/tests/main/driver/test_safety_checks.py @@ -5,7 +5,7 @@ from ndsl import Quantity from ndsl.config import Backend -from ndsl.constants import X_DIM, Y_DIM, Z_DIM +from ndsl.constants import I_DIM, J_DIM, K_DIM from pace import SafetyChecker @@ -63,7 +63,7 @@ def test_check_state_domain_only(): u_data[0:1, 0:1, :] = 100 u_quantity = Quantity( u_data, - (X_DIM, Y_DIM, Z_DIM), + (I_DIM, J_DIM, K_DIM), "unknown", origin=(1, 1, 0), extent=(3, 3, 2), @@ -81,7 +81,7 @@ def test_check_nan_value(): u_data[2, 2, 1] = np.nan u_quantity = Quantity( u_data, - (X_DIM, Y_DIM, Z_DIM), + (I_DIM, J_DIM, K_DIM), "unknown", origin=(0, 0, 0), extent=(4, 4, 2), diff --git a/tests/main/fv3core/test_grid.py b/tests/main/fv3core/test_grid.py index 572efc2d..7f5530a1 100644 --- a/tests/main/fv3core/test_grid.py +++ b/tests/main/fv3core/test_grid.py @@ -6,12 +6,12 @@ import ndsl.dsl.gt4py as gt from ndsl import GridIndexing from ndsl.constants import ( - X_DIM, - X_INTERFACE_DIM, - Y_DIM, - Y_INTERFACE_DIM, - Z_DIM, - Z_INTERFACE_DIM, + I_DIM, + I_INTERFACE_DIM, + J_DIM, + J_INTERFACE_DIM, + K_DIM, + K_INTERFACE_DIM, ) from ndsl.dsl.typing import Index3D @@ -280,7 +280,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (3, 3, 0), (4, 4, 7), @@ -289,7 +289,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], tuple(), (3, 3, 0), (4, 4, 7), @@ -298,7 +298,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [Z_DIM, Y_DIM, X_DIM], + [K_DIM, J_DIM, I_DIM], (0, 0, 0), (0, 3, 3), (7, 4, 4), @@ -307,7 +307,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Z_DIM], + [I_DIM, K_DIM], (0, 0), (3, 0), (4, 7), @@ -316,7 +316,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (1, 0, 0), (2, 3, 0), (6, 4, 7), @@ -325,7 +325,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 1, 0), (3, 2, 0), (4, 6, 7), @@ -335,7 +335,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 1), (3, 3, -1), (4, 4, 9), @@ -344,7 +344,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (2, 2), (1, 1, 0), (8, 8, 7), @@ -353,7 +353,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM], + [I_DIM, J_DIM], (2, 2), (1, 1), (8, 8), @@ -362,7 +362,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_INTERFACE_DIM, Y_DIM, Z_DIM], + [I_INTERFACE_DIM, J_DIM, K_DIM], (0, 0, 0), (3, 3, 0), (5, 4, 7), @@ -371,7 +371,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_INTERFACE_DIM, Z_DIM], + [I_DIM, J_INTERFACE_DIM, K_DIM], (0, 0, 0), (3, 3, 0), (4, 5, 7), @@ -380,7 +380,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_INTERFACE_DIM], + [I_DIM, J_DIM, K_INTERFACE_DIM], (0, 0, 0), (3, 3, 0), (4, 4, 8), @@ -389,7 +389,7 @@ def test_domain_compute( pytest.param( 3, (4, 4, 7), - [X_INTERFACE_DIM, Y_DIM, Z_DIM], + [I_INTERFACE_DIM, J_DIM, K_DIM], (0, 3), (3, 0, 0), (5, 10, 7), @@ -398,7 +398,7 @@ def test_domain_compute( pytest.param( 1, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (1, 1, 0), (4, 4, 7), @@ -407,7 +407,7 @@ def test_domain_compute( pytest.param( 3, (2, 3, 6), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (3, 3, 0), (2, 3, 6), @@ -456,7 +456,7 @@ def test_get_origin_domain( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (3, 3, 0), (4, 4, 7), @@ -465,7 +465,7 @@ def test_get_origin_domain( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], tuple(), (3, 3, 0), (4, 4, 7), @@ -518,7 +518,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (5, 6, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (8, 9, 7), id="compute", @@ -526,7 +526,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (5, 6, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], tuple(), (8, 9, 7), id="compute_empty_halo", @@ -534,7 +534,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (5, 6, 7), - [Z_DIM, Y_DIM, X_DIM], + [K_DIM, J_DIM, I_DIM], (0, 0, 0), (7, 9, 8), id="compute_reverse", @@ -542,7 +542,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 0, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 0, 0), (4, 4, 7), id="no_halos_anywhere", @@ -550,7 +550,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (4, 4, 7), - [X_INTERFACE_DIM, Y_DIM, Z_DIM], + [I_INTERFACE_DIM, J_DIM, K_DIM], (0, 0, 0), (8, 7, 7), id="x_interface", @@ -558,7 +558,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_INTERFACE_DIM, Z_DIM], + [I_DIM, J_INTERFACE_DIM, K_DIM], (0, 0, 0), (7, 8, 7), id="y_interface", @@ -566,7 +566,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_INTERFACE_DIM], + [I_DIM, J_DIM, K_INTERFACE_DIM], (0, 0, 0), (7, 7, 8), id="z_interface", @@ -574,7 +574,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (3, 3), (10, 10, 7), id="halos_required", @@ -582,7 +582,7 @@ def test_get_origin_domain_restricted_vertical( pytest.param( 3, (4, 4, 7), - [X_DIM, Y_DIM, Z_DIM], + [I_DIM, J_DIM, K_DIM], (0, 3), (7, 10, 7), id="y_halos_required", diff --git a/tests/mpi/ext_grid/test_external_grid.py b/tests/mpi/ext_grid/test_external_grid.py index a867d182..70f0d38a 100644 --- a/tests/mpi/ext_grid/test_external_grid.py +++ b/tests/mpi/ext_grid/test_external_grid.py @@ -12,7 +12,7 @@ TilePartitioner, ) from ndsl.comm.partitioner import get_tile_index -from ndsl.constants import PI, RADIUS, X_INTERFACE_DIM, Y_INTERFACE_DIM +from ndsl.constants import I_INTERFACE_DIM, J_INTERFACE_DIM, PI, RADIUS from pace import Driver, DriverConfig from tests.paths import EXAMPLE_CONFIGS_DIR, REPO_ROOT @@ -96,7 +96,7 @@ def test_extgrid_equals_generated(config_file_path: str, ranks: int): subtile_slice_grid = cube_comm.partitioner.tile.subtile_slice( rank=cube_comm.rank, - global_dims=[X_INTERFACE_DIM, Y_INTERFACE_DIM], + global_dims=[I_INTERFACE_DIM, J_INTERFACE_DIM], global_extent=(npx, npy), overlap=True, ) From 5e08f015280f26919c6564d0c821074cb64a2689 Mon Sep 17 00:00:00 2001 From: Roman Cattaneo Date: Mon, 2 Mar 2026 16:38:15 +0100 Subject: [PATCH 06/10] update pyFV3 and pySHiELD to latest version of 2026.02.00 branch --- pyFV3 | 2 +- pySHiELD | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyFV3 b/pyFV3 index e96ebc64..3cb6668c 160000 --- a/pyFV3 +++ b/pyFV3 @@ -1 +1 @@ -Subproject commit e96ebc6475ee5bc93e0eb85ad87bbdbe471891ac +Subproject commit 3cb6668c117def1ca7974fefb403547eca17a831 diff --git a/pySHiELD b/pySHiELD index 9d1e5a60..3de9f74a 160000 --- a/pySHiELD +++ b/pySHiELD @@ -1 +1 @@ -Subproject commit 9d1e5a60c200c137d900e8bb8c6ef1b9bf6e3873 +Subproject commit 3de9f74a59532080d9d4bed6114b9b19f52629ef From e2ab1516c5f98e4f32b8cff3c4caf2cc73cb1daa Mon Sep 17 00:00:00 2001 From: Roman Cattaneo Date: Mon, 2 Mar 2026 16:59:13 +0100 Subject: [PATCH 07/10] update pyFV3 (Backend in GEOSDycoreWrapper) --- pyFV3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyFV3 b/pyFV3 index 3cb6668c..d9755004 160000 --- a/pyFV3 +++ b/pyFV3 @@ -1 +1 @@ -Subproject commit 3cb6668c117def1ca7974fefb403547eca17a831 +Subproject commit d9755004f166cf44279d9c65de9253618c5f93e5 From ed79d128a836d1f77f158eece9a63471ed3de2bf Mon Sep 17 00:00:00 2001 From: Roman Cattaneo Date: Wed, 4 Mar 2026 18:31:04 +0100 Subject: [PATCH 08/10] ci: NDSL 2026.02.00 and switch to python 3.12 --- .github/workflows/create_cache.yml | 4 ++-- .github/workflows/lint.yaml | 4 ++-- .github/workflows/main_unit_tests.yaml | 5 ++--- NDSL | 2 +- pyproject.toml | 10 ++++------ 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/create_cache.yml b/.github/workflows/create_cache.yml index fa1b21a6..a577fb3a 100644 --- a/.github/workflows/create_cache.yml +++ b/.github/workflows/create_cache.yml @@ -25,10 +25,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: Setup Python 3.11 + - name: Setup Python 3.12 uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: '3.12' - uses: actions/cache@v5 id: cache diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 7cc8e5c8..6f79dd1a 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -17,10 +17,10 @@ jobs: with: submodules: 'recursive' - - name: Step Python 3.11 + - name: Step Python 3.12 uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: '3.12' # Only restore (don't save) caches on PRs. New caches created from PRs won't be # accessible from other PRs, see workflows/create-cache.yaml. diff --git a/.github/workflows/main_unit_tests.yaml b/.github/workflows/main_unit_tests.yaml index 24835f7d..6bfa0920 100644 --- a/.github/workflows/main_unit_tests.yaml +++ b/.github/workflows/main_unit_tests.yaml @@ -34,7 +34,7 @@ jobs: run: shell: bash -el {0} env: - python_default: '3.11' + python_default: '3.12' steps: - name: "External trigger: Checkout pace/develop" @@ -42,8 +42,7 @@ jobs: uses: actions/checkout@v6 with: submodules: 'recursive' - repository: FlorianDeconinck/pace - ref: update/2026.02.00 + repository: NOAA-GFDL/pace path: pace - name: 'Setup Python ${{ inputs.python_version && inputs.python_version || env.python_default }}' diff --git a/NDSL b/NDSL index 40f0a2dc..2430f879 160000 --- a/NDSL +++ b/NDSL @@ -1 +1 @@ -Subproject commit 40f0a2dcc3a0784930d0400561a307c55563ec6f +Subproject commit 2430f879bb996e4ff301ecd1d9bf72804fb0e4c4 diff --git a/pyproject.toml b/pyproject.toml index 7711fece..fc4d0617 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,14 +9,15 @@ classifiers = [ "Intended Audience :: Developers", "Natural Language :: English", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.11" + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" ] dynamic = ["dependencies"] license = "Apache-2.0" license-files = ["LICENSE.md"] name = "pace" readme = "README.md" -requires-python = ">=3.11,<3.12" +requires-python = ">=3.11,<3.13" version = "0.2.0" [project.optional-dependencies] @@ -77,10 +78,7 @@ warn_unreachable = true ignore_errors = true module = [ # We currently can't type stencils - "pyshield.stencils.*", - # Will be fixed with NDSL version 2026.01.00, see - # https://github.com/NOAA-GFDL/NDSL/pull/360 - "pyfv3.testing.translate_fvdynamics" + "pyshield.stencils.*" ] [tool.setuptools] From 647f158bd7073d66880ba7ae9d5d26969fdf4ad3 Mon Sep 17 00:00:00 2001 From: Roman Cattaneo Date: Thu, 5 Mar 2026 08:45:26 +0100 Subject: [PATCH 09/10] update pyFV3 and pySHiELD to latest develop This propagates the breaking changes from NDSL 2026.02.00 --- pyFV3 | 2 +- pySHiELD | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyFV3 b/pyFV3 index d9755004..731933a1 160000 --- a/pyFV3 +++ b/pyFV3 @@ -1 +1 @@ -Subproject commit d9755004f166cf44279d9c65de9253618c5f93e5 +Subproject commit 731933a1b971392e58a574c6d34c7d893888899b diff --git a/pySHiELD b/pySHiELD index 3de9f74a..80558ac3 160000 --- a/pySHiELD +++ b/pySHiELD @@ -1 +1 @@ -Subproject commit 3de9f74a59532080d9d4bed6114b9b19f52629ef +Subproject commit 80558ac38417e313aab1e241b5a0e0eb66f1b135 From fe498a8b9c172a50895fc7a67fc9c9fef02e9072 Mon Sep 17 00:00:00 2001 From: Roman Cattaneo Date: Thu, 5 Mar 2026 10:48:53 +0100 Subject: [PATCH 10/10] removed debug print of config --- pace/driver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pace/driver.py b/pace/driver.py index 3289a1f8..f6f825d8 100644 --- a/pace/driver.py +++ b/pace/driver.py @@ -338,7 +338,6 @@ def write_for_restart( if "case" in config_dict["initialization"]["config"].keys(): del config_dict["initialization"]["config"]["case"] with open(f"{restart_path}/restart.yaml", "w") as file: - print(config_dict) yaml.safe_dump(config_dict, file)