From 4a9473e0ff6d556eb28dff57d2aea63fe70a9f1b Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:48:44 -0600 Subject: [PATCH 01/20] Created aggregate static_variables, dynamic_variables, and processes --- examples/model_architecture.ipynb | 50 +- examples/model_architecture_nsm.ipynb | 424 +-- src/clearwater_modules/nsm1/__init__.py | 40 +- .../nsm1/balgae/dynamic_variables.py | 1 - .../nsm1/carbon/static_variables.py | 2 +- src/clearwater_modules/nsm1/constants.py | 34 +- .../nsm1/dynamic_variables.py | 1426 +++++++ src/clearwater_modules/nsm1/n2/processes.py | 4 +- .../nsm1/pathogens/processes.py | 6 +- src/clearwater_modules/nsm1/processes.py | 3307 +++++++++++++++++ .../nsm1/state_variables.py | 56 +- .../nsm1/static_variables.py | 928 +++++ 12 files changed, 5755 insertions(+), 523 deletions(-) create mode 100644 src/clearwater_modules/nsm1/dynamic_variables.py create mode 100644 src/clearwater_modules/nsm1/processes.py create mode 100644 src/clearwater_modules/nsm1/static_variables.py diff --git a/examples/model_architecture.ipynb b/examples/model_architecture.ipynb index d3a4930..f94a812 100644 --- a/examples/model_architecture.ipynb +++ b/examples/model_architecture.ipynb @@ -618,55 +618,55 @@ " q_longwave_down (year, x, y) float64 nan 337.8\n", " q_longwave_up (year, x, y) float64 nan 406.2\n", " q_net (year, x, y) float64 nan -151.1\n", - " dTdt_water_c (year, x, y) float64 nan -3.619e-05
  • " ], "text/plain": [ "\n", diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index 8ca83c1..1966b8f 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -72,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "3bce5192", "metadata": {}, "outputs": [ @@ -80,399 +80,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "Initializing from dicts...\n", - "Model initialized from input dicts successfully!.\n" + "Initializing from dicts...\n" ] }, { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
    <xarray.Dataset>\n",
    -       "Dimensions:  (year: 1, x: 1, y: 1)\n",
    -       "Coordinates:\n",
    -       "  * year     (year) int32 0\n",
    -       "  * x        (x) float64 1.0\n",
    -       "  * y        (y) float64 1.0\n",
    -       "Data variables:\n",
    -       "    *empty*
    " - ], - "text/plain": [ - "\n", - "Dimensions: (year: 1, x: 1, y: 1)\n", - "Coordinates:\n", - " * year (year) int32 0\n", - " * x (x) float64 1.0\n", - " * y (y) float64 1.0\n", - "Data variables:\n", - " *empty*" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "ename": "ValueError", + "evalue": "No initial value found for state variable: POM2.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[6], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\model.py:170\u001b[0m, in \u001b[0;36mNutrientBudget.__init__\u001b[1;34m(self, initial_state_values, updateable_static_variables, algae_parameters, alkalinity_parameters, balgae_parameters, carbon_parameters, CBOD_parameters, DOX_parameters, nitrogen_parameters, POM_parameters, N2_parameters, phosphorus_parameters, pathogen_parameters, global_parameters, global_vars, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 152\u001b[0m static_variable_values \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 153\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__algae_parameters,\n\u001b[0;32m 154\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__alkalinity_parameters,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 164\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_parameters,\n\u001b[0;32m 165\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_vars}\n\u001b[0;32m 167\u001b[0m \u001b[38;5;66;03m# TODO: make sure this feature works -> test it, but post demo\u001b[39;00m\n\u001b[0;32m 168\u001b[0m \u001b[38;5;66;03m#static_variable_values['use_sed_temp'] = use_sed_temp\u001b[39;00m\n\u001b[1;32m--> 170\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[0;32m 171\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 174\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhotstart_dataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_dim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:74\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minitial_state_values, \u001b[38;5;28mdict\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstatic_variable_values, \u001b[38;5;28mdict\u001b[39m):\n\u001b[0;32m 73\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from dicts...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m---> 74\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_dataset_from_dicts\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 75\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 76\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 77\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 78\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 80\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(hotstart_dataset, xr\u001b[38;5;241m.\u001b[39mDataset):\n\u001b[0;32m 81\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from hotstart dataset...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:113\u001b[0m, in \u001b[0;36mModel._init_dataset_from_dicts\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables)\u001b[0m\n\u001b[0;32m 111\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m state_var \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstate_variables:\n\u001b[0;32m 112\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m state_var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m initial_state_values\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[1;32m--> 113\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 114\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo initial value found for state variable: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mstate_var\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 115\u001b[0m )\n\u001b[0;32m 117\u001b[0m \u001b[38;5;66;03m# reassign updateable_static_variables to state variables\u001b[39;00m\n\u001b[0;32m 118\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m static \u001b[38;5;129;01min\u001b[39;00m updateable_static_variables:\n", + "\u001b[1;31mValueError\u001b[0m: No initial value found for state variable: POM2." + ] } ], "source": [ @@ -484,7 +107,6 @@ "import warnings\n", "warnings.filterwarnings(\"ignore\")\n", "from clearwater_modules.nsm1.model import NutrientBudget\n", - "import clearwater_modules.nsm1.model as test\n", "\n", "\n", "\n", @@ -511,7 +133,6 @@ " 'AWn': 7.2,\n", " 'AWp': 1,\n", " 'AWa': 1000,\n", - " \n", " 'KL': 10,\n", " 'KsN': 0.04,\n", " 'KsP': 0.0012,\n", @@ -520,7 +141,13 @@ " 'krp_20': 0.2,\n", " 'vsap': 0.15,\n", " 'growth_rate_option': 1,\n", - " 'light_limitation_option': 1\n", + " 'light_limitation_option': 1,\n", + " 'lambda0': .5,\n", + " 'lambda1': .5,\n", + " 'lambda2': .5,\n", + " 'lambdas': .5,\n", + " 'lambdam': .5, \n", + " 'Fr_PAR': .5 \n", "}\n", "\n", "balgae_parameters = {\n", @@ -627,14 +254,9 @@ " 'kaw_20_user': 999,\n", " 'kah_20_user': 999,\n", " 'hydraulic_reaeration_option': 2,\n", - " 'wind_reaeration_option': 2,\n", - " 'Fr_PAR': .5,\n", - " 'lambda0': .5,\n", - " 'lambda1': .5,\n", - " 'lambda2': .5,\n", - " 'lambdas': .5,\n", - " 'lambdam': .5, \n", + " 'wind_reaeration_option': 2, \n", " 'timestep': 86400,\n", + " 'TwaterC': 20,\n", " 'velocity': 1,\n", " 'flow': 2,\n", " 'topwidth': 1,\n", diff --git a/src/clearwater_modules/nsm1/__init__.py b/src/clearwater_modules/nsm1/__init__.py index a807441..b359a7f 100644 --- a/src/clearwater_modules/nsm1/__init__.py +++ b/src/clearwater_modules/nsm1/__init__.py @@ -1,36 +1,4 @@ -""" -======================================================================================= -Nutrient Simulation Module 1 (NSM1) -======================================================================================= - -Developed by: -* Dr. Todd E. Steissberg (ERDC-EL) -* Dr. Billy E. Johnson (ERDC-EL, LimnoTech) -* Dr. Zhonglong Zhang (Portland State University) -* Mr. Mark Jensen (HEC) - -This module computes the water quality of a single computational cell. The algorithms -and structure of this program were adapted from the Fortran 95 version of this module, -developed by: -* Dr. Billy E. Johnson (ERDC-EL) -* Dr. Zhonglong Zhang (Portland State University) -* Mr. Mark Jensen (HEC) - -Version 1.0 - -Initial Version: June 5, 2021 -""" - -from clearwater_modules.nsm1 import algae -from clearwater_modules.nsm1 import alkalinity -from clearwater_modules.nsm1 import balgae -from clearwater_modules.nsm1 import carbon -from clearwater_modules.nsm1 import CBOD -from clearwater_modules.nsm1 import DOX -from clearwater_modules.nsm1 import nitrogen -from clearwater_modules.nsm1 import POM - - -class NSM1: - def __init__(self): - pass +from clearwater_modules.nsm1 import state_variables +from clearwater_modules.nsm1 import dynamic_variables +from clearwater_modules.nsm1 import static_variables +from clearwater_modules.nsm1.model import NutrientBudget \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/balgae/dynamic_variables.py b/src/clearwater_modules/nsm1/balgae/dynamic_variables.py index 67b00db..bff3bca 100644 --- a/src/clearwater_modules/nsm1/balgae/dynamic_variables.py +++ b/src/clearwater_modules/nsm1/balgae/dynamic_variables.py @@ -12,7 +12,6 @@ class Variable(base.Variable): ... - Variable( name='mub_max_tc', long_name='Maximum benthic algal growth rate', diff --git a/src/clearwater_modules/nsm1/carbon/static_variables.py b/src/clearwater_modules/nsm1/carbon/static_variables.py index 91780df..ad5bcfe 100644 --- a/src/clearwater_modules/nsm1/carbon/static_variables.py +++ b/src/clearwater_modules/nsm1/carbon/static_variables.py @@ -72,6 +72,6 @@ class Variable(base.Variable): name='roc', long_name='O2:C ratio for carbon oxidation', units='mg-O2/mg-C', - description='32/12', + description='O2:C ratio for carbon oxidation (32/12)', use='static' ) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index 37ed441..dbc27e4 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -10,7 +10,6 @@ class AlgaeStaticVariables(TypedDict): AWn: float AWp: float AWa: float - KL: float KsN: float KsP: float @@ -19,7 +18,13 @@ class AlgaeStaticVariables(TypedDict): krp_20: float vsap: float growth_rate_option: int - light_limitation_option: int + light_limitation_option: int + lambda0: float + lambda1: float + lambda2: float + lambdas: float + lambdam: float + Fr_PAR: float DEFAULT_ALGAE = AlgaeStaticVariables( AWd = 100, @@ -27,7 +32,6 @@ class AlgaeStaticVariables(TypedDict): AWn= 7.2, AWp= 1, AWa= 1000, - KL= 10, KsN= 0.04, KsP= 0.0012, @@ -36,7 +40,13 @@ class AlgaeStaticVariables(TypedDict): krp_20= 0.2, vsap= 0.15, growth_rate_option = 1, - light_limitation_option = 1 + light_limitation_option = 1, + lambda0 = .5, + lambda1 = .5, + lambda2 = .5, + lambdas = .5, + lambdam = .5, + Fr_PAR = .5 ) class AlkalinityStaticVariables(TypedDict): @@ -326,13 +336,8 @@ class GlobalVars(TypedDict): kah_20_user: float hydraulic_reaeration_option: int wind_reaeration_option: int - Fr_PAR: float - lambda0: float - lambda1: float - lambda2: float - lambdas: float - lambdam: float timestep: float + TwaterC: float velocity: float flow: float topwidth: float @@ -356,14 +361,9 @@ class GlobalVars(TypedDict): kaw_20_user = 999, kah_20_user = 999, hydraulic_reaeration_option = 2, - wind_reaeration_option = 2, - Fr_PAR = .5, - lambda0 = .5, - lambda1 = .5, - lambda2 = .5, - lambdas = .5, - lambdam = .5, + wind_reaeration_option = 2, timestep = 86400, + TwaterC = 20, velocity = 1, flow = 2, topwidth = 1, diff --git a/src/clearwater_modules/nsm1/dynamic_variables.py b/src/clearwater_modules/nsm1/dynamic_variables.py new file mode 100644 index 0000000..cabe5eb --- /dev/null +++ b/src/clearwater_modules/nsm1/dynamic_variables.py @@ -0,0 +1,1426 @@ +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + +import clearwater_modules.nsm1.processes as processes + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +############################################ From dynamic_variables_global +Variable( + name='depth', + long_name='Average water depth in cell', + units='m', + description='Average water depth in cell computed by dividing volume by surface area', + use='dynamic', + process=processes.compute_depth +) + +Variable( + name='TwaterK', + long_name='Water Temperature K', + units='K', + description='Water temperature degree kelvin', + use='dynamic', + process=processes.TwaterK +) + +Variable( + name='SOD_tc', + long_name='Sediment Oxygen Demand at water temperature tc', + units='mg/L', + description='Sediment Oxygen Demand at water temperature tc', + use='dynamic', + process=processes.SOD_tc +) + +Variable( + name='kah_20', + long_name='Hydraulic oxygen reaeration rate adjusted for hydraulics', + units='1/d', + description='Hydraulic oxygen reaeration rate adjusted for hydraulic parameters according to XX lit', + use='dynamic', + process=processes.kah_20 +) + +Variable( + name='kah_tc', + long_name='Hydraulic oxygen reaeration rate adjusted for temperature', + units='1/d', + description='Hydraulic oxygen reaeration rate adjusted for temperature', + use='dynamic', + process=processes.kah_tc +) + +Variable( + name='kaw_20', + long_name='Wind oxygen reaeration velocity adjusted for hydraulics', + units='m/d', + description='Wind oxygen reaeration velocity adjusted for hydraulic parameters according to XX lit', + use='dynamic', + process=processes.kaw_20 +) + +Variable( + name='kaw_tc', + long_name='Wind oxygen reaeration velocity adjusted for temperature', + units='m/d', + description='Wind oxygen reaeration velocity adjusted for temperature', + use='dynamic', + process=processes.kaw_tc +) + +Variable( + name='ka_tc', + long_name='Oxygen reaeration rate', + units='1/d', + description='Oxygen reaeration rate', + use='dynamic', + process=processes.ka_tc +) + +Variable( + name='L', + long_name='Light attenuation coefficient', + units='unitless', + description='Light attenuation coefficient', + use='dynamic', + process=processes.L +) + +Variable( + name='PAR', + long_name='surface light intensity', + units='W/m2', + description='surface light intensity', + use='dynamic', + process=processes.PAR +) + +Variable( + name='fdp', + long_name='Fraction phosphorus dissolved', + units='Unitless', + description='Fraction phosphorus dissolved', + use='dynamic', + process=processes.fdp +) + +############################################ From algae +Variable( + name='rna', + long_name='Algal N:Chla Ratio', + units='mg-N/ug Chla', + description='Algal N:Chla Ratio', + use='dynamic', + process=processes.rna +) + +Variable( + name='rpa', + long_name='Algal P:Chla Ratio', + units='mg-P/ug Chla', + description='Algal P:Chla Ratio', + use='dynamic', + process=processes.rpa +) + +Variable( + name='rca', + long_name='Algal C:Chla Ratio', + units='mg-C/ug Chla', + description='Algal C:Chla Ratio', + use='dynamic', + process=processes.rca +) + +Variable( + name='rda', + long_name='Algal D:Chla Ratio', + units='mg-D/ug Chla', + description='Algal D:Chla Ratio', + use='dynamic', + process=processes.rda +) + +Variable( + name='mu_max_tc', + long_name='Max Algae Growth with Temperature Correction', + units='1/d', + description='Max Algae Growth with Temperature Correction', + use='dynamic', + process=processes.mu_max_tc, +) + +Variable( + name='krp_tc', + long_name='Algal Respiration Rate with Temperature Correction', + units='1/d', + description='Algal Respiration Rate with Temperature Correction', + use='dynamic', + process=processes.krp_tc, +) + +Variable( + name='kdp_tc', + long_name='Algal Mortality Rate with Temperature Correction', + units='1/d', + description='Algal Mortality Rate with Temperature Correction', + use='dynamic', + process=processes.kdp_tc, +) + +Variable( + name='FL', + long_name='Algal Light Limitation', + units='unitless', + description='Algal Light Limitation', + use='dynamic', + process=processes.FL, +) + +Variable( + name='FN', + long_name='Algal Nitrogen Limitation', + units='unitless', + description='Algal Nitrogen Limitation', + use='dynamic', + process=processes.FN, +) + +Variable( + name='FP', + long_name='Algal Phosphorus Limitation', + units='unitless', + description='Algal Phosphorus Limitation', + use='dynamic', + process=processes.FP, +) + +Variable( + name='mu', + long_name='Algal Growth Rate', + units='1/d', + description='Algal Growth Rate', + use='dynamic', + process=processes.mu, +) + +Variable( + name='ApGrowth', + long_name='Algal Growth', + units='ug-Chala/L/d', + description='Algal Growth', + use='dynamic', + process=processes.ApGrowth, +) + +Variable( + name='ApRespiration', + long_name='Algal Respiration', + units='ug-Chala/L/d', + description='Algal Respiration', + use='dynamic', + process=processes.ApRespiration, +) + +Variable( + name='ApDeath', + long_name='Algal Death', + units='ug-Chala/L/d', + description='Algal Death', + use='dynamic', + process=processes.ApDeath, +) + +Variable( + name='ApSettling', + long_name='Algal Settling', + units='ug-Chala/L/d', + description='Algal Settling', + use='dynamic', + process=processes.ApSettling, +) + +Variable( + name='dApdt', + long_name='Algal Biomass Concentration Change', + units='ug-Chala/L/d', + description='Algal Biomass Concentration Change', + use='dynamic', + process=processes.dApdt, +) + +############################################ From benthic algae +Variable( + name='mub_max_tc', + long_name='Maximum benthic algal growth rate', + units='1/d', + description='Maximum benthic algal growth rate with temperature correction', + use='dynamic', + process=processes.mub_max_tc +) + +Variable( + name='krb_tc', + long_name='Benthic algae respiration rate', + units='1/d', + description='Benthic algae respiration rate with temperature correction', + use='dynamic', + process=processes.krb_tc +) + +Variable( + name='kdb_tc', + long_name='Benthic algae mortality rate', + units='1/d', + description='Benthic algae mortality rate with temperature correction', + use='dynamic', + process=processes.kdb_tc +) + +Variable( + name='rnb', + long_name='Ratio nitrogen to dry weight', + units='mg-N/mg-D', + description='Ratio benthic algae nitrogen to dry weight', + use='dynamic', + process=processes.rnb +) + +Variable( + name='rpb', + long_name='Ratio benthic algae phosphorus to dry weight', + units='mg-P/mg-D', + description='Ratio benthic algae phosphorus to dry weight', + use='dynamic', + process=processes.rpb +) + +Variable( + name='rcb', + long_name='Ratio benthic algae carbon to dry weight', + units='mg-C/mg-D', + description='Ratio benthic algae carbon to dry weight', + use='dynamic', + process=processes.rcb +) + +Variable( + name='rab', + long_name='Ratio benthic algae chlorophyll-a to dry weight', + units='ug-Chala-a/mg-D', + description='Ratio benthic algae chlorophyll-a to dry weight', + use='dynamic', + process=processes.rab +) + +Variable( + name='FLb', + long_name='Benthic algal light limitation factor', + units='unitless', + description='Benthic algal light limitation factor', + use='dynamic', + process=processes.FLb +) + +Variable( + name='FNb', + long_name='Benthic algal nitrogen limitation factor', + units='unitless', + description='Benthic algal nitrogen limitation factor', + use='dynamic', + process=processes.FNb +) + +Variable( + name='FPb', + long_name='Benthic algal phosphorous limitation factor', + units='unitless', + description='Benthic algal phosphorous limitation factor', + use='dynamic', + process=processes.FPb +) + +Variable( + name='FSb', + long_name='Benthic algal density attenuation', + units='unitless', + description='Benthic algal density attenuation', + use='dynamic', + process=processes.FSb +) + +Variable( + name='mub', + long_name='Benthic algae specific growth rate', + units='1/d', + description='Benthic algae specific growth rate', + use='dynamic', + process=processes.mub +) + +Variable( + name='AbGrowth', + long_name='Benthic algae growth rate', + units='g/m^2/d', + description='Benthic algae growth rate', + use='dynamic', + process=processes.AbGrowth +) + +Variable( + name='AbRespiration', + long_name='Benthic algae respiration rate', + units='g/m^2/d', + description='Benthic algae respiration rate', + use='dynamic', + process=processes.AbRespiration +) + +Variable( + name='AbDeath', + long_name='Benthic algae death rate', + units='g/m^2/d', + description='Benthic algae death rate', + use='dynamic', + process=processes.AbDeath +) + +Variable( + name='dAbdt', + long_name='Change in benthic algae concentration', + units='g/m^2/d', + description='Change in benthic algae concentration', + use='dynamic', + process=processes.dAbdt +) + +Variable(#TODO: figure out what this is... + name='Chlb', + long_name='Chlorophyll-a concentration', + units='mg-Chla/m^2', + description='Chlorophyll-a concentration', + use='dynamic', + process=processes.Chlb +) + +############################################ From nitrogen +Variable( + name='knit_tc', + long_name='Nitrification rate ammonia decay', + units='1/d', + description='Nitrification rate ammonia decay temperature correction', + use='dynamic', + process=processes.knit_tc +) + +Variable( + name='rnh4_tc', + long_name='Sediment release rate of NH4', + units='1/d', + description=' Sediment release rate of NH4 temperature correction', + use='dynamic', + process=processes.rnh4_tc +) + +Variable( + name='vno3_tc', + long_name='Sediment denitrification velocity', + units='m/d', + description='Sediment denitrification velocity temperature correction', + use='dynamic', + process=processes.vno3_tc +) + +Variable( + name='kon_tc', + long_name='Decay rate of OrgN to NH4', + units='1/d', + description='Decay rate of OrgN to NH4 temperature correction', + use='dynamic', + process=processes.kon_tc +) + +Variable( + name='kdnit_tc', + long_name='Denitrification rate', + units='1/d', + description='Denitrification rate temperature correction', + use='dynamic', + process=processes.kdnit_tc +) + +Variable( + name='ApUptakeFr_NH4', + long_name='Fraction of actual floating algal uptake from ammonia pool', + units='unitless', + description='Fraction of actual floating algal uptake from ammonia pool', + use='dynamic', + process=processes.ApUptakeFr_NH4 +) + +Variable( + name='ApUptakeFr_NO3', + long_name='Fraction of actual floating algal uptake from nitrate pool', + units='unitless', + description='Fraction of actual floating algal uptake from nitrate pool', + use='dynamic', + process=processes.ApUptakeFr_NO3 +) + +Variable( + name='AbUptakeFr_NH4', + long_name='Fraction of actual benthic algal uptake from ammonia pool', + units='unitless', + description='Fraction of actual benthic algal uptake from ammonia pool', + use='dynamic', + process=processes.AbUptakeFr_NH4 +) + +Variable( + name='AbUptakeFr_NO3', + long_name='Fraction of actual benthic algal uptake from nitrate pool', + units='unitless', + description='Fraction of actual benthic algal uptake from nitrate pool', + use='dynamic', + process=processes.AbUptakeFr_NO3 +) + +Variable( + name='ApDeath_OrgN', + long_name='Algae -> OrgN', + units='mg-N/L/d', + description='Algae conversion to Organic nitrogen', + use='dynamic', + process=processes.ApDeath_OrgN +) + +Variable( + name='AbDeath_OrgN', + long_name='Benthic Algae -> OrgN', + units='mg-N/L/d', + description='Benthic algae conversion to Organic nitrogen', + use='dynamic', + process=processes.AbDeath_OrgN +) + +Variable( + name='OrgN_NH4_Decay', + long_name='OrgN -> NH4', + units='mg-N/L/d', + description='Organic nitrogen to ammonium decay', + use='dynamic', + process=processes.OrgN_NH4_Decay +) + +Variable( + name='OrgN_Settling', + long_name='OrgN -> bed', + units='mg-N/L/d', + description='Organic nitrogen to bed settling', + use='dynamic', + process=processes.OrgN_Settling +) + +Variable( + name='dOrgNdt', + long_name='Change in organic nitrogen', + units='mg-N/L', + description='Change in organic nitrogen', + use='dynamic', + process=processes.dOrgNdt +) + +Variable( + name='NH4_Nitrification', + long_name='NH4 -> NO3 Nitrification', + units='mg-N/L/d', + description='NH4 Nitrification', + use='dynamic', + process=processes.NH4_Nitrification +) + +Variable( + name='NH4fromBed', + long_name='bed -> NH4 (diffusion)', + units='mg-N/L/d', + description='Sediment bed release of NH4', + use='dynamic', + process=processes.NH4fromBed +) + +Variable( + name='NH4_ApRespiration', + long_name='Floating algae -> NH4', + units='mg-N/L/d', + description='Floating algae to NH4', + use='dynamic', + process=processes.NH4_ApRespiration +) + +Variable( + name='NH4_ApGrowth', + long_name='NH4 -> Floating algae', + units='mg-N/L/d', + description='NH4 uptake to algae', + use='dynamic', + process=processes.NH4_ApGrowth +) + +Variable( + name='NH4_AbRespiration', + long_name='Benthic algae -> NH4', + units='mg-N/L/d', + description='Benthic algae release of NH4', + use='dynamic', + process=processes.NH4_AbRespiration +) + +Variable( + name='NH4_AbGrowth', + long_name='NH4 -> Benthic Algae', + units='mg-N/L/d', + description='Benthic algae uptake of NH4', + use='dynamic', + process=processes.NH4_AbGrowth +) + +Variable( + name='dNH4dt', + long_name='Change in ammonium concentration', + units='mg-N/L', + description='Change in ammonium concentration', + use='dynamic', + process=processes.dNH4dt +) + +Variable( + name='NO3_Denit', + long_name='NO3 -> Loss', + units='mg-N/L/d', + description='NO3 loss from denitrification', + use='dynamic', + process=processes.NO3_Denit +) + +Variable( + name='NO3_BedDenit', + long_name='Sediment denitrification', + units='mg-N/L/d', + description='Sediment denitrification', + use='dynamic', + process=processes.NO3_BedDenit +) + +Variable( + name='NO3_ApGrowth', + long_name='NO3 -> Floating algae', + units='mg-N/L/d', + description='NO3 uptake to floating algae', + use='dynamic', + process=processes.NO3_ApGrowth +) + +Variable( + name='NO3_AbGrowth', + long_name='NO3 -> Benthic algae', + units='mg-N/L/d', + description='NO3 uptake to benthic algae', + use='dynamic', + process=processes.NO3_AbGrowth +) + +Variable( + name='dNO3dt', + long_name='Change in nitrate concentration', + units='mg-N/L', + description='Change in nitrate concentration', + use='dynamic', + process=processes.dNO3dt +) + +Variable( + name='DIN', + long_name='Dissolve inorganic nitrogen', + units='mg-N/L', + description='Dissolve inorganic nitrogen', + use='dynamic', + process=processes.DIN +) + +Variable( + name='TON', + long_name='Total organic nitrogen', + units='mg-N/L', + description='Total organic nitrogen', + use='dynamic', + process=processes.TON +) + +Variable( + name='TKN', + long_name='Total kjeldhl nitrogen', + units='mg-N/L', + description='Total kjeldhl nitrogen', + use='dynamic', + process=processes.TKN +) + +Variable( + name='TN', + long_name='Total nitrogen', + units='mg-N/L', + description='Total nitrogen', + use='dynamic', + process=processes.TN +) + +Variable( + name='NitrificationInhibition', + long_name='Nitrification Inhibitation (limits nitrification under low DO conditions)', + units='unitless', + description='Nitrification Inhibitation (limits nitrification under low DO conditions)', + use='dynamic', + process=processes.NitrificationInhibition +) + +############################################ From phosphorus +Variable( + name='kop_tc', + long_name='Decay rate of organic P to DIP', + units='1/d', + description='Decay rate of organic P to DIP temperature correction', + use='dynamic', + process=processes.kop_tc +) + +Variable( + name='rpo4_tc', + long_name='Benthic sediment release rate of DIP', + units='g-P/m2/d', + description='Benthic sediment release rate of DIP temperature correction', + use='dynamic', + process=processes.rpo4_tc +) + +Variable( + name='OrgP_DIP_decay', + long_name='Organic phosphorus decay to dissolve inorganic phosphorus', + units='mg-P/L/d', + description='Organic phosphorus decay to dissolve inorganic phosphorus', + use='dynamic', + process=processes.OrgP_DIP_decay +) + +Variable( + name='OrgP_Settling', + long_name='Organic phosphorus settling to sediment', + units='mg-P/L/d', + description='Organic phosphorus settling to sediment', + use='dynamic', + process=processes.OrgP_Settling +) + +Variable( + name='ApDeath_OrgP', + long_name='Algal death turning into organic phosphorus', + units='mg-P/L/d', + description='Algal death turning into organic phosphorus', + use='dynamic', + process=processes.ApDeath_OrgP +) + +Variable( + name='AbDeath_OrgP', + long_name='Benthic algal death turning into organic phosphorus', + units='mg-P/L/d', + description='Benthic algal death turning into organic phosphorus', + use='dynamic', + process=processes.AbDeath_OrgP +) + +Variable( + name='dOrgPdt', + long_name='Change in organic phosphorus concentration', + units='mg-P/L/d', + description='Change in organic phosphorus concentration', + use='dynamic', + process=processes.dOrgPdt +) + +Variable( + name='DIPfromBed_SedFlux', + long_name='Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules', + units='mg-P/L/d', + description='Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules', + use='dynamic', + process=processes.DIPfromBed_SedFlux +) + +Variable(#TODO: find correct process + name='DIPfromBed', + long_name='Dissolved Organic Phosphorus coming from Bed calculated without SedFlux modules', + units='mg-P/L/d', + description='Dissolved Organic Phosphorus coming from Bed calculated without SedFlux modules', + use='dynamic', + process=processes.DIPfromBed +) + +Variable( + name='TIP_Settling', + long_name='Total inorganic phosphorus settling from water to bed', + units='mg-P/L/d', + description='Total inorganic phosphorus settling from water to bed', + use='dynamic', + process=processes.TIP_Settling +) + +Variable( + name='OrgP_DIP_decay', + long_name='Total organic phosphorus decaying to dissolved inorganic phosphrous', + units='mg-P/L/d', + description='Total organic phosphorus decaying to dissolved inorganic phosphrous', + use='dynamic', + process=processes.OrgP_DIP_decay +) + +Variable( + name='DIP_ApRespiration', + long_name='Dissolved inorganic phosphorus released from algal respiration', + units='mg-P/L/d', + description='Dissolved inorganic phosphorus released from algal respiration', + use='dynamic', + process=processes.DIP_ApRespiration +) + +Variable( + name='DIP_ApGrowth', + long_name='Dissolved inorganic phosphorus consumed for algal growth', + units='mg-P/L/d', + description='Dissolved inorganic phosphorus consumed for algal growth', + use='dynamic', + process=processes.DIP_ApGrowth +) + +Variable( + name='DIP_AbRespiration', + long_name='Dissolved inorganic phosphorus released for benthic algal respiration', + units='mg-P/L/d', + description='Dissolved inorganic phosphorus released for benthic algal respiration', + use='dynamic', + process=processes.DIP_AbRespiration +) + +Variable( + name='DIP_AbGrowth', + long_name='Dissolved inorganic phosphorus consumed for benthic algal growth', + units='mg-P/L/d', + description='Dissolved inorganic phosphorus consumed for benthic algal growth', + use='dynamic', + process=processes.DIP_AbGrowth +) + +Variable( + name='dTIPdt', + long_name='Change in dissolved inorganic phosphorus water concentration', + units='mg-P/L/d', + description='Change in dissolved inorganic phosphorus water concentration', + use='dynamic', + process=processes.dTIPdt +) + +Variable( + name='TOP', + long_name='Total organic phosphorus', + units='mg-P/L', + description='Total organic phosphorus', + use='dynamic', + process=processes.TOP +) + +Variable( + name='TP', + long_name='Total phosphorus', + units='mg-P/L', + description='Total phosphorus', + use='dynamic', + process=processes.TP +) + +Variable( + name='DIP', + long_name='Dissolve inorganic phosphorus', + units='mg-P/L', + description='Dissolve inorganic phosphorus', + use='dynamic', + process=processes.DIP +) + +############################################ From POM +Variable( + name='kpom_tc', + long_name='POM dissolution rate adjusted for temperature', + units='1/d', + description='POM dissolution rate adjusted for temperature', + use='dynamic', + process=processes.kpom_tc +) + +Variable( + name='POM_algal_settling', + long_name='POM concentration change due to algal settling', + units='mg/L/d', + description='POM concentration change due to algal settling', + use='dynamic', + process=processes.POM_algal_settling +) + +Variable( + name='POM_dissolution', + long_name='POM concentration change due to dissolution', + units='mg/L/d', + description='POM concentration change due to dissolution', + use='dynamic', + process=processes.POM_dissolution +) + +Variable( + name='POM_POC_settling', + long_name='POM concentration change due to POC settling', + units='mg/L/d', + description='POM concentration change due to POC settling', + use='dynamic', + process=processes.POM_POC_settling +) + +Variable( + name='POM_benthic_algae_mortality', + long_name='POM concentration change due to algae mortality', + units='mg/L/d', + description='POM concentration change due to algae mortality', + use='dynamic', + process=processes.POM_benthic_algae_mortality +) + +Variable( + name='POM_burial', + long_name='POM concentration change due to burial', + units='mg/L/d', + description='POM concentration change due to burial', + use='dynamic', + process=processes.POM_burial +) + +Variable( + name='dPOMdt', + long_name='Change in POM concentration for one timestep', + units='mg/L/d', + description='Change in POM concentration for one timestep', + use='dynamic', + process=processes.dPOMdt +) + +############################################ From CBOD +Variable( + name='kbod_tc', + long_name='Temperature adjusted oxidation rate', + units='1/d', + description='Temperature adjusted oxidation rate', + use='dynamic', + process=processes.kbod_tc +) + +Variable( + name='ksbod_tc', + long_name='Temperature adjusted sedimentation rate', + units='m/d', + description='Temperature adjusted sedimentation rate', + use='dynamic', + process=processes.ksbod_tc +) + +Variable( + name='CBOD_oxidation', + long_name='CBOD oxidation', + units='mg/L/d', + description='CBOD oxidation', + use='dynamic', + process=processes.CBOD_oxidation +) + +Variable( + name='CBOD_sedimentation', + long_name='CBOD sedimentation', + units='mg/L/d', + description='CBOD sedimentation', + use='dynamic', + process=processes.CBOD_sedimentation +) + +Variable( + name='dCBODdt', + long_name='Change in CBOD concentration for the given timestep', + units='mg/L/d', + description='Change in CBOD concentration for the given timestep', + use='dynamic', + process=processes.dCBODdt +) + +############################################ From carbon +Variable( + name='kpoc_tc', + long_name='Temperature adjusted POC hydrolysis rate', + units='1/d', + description='Temperature adjusted POC hydrolysis rate', + use='dynamic', + process=processes.kpoc_tc, +) + +Variable( + name='POC_settling', + long_name='POC concentration removed from cell due to settling', + units='mg/L/d', + description='POC concentration removed from cell due to settling', + use='dynamic', + process=processes.POC_settling, +) + +Variable( + name='POC_hydrolysis', + long_name='POC concentration removed from cell due to hydrolysis', + units='mg/L/d', + description='POC concentration removed from cell due to hydrolysis', + use='dynamic', + process=processes.POC_hydrolysis, +) + +Variable( + name='POC_algal_mortality', + long_name='POC concentration added to cell due to algal mortality', + units='mg/L/d', + description='POC concentration added to cell due to algal mortality', + use='dynamic', + process=processes.POC_algal_mortality, +) + +Variable( + name='POC_benthic_algae_mortality', + long_name='POC concentration added to cell due to benthic algae mortality', + units='mg/L/d', + description='POC concentration added to cell due to benthic algae mortality', + use='dynamic', + process=processes.POC_benthic_algae_mortality, +) + +Variable( + name='dPOCdt', + long_name='POC concentration change per timestep', + units='mg/L/d', + description='POC concentration change per timestep', + use='dynamic', + process=processes.dPOCdt +) + +Variable( + name='kdoc_tc', + long_name='Dissolved organic carbon oxidation rate adjusted for temperature', + units='1/d', + description='Dissolved organic carbon oxidation rate adjusted for temperature', + use='dynamic', + process=processes.kdoc_tc +) + +Variable( + name='DOC_algal_mortality', + long_name='DOC concentration added to cell due to algal mortality', + units='mg/L/d', + description='DOC concentration added to cell due to algal mortality', + use='dynamic', + process=processes.DOC_algal_mortality +) + +Variable( + name='DOC_benthic_algae_mortality', + long_name='DOC concentration added to cell due to benthic algae mortality', + units='mg/L/d', + description='DOC concentration added to cell due to benthic algae mortality', + use='dynamic', + process=processes.DOC_benthic_algae_mortality, +) + +Variable( + name='DOC_oxidation', + long_name='DOC concentration lost to cell due to oxidation', + units='mg/L/d', + description='DOC concentration lost to cell due to oxidation', + use='dynamic', + process=processes.DOC_oxidation +) + +Variable( + name='dDOCdt', + long_name='DOC concentration change per timestep', + units='mg/L/d', + description='DOC concentration change per timestep', + use='dynamic', + process=processes.dDOCdt +) + +Variable( + name='K_H', + long_name='Henrys coefficient', + units='mol/L-atm', + description='Henrys coefficient controlling the relative proportion of gaseous and aqueous phase CO2', + use='dynamic', + process=processes.Henrys_k +) + +Variable( + name='Atm_CO2_reaeration', + long_name='Atmospheric CO2 reaeration', + units='mg/L/d', + description='Amount of DIC concentration change due to atmospheric exchange', + use='dynamic', + process=processes.Atmospheric_CO2_reaeration +) + +Variable( + name='DIC_algal_respiration', + long_name='DIC generated by algal respiration', + units='mg/L/d', + description='DIC generated by algal respiration', + use='dynamic', + process=processes.DIC_algal_respiration +) + +Variable( + name='DIC_algal_photosynthesis', + long_name='DIC consumed by algal photosynthesis', + units='mg/L/d', + description='DIC consumed by algal photosynthesis', + use='dynamic', + process=processes.DIC_algal_photosynthesis +) + +Variable( + name='DIC_benthic_algae_respiration', + long_name='DIC generated by benthic algae respiration', + units='mg/L/d', + description='DIC generated by benthic algae respiration', + use='dynamic', + process=processes.DIC_benthic_algae_respiration +) + +Variable( + name='DIC_benthic_algae_photosynthesis', + long_name='DIC consumed by benthic algae photosynthesis', + units='mg/L/d', + description='DIC consumed by benthic algae photosynthesis', + use='dynamic', + process=processes.DIC_benthic_algae_photosynthesis +) + +Variable( + name='DIC_CBOD_oxidation', + long_name='DIC concentration change due to CBOD oxidation', + units='mg/L/d', + description='DIC concentration change due to CBOD oxidation', + use='dynamic', + process=processes.DIC_CBOD_oxidation +) + +Variable( + name='DIC_sed_release', + long_name='DIC concentration change due to sediment release', + units='mg/L/d', + description='DIC concentration change due to sediment release', + use='dynamic', + process=processes.DIC_sed_release +) + +Variable( + name='dDICdt', + long_name='DIC concentration change per timestep', + units='mg/L/d', + description='DIC concentration change per timestep', + use='dynamic', + process=processes.dDICdt +) + +############################################ From DOX +Variable( + name='DOX_sat', + long_name='DO saturation concentration', + units='mg/L', + description='DO saturation concentration in water as a function of water temperature (K)', + use='dynamic', + process=processes.DOX_sat +) + +Variable( + name='pwv', + long_name='Partial pressure of water vapor', + units='atm', + description='Partial pressure of water vapor', + use='dynamic', + process=processes.pwv +) + +Variable( + name='DOs_atm_alpha', + long_name='DO saturation atmospheric correction coefficient', + units='unitless', + description='DO saturation atmospheric correction coefficient', + use='dynamic', + process=processes.DOs_atm_alpha +) + +Variable( + name='Atm_O2_reaeration', + long_name='Atmospheric oxygen reaeration', + units='mg/L/d', + description='Atmospheric oxygen reaeration, can fluctuate both in and out of waterbody', + use='dynamic', + process=processes.Atm_O2_reaeration +) + +# TODO: UPDATE BASED ON FORTRAN +Variable( + name='DOX_ApGrowth', + long_name='Dissolved oxygen flux due to algal photosynthesis', + units='mg/L/d', + description='Dissolved oxygen flux due to algal photosynthesis', + use='dynamics', + process=processes.DOX_ApGrowth +) + +# TODO: UPDATE BASED ON FORTRAN +Variable( + name='DOX_algal_respiration', + long_name='Dissolved oxygen flux due to algal respiration', + units='mg/L/d', + description='Dissolved oxygen flux due to algal respiration', + use='dynamic', + process=processes.DOX_ApRespiration +) + +Variable( + name='DOX_Nitrification', + long_name='Dissolved oxygen flux due to nitrification', + units='mg/L/d', + description='Dissolved oxygen flux due to nitrification', + use='dynamic', + process=processes.DOX_Nitrification +) + +Variable( + name='DOX_DOC_Oxidation', + long_name='Dissolved oxygen flux due to DOC oxidation', + units='mg/L/d', + description='Dissolved oxygen flux due to DOC oxidation', + use='dynamic', + process=processes.DOX_DOC_Oxidation +) + +Variable( + name='DOX_CBOD_Oxidation', + long_name='Dissolved oxygen flux due to CBOD oxidation', + units='mg/L/d', + description='Dissolved oxygen flux due to CBOD oxidation', + use='dynamic', + process=processes.DOX_CBOD_Oxidation +) + +Variable( + name='DOX_AbGrowth', + long_name='Dissolved oxygen flux due to benthic algae photosynthesis', + units='mg/L/d', + description='Dissolved oxygen flux due to benthic algae photosynthesis', + use='dynamics', + process=processes.DOX_AbGrowth +) + +Variable( + name='DOX_AbRespiration', + long_name='Dissolved oxygen flux due to benthic algae respiration', + units='mg/L/d', + description='Dissolved oxygen flux due to benthic algae respiration', + use='dynamic', + process=processes.DOX_AbRespiration +) + +Variable( + name='DOX_SOD', + long_name='Dissolved oxygen flux due to sediment oxygen demand', + units='mg/L/d', + description='Dissolved oxygen flux due to sediment oxygen demand', + use='dynamic', + process=processes.DOX_SOD +) + +Variable( + name='dDOXdt', + long_name='Change in dissolved oxygen concentration for one timestep', + units='mg/L/d', + description='Change in dissolved oxygen concentration for one timestep', + use='dynamic', + process=processes.dDOXdt +) + +############################################ From pathogen +Variable( + name='kdx_tc', + long_name='Pathogen death rate', + units='1/d', + description='Pathogen death rate with temperature correction', + use='dynamic', + process=processes.kdx_tc +) + +Variable( + name='PathogenDeath', + long_name='Pathogen natural death', + units='cfu/100mL/d', + description='Pathogen natural death', + use='dynamic', + process=processes.PathogenDeath +) + +Variable( + name='PathogenDecay', + long_name='Pathogen death due to light', + units='cfu/100mL/d', + description='Pathogen death due to light', + use='dynamic', + process=processes.PathogenDecay +) + +Variable( + name='PathogenSettling', + long_name='Pathogen settling', + units='cfu/100mL/d', + description='Pathogen settling', + use='dynamic', + process=processes.PathogenSettling +) + +Variable( + name='dPXdt', + long_name='Change in pathogen concentration', + units='cfu/100mL/d', + description='Change in pathogen concentration', + use='dynamic', + process=processes.dPXdt +) + +############################################ From alkalinity +Variable( + name='Alk_denitrification', + long_name='Alkalinity change due to denitrification', + units='mg/L/d', + description='Alkalinity change due to denitrification', + use='dynamic', + process=processes.Alk_denitrification +) + +Variable( + name='Alk_nitrification', + long_name='Alkalinity change due to nitrification', + units='mg/L/d', + description='Alkalinity change due to nitrification', + use='dynamic', + process=processes.Alk_nitrification +) + +Variable( + name='Alk_algal_growth', + long_name='Alkalinity change due to algal growth', + units='mg/L/d', + description='Alkalinity change due to algal growth', + use='dynamic', + process=processes.Alk_algal_growth +) + +Variable( + name='Alk_algal_respiration', + long_name='Alkalinity change due to algal respiration', + units='mg/L/d', + description='Alkalinity change due to algal respiration', + use='dynamic', + process=processes.Alk_algal_respiration +) + +Variable( + name='Alk_benthic_algae_growth', + long_name='Alkalinity change due to benthic algae growth', + units='mg/L/d', + description='Alkalinity change due to benthic algae growth', + use='dynamic', + process=processes.Alk_benthic_algae_growth +) + +Variable( + name='Alk_benthic_algae_respiration', + long_name='Alkalinity change due to benthic algae growth', + units='mg/L/d', + description='Alkalinity change due to benthic algae growth', + use='dynamic', + process=processes.Alk_benthic_algae_respiration +) + +Variable( + name='dAlkdt', + long_name='Alkalinity concentration change per timestep', + units='mg/L/d', + description='Alkalinity concentration change per timestep', + use='dynamic', + process=processes.dAlkdt +) + +############################################ From N2 +Variable( + name='KHN2_tc', + long_name='Henrys law constant', + units='mol/L/atm', + description='Henrys law constant temperature corrected', + use='dynamic', + process=processes.KHN2_tc +) + +Variable( + name='P_wv', + long_name='Partial pressure water vapor', + units='atm', + description='Partial pressure water vapor', + use='dynamic', + process=processes.P_wv +) + +Variable( + name='N2sat', + long_name='N2 at saturation', + units='mg-N/L', + description='N2 at saturation f(Twater and atm pressure)', + use='dynamic', + process=processes.N2sat +) + +Variable( + name='dN2dt', + long_name='Change in N2 air concentration', + units='mg-N/L/d', + description='Change in N2 air concentration', + use='dynamic', + process=processes.dN2dt +) + +Variable( + name='TDG', + long_name='Total dissolved gas', + units='%', + description='Total dissolved gas', + use='dynamic', + process=processes.TDG +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/n2/processes.py b/src/clearwater_modules/nsm1/n2/processes.py index 75341f4..5e6005b 100644 --- a/src/clearwater_modules/nsm1/n2/processes.py +++ b/src/clearwater_modules/nsm1/n2/processes.py @@ -82,6 +82,7 @@ def dN2dt( def N2( N2: xr.DataArray, dN2dt : xr.DataArray, + timestep: xr.DataArray ) -> xr.DataArray: """Calculate change in N2 air concentration (mg-N/L/d) @@ -89,9 +90,10 @@ def N2( Args: N2: Nitrogen concentration air (mg-N/L) dN2dt: Change in nitrogen concentration air + timestep: Current iteration timestep (d) """ - return N2 + dN2dt + return N2 + dN2dt * timestep @numba.njit def TDG( diff --git a/src/clearwater_modules/nsm1/pathogens/processes.py b/src/clearwater_modules/nsm1/pathogens/processes.py index 509094a..2488f49 100644 --- a/src/clearwater_modules/nsm1/pathogens/processes.py +++ b/src/clearwater_modules/nsm1/pathogens/processes.py @@ -95,7 +95,8 @@ def dPXdt( @numba.njit def PX( PX:xr.DataArray, - dPXdt: xr.DataArray + dPXdt: xr.DataArray, + timestep: xr.DataArray ) -> xr.DataArray : @@ -104,5 +105,6 @@ def PX( Args: dPXdt: change in pathogen concentration (cfu/100mL/d) PX: Pathogen concentration (cfu/100mL) + timestep: Current iteration timestep (d) """ - return PX+dPXdt \ No newline at end of file + return PX + timestep * dPXdt \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py new file mode 100644 index 0000000..2403161 --- /dev/null +++ b/src/clearwater_modules/nsm1/processes.py @@ -0,0 +1,3307 @@ +import warnings +import numba +import numpy as np +import xarray as xr +import math + +############################################ From shared processes +@numba.njit +def celsius_to_kelvin(tempc: xr.DataArray) -> xr.DataArray: + return tempc + 273.16 + + +@numba.njit +def kelvin_to_celsius(tempk: xr.DataArray) -> xr.DataArray: + return tempk - 273.16 + +@numba.njit +def arrhenius_correction( + TwaterC: xr.DataArray, + rc20: xr.DataArray, + theta: xr.DataArray, +) -> xr.DataArray: + """ + Computes an adjusted kinetics reaction rate coefficient for the specified water + temperature using the van't Hoff form of the Arrhenius equation + + Parameters + ---------- + TwaterC : xr.DataArray + Water temperature in degrees Celsius + rc20 : xr.DataArray + Kinetics reaction (decay) coefficient at 20 degrees Celsius + theta : xr.DataArray + Temperature correction factor + + Returns + ---------- + float + Adjusted kinetics rate for the specified water temperature + """ + return rc20 * theta**(TwaterC - 20.0) + +@numba.njit +def compute_depth( + surface_area: xr.DataArray, + volume: xr.DataArray +) -> xr.DataArray: + """Compute depth of a computation cell + + Args: + surface_area: state variable for surface area of computational cell provided by CWR engine + volume: state variable for volume of computational cell provided by CWR engine + """ + return volume / surface_area + +@numba.njit +def TwaterK( + TwaterC : xr.DataArray, +) -> xr.DataArray : + """Calculate temperature in kelvin (K) + Args: + TwaterC: water temperature celcius (C) + """ + return celsius_to_kelvin(TwaterC) + + +def kah_20( + kah_20_user: xr.DataArray, + hydraulic_reaeration_option: xr.DataArray, + velocity: xr.DataArray, + depth: xr.DataArray, + flow: xr.DataArray, + topwidth: xr.DataArray, + slope: xr.DataArray, + shear_velocity: xr.DataArray +) -> xr.DataArray: + """Calculate hydraulic oxygen reaeration rate based on flow parameters in different cells + + Args: + kah_20_user: User defined O2 reaeration rate at 20 degrees (1/d) + hydraulic_reaeration_option: Integer value which selects method for computing O2 reaeration rate + velocity: Average water velocity in cell (m/s) + depth: Average water depth in cell (m) + flow: Average flow rate in cell (m3/s) + topwidth: Average topwidth of cell (m) + slope: Average slope of bottom surface + shear_velocity: Average shear velocity on bottom surface (m/s) + """ + + da: xr.DataArray = xr.where(hydraulic_reaeration_option == 1, kah_20_user, + xr.where(hydraulic_reaeration_option == 2, (3.93 * velocity**0.5) / (depth**1.5), + xr.where(hydraulic_reaeration_option == 3, (5.32 * velocity**0.67) / (depth**1.85), + xr.where(hydraulic_reaeration_option == 4, (5.026 * velocity) / (depth**1.67), + xr.where(hydraulic_reaeration_option == 5, xr.where(depth < 0.61, (5.32 * velocity**0.67) / (depth**1.85), xr.where(depth > 0.61, (3.93 * velocity**0.5) / (depth**1.5), (5.026 * velocity) / (depth**1.67))), + xr.where(hydraulic_reaeration_option == 6, xr.where(flow < 0.556, 517 * (velocity * slope)**0.524 * flow**-0.242, 596 * (velocity * slope)**0.528 * flow**-0.136), + xr.where(hydraulic_reaeration_option == 7, xr.where(flow < 0.556, 88 * (velocity * slope)**0.313 * depth**-0.353, 142 * (velocity * slope)**0.333 * depth**-0.66 * topwidth**-0.243), + xr.where(hydraulic_reaeration_option == 8, xr.where(flow < 0.425, 31183 * velocity * slope, 15308 * velocity * slope), + xr.where(hydraulic_reaeration_option == 9, 2.16 * (1 + 9 * (velocity / (9.81 * depth)**0.5)**0.25) * shear_velocity / depth, -9999 + ))))))))) + return da + + +@numba.njit +def kah_tc( + TwaterC: xr.DataArray, + kah_20: xr.DataArray, + theta: xr.DataArray +) -> xr.DataArray: + """Calculate the temperature adjusted hydraulic oxygen reaeration rate (/d) + + Args: + TwaterC: Water temperature in Celsius + kah_20: Hydraulic oxygen reaeration rate at 20 degrees Celsius + theta: Arrhenius coefficient + """ + return arrhenius_correction(TwaterC, kah_20, theta) + + +def kaw_20( + kaw_20_user: xr.DataArray, + wind_speed: xr.DataArray, + wind_reaeration_option: xr.DataArray +) -> xr.DataArray: + """Calculate the wind oxygen reaeration velocity (m/d) based on wind speed, r stands for regional + + Args: + kaw_20_user: User defined wind oxygen reaeration velocity at 20 degrees C (m/d) + wind_speed: Wind speed at 10 meters above the water surface (m/s) + wind_reaeration_option: Integer value which selects method for computing wind oxygen reaeration velocity + """ + Uw10 = wind_speed * (10 / 2)**0.143 + + da: xr.DataArray = xr.where(wind_reaeration_option == 1, kaw_20_user, + xr.where(wind_reaeration_option == 2, 0.864 * Uw10, + xr.where(wind_reaeration_option == 3, xr.where(Uw10 <= 3.5, 0.2 * Uw10, 0.057 * Uw10**2), + xr.where(wind_reaeration_option == 4, 0.728 * Uw10**0.5 - 0.317 * Uw10 + 0.0372 * Uw10**2, + xr.where(wind_reaeration_option == 5, 0.0986 * Uw10**1.64, + xr.where(wind_reaeration_option == 6, 0.5 + 0.05 * Uw10**2, + xr.where(wind_reaeration_option == 7, xr.where(Uw10 <= 5.5, 0.362 * Uw10**0.5, 0.0277 * Uw10**2), + xr.where(wind_reaeration_option == 8, 0.64 + 0.128 * Uw10**2, + xr.where(wind_reaeration_option == 9, xr.where(Uw10 <= 4.1, 0.156 * Uw10**0.63, 0.0269 * Uw10**1.9), + xr.where(wind_reaeration_option == 10, 0.0276 * Uw10**2, + xr.where(wind_reaeration_option == 11, 0.0432 * Uw10**2, + xr.where(wind_reaeration_option == 12, 0.319 * Uw10, + xr.where(wind_reaeration_option == 13, xr.where(Uw10 < 1.6, 0.398, 0.155 * Uw10**2), -9999 + ))))))))))))) + + return da + + +@numba.njit +def kaw_tc( + TwaterC: xr.DataArray, + kaw_20: xr.DataArray, + theta: xr.DataArray +) -> xr.DataArray: + """Calculate the temperature adjusted wind oxygen reaeration velocity (m/d) + + Args: + water_temp_c: Water temperature in Celsius + kaw_20: Wind oxygen reaeration velocity at 20 degrees Celsius + theta: Arrhenius coefficient + """ + return arrhenius_correction(TwaterC, kaw_20, theta) + + +@numba.njit +def ka_tc( + kah_tc: xr.DataArray, + kaw_tc: xr.DataArray, + depth: xr.DataArray +) -> xr.DataArray: + """Compute the oxygen reaeration rate, adjusted for temperature (1/d) + + Args: + kah_tc: Oxygen reaeration rate adjusted for temperature (1/d) + kaw_tc: Wind oxygen reaeration velocity adjusted for temperature (m/d) + depth: Average water depth in cell (m) + """ + return kaw_tc / depth + kah_tc + +def SOD_tc( + SOD_20: xr.DataArray, + TwaterC: xr.DataArray, + theta: xr.DataArray, + DOX: xr.DataArray, + KsSOD: xr.DataArray, + use_DOX: xr.DataArray +) -> xr.DataArray: + """Compute the sediment oxygen demand corrected by temperature and dissolved oxygen concentration + + Args: + SOD_20: Sediment oxygen demand at 20 degrees celsius (mg-O2/m2) + TwaterC: Water temperature in degrees C + theta: Arrhenius coefficient + use_DOX: Option to consider DOX concentration in water in calculation of sediment oxygen demand + """ + SOD_tc = arrhenius_correction(TwaterC, SOD_20, theta) + + da: xr.DataArray = xr.where(use_DOX == True, SOD_tc * DOX / (DOX + KsSOD), SOD_tc) + + return da + +@numba.njit +def L( + lambda0: xr.DataArray, + lambda1: xr.DataArray, + lambda2: xr.DataArray, + lambdas: xr.DataArray, + lambdam: xr.DataArray, + Solid: xr.DataArray, + POC: xr.DataArray, + fcom: xr.DataArray, + use_Algae: xr.DataArray, + use_POC: xr.DataArray, + Ap: xr.DataArray, + +) -> xr.DataArray: + """Compute L: lambda: light extinction coefficient (unitless) + + Args: + lambda0: background portion (1/m) + lambda1: linear self shading (1/m/(ug Chla/L)) + lambda2: non-linear (unitless), + lambdas: ISS portion (L/mg/m), + lambdam: POM portion (L/mg/m) + Solid: #TODO define this + POC: particulate organic carbon (mg-C/L) + fcom: ratio of carbon to organic matter (mg-C/mg-D) + use_Algae: true/false use algae module (t/f) + use_POC: true/falseo use particulate organic carbon module (t/f) + Ap: algae concentration (ug-Chla/L) + """ + L=lambda0 + lambdas * Solid + + L=xr.where (use_POC, L+lambdam*POC/fcom, L) + L=xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**0.66667, L) + + return L + +@numba.njit +def PAR( + use_Algae : bool, + use_Balgae: bool, + q_solar: xr.DataArray, + Fr_PAR: xr.DataArray, +) -> xr.DataArray : + """Calculate temperature in kelvin (K) + Args: + use_Algae : true/false use algae module (t/f) + use_Balgae: true/falsoe use balgae module (t/f) + q_solar: solar radiation (1/d), + Fr_PAR: fraction of solar radiation within the PAR of the spectrum + """ + return xr.where (use_Algae or use_Balgae, q_solar * Fr_PAR) + + +@numba.njit +def fdp( + use_TIP: bool, + Solid : xr.DataArray, + kdpo4: xr.DataArray +) -> xr.DataArray : + + """Calculate kop_tc: Decay rate of organic P to DIP temperature correction (1/d). + + Args: + use_TIP: true/false use total inorganic phosphrous, + Solid : #TODO define this + kdpo4: solid partitioning coeff. of PO4 (L/kg) + """ + + return xr.where(use_TIP, 1/(1+kdpo4 * Solid/0.000001), 0) + +############################################ From algae +@numba.njit +def rna( + AWn: xr.DataArray, + AWa: xr.DataArray +) -> xr.DataArray: + """Calculate rna (mg-N/ug-Chla). + + Args: + AWn: Nitrogen Weight (mg) + AWa: Algal Chlorophyll (ug-Chla) + """ + return AWn/AWa + + +@numba.njit +def rpa( + AWp: xr.DataArray, + AWa: xr.DataArray +) -> xr.DataArray: + """Calculate rpa (mg-P/ug-Chla). + + Args: + AWp: Phosphorus Weight (mg) + AWa: Algal Chlorophyll (ug-Chla) + """ + + return AWp/AWa + + +@numba.njit +def rca( + AWc: xr.DataArray, + AWa: xr.DataArray +) -> xr.DataArray: + """Calculate rca (mg-C/ug-Chla). + + Args: + AWc: Carbon Weight (mg) + AWa: Algal Chlorophyll (ug-Chla) + """ + return AWc/AWa + + +@numba.njit +def rda( + AWd: xr.DataArray, + AWa: xr.DataArray +) -> xr.DataArray: + """Calculate rda (mg-D/ug-Chla). + + Args: + AWd: Dry Algal Weight (mg) + AWa: Algal Chlorophyll (ug-Chla) + """ + return AWd/AWa + + +@numba.njit +def mu_max_tc( + TwaterC: xr.DataArray, + mu_max_20: xr.DataArray +) -> xr.DataArray: + """Calculate mu_max_tc (1/d). + + Args: + TwaterC: Water temperature (C) + mu_max: Max Algae growth (1/d) + """ + + return arrhenius_correction(TwaterC, mu_max_20, 1.047) + + +@numba.njit +def krp_tc( + TwaterC: xr.DataArray, + krp_20: xr.DataArray +) -> xr.DataArray: + """Calculate krp_tc (1/d). + + Args: + TwaterC: Water temperature (C) + krp: Algal respiration rate at 20 degree (1/d) + """ + + return arrhenius_correction(TwaterC, krp_20, 1.047) + + +@numba.njit +def kdp_tc( + TwaterC: xr.DataArray, + kdp_20: xr.DataArray +) -> xr.DataArray: + """Calculate kdp_tc (1/d). + + Args: + TwaterC: Water temperature (C) + kdp: Algal death rate at 20 degree (1/d) + """ + + return arrhenius_correction(TwaterC, kdp_20, 1.047) + + +@numba.njit +def FL( + L: xr.DataArray, + depth: xr.DataArray, + Ap: xr.DataArray, + PAR: xr.DataArray, + light_limitation_option: int, + KL: xr.DataArray, +) -> xr.DataArray: + """Calculate Algal light limitation: FL (unitless). + + Args: + L: Lambda light attenuation coefficient (unitless) + depth: Water depth (m) + Ap: Algae Concentration (mg-Chla/L) + PAR: Surface light intensity (W/m^2) + light_limitation_option: Algal light limitation option 1) Half-saturation, 2) Smith model, 3) Steele model (unitless) + KL: Light limitation constant for algal growth (W/m^2) + """ + + KEXT = L * depth + + FL = xr.where(Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, 0, + xr.where(light_limitation_option==1, (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), + xr.where(light_limitation_option==2, + xr.where(abs(KL)<0.0000000001, 1, (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5)))), + xr.where(light_limitation_option==3, + xr.where(abs(KL)<0.0000000001,0,(2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL))), "NaN")))) + + + FL= xr.where(FL > 1.0, 1.0, + xr.where(FL<0.0, 0.0, FL)) + + return FL + + +@numba.njit +def FN( + use_NH4: bool, + use_NO3: bool, + NH4: xr.DataArray, + NO3: xr.DataArray, + KsN: xr.DataArray, + +) -> xr.DataArray: + """Calculate Algal nitrogen limitation: FN (unitless). + + Args: + use_NH4: Use NH4 module true or false (true/false) + use_NO3: Use NO3 module true or false (true/false) + NH4: Ammonium concentration (mg-N/L) + NO3: Nitrate concentration (mg-N/L) + KsN: Michaelis-Menton half-saturation constant relating inorganic N to algal growth (mg-N/L) + """ + + FN = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsN + NH4 + NO3), 1) + FN = xr.where(math.isnan(FN), 0, + xr.where(FN>1.0,1.0,FN)) + + return FN + + +@numba.njit +def FP( + fdp: xr.DataArray, + TIP: xr.DataArray, + use_TIP: bool, + KsP: xr.DataArray +) -> xr.DataArray: + """Calculate Algal phosphorous limitation: FP (unitless). + + Args: + use_TIP: Use Total Inorganic Phosphorus module true or false (true/false) + TIP: Total Inorganic Phosphorus concentration (mg-P/L) + KsP: Michaelis-Menton half-saturation constant relating inorganic P to algal growth (mg-P/L) + fdp: Fraction P dissolved (unitless) + """ + + FP = xr.where(use_TIP, fdp * TIP / (KsP + fdp * TIP), 1.0) + FP = xr.where(math.isnan(FP), 0, + xr.where(FP>1.0, 1, FP)) + + return FP + + +@numba.njit +def mu( + mu_max_tc: xr.DataArray, + growth_rate_option: int, + FL: xr.DataArray, + FP: xr.DataArray, + FN: xr.DataArray + +) -> xr.DataArray: + """Calculate Algal growth rate with three options 1) Multiplicative, 2) Limiting nutrient, 3) Harmonic Mean (1/d) + + Args: + mu_max_tc: Max algae growth temperature corrected (1/d) + growth_rate_option: Algal growth rate with options 1) Multiplicative, 2) Limiting nutrient, 3) Harmonic Mean (unitless) + FL: Algae light limitation factor (unitless) + FP: Algae phosphorus limitation factor (unitless) + FN: Algae nitrogen limitation factor (unitless) + """ + + return xr.where(growth_rate_option == 1, mu_max_tc * FL * FP * FN, + xr.where(growth_rate_option == 2, mu_max_tc * FL * min(FP, FN), + xr.where(growth_rate_option == 3, + xr.where(FN==0.0 or FP==0.0, 0.0, mu_max_tc * FL * 2.0 / (1.0 / FN + 1.0 / FP)), "NaN"))) + + +@numba.njit +def ApGrowth( + mu: xr.DataArray, + Ap: xr.DataArray +) -> xr.DataArray: + """Calculate Algal growth (ug-Chla/L/d) + + Args: + mu: Algal growth rate (1/d) + Ap: Algae concentration (ug-Chla/L) + """ + + return mu * Ap + + +@numba.njit +def ApRespiration( + krp_tc: xr.DataArray, + Ap: xr.DataArray +) -> xr.DataArray: + """Calculate Algal Respiration (ug-Chla/L/d) + + Args: + krp_tc: Algal respiration rate temperature corrected (1/d) + Ap: Algae concentration (ug-Chla/L) + """ + + return krp_tc * Ap + + +@numba.njit +def ApDeath( + kdp_tc: xr.DataArray, + Ap: xr.DataArray +) -> xr.DataArray: + """Calculate Algal death (ug-Chla/L/d) + + Args: + kdp_tc: Algal death rate temperature corrected (1/d) + Ap: Algae concentration (ug-Chla/L) + """ + return kdp_tc * Ap + + +@numba.njit +def ApSettling( + vsap: xr.DataArray, + Ap: xr.DataArray, + depth: xr.DataArray +) -> xr.DataArray: + """Calculate Algal setting rate (ug-Chla/L/d) + + Args: + vsap: Algal settling velocity (m/d) + Ap: Algae concentration (ug-Chla/L) + depth: Depth from Water Surface (m)s + """ + return vsap / depth * Ap + + +@numba.njit +def dApdt( + ApGrowth: xr.DataArray, + ApRespiration: xr.DataArray, + ApDeath: xr.DataArray, + ApSettling: xr.DataArray +) -> xr.DataArray: + """Calculate change in algae biomass concentration (ug-Chla/L/d) + + Args: + ApGrowth: Algal growth (ug-Chla/L/d) + ApRespiration: Algal respiration (ug-Chla/L/d) + ApDeath: Algal death (ug-Chla/L/d) + ApSettling: Algal settling (ug-Chla/L/d) + """ + + return ApGrowth - ApRespiration - ApDeath - ApSettling + + +@numba.njit +def Ap( + Ap: xr.DataArray, + dApdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Calculate new algae concentration (ug-Chla/L) + + Args: + Ap: Initial algae biomass concentration (ug-Chla/L) + dApdt: Change in algae biomass concentration (ug-Chla/L/d) + timestep: current iteration timestep (d) + """ + return Ap + dApdt * timestep + +############################################ From benthic algae +@numba.njit +def mub_max_tc( + mub_max_20: xr.DataArray, + TwaterC: xr.DataArray +) -> xr.DataArray: + """Calculate mub_max_tc: Maximum benthic algal growth rate with temperature correction (1/d). + + Args: + mu_max_20: Maximum benthic algal growth rate at 20C (1/d) + TwaterC: Water temperature (C) + """ + return arrhenius_correction(TwaterC, mub_max_20, 1.047) + + +@numba.njit +def krb_tc( + krb_20: xr.DataArray, + TwaterC: xr.DataArray +) -> xr.DataArray: + """Calculate krb_tc: Benthic algae respiration rate with temperature correction (1/d). + + Args: + krb_20: Benthic algae respiration rate at 20C (1/d) + TwaterC: Water temperature (C) + """ + return arrhenius_correction(TwaterC, krb_20, 1.06) + + +@numba.njit +def kdb_tc( + kdb_20: xr.DataArray, + TwaterC: xr.DataArray +) -> xr.DataArray: + """Calculate kdb_tc: Benthic algae mortality rate with temperature correction (1/d). + + Args: + kdb_20: Benthic algae mortality rate at 20C (1/d) + TwaterC: Water temperature (C) + """ + return arrhenius_correction(TwaterC, kdb_20, 1.047) + + +@numba.njit +def rnb( + BWn: xr.DataArray, + BWd: xr.DataArray +) -> xr.DataArray: + """Calculate rnb (mg-N/mg-D). + + Args: + BWn: Benthic algae nitrogen (unitless) + BWd: Benthic algae dry weight (unitless) + """ + return BWn/BWd + + +@numba.njit +def rpb( + BWp: xr.DataArray, + BWd: xr.DataArray +) -> xr.DataArray: + """Calculate rpd: Benthic algae phosphorus to dry weight ratio (mg-P/mg-D). + + Args: + BWp: Benthic algae phosphorus (mg-P) + BWd: Benthic algae dry weight (mg-D) + """ + return BWp/BWd + + +@numba.njit +def rcb( + BWc: xr.DataArray, + BWd: xr.DataArray +) -> xr.DataArray: + """Calculate rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D). + + Args: + BWc: Benthic algae carbon (mg-C) + BWd: Benthic algae dry weight (mg-D) + """ + return BWc/BWd + + +@numba.njit +def rab( + BWa: xr.DataArray, + BWd: xr.DataArray +) -> xr.DataArray: + """Calculate rab: Benthic algae chlorophyll-a to dry weight ratio (ug-Chla-a/mg-D). + + Args: + BWa: Benthic algae chlorophyll-a (ug-Chla-a) + BWd: Benthic algae dry weight (mg-D) + """ + return BWa/BWd + + +@numba.njit +def FLb( + L: xr.DataArray, + depth: xr.DataArray, + Ab: xr.DataArray, + PAR: xr.DataArray, + b_light_limitation_option: xr.DataArray, + KLb: xr.DataArray, + +) -> xr.DataArray: + """Calculate Benthic algal light limitation: FLb (unitless). + + Args: + L: Lambda light attenuation coefficient (unitless) + depth: Water depth (m) + Ab: Benthic algae Concentration (g/m^2) + PAR: Surface light intensity (W/m^2) + b_light_limitation_option: Benthic light limitation option 1) Half-saturation, 2) Smith model, 3) Steele model (unitless) + KLb: Light limitation constant for benthic algal growth (W/m^2) + """ + + # Note that KENT is defined differently here than it was for the algal equations. + # The equations are different, this expression is more convenient here. + KEXT = math.exp(-L*depth) + + FLb = xr.where(Ab <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, 0.0, + xr.where(b_light_limitation_option == 1, PAR * KEXT / (KLb + PAR * KEXT), + xr.where(b_light_limitation_option == 2, PAR * KEXT / ((KLb**2.0 + (PAR * KEXT)**2.0)**0.5), + xr.where(b_light_limitation_option == 3, + xr.where(abs(KLb) < 1.0E-10, 0.0, PAR * KEXT / KLb * math.exp(1.0 - PAR * KEXT / KLb)), "NaN" + )))) + FLb = xr.where(FLb > 1.0, 1.0, + xr.where(FLb < 0.0, 0.0, FLb)) + + return FLb + + +@numba.njit +def FNb( + use_NH4: bool, + use_NO3: bool, + NH4: xr.DataArray, + NO3: xr.DataArray, + KsNb: xr.DataArray, + +) -> xr.DataArray: + """Calculate Benthic algae nitrogen limitation: FNb (unitless). + + Args: + use_NH4: Use NH4 module true or false (true/false) + use_NO3: Use NO3 module true or false (true/false) + NH4: Ammonium concentration (mg-N/L) + NO3: Nitrate concentration (mg-N/L) + KsNb: Michaelis-Menton half-saturation constant relating inorganic N to benthic algal growth (mg-N/L) + """ + FNb = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsNb + NH4 + NO3),1) + FNb = xr.where(math.isnan(FNb),0.0, + xr.where(FNb < 1.0, 1, FNb)) + + return FNb + + +@numba.njit +def FPb( + fdp: xr.DataArray, + TIP: xr.DataArray, + use_TIP: bool, + KsPb: xr.DataArray +) -> xr.DataArray: + """Calculate benthic algae phosphorous limitation: FPb (unitless). + + Args: + use_TIP: Use Total Inorganic Phosphorus module true or false (true/false) + TIP: Total Inorganic Phosphorus concentration (mg-P/L) + KsPb: Michaelis-Menton half-saturation constant relating inorganic P to benthic algal growth (mg-P/L) + fdp: Fraction P dissolved (unitless) + """ + + FPb = xr.where(use_TIP, fdp * TIP / (KsPb + fdp * TIP),1.0) + FPb = xr.where(math.isnan(FPb),0.0, + xr.where(FPb > 1.0, 1.0, FPb)) + + return FPb + + +@numba.njit +def FSb( + Ab: xr.DataArray, + Ksb: xr.DataArray, + +) -> xr.DataArray: + """Calculate benthic density attenuation (unitless) + + Args: + Ab: Benthic algae concentration (g/m^2) + Ksb: Half-saturation density constant for benthic algae growth (g-D/m^2) + + """ + + FSb = 1.0 - (Ab / (Ab + Ksb)) + FSb = xr.where(math.isnan(FSb), 1.0, + xr.where(FSb > 1.0, 1.0, FSb)) + + return FSb + + +@numba.njit +def mub( + mub_max_tc: xr.DataArray, + b_growth_rate_option: int, + FLb: xr.DataArray, + FPb: xr.DataArray, + FNb: xr.DataArray, + FSb: xr.DataArray, + +) -> xr.DataArray: + """Calculate benthic algae specific growth rate (1/d) + + Args: + mub_max_tc: Maximum benthic algal growth rate with temperature correction (1/d) + b_growth_rate_option: Benthic Algal growth rate with three options 1) Multiplicative, 2) Limiting Nutrient + FLb: Benethic algal light limitation (unitless) + FPb: Benthic algae phosphorous limitation (unitless) + FNb: Benthic algae nitrogen limitation (unitless) + FSb: Benthic density attenuation (unitless), + """ + + # Benthic Local Specific Growth Rate + return xr.where(b_growth_rate_option == 1, mub_max_tc * FLb * FPb * FNb * FSb, mub_max_tc * FLb * FSb * min(FPb, FNb)) + + + +@numba.njit +def AbGrowth( + mub: xr.DataArray, + Ab: xr.DataArray +) -> xr.DataArray: + """Calculate Benthic algal growth (g/m^2/d) + + Args: + mub: Benthic algae growth rate (1/d) + Ab: Benthic algae concentration (g/m^2) + """ + + return mub * Ab + + +@numba.njit +def AbRespiration( + krb_tc: xr.DataArray, + Ab: xr.DataArray +) -> xr.DataArray: + """Calculate benthic algal Respiration (g/m^2/d) + + Args: + krb_tc: Benthic algal respiration rate temperature corrected (1/d) + Ab: Algae concentration (g/m^2) + """ + return krb_tc * Ab + + +@numba.njit +def AbDeath( + kdb_tc: xr.DataArray, + Ab: xr.DataArray +) -> xr.DataArray: + """Calculate benthic algae death (g/m^2/d) + + Args: + kdb_tc: Benthic algae death rate temperature corrected (1/d) + Ab: Benthic algae concentration (g/m^2) + """ + + return kdb_tc * Ab + + +@numba.njit +def dAbdt( + AbGrowth: xr.DataArray, + AbRespiration: xr.DataArray, + AbDeath: xr.DataArray + +) -> xr.DataArray: + """Calculate change in benthic algae concentration (g/m^2/d) + + Args: + AbGrowth: Benthic algae growth rate (g/m^2/d) + AbRespiration: Benthic algae respiration rate (g/m^2/d) + AbDeath: Benthic algae death rate (g/m^2/d) + """ + return AbGrowth - AbRespiration - AbDeath + + +@numba.njit +def Ab( + Ab: xr.DataArray, + dAbdt: xr.DataArray, + timestep: xr.DataArray, + +) -> xr.DataArray: + """Calculate Ab: New concentration benthic algae (mg-N/L) + + Args: + Ab: Concentration of benthic algae (mg-N/L) + dAbdt: Change in Ab (mg-N/L/d) + timestep: current iteration timestep (d) + + """ + + return Ab + dAbdt * timestep + +@numba.njit +def Chlb( + rab: xr.DataArray, + Ab: xr.DataArray, + +) -> xr.DataArray: + """Calculate chlorophyll-a concentration (mg-Chla/m^2) + + Args: + rab: Balgae Chla to Dry ratio (mg-D/ug-Chla) + Ab: Benthic algae concentration (g/m^2) + """ + + return rab * Ab + + +############################################ From nitrogen + +@numba.njit +def knit_tc( + TwaterC: xr.DataArray, + knit_20: xr.DataArray +) -> xr.DataArray: + """Calculate knit_tc: Nitrification rate ammonia decay NH4 to NO3 temperature correction (1/d). #TODO only if use_NH4 = true + + Args: + TwaterC: Water temperature (C) + knit_20: Nitrification rate ammonia decay (1/d) + """ + + return arrhenius_correction(TwaterC, knit_20, 1.083) + + +@numba.njit +def rnh4_tc( + TwaterC: xr.DataArray, + rnh4_20: xr.DataArray +) -> xr.DataArray: + """Calculate rnh4_tc: Sediment release rate of NH4 temperature correction(1/d). #TODO only if use_sedflux = true + + Args: + TwaterC: Water temperature (C) + rnh4_20: Sediment release rate of NH4 (1/d) + """ + + return arrhenius_correction(TwaterC, rnh4_20, 1.074) + + +@numba.njit +def vno3_tc( + TwaterC: xr.DataArray, + vno3_20: xr.DataArray +) -> xr.DataArray: + """Calculate vno3_tc: Sediment denitrification velocity temperature correction (m/d). #TODO only if use_sedflux = true + + Args: + TwaterC: Water temperature (C) + vno3_20: Sedimet release rate of NO3 (1/d) + """ + + return arrhenius_correction(TwaterC, vno3_20, 1.08) + + +@numba.njit +def kon_tc( + TwaterC: xr.DataArray, + kon_20: xr.DataArray +) -> xr.DataArray: + """Calculate kon_tc: Decay rate of OrgN to NH4 temperature correction(1/d). #TODO only if use_OrgN = true + + Args: + TwaterC: Water temperature (C) + kon_20: Decay rate of OrgN to NH4 (1/d) + """ + + return arrhenius_correction(TwaterC, kon_20, 1.074) + + +@numba.njit +def kdnit_tc( + TwaterC: xr.DataArray, + kdnit_20: xr.DataArray +) -> xr.DataArray: + """Calculate kdnit_tc: Denitrification rate temperature correction (1/d). #TODO only if use_NO3 = true + + Args: + TwaterC: Water temperature (C) + kdnit_20: Denitrification rate (1/d) + """ + + return arrhenius_correction(TwaterC, kdnit_20, 1.045) + + +@numba.njit +def ApUptakeFr_NH4( + use_NH4: bool, + use_NO3: bool, + use_Algae: bool, + PN: xr.DataArray, + NH4: xr.DataArray, + NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate ApUptakeFr_NH4: + + Args: + use_NH4: use ammonium module (unitless) + use_NO3: use nitrate module (unitless) + use_Algae: use algae module (unitless) + PN: NH4 preference factor algae (unitless) + NH4: Ammonium water concentration (mg-N/L) + NO3: Nitrate water concentration (mg-N/L) + """ + ApUptakeFr_NH4 = 0 + + # set value of UptakeFr_NH4/NO3 for special conditions + ApUptakeFr_NH4 = xr.where(use_NH4 and not use_NO3, 1.0, + xr.where(not use_NH4 and use_NO3, 0.0, + xr.where(not use_NH4 and not use_NO3, 0.5, + xr.where(use_Algae and use_NH4 and use_NO3, PN * NH4 / (PN * NH4 + (1.0 - PN) * NO3), "NaN")))) + + # Check for case when NH4 and NO3 are very small. If so, force uptake_fractions appropriately. + ApUptakeFr_NH4 = xr.where(math.isnan(ApUptakeFr_NH4),PN,ApUptakeFr_NH4) + + return ApUptakeFr_NH4 + + +@numba.njit +def ApUptakeFr_NO3( + ApUptakeFr_NH4: xr.DataArray +) -> xr.DataArray: + """Calculate ApUptakeFr_NO3: Fraction of actual xr.DataArraying algal uptake from nitrate pool (unitless) + + Args: + ApUptakeFr_NH4: Fraction of actual xr.DataArraying algal uptake from ammonia pool + """ + + return 1 - ApUptakeFr_NH4 + + +@numba.njit +def AbUptakeFr_NH4( + use_NH4: bool, + use_NO3: bool, + use_Balgae: bool, + PNb: xr.DataArray, + NH4: xr.DataArray, + NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate AbUptakeFr_NH4: Fraction of actual benthic algal uptake from ammonia pool + + Args: + use_NH4: use ammonium module (unitless) + use_NO3: use nitrate module (unitless) + use_Balgae: use benthic algae module (unitless) + PNb: NH4 preference factor benthic algae (unitless) + NH4: Ammonium water concentration (mg-N/L) + NO3: Nitrate water concentration (mg-N/L) + """ + AbUptakeFr_NH4 = 0 + AbUptakeFr_NH4 = xr.where(use_NH4 and not use_NO3, 1.0, + xr.where(not use_NH4 and use_NO3, 0.0, + xr.where(not use_NH4 and not use_NO3, 0.5, + xr.where(use_Balgae and use_NH4 and use_NO3, (PNb * NH4) / (PNb * NH4 + (1.0 - PNb) * NO3), "NaN")))) + + AbUptakeFr_NH4 = xr.where(math.isnan(AbUptakeFr_NH4),PNb,AbUptakeFr_NH4) + + return AbUptakeFr_NH4 + + +@numba.njit +def AbUptakeFr_NO3( + AbUptakeFr_NH4: xr.DataArray +) -> xr.DataArray: + """Calculate AbUptakeFr_NO3: Fraction of actual benthic algal uptake from nitrate pool (unitless) + + Args: + AbUptakeFr_NH4: Fraction of actual benthic algal uptake from ammonia pool + """ + + return 1 - AbUptakeFr_NH4 + +@numba.njit +def OrgN_NH4_Decay( + kon_tc: xr.DataArray, + OrgN: xr.DataArray, + use_OrgN: bool +) -> xr.DataArray: + """Calculate OrgN_NH4: OrgN -> NH4 (mg-N/L/d) + + Args: + kon_tc: Decay rate of organic nitrogen to nitrate with temperature correction (1/d), + OrgN: Concentration of organic nitrogen (mg-N/L) + use_OrgN: true/false use organic nitrogen (t/f) + """ + + return xr.where(use_OrgN, kon_tc * OrgN,0) + +@numba.njit +def OrgN_Settling( + vson: xr.DataArray, + depth: xr.DataArray, + OrgN: xr.DataArray, +) -> xr.DataArray: + """Calculate OrgN_Settling: OrgN -> bed (mg-N/L/d) + + Args: + vson: Organic nitrogen settling velocity (m/d) + depth: water depth (m) + """ + + return vson / depth * OrgN + +@numba.njit +def ApDeath_OrgN( + use_Algae: bool, + rna: xr.DataArray, + ApDeath: xr.DataArray, +) -> xr.DataArray: + """Calculate ApDeath_OrgN: Algae -> OrgN (mg-N/L/d) + + Args: + use_Algae: true/false to use algae module (unitless) + rna: Algal N: Chla ratio (mg-N/ug-Chla) + ApDeath: Algal death rate (ug-Chla/L/d) + """ + + return xr.where(use_Algae, rna * ApDeath, 0.0) + +@numba.njit +def AbDeath_OrgN( + use_Balgae: bool, + rnb: xr.DataArray, + Fw: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + AbDeath: xr.DataArray, +) -> xr.DataArray: + """Calculate ApDeath_OrgN: Algae -> OrgN (mg-N/L/d) + + Args: + use_Balgae: true/false to use benthic algae module (unitless), + rnb: Benthic algal N: Benthic Algal Dry Weight (mg-N/mg-D) + Fw: Fraction benthic algae mortality into water column (unitless) + Fb: Fraction of bottom area for benthic algae (unitless) + depth: water depth (m) + AbDeath: Benthic algal death rate (g/m^2/d) + """ + + return xr.where(use_Balgae, rnb * Fw * Fb * AbDeath / depth, 0.0) + +@numba.njit +def dOrgNdt( + use_OrgN: bool, + ApDeath_OrgN: xr.DataArray, + AbDeath_OrgN: xr.DataArray, + OrgN_NH4_Decay: xr.DataArray, + OrgN_Settling: xr.DataArray, + +) -> xr.DataArray: + """Calculate dOrgNdt: Change in Organic Nitrogen (mg-N/L/d) + + Args: + use_OrgN: true/false to use organic nitrogen module (unitless) + ApDeath_OrgN: Algae -> OrgN (mg-N/L/d) + AbDeath_OrgN: Benthic Algae -> OrgN (mg-N/L/d) + OrgN_NH4_Decay: OrgN -> NH4 (mg-N/L/d) + OrgN_Settling: OrgN -> bed (mg-N/L/d) + + """ + + return xr.where(use_OrgN, ApDeath_OrgN + AbDeath_OrgN - OrgN_NH4_Decay - OrgN_Settling,0) + +@numba.njit +def OrgN( + OrgN: xr.DataArray, + dOrgNdt: xr.DataArray, + timestep: xr.DataArray, + +) -> xr.DataArray: + """Calculate OrgN: New concentration OrgN (mg-N/L) + + Args: + OrgN: Concentration of organic nitrogen (mg-N/L) + dOrgNdt: Change in Organic Nitrogen (mg-N/L/d) + timestep: current iteration timestep (d) + + """ + + return OrgN + dOrgNdt * timestep + +@numba.njit +def NitrificationInhibition( + use_DOX: bool, + KNR: xr.DataArray, + DOX: xr.DataArray, + +) -> xr.DataArray: + """Calculate NitrificationInhibition: Nitrification Inhibitation (limits nitrification under low DO conditions) + + Args: + KNR: Oxygen inhabitation factor for nitrification (mg-O2/L), + DOX: Dissolved oxygen concentration (mg-O2/L), + use_DOX: true/false to use dissolve oxygen module (unitless), + + """ + + return xr.where (use_DOX, 1.0 - math.exp(-KNR * DOX), 1.0) + +@numba.njit +def NH4_Nitrification( + NitrificationInhibition: xr.DataArray, + NH4: xr.DataArray, + knit_tc: xr.DataArray, + use_NH4: xr.DataArray + +) -> xr.DataArray: + """Calculate NH4_Nitrification: NH4 -> NO3 Nitrification (mg-N/L/day) + + Args: + NitrificationInhibition: Nitrification Inhibitation (limits nitrification under low DO conditions) + knit_tc: Nitrification rate ammonia decay NH4 to NO3 temperature correction (1/d). + NH4: Ammonium concentration (mg-N/L), + """ + + return xr.where(use_NH4,NitrificationInhibition * knit_tc * NH4,0) + +@numba.njit +def NH4fromBed( + use_SedFlux: bool, + JNH4: xr.DataArray, + depth: xr.DataArray, + rnh4_tc: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4fromBed: bed -> NH4 (diffusion) (mg-N/L/day) + + Args: + use_SedFlux: true/false to use sediment flux module (unitless), + depth: water depth (m), + JNH4: Sediment water flux of ammonium (g-N/m^2/d), + rnh4_tc: Sediment release rate of NH4 temperature correction(1/d). + + """ + + return xr.where(use_SedFlux, JNH4 / depth, rnh4_tc / depth) + +@numba.njit +def NH4_ApRespiration( + use_Algae: bool, + ApRespiration: xr.DataArray, + rna: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4_ApRespiration: Floating algae -> NH4 (mg-N/L/day) + + Args: + use_Algae: true/false to use algae module (unitless), + rna: Algal N: Chla ratio (mg-N/ug-Chla), + ApRespiration: Algal respiration rate (ug-Chla/L/d), + """ + + return xr.where (use_Algae, rna * ApRespiration, 0.0) + +@numba.njit +def NH4_ApGrowth( + use_Algae: bool, + ApGrowth: xr.DataArray, + rna: xr.DataArray, + ApUptakeFr_NH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4_ApGrowth: NH4 -> Floating algae (mg-N/L/day) + + Args: + use_Algae: true/false to use algae module (unitless), + rna: Algal N: Chla ratio (mg-N/ug-Chla), + ApGrowth: Algal growth rate (ug-Chla/L/d), + ApUptakeFr_NH4: Fraction of actual xr.DataArraying algal uptake from ammonia pool + """ + + return xr.where(use_Algae, ApUptakeFr_NH4 * rna * ApGrowth, 0.0) + +@numba.njit +def NH4_AbRespiration( + use_Balgae: bool, + rnb: xr.DataArray, + AbRespiration: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4_AbRespiration: Benthic algae -> NH4 (mg-N/L/day) + + Args: + use_Balgae: true/false to use benthic algae module (unitless), + rnb: xr.DataArray, + AbRespiration: Benthic algal respiration rate (g/m^2/d), + """ + # TODO changed the calculation for respiration from the inital FORTRAN due to conflict with the reference guide + + return xr.where(use_Balgae, rnb * AbRespiration, 0.0 ) + +@numba.njit +def NH4_AbGrowth( + use_Balgae: bool, + rnb: xr.DataArray, + AbGrowth: xr.DataArray, + AbUptakeFr_NH4: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4_AbGrowth: NH4 -> Benthic Algae (g-N/L/day) + + Args: + use_Balgae: true/false to use benthic algae module (unitless), + rnb: xr.DataArray, + AbGrowth: Benthic alga growth rate (g/m^2/d), + depth: water depth (m), + Fb: Fraction of bottom area for benthic algae (unitless), + AbUptakeFr_NH4: Fraction of actual benthic algal uptake from ammonia pool + """ + + return xr.where(use_Balgae,(AbUptakeFr_NH4 * rnb * Fb * AbGrowth) / depth, 0.0 ) + +@numba.njit +def dNH4dt( + use_NH4: bool, + NH4_Nitrification: xr.DataArray, + NH4fromBed: xr.DataArray, + NH4_ApRespiration: xr.DataArray, + NH4_ApGrowth: xr.DataArray, + NH4_AbRespiration: xr.DataArray, + NH4_AbGrowth: xr.DataArray, + + +) -> xr.DataArray: + """Calculate dNH4dt: Change in Ammonium (mg-N/L) + + Args: + use_OrgN: true/false to use organic nitrogen module (unitless), + use_NH4: true/false to use ammonium module (unitless), + NH4_Nitrification: NH4 -> NO3 Nitrification (mg-N/L/day) + NH4fromBed: bed -> NH4 (diffusion) (mg-N/L/day) + NH4_ApRespiration: Floating algae -> NH4 (mg-N/L/day) + NH4_ApGrowth: NH4 -> Floating algae (mg-N/L/day) + NH4_AbRespiration: Benthic algae -> NH4 (mg-N/L/day) + NH4_AbGrowth: NH4 -> Benthic Algae (g-N/L/day) + + Ammonia Nitrogen (NH4) (mg-N/day*L) + dNH4/dt = OrgN_NH4_Decay + (OrgN -> NH4) + - NH4 Oxidation (NH4 -> NO3) + - NH4AlgalUptake (NH4 -> xr.DataArraying Algae) + + Benthos NH4 (Benthos -> NH4) + - Benthic Algae Uptake (NH4 -> Benthic Algae) + + """ + + return xr.where(use_NH4, OrgN_NH4_Decay - NH4_Nitrification + NH4fromBed + NH4_ApRespiration - NH4_ApGrowth + NH4_AbRespiration - NH4_AbGrowth, 0.0) + +@numba.njit +def NH4( + NH4: xr.DataArray, + dNH4dt: xr.DataArray, + timestep: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH4: New concentration NH4 (mg-N/L) + + Args: + NH4: Concentration of NH4 (mg-N/L) + dNH4dt: Change in NH4 (mg-N/L/d) + timestep: current iteration timestep (d) + + """ + + return NH4 + dNH4dt * timestep + +@numba.njit +def NO3_Denit( + use_DOX: bool, + DOX: xr.DataArray, + KsOxdn: xr.DataArray, + kdnit_tc: xr.DataArray, + NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO3_Denit: NO3 -> Loss (mg-N/L/day) + + Args: + use_DOX: true/false to use dissolve oxygen module (unitless), + KsOxdn: Half-saturation oxygen inhibition constant for denitrification (mg-O2/L) + DOX: Dissolved oxygen concentration (mg-O2/L), + NO3: Nitrate concentration (mg-N/L), + kdnit_tc: Denitrification rate temperature correction (1/d) + + """ + return xr.where(use_DOX,xr.where(math.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3),kdnit_tc * NO3,(1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3),0.0) + +@numba.njit +def NO3_BedDenit( + use_SedFlux: bool, + JNO3: xr.DataArray, + depth: xr.DataArray, + vno3_tc: xr.DataArray, + NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO3_BedDenit: Sediment denitrification (mg-N/L/day) + + Args: + use_SedFlux: true/false to use sediment flux module (unitless), + depth: water depth (m), + NO3: Nitrate concentration (mg-N/L), + JNO3: Sediment water flux of nitrate (g-N/m^2/d), + vno3_tc: Sediment denitrification velocity temperature correction (m/d) + + """ + + return xr.where(use_SedFlux, JNO3 / depth,vno3_tc * NO3 / depth) + +@numba.njit +def NO3_ApGrowth( + use_Algae: bool, + ApUptakeFr_NO3: xr.DataArray, + rna: xr.DataArray, + ApGrowth: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO3_ApGrowth: NO3 -> Floating algae (mg-N/L/day) + + Args: + use_Algae: true/false to use algae module (unitless), + rna: Algal N: Chla ratio (mg-N/ug-Chla), + ApGrowth: Algal growth rate (ug-Chla/L/d), + ApUptakeFr_NO3: Fraction of actual algal uptake from nitrate pool (unitless) + + + """ + + return xr.where(use_Algae, ApUptakeFr_NO3 * rna * ApGrowth, 0.0) + +@numba.njit +def NO3_AbGrowth( + use_Balgae: bool, + AbUptakeFr_NO3: xr.DataArray, + rnb: xr.DataArray, + Fb: xr.DataArray, + AbGrowth: xr.DataArray, + depth: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO3_AbGrowth: NO3 -> Benthic Algae (g-N/L/day) + + Args: + use_Balgae: true/false to use benthic algae module (unitless), + depth: water depth (m), + rnb: Benthic algal N: Benthic Algal Dry Weight (mg-N/mg-D), + Fb: Fraction of bottom area for benthic algae (unitless), + AbGrowth: Benthic alga growth rate (g/m^2/d), + AbUptakeFr_NO3: Fraction of actual benthic algal uptake from nitrate pool (unitless) + """ + + return xr.where(use_Balgae, (AbUptakeFr_NO3 * rnb * Fb * AbGrowth) / depth, 0.0) + + +@numba.njit +def dNO3dt( + use_NO3: bool, + NH4_Nitrification: xr.DataArray, + NO3_Denit: xr.DataArray, + NO3_BedDenit: xr.DataArray, + NO3_ApGrowth: xr.DataArray, + NO3_AbGrowth: xr.DataArray, + +) -> xr.DataArray: + """Calculate dNO3dt: Change in nitrate (mg-N/L) + + Args: + use_NH4: true/false to use ammonium module (unitless), + use_NO3: true/false to use nitrate module (unitless), + NH4_Nitrification: NH4 -> NO3 Nitrification (mg-N/L/day) + NO3_Denit: NO3 -> Loss (mg-N/L/day), + NO3_BedDenit: Sediment denitrification (mg-N/L/day) + NO3_ApGrowth: NO3 -> Floating algae (mg-N/L/day) + NO3_AbGrowth: NO3 -> Benthic Algae (g-N/L/day) + + Nitrite Nitrogen (NO3) (mg-N/day*L) + dNO3/dt = NH4 Oxidation (NH4 -> NO3) + - NO3 Sediment Denitrification + - NO3 Algal Uptake (NO3-> xr.DataArraying Algae) + - NO3 Benthic Algal Uptake (NO3-> Benthic Algae) + + """ + + + return xr.where(use_NO3, NH4_Nitrification - NO3_Denit - NO3_BedDenit - NO3_ApGrowth - NO3_AbGrowth ,0) + +@numba.njit +def NO3( + NO3: xr.DataArray, + dNO3dt: xr.DataArray, + timestep: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO3: New concentration NO# (mg-N/L) + + Args: + NO3: Concentration of NO3 (mg-N/L) + dNO3dt: Change in NO3(mg-N/L/d) + timestep: current iteration timestep (d) + + """ + + return NO3 + dNO3dt * timestep + + +@numba.njit +def DIN( + use_NH4: bool, + use_NO3: bool, + NH4: xr.DataArray, + NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIN: Dissolve inorganic nitrogen (mg-N/L) + + Args: + use_NH4: true/false to use ammonium module (unitless), + use_NO3: true/false to use nitrate module (unitless), + NH4: Ammonium concentration (mg-N/L), + NO3: Nitrate concentration (mg-N/L), + """ + DIN = 0.0 + DIN = xr.where(use_NH4, DIN + NH4,DIN) + DIN = xr.where(use_NO3, DIN + NO3, DIN) + + return DIN + + +@numba.njit +def TON( + use_OrgN: bool, + use_Algae: bool, + OrgN: xr.DataArray, + rna: xr.DataArray, + Ap: xr.DataArray + +) -> xr.DataArray: + """Calculate TON: Total organic nitrogen (mg-N/L) + + Args: + use_OrgN: true/false to use organic nitrogen module (unitless), + use_Algae: true/false to use algae module (unitless), + OrgN: Organic nitrogen concentration (mg-N/L), + rna: Algal N: Chla ratio (mg-N/ug-Chla), + Ap: Algae water concentration (ug-Chla/L) + + """ + TON = 0.0 + TON = xr.where(use_OrgN, TON + OrgN, TON) + TON = xr.where(use_Algae, TON + rna * Ap, TON) + + return TON + + +@numba.njit +def TKN( + use_NH4: bool, + NH4: xr.DataArray, + TON: xr.DataArray + +) -> xr.DataArray: + """Calculate TKN: Total kjeldhl (mg-N/L) + + Args: + use_NH4: true/false to use organic nitrogen module (unitless), + NH4: Ammonium concentration (mg-N/L) + TON: Total organic nitrogen (mg-N/L) + """ + TKN = 0.0 + TKN = xr.where(use_NH4, TKN + NH4, TKN) + + return TKN + TON + + +@numba.njit +def TN( + DIN: xr.DataArray, + TON: xr.DataArray, + +) -> xr.DataArray: + """Calculate TN: Total nitrogen (mg-N/L) + + Args: + DIN: Dissolve inorganic nitrogen (mg-N/L) + TON: Total organic nitrogen (mg-N/L) + """ + + return DIN + TON + +################################### From phosphorus +@numba.njit +def kop_tc( + TwaterC : xr.DataArray, + kop_20: xr.DataArray +) -> xr.DataArray : + + """Calculate kop_tc: Decay rate of organic P to DIP temperature correction (1/d). + + Args: + TwaterC: Water temperature (C) + kop_20: Decay rate of organic P to DIP at 20C (1/d) + """ + + return arrhenius_correction(TwaterC, kop_20, 1.047) + +@numba.njit +def rpo4_tc( + TwaterC : xr.DataArray, + rpo4_20: xr.DataArray +) -> xr.DataArray : + + """Calculate rpo4_tc: Benthic sediment release rate of DIP temperature correction(g-P/m2/d). + + Args: + TwaterC: Water temperature (C) + kop_20: Benthic sediment release rate of DIP at 20C (1/d) + """ + + return arrhenius_correction(TwaterC, rpo4_20, 1.074) + +@numba.njit +def OrgP_DIP_decay( + kop_tc : xr.DataArray, + OrgP: xr.DataArray, + use_OrgP: bool, +) -> xr.DataArray : + + """Calculate OrgP_DIP: organic phosphorus decay to dissolve inorganic phosphorus (mg-P/L/d). + + Args: + kop_tc: Decay rate of organic P to DIP temperature correction (1/d) + OrgP: Organic phosphorus concentration (mg-P/L) + use_OrgP: true/false use organic phosphorus (t/f) + """ + return xr.where(use_OrgP,kop_tc * OrgP,0) + +@numba.njit +def OrgP_Settling( + vsop : xr.DataArray, + depth: xr.DataArray, + OrgP: xr.DataArray, +) -> xr.DataArray : + + """Calculate OrgP_Settling: organic phosphorus settling to sediment (mg-P/L/d). + + Args: + vsop: Organic phosphorus settling velocity (m/d) + depth: water depth (m) + OrgP: Organic phosphorus concentration (mg-P/L) + """ + return (vsop / depth) * OrgP + +@numba.njit +def ApDeath_OrgP( + rpa : xr.DataArray, + ApDeath: xr.DataArray, + use_Algae: bool, +) -> xr.DataArray : + + """Calculate ApDeath_OrgP: Algal death turning into organic phosphorus (mg-P/L/d). + + Args: + rpa: Algal P : Chla ratio (mg-P/ug-Chla) + ApDeath: Algal death rate (ug-Chla/L/d) + use_Algae: true/false to use algae module (T/F) + + """ + + return xr.where(use_Algae, rpa * ApDeath,0) + +@numba.njit +def AbDeath_OrgP( + rpb : xr.DataArray, + AbDeath: xr.DataArray, + Fw: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_Balgae: bool +) -> xr.DataArray : + + """Calculate AbDeath_OrgP: Benthic algal death turning into organic phosphorus (mg-P/L/d). + + Args: + rpb : Benthic algal P: Benthic algal dry (mg-P/mg-D) + AbDeath: Benthic algal death rate (g/m^2/d) + Fw: Fraction benthic algal death to water column (unitless) + Fb: Fraction bottom area avalible for benthic algae (unitless) + depth: water depth (m) + use_Balgae: true/false use benthic algae module (t/f) + + """ + + return xr.where(use_Balgae, (rpb * Fw *Fb * AbDeath) / depth,0) + +@numba.njit +def dOrgPdt( + ApDeath_OrgP : xr.DataArray, + AbDeath_OrgP: xr.DataArray, + OrgP_DIP_decay: xr.DataArray, + OrgP_Settling: xr.DataArray, + use_OrgP: bool, +) -> xr.DataArray : + """Calculate dOrgPdt: change in organic phosphorus concentration (mg-P/L/d). + + Args: + ApDeath_OrgP: Algal death turns into organic phosphrous + AbDeath_OrgP: Benthic algal death turns into organic phosphrous + OrgP_DIP_decay: Organic phosphrous decaying into dissolve inorganic phosphrous + OrgP_Settling: Organic phosphrous settling into sediment + use_OrgP: true/false to use organic phosphorus module (true/false) + use_Algae: true/false to use algae module (true/false) + use_Balgae: true/false to use benthic algae module (true/false) + """ + + return xr.where(use_OrgP, -OrgP_DIP_decay-OrgP_Settling + ApDeath_OrgP + AbDeath_OrgP, 0) + +#TODO will this be a problem if use_SedFlux is False +def DIPfromBed_SedFlux( + use_SedFlux: bool, + JDIP: xr.DataArray, + depth:xr.DataArray, + rpo4_tc: xr.DataArray, +) -> xr.DataArray : + """Calculate DIPfromBed_SedFlux: Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules (mg-P/L/d). + + Args: + use_SedFlux: true/false to use the sediment flux module (unitless) + JDIP: Sediment-water flux of phosphate (g-P/m^2/d) + depth: water depth (m) + rpo4_tc: Benthic sediment release rate of DIP temperature correction(g-P/m2/d) + """ + return xr.where(use_SedFlux, JDIP / depth, rpo4_tc/depth) + +@numba.njit +def DIPfromBed( + depth:xr.DataArray, + rpo4_tc: xr.DataArray, +) -> xr.DataArray : + """Calculate DIPfromBed: Dissolved Organic Phosphorus coming from Bed calculated without a SedFlux module (mg-P/L/d). + + Args: + depth: water depth (m) + rpo4_tc: Benthic sediment release rate of DIP temperature correction(g-P/m2/d) + """ + return rpo4_tc / depth + +#TODO calcuate fdp? +@numba.njit +def TIP_Settling( + vs: xr.DataArray, + depth: xr.DataArray, + fdp: xr.DataArray, + TIP: xr.DataArray +) -> xr.DataArray : + + """Calculate TIP_Settling: Total inorganic phosphorus settling from water to bed (mg-P/L/d). + + Args: + vs: Sediment settling velocity (m/d) + depth: water depth (m) + fdp: Fraction phosphorus dissolved (unitless) + TIP: Total inorganic phosphorus water concentration (mg-P/L) + """ + return vs / depth * (1.0 - fdp) * TIP + +@numba.njit +def DIP_ApRespiration( + rpa: xr.DataArray, + ApRespiration: xr.DataArray, + use_Algae: bool + +) -> xr.DataArray : + """Calculate DIP_ApRespiration: Dissolved inorganic phosphorus released from algal respiration (mg-P/L/d). + + Args: + rpa: Algal P : Chla ratio (mg-P/ug-Chla) + ApRespiration: Algal respiration rate (ug-Chla/L/d) + use_Algae: true/false to use algae module (t/f) + """ + return xr.where(use_Algae, rpa * ApRespiration,0) + +@numba.njit +def DIP_ApGrowth( + rpa: xr.DataArray, + ApGrowth: xr.DataArray, + use_Algae: bool + +) -> xr.DataArray : + """Calculate DIP_ApGrowth: Dissolved inorganic phosphorus consumed for algal growth (mg-P/L/d). + + Args: + rpa: Algal P : Chla ratio (mg-P/ug-Chla) + ApGrowth: Algal growth rate (ug-Chla/L/d) + use_Algae: true/false to use algae module (t/f) + """ + return xr.where(use_Algae, rpa * ApGrowth,0) + +@numba.njit +def DIP_AbRespiration( + rpb: xr.DataArray, + AbRespiration: xr.DataArray, + use_Balgae: bool + +) -> xr.DataArray : + """Calculate DIP_AbRespiration: Dissolved inorganic phosphorus released for benthic algal respiration (mg-P/L/d). + + Args: + rpb: Benthic algal P : Benthic algal dry ratio (mg-P/mg-D) + AbRespiration: Benthic algal respiration rate (g/m^2/d) + use_Blgae: true/false to use benthic algae module (t/f) + """ + return xr.where(use_Balgae, rpb * AbRespiration,0) + +@numba.njit +def DIP_AbGrowth( + rpb: xr.DataArray, + AbGrowth: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_Balgae: bool + +) -> xr.DataArray : + """Calculate DIP_AbGrowth: Dissolved inorganic phosphorus consumed for benthic algal growth (mg-P/L/d). + + Args: + rpb: Benthic algal P : Benthic algal dry ratio (mg-P/mg-D) + AbGrowth: Benthic algal growth rate (g/m^2/d) + Fb: Fraction of bottom area available for benthic algal (unitless) + depth: water depth (m) + use_Balgae: true/false to use benthic algae module (t/f) + """ + return xr.where(use_Balgae, rpb * Fb * AbGrowth / depth,0) + +@numba.njit +def dTIPdt( + OrgP_DIP_decay: xr.DataArray, + TIP_Settling: xr.DataArray, + DIPfromBed: xr.DataArray, + DIP_ApRespiration: xr.DataArray, + DIP_ApGrowth: xr.DataArray, + DIP_AbRespiration: xr.DataArray, + DIP_AbGrowth: xr.DataArray, + use_TIP: bool, + +) -> xr.DataArray : + + """Calculate dTIPdt: Change in dissolved inorganic phosphorus water concentration (mg-P/L/d). + + Args: + OrgP_DIP_decay: Total organic phosphorus decaying to dissolved inorganic phosphrous (mg-P/L/d), + TIP_Settling: Total inorganic phosphorus settling from water to bed (mg-P/L/d), + DIPfromBed_NoSedFlux: Dissolved Organic Phosphorus coming from Bed calculated without SedFlux modules (mg-P/L/d), + DIPfromBed_SedFlux: Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules (mg-P/L/d), + DIP_ApRespiration: Dissolved inorganic phosphorus released from algal respiration (mg-P/L/d), + DIP_ApGrowth: Dissolved inorganic phosphorus consumed for algal growth (mg-P/L/d), + DIP_AbRespiration: Dissolved inorganic phosphorus released for benthic algal respiration (mg-P/L/d), + DIP_AbGrowth: Dissolved inorganic phosphorus consumed for benthic algal growth (mg-P/L/d), + use_TIP: true/false to use total inorganic phosphorus module (true/false), + + + dTIP/dt = OrgP Decay (OrgP -> DIP) + - DIP AlgalUptake (DIP -> xr.DataArraying Algae) + - DIP BenthicAlgae Uptake (DIP -> xr.DataArraying Algae) + - TIP Settling (TIP -> bed) + + DIP From Benthos (Benthos -> DIP) + """ + + return xr.where(use_TIP, - TIP_Settling + DIPfromBed + OrgP_DIP_decay + DIP_ApRespiration - DIP_ApGrowth + DIP_AbRespiration - DIP_AbGrowth, 0) + + +@numba.njit +def TIP( + TIP: xr.DataArray, + dTIPdt: xr.DataArray, + timestep: xr.DataArray + +) -> xr.DataArray : + """Calculate TIP: New total inorganic phosphorus (mg-P/L). + + Args: + dTIPdt: Change in total inorganic phosphorus (mg-P/L/d) + TIP: Total inorganic phosphorus water concentration (mg-P/L), + timestep: current iteration timestep (d) + """ + return TIP + dTIPdt * timestep + +@numba.njit +def OrgP( + OrgP: xr.DataArray, + dOrgPdt: xr.DataArray, + timestep: xr.DataArray + +) -> xr.DataArray : + """Calculate OrgP: New total organic phosphorus (mg-P/L). + + Args: + dOrgPdt: Change in total organic phosphorus (mg-P/L/d) + OrgP: Total organic phosphorus water concentration (mg-P/L), + timestep: current iteration timestep (d) + """ + return OrgP + dOrgPdt * timestep + +@numba.njit +def TOP( + use_OrgP: bool, + OrgP: xr.DataArray, + use_Algae: bool, + rpa: xr.DataArray, + Ap: xr.DataArray + +) -> xr.DataArray : + """Calculate TOP: Total organic phosphorus (mg-P/L). + + Args: + use_OrgP: true/false to use organic phosphorus module (true/false), + OrgP: New organic phosphorus water concentration (mg-P/L), + use_Algae: true/false to use algae module (true/false), + rpa: Algal P: Chla ratio (mg-P/ug-Chla), + Ap: Algal water concentration (ug-Chla/L) + """ + TOP = 0.0 + TOP = xr.where(use_OrgP, TOP + OrgP,TOP) + TOP = xr.where(use_Algae, TOP + rpa*Ap, TOP) + + return TOP + + +@numba.njit +def TP( + use_TIP: bool, + TOP: xr.DataArray, + TIP: xr.DataArray + +) -> xr.DataArray : + """Calculate TP: Total phosphorus (mg-P/L). + + Args: + use_TIP: true/false to use total inorganic phosphorus module (true/false), + TIP: New total inorganic phosphorus water concentration (mg-P/L), + TOP: Total organic phosphorus water concentration (mg-P/L) + """ + TP = TOP + TP = xr.where(use_TIP,TP + TIP,TP) + +@numba.njit +def DIP( + fdp: xr.DataArray, + TIP: xr.DataArray + +) -> xr.DataArray : + """Calculate DIP: Dissolve inorganich phosphorus (mg-P/L). + + Args: + fdp: fraction P dissolved + TIP: New total inorganic phosphorus water concentration (mg-P/L), + """ + return TIP * fdp + + +################################### From POM +@numba.njit +def kpom_tc( + TwaterC: float, + kpom_20: float, +) -> float: + """Calculate the temperature adjusted POM dissolution rate (1/d) + + Args: + TwaterC: Water temperature in Celsius + kpom_20: POM dissolution rate at 20 degrees Celsius (1/d) + """ + return arrhenius_correction(TwaterC, kpom_20, 1.047) + + +def POM_algal_settling( + Ap: xr.DataArray, + vsap: xr.DataArray, + rda: xr.DataArray, + depth: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculates the particulate organic matter concentration change due to algal mortality + + Args: + Ap: Algae concentration (mg/L) + vsap: Algal settling velocity (m/d) + rda: Ratio of algal biomass to chlorophyll-a + depth: Depth of water in computation cell (m) + use_Algae: Option to consider algal kinetics + """ + da: xr.DataArray = xr.where(use_Algae == True, vsap * Ap * rda / depth, 0) + + return da + + +@numba.njit +def POM_dissolution( + POM: xr.DataArray, + kpom_tc: xr.DataArray +) -> xr.DataArray: + """Calculates the particulate organic matter concentration change due to POM dissolution + + Args: + POM: Concentration of particulate organic matter (mg/L) + kpom_tc: POM dissolution rate corrected for temperature (1/d) + """ + + return POM * kpom_tc + + +def POM_POC_settling( + POC: xr.DataArray, + vsoc: xr.DataArray, + depth: xr.DataArray, + focm: xr.DataArray, + use_POC: xr.DataArray +) -> xr.DataArray: + """Calculates particulate organic matter concentration change due to POM settling + + Args: + POC: Concentration of particulate organic carbon (mg/L) + vsoc: POC settling velocity (m/d) + depth: Depth of water (m) + fcom: Fraction of carbon in organic matter (mg-C/mg-D) + use_POC: Option to consider particulate organic carbon + """ + da: xr.DataArray = xr.where(use_POC == True, vsoc * POC / depth / focm, 0) + + return da + + +def POM_benthic_algae_mortality( + Ab: xr.DataArray, + kdb_tc: xr.DataArray, + Fb: xr.DataArray, + Fw: xr.DataArray, + depth: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculates particulate organic matter concentration change due to benthic algae mortality + + Args: + Ab: Benthic algae concentration (mg/L) + kdb_tc: Benthic algae death rate (1/d) + Fb: Fraction of bottom area available for benthic algae growth + Fw: Fraction of benthic algae mortality into water column + depth: Depth of water in computation cell (m) + use_Balgae: Option for considering benthic algae in DOC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Balgae == True, Ab * kdb_tc * Fb * (1 - Fw) / depth, 0) + + return da + + +@numba.njit +def POM_burial( + vb: xr.DataArray, + POM: xr.DataArray, + depth: xr.DataArray +) -> xr.DataArray: + """Calculates particulate organic matter concentration change due to POM burial in the sediments + + Args: + vb: Velocity of burial (m/d) + POM: POM concentration (mg/L) + depth: Depth of water in computation cell (m) + """ + return vb * POM / depth + + +@numba.njit +def dPOMdt( + POM_algal_settling: xr.DataArray, + POM_dissolution: xr.DataArray, + POM_POC_settling: xr.DataArray, + POM_benthic_algae_mortality: xr.DataArray, + POM_burial: xr.DataArray, +) -> xr.DataArray: + """Calculates the concentration change of POM for one timestep + + Args: + POM_algal_settling: POM concentration change due to algal settling (mg/L/d) + POM_dissolution: POM concentration change due to dissolution (mg/L/d) + POM_POC_settling: POM concentration change due to POC settling (mg/L/d) + POM_benthic_algae_mortality: POM concentration change due to benthic algae mortality (mg/L/d) + POM_burial: POM concentration change due to burial (mg/L/d) + """ + return POM_algal_settling - POM_dissolution + POM_POC_settling + POM_benthic_algae_mortality - POM_burial + + +@numba.njit +def POM( + dPOMdt: xr.DataArray, + POM: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Computes updated particulate organic matter concentration (mg/L) + + Args: + dPOMdt: Change in POM concentration over timestep (mg/L/d) + POM: POM concentration from previous timestep (mg/L) + timestep: Current iteration timestep (d) + """ + return POM + dPOMdt * timestep + + +################################## From CBOD +@numba.njit +def kbod_tc( + TwaterC: xr.DataArray, + kbod_20: xr.DataArray, +) -> xr.DataArray: + """Calculate the temperature adjusted CBOD oxidation rate (1/d) + + Args: + TwaterC: water temperature in Celsius + kbod_20: CBOD oxidation rate at 20 degrees Celsius (1/d) + """ + + kbod_tc = arrhenius_correction(TwaterC, kbod_20, 1.047) + return kbod_tc + + +@numba.njit +def ksbod_tc( + TwaterC: xr.DataArray, + ksbod_20: xr.DataArray, +) -> xr.DataArray: + """Calculate the temperature adjusted CBOD sedimentation rate (m/d) + + Args: + TwaterC: water temperature in Celsius + ksbod_20: CBOD sedimentation rate at 20 degrees Celsius (m/d) + """ + + ksbod_tc = arrhenius_correction(TwaterC, ksbod_20, 1.024) + return ksbod_tc + + + +def CBOD_oxidation( + DOX: xr.DataArray, + CBOD: xr.DataArray, + kbod_tc: xr.DataArray, + KsOxbod: xr.DataArray, + use_DOX: xr.DataArray +) -> xr.DataArray: + """Calculates CBOD oxidation + + Args: + DOX: Dissolved oxygen concentration (mg-O2/L) + CBOD: Carbonaceous biochemical oxygen demand (mg-O2/L) + kbod_tc: Temperature adjusted CBOD oxidation rate (1/d) + KsOxbod: Half-saturation oxygen attenuation for CBOD oxidation (mg-O2/L) + use_DOX: Option to consider DOX concentration in calculation of CBOD oxidation + """ + da: xr.DataArray = xr.where(use_DOX == True, (DOX / (KsOxbod + DOX)) * kbod_tc * CBOD, kbod_tc * CBOD) + + return da + + +@numba.njit +def CBOD_sedimentation( + CBOD: xr.DataArray, + ksbod_tc: xr.DataArray +) -> xr.DataArray: + """Calculates CBOD sedimentation for each group + + Args: + CBOD: CBOD concentration (mg-O2/L) + ksbod_tc: Temperature adjusted sedimentation rate (m/d) + """ + + CBOD_sedimentation = CBOD * ksbod_tc + return CBOD_sedimentation + + +@numba.njit +def dCBODdt( + CBOD_oxidation: xr.DataArray, + CBOD_sedimentation: xr.DataArray +) -> xr.DataArray: + """Computes change in each CBOD group for a given timestep + + Args: + CBOD_oxidation: CBOD concentration change due to oxidation (mg/L/d) + CBOD_sedimentation: CBOD concentration change due to sedimentation (mg/L/d) + """ + return - CBOD_oxidation - CBOD_sedimentation + + +@numba.njit +def CBOD( + CBOD: xr.DataArray, + dCBODdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Calculates new CBOD concentration for next timestep + + Args: + CBOD: CBOD concentration from previous timestep (mg/L) + dCBODdt: CBOD concentration change for current timestep (mg/L/d) + timestep: current iteration timestep (d) + """ + return CBOD + dCBODdt * timestep + +############################### From Carbon + +@numba.njit +def kpoc_tc( + TwaterC: xr.DataArray, + kpoc_20: xr.DataArray, +) -> xr.DataArray: + """Calculate the temperature adjusted POC hydrolysis rate (/d) + + Args: + TwaterC: Water temperature in Celsius + kpoc_20: POC hydrolysis rate at 20 degrees Celsius (1/d) + """ + return arrhenius_correction(TwaterC, kpoc_20, 1.047) + + +@numba.njit +def POC_hydrolysis( + kpoc_tc: xr.DataArray, + POC: xr.DataArray, +) -> xr.DataArray: + """Calculate the POC concentration change due to hydrolysis for a given timestep + + Args: + kpoc_tc: POC hydrolysis rate at given water temperature (1/d) + POC: POC concentration (mg/L) + """ + return kpoc_tc * POC + + +@numba.njit +def POC_settling( + vsoc: xr.DataArray, + depth: xr.DataArray, + POC: xr.DataArray +) -> xr.DataArray: + """Calculate the POC concentration change due to settling for a given timestep + + Args: + vsoc: POC settling velocity (m/d) + depth: Water depth of cell (m) + POC: POC concentration (mg/L) + """ + return vsoc / depth * POC + + +def POC_algal_mortality( + f_pocp: xr.DataArray, + kdp_tc: xr.DataArray, + rca: xr.DataArray, + Ap: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculate the POC concentration change due to algal mortality + + Args: + f_pocp: Fraction of algal mortality into POC + kdp_tc: Algal death rate at water temperature (1/d) + rca: Algal C to chlorophyll-a ratio (mg-C/ugChla) + Ap: Algae concentration (mg/L) + use_Algae: Option for considering algae in POC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Algae == True, f_pocp * kdp_tc * rca * Ap, 0) + + return da + + +def POC_benthic_algae_mortality( + depth: xr.DataArray, + F_pocb: xr.DataArray, + kdb_tc: xr.DataArray, + rcb: xr.DataArray, + Ab: xr.DataArray, + Fb: xr.DataArray, + Fw: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculate the POC concentration change due to benthic algae mortality + + Args: + depth: Water depth in cell (m) + F_pocb: Fraction of benthic algal mortality into POC + kdb_tc: Benthic algae death rate (1/d) + rcb: Benthic algae C to biomass weight ratio (mg-C/mg-D) + Ab: Benthic algae concentration (mg/L) + Fb: Fraction of bottom area available for benthic algae growth + Fw: Fraction of benthic algae mortality into water column + use_Balgae: Option for considering benthic algae in POC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * F_pocb * kdb_tc * rcb * Ab * Fb * Fw, 0) + + return da + +@numba.njit +def dPOCdt( + POC_settling: xr.DataArray, + POC_hydrolysis: xr.DataArray, + POC_algal_mortality: xr.DataArray, + POC_benthic_algae_mortality: xr.DataArray +) -> xr.DataArray: + """Calculate the change in POC concentration + + Args: + POC_settling: Concentration change of POC due to settling (mg/L/d) + POC_hydrolysis: Concentration change of POC due to hydrolysis (mg/L/d) + POC_algal_mortality: Concentration change of POC due to algal mortality (mg/L/d) + POC_benthic_algae_mortality: Concentration change of POC due to benthic algae mortality (mg/L/d) + """ + return POC_algal_mortality + POC_benthic_algae_mortality - POC_settling - POC_hydrolysis + + +@numba.njit +def POC( + POC: xr.DataArray, + dPOCdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Calculate the POC concentration at the next time step + + Args: + POC: Concentration of POC from previous timestep (mg/L) + dPOCdt: POC concentration change for current timestep (mg/L/d) + timestep: current iteration timestep (d) + """ + return POC + dPOCdt * timestep + + +def DOC_algal_mortality( + f_pocp: xr.DataArray, + kdp_tc: xr.DataArray, + rca: xr.DataArray, + Ap: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculate the DOC concentration change due to algal mortality + + Args: + f_pocp: Fraction of algal mortality into POC + kdp_tc: Algal death rate at water temperature (1/d) + rca: Algal C to chlorophyll-a ratio (mg-C/ug-Chla) + Ap: Algae concentration (mg/L) + use_Algae: Option for considering algae in DOC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Algae == True, (1 - f_pocp) * kdp_tc * rca * Ap, 0) + + return da + + +def DOC_benthic_algae_mortality( + depth: xr.DataArray, + F_pocb: xr.DataArray, + kdb_tc: xr.DataArray, + rcb: xr.DataArray, + Ab: xr.DataArray, + Fb: xr.DataArray, + Fw: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculate the DOC concentration change due to benthic algae mortality + + Args: + depth: Water depth in cell (m) + F_pocb: Fraction of benthic algal mortality into POC + kdb_tc: Benthic algae death rate (1/d) + rcb: Benthic algae C to biomass weight ratio (mg-C/mg-D) + Ab: Benthic algae concentration (mg/L) + Fb: Fraction of bottom area available for benthic algae growth + Fw: Fraction of benthic algae mortality into water column + use_Balgae: Option for considering benthic algae in DOC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * (1 - F_pocb) * kdb_tc * rcb * Ab * Fb * Fw, 0) + + return da + + +@numba.njit +def kdoc_tc( + TwaterC: xr.DataArray, + kdoc_20: xr.DataArray, +) -> xr.DataArray: + """Calculate the temperature adjusted DOC oxidation rate (1/d) + + Args: + TwaterC: Water temperature in Celsius + kdoc_20: DOC oxidation rate at 20 degrees Celsius (1/d) + """ + return arrhenius_correction(TwaterC, kdoc_20, 1.047) + + +def DOC_oxidation( + DOX: xr.DataArray, + KsOxmc: xr.DataArray, + kdoc_tc: xr.DataArray, + DOC: xr.DataArray, + use_DOX: xr.DataArray +) -> xr.DataArray: + """Calculates the DOC concentration change due to oxidation + + Args: + DOX: Concentration of dissolved oxygen (mg/L) + KsOxmc: Half saturation oxygen attenuation constant for DOC oxidation rate (mg-O2/L) + kdoc_tc: DOC oxidation rate (1/d) + DOC: Concentration of dissolved organic carbon (mg/L) + use_DOX: Option for considering dissolved oxygen concentration in DOC oxidation calculation (boolean) + """ + da: xr.DataArray = xr.where(use_DOX == True, DOX / (KsOxmc + DOX) * kdoc_tc * DOC, kdoc_tc * DOC) + + return da + + +@numba.njit +def dDOCdt( + DOC_oxidation: xr.DataArray, + POC_hydrolysis: xr.DataArray, + DOC_algal_mortality: xr.DataArray, + DOC_benthic_algae_mortality: xr.DataArray +) -> xr.DataArray: + """Calculates the change in DOC concentration + + Args: + POC_hydrolysis: DOC concentration change due to POC hydrolysis (mg/L/d) + DOC_POM_dissolution: DOC concentration change due to POM dissolution (mg/L/d) + DOC_denitrification: DOC concentration change due to DOC denitrification (mg/L/d) + DOC_algal_mortality: DOC concentration change due to algal mortality (mg/L/d) + DOC_benthic_algae_mortality: DOC concentration change due to benthic algae mortality (mg/L/d) + DOC_oxidation: DOC concentration change due to DOC oxidation (mg/L/d) + """ + return POC_hydrolysis + DOC_algal_mortality + DOC_benthic_algae_mortality - DOC_oxidation + + +@numba.njit +def DOC( + DOC: xr.DataArray, + dDOCdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Calculate the DOC concentration at the next time step + + Args: + DOC: Dissolved organic carbon concentration from previous timestep (mg/L) + dDOCdt: Dissolved organic carbon concentration change for current timestep (mg/L/d) + timestep: current iteration timestep (d) + """ + return DOC + dDOCdt * timestep + + +@numba.njit +def Henrys_k( + TwaterC: xr.DataArray +) -> xr.DataArray: + """Calculates the temperature dependent Henry's coefficient (mol/L/atm) + + Args: + TwaterC: Water temperature in celsius + """ + return 10**(2385.73 / (TwaterC + 273.15) + .0152642 * (TwaterC + 273.15) - 14.0184) + +@numba.njit +def Atmospheric_CO2_reaeration( + ka_tc: xr.DataArray, + K_H: xr.DataArray, + pCO2: xr.DataArray, + FCO2: xr.DataArray, + DIC: xr.DataArray +) -> xr.DataArray: + """Calculates the atmospheric input of CO2 into the waterbody + + Args: + ka_tc: CO2 reaeration rate adjusted for temperature, same as O2 reaeration rate (1/d) + K_H: Henry's Law constant (mol/L/atm) + pCO2: Partial pressure of CO2 in the atmosphere (ppm) + FCO2: Fraction of CO2 in total inorganic carbon + DIC: Dissolved inorganic carbon concentration (mg/L) + """ + return 12 * ka_tc * (10**-3 * K_H * pCO2 - 10**3 * FCO2 * DIC) + + +def DIC_algal_respiration( + ApRespiration: xr.DataArray, + rca: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculates DIC concentration change due to algal respiration + + Args: + ApRespiration: Algae respiration calculated in algae module (ug-Chla/L/d) + rca: Ratio of carbon to chlorophyll-a (mg-C/ug-Chla) + use_Algae: Option to consider algae in the DIC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Algae == True, ApRespiration * rca, 0) + + return da + + +def DIC_algal_photosynthesis( + ApGrowth: xr.DataArray, + rca: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculates DIC concentration change due to algal photosynthesis + + Args: + ApGrowth: Algal photosynthesis calculated in algae module (ug-Chla/L/d) + rca: Ratio of carbon to chlorophyll-a (mg-C/ug-Chla) + use_Algae: Option to consider algae in the DIC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Algae == True, ApGrowth * rca, 0) + + return da + + +def DIC_benthic_algae_respiration( + AbRespiration: xr.DataArray, + rcb: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculates DIC flux due to benthic algae respiration + + Args: + AbRespiration: Benthic algae respiration calculated in benthic algae module (g/m2/d) + rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D) + Fb: Fraction of bottom area available for benthic algae growth + depth: Depth of water (m) + use_Balgae: Option to consider benthic algae in the DIC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Balgae == True, AbRespiration * rcb * Fb * (1 / depth), 0) + + return da + + +def DIC_benthic_algae_photosynthesis( + AbGrowth: xr.DataArray, + rcb: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculates DIC flux due to benthic algae growth + + Args: + AbGrowth: Benthic algae photosynthesis calculated in the benthic algae module (g/m2/d) + rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D) + Fb: Fraction of bottom area available for benthic algae growth + depth: Depth of water (m) + use_Balgae: Option to consider benthic algae in the DIC budget (boolean) + """ + da: xr.DataArray = xr.where(use_Balgae == True, AbGrowth * rcb * Fb * (1 / depth), 0) + + return da + + +def DIC_CBOD_oxidation( + DOX: xr.DataArray, + CBOD: xr.DataArray, + roc: xr.DataArray, + kbod_tc: xr.DataArray, #imported from CBOD module + KsOxbod: xr.DataArray, #imported from CBOD module + use_DOX: xr.DataArray +) -> xr.DataArray: + """Calculates DIC concentration change due to CBOD oxidation + + Args: + DOX: Dissolved oxygen concentration (mg/L) + CBOD: Carbonaceous biochemical oxygen demand concentration (mg/L) + roc: Ratio of O2 to carbon for carbon oxidation (mg-O2/mg-C) + kbod_tc: CBOD oxidation rate (1/d) + KsOxbod: Half saturation oxygen attenuation constant for CBOD oxidation (mg-O2/L) + use_DOX: Option to consider dissolved oxygen in CBOD oxidation calculation (boolean) + """ + + da: xr.DataArray = xr.where(use_DOX == True, (1 / roc) * (DOX / (KsOxbod + DOX)) * kbod_tc * CBOD, CBOD * kbod_tc) + + return da + + +def DIC_sed_release( + SOD_tc: xr.DataArray, + roc: xr.DataArray, + depth: xr.DataArray, + JDIC: xr.DataArray, + use_SedFlux: xr.DataArray +) -> xr.DataArray: + """Computes the sediment release of DIC + + Args: + SOD_tc: Sediment oxygen demand adjusted for water temperature (mg-O2/L/d) + roc: Ratio of O2 to carbon for carbon oxidation (mg-O2/mg-C) + depth: Water depth (m) + JDIC: Sediment-water flux of dissolved inorganic carbon (g-C/m2/d) + use_SedFlux: Option to consider full sediment flux budget in DIC sediment contribution (bool) + """ + da: xr.DataArray = xr.where(use_SedFlux == True, JDIC / depth, SOD_tc / roc / depth) + + return da + + +@numba.njit +def dDICdt( + Atm_CO2_reaeration: xr.DataArray, + DIC_algal_respiration: xr.DataArray, + DIC_algal_photosynthesis: xr.DataArray, + DIC_benthic_algae_respiration: xr.DataArray, + DIC_benthic_algae_photosynthesis: xr.DataArray, + DIC_DOC_oxidation: xr.DataArray, + DIC_CBOD_oxidation: xr.DataArray, + DIC_sed_release: xr.DataArray +) -> xr.DataArray: + """Calculates the change in DIC + + Args: + Atm_CO2_reaeration: DIC concentration change due to atmospheric CO2 reaeration (mg/L/d) + DIC_algal_respiration: DIC concentration change due to algal respiration (mg/L/d) + DIC_algal_photosynthesis: DIC concentration change due to algal photosynthesis (mg/L/d) + DIC_benthic_algae_respiration: DIC concentration change due to benthic algae respiration (mg/L/d) + DIC_benthic_algae_photosynthesis: DIC concentration change due to benthic algae photosynthesis (mg/L/d) + DIC_CBOD_oxidation: DIC concentration change due to CBOD oxidation (mg/L/d) + DIC_sed_release: DIC concentration change due to sediment release (mg/L/d) + """ + return Atm_CO2_reaeration + DIC_algal_respiration + DIC_benthic_algae_respiration + DIC_DOC_oxidation + DIC_CBOD_oxidation + DIC_sed_release - DIC_algal_photosynthesis - DIC_benthic_algae_photosynthesis + + +@numba.njit +def DIC( + DIC: xr.DataArray, + dDICdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Calculate the DIC concentration at the next time step + + Args: + DIC: Concentration of DIC from previous timestep (mg/L) + dDICdt: Change in concentration of DIC for current timestep (mg/L/d) + timestep: Current iteration timestep (d) + """ + return DIC + dDICdt * timestep + + +######################################## From DOX + + +#TODO: make sure np.exp will work here... +@numba.njit +def pwv( + TwaterK: xr.DataArray +) -> xr.DataArray: + """Calculate partial pressure of water vapor + + Args: + TwaterK: Water temperature kelvin + """ + return np.exp(11.8571 - 3840.70 / TwaterK - 216961 / TwaterK ** 2) + + +@numba.njit +def DOs_atm_alpha( + TwaterK: xr.DataArray +) -> xr.DataArray: + """Calculate DO saturation atmospheric correction coefficient + + Args: + TwaterK: Water temperature kelvin + """ + return .000975 - 1.426 * 10 ** -5 * TwaterK + 6.436 * 10 ** -8 * TwaterK ** 2 + + +@numba.njit +def DOX_sat( + TwaterK: xr.DataArray, + pressure_atm: xr.DataArray, + pwv: xr.DataArray, + DOs_atm_alpha: xr.DataArray +) -> xr.DataArray: + """Calculate DO saturation value + + Args: + TwaterK: Water temperature kelvin + pressure_atm: Atmospheric pressure (atm) + pwv: Patrial pressure of water vapor (atm) + DOs_atm_alpha: DO saturation atmospheric correction coefficient + """ + DOX_sat_uncorrected = np.exp(-139.34410 + 1.575701 * 10 ** 5 / TwaterK - 6.642308 * 10 ** 7 / TwaterK ** 2 + + 1.243800 * 10 ** 10 / TwaterK - 8.621949 * 10 ** 11 / TwaterK) + + DOX_sat_corrected = DOX_sat_uncorrected * pressure_atm * \ + (1 - pwv / pressure_atm) * (1 - DOs_atm_alpha * pressure_atm) / \ + ((1 - pwv) * (1 - DOs_atm_alpha)) + return DOX_sat_corrected + + +@numba.njit +def Atm_O2_reaeration( + ka_tc: xr.DataArray, + DOX_sat: xr.DataArray, + DOX: xr.DataArray +) -> xr.DataArray: + """Compute the atmospheric O2 reaeration flux + + Args: + ka_tc: Oxygen reaeration rate adjusted for temperature (1/d) + DOX_sat: Dissolved oxygen saturation concentration (mg/L) + DOX: Dissolved oxygen concentration (mg/L) + """ + return ka_tc * (DOX_sat - DOX) + + +def DOX_ApGrowth( + ApGrowth: xr.DataArray, + rca: xr.DataArray, + roc: xr.DataArray, + ApUptakeFr_NH4: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Compute DOX flux due to algal photosynthesis + + Args: + ApGrowth: Algae photosynthesis, calculated in the algae module (ug-Chla/L/d) + rca: Ratio of algal carbon to chlorophyll-a (mg-C/ug-Chla) + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + ApUptakeFr_NH4: Fraction of actual algal uptake that is from the ammonia pool, calculated in nitrogen module + """ + da: xr.DataArray = xr.where(use_Algae == True, ApGrowth * rca * roc * (138 / 106 - 32 * ApUptakeFr_NH4 / 106), 0) + + return da + + +def DOX_ApRespiration( + ApRespiration: xr.DataArray, + rca: xr.DataArray, + roc: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Compute DOX flux due to algal photosynthesis + + Args: + ApRespiration: algae respiration, calculated in the algae module + rca: Ratio of algal carbon to chlorophyll-a (mg-C/ug-Chla) + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + """ + da: xr.DataArray = xr.where(use_Algae == True, ApRespiration * rca * roc, 0) + + return da + + +def DOX_Nitrification( + KNR: xr.DataArray, + DOX: xr.DataArray, + ron: xr.DataArray, + knit_tc: xr.DataArray, + NH4: xr.DataArray, + use_NH4: xr.DataArray +) -> xr.DataArray: + """Compute DOX flux due to nitrification of ammonia + + Args: + KNR: Oxygen inhibition factor for nitrification (mg-O2/L) + DOX: Dissolved oxygen concentration (mg/L) + ron: Ratio of oxygen to nitrogen for nitrificiation (mg-O2/mg-N) + knit_tc: Nitrification rate of NH4 to NO3 (1/d) + NH4: Ammonia/ammonium concentration + """ + da: xr.DataArray = xr.where(use_NH4 == True, (1.0 - np.exp(-KNR * DOX)) * ron * knit_tc * NH4, 0) + + return da + + +def DOX_DOC_Oxidation( + DOC_Oxidation: xr.DataArray, + roc: xr.DataArray, + use_DOC: xr.DataArray +) -> xr.DataArray: + """Computes dissolved oxygen flux due to oxidation of dissolved organic carbon + + Args: + DOC_Oxidation: Dissolved organic carbon oxidation, calculated in carbon module (mg/L/d) + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + """ + da: xr.DataArray = xr.where(use_DOC == True, roc * DOC_Oxidation, 0) + + return da + + +@numba.njit +def DOX_CBOD_Oxidation( + DIC_CBOD_Oxidation: xr.DataArray, + roc: xr.DataArray +) -> xr.DataArray: + """Compute dissolved oxygen flux due to CBOD oxidation + + Args: + DIC_CBOD_Oxidation: Carbonaceous biochemical oxygen demand oxidation, calculated in CBOD module (mg/L/d) + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + """ + return DIC_CBOD_Oxidation * roc + + +def DOX_AbGrowth( + AbUptakeFr_NH4: xr.DataArray, + roc: xr.DataArray, + rcb: xr.DataArray, + AbGrowth: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_BAlgae: xr.DataArray +) -> xr.DataArray: + """Compute dissolved oxygen flux due to benthic algae growth + + Args: + AbUptakeFr_NH4: Fraction of actual benthic algal uptake that is from the ammonia pool, calculated in nitrogen module + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D) + AbGrowth: Benthic algae photosynthesis, calculated in benthic algae module (mg/L/d) + Fb: Fraction of bottom area available for benthic algae growth + depth: Water depth (m) + use_BAlgae: Option to consider benthic algae in the DOX budget + """ + da: xr.DataArray = xr.where(use_BAlgae == True, (138 / 106 - 32 / 106 * AbUptakeFr_NH4) * roc * rcb * AbGrowth * Fb / depth, 0) + + return da + + +def DOX_AbRespiration( + roc: xr.DataArray, + rcb: xr.DataArray, + AbRespiration: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, + use_BAlgae: xr.DataArray +) -> xr.DataArray: + """Compute dissolved oxygen flux due to benthic algae respiration + + Args: + roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) + rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D) + AbRespiration: Benthic algae respiration, calculated in the benthic algae module + Fb: Fraction of bottom area available for benthic algae growth + depth: Water depth (m) + use_BAlgae: Option to consider benthic algae in the DOX budget + """ + + da: xr.DataArray = xr.where(use_BAlgae == True, roc * rcb * AbRespiration * Fb / depth, 0) + + return da + + +def DOX_SOD( + SOD_Bed: xr.DataArray, + depth: xr.DataArray, + SOD_tc: xr.DataArray, + use_SedFlux: xr.DataArray +) -> xr.DataArray: + """Compute dissolved oxygen flux due to sediment oxygen demand + + Args: + SOD_Bed: Sediment oxygen demand if calculated using the SedFlux module (mg-O2/m2) + depth: Water depth (m) + SOD_tc: Sediment oxygen demand not considering the SedFlux budget (mg-O2/m2) + use_SedFlux: Option to consider sediment flux in DOX budget (boolean) + """ + + da: xr.DataArray = xr.where(use_SedFlux == 1, SOD_Bed / depth, SOD_tc / depth) + + return da + +@numba.njit +def dDOXdt( + Atm_O2_reaeration: xr.DataArray, + DOX_ApGrowth: xr.DataArray, + DOX_ApRespiration: xr.DataArray, + DOX_Nitrification: xr.DataArray, + DOX_DOC_Oxidation: xr.DataArray, + DOX_CBOD_Oxidation: xr.DataArray, + DOX_AbGrowth: xr.DataArray, + DOX_AbRespiration: xr.DataArray, + DOX_SOD: xr.DataArray +) -> xr.DataArray: + """Compute change in dissolved oxygen concentration for one timestep + + Args: + Atm_O2_reaeration: DOX concentration change due to atmospheric O2 reaeration (mg/L/d) + DOX_ApGrowth: DOX concentration change due to algal photosynthesis (mg/L/d) + DOX_ApRespiration: DOX concentration change due to algal respiration (mg/L/d) + DOX_Nitrification: DOX concentration change due to nitrification (mg/L/d) + DOX_DOC_Oxidation: DOX concentration change due to DOC oxidation (mg/L/d) + DOX_CBOD_Oxidation: DOX concentration change due to CBOD oxidation (mg/L/d) + DOX_AbGrowth: DOX concentration change due to benthic algae photosynthesis (mg/L/d) + DOX_AbRespiration: DOX concentration change due to benthic algae respiration (mg/L/d) + DOX_SOD: DOX concentration change due to sediment oxygen demand (mg/L/d) + """ + return Atm_O2_reaeration + DOX_ApGrowth - DOX_ApRespiration - DOX_Nitrification - DOX_DOC_Oxidation - DOX_CBOD_Oxidation + DOX_AbGrowth - DOX_AbRespiration - DOX_SOD + + +@numba.njit +def DOX( + DOX: xr.DataArray, + dDOXdt: xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + """Computes updated dissolved oxygen concentration + + Args: + DOX: Dissolved oxygen concentration from previous timestep + dDOXdt: Change in dissolved oxygen concentration over timestep + timestep: Current iteration timestep (d) + """ + return DOX + dDOXdt * timestep + +######################################### From pathogen + + +@numba.njit +def kdx_tc( + TwaterC : xr.DataArray, + kdx_20: xr.DataArray +) -> xr.DataArray : + + """Calculate kdx_tc: pathogen death rate (1/d). + + Args: + TwaterC: Water temperature (C) + kdx_20: Pathogen death rate at 20 degree (1/d) + """ + + return arrhenius_correction(TwaterC, kdx_20, 1.07) + +@numba.njit +def PathogenDeath( + kdx_tc : xr.DataArray, + PX: xr.DataArray +) -> xr.DataArray : + + """Calculate PathogenDeath: pathogen natural death (cfu/100mL/d). + + Args: + kdx_tc: pathogen death rate with temperature correction (1/d), + PX: pathogen concentration (cfu/100mL) + + """ + return kdx_tc * PX + +@numba.njit +def PathogenDecay( + apx: xr.DataArray, + q_solar: xr.DataArray, + L: xr.DataArray, + depth: xr.DataArray, + PX: xr.DataArray +) -> xr.DataArray : + + """Calculate PathogenDecay: pathogen death due to light (cfu/100mL/d). + + Args: + apx: light efficiency factor for pathogen decay, + q_solar: Incident short-wave solar radiation (W/m2), + L: lambda (1/m), + depth: water depth (m), + PX: Pathogen concentration (cfu/100mL) + + """ + return apx * q_solar / (L * depth) * (1 - math.exp(-L * depth)) * PX + +@numba.njit +def PathogenSettling( + vx: xr.DataArray, + depth: xr.DataArray, + PX: xr.DataArray +) -> xr.DataArray : + + """Calculate PathogenSettling: pathogen settling (cfu/100mL/d). + + Args: + vx: pathogen net settling velocity (m) + depth: water depth (m), + PX: Pathogen concentration (cfu/100mL) + """ + return vx/depth*PX + +@numba.njit +def dPXdt( + PathogenDeath: xr.DataArray, + PathogenDecay: xr.DataArray, + PathogenSettling: xr.DataArray + +) -> xr.DataArray : + + """Calculate dPXdt: change in pathogen concentration (cfu/100mL/d). + + Args: + PathogenSettling: pathogen settling (cfu/100mL/d) + PathogenDecay: pathogen death due to light (cfu/100mL/d) + PathogenDeath: pathogen natural death (cfu/100mL/d) + + """ + return -PathogenDeath - PathogenDecay - PathogenSettling + +@numba.njit +def PX( + PX:xr.DataArray, + dPXdt: xr.DataArray, + timestep: xr.DataArray + +) -> xr.DataArray : + + """Calculate PX: New pathogen concentration (cfu/100mL). + + Args: + dPXdt: change in pathogen concentration (cfu/100mL/d) + PX: Pathogen concentration (cfu/100mL) + timestep: Current iteration timestep (d) + """ + return PX + timestep * dPXdt + + +##################################### From alkalinity + +def Alk_denitrification( + DOX: xr.DataArray, + NO3: xr.DataArray, + kdnit_tc: xr.DataArray, + KsOxdn: xr.DataArray, + r_alkden: xr.DataArray, + use_NO3: xr.DataArray, + use_DOX: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to denitrification of nitrate + + Args: + DOX: Concentration of dissolved oxygen (mg/L) + NO3: Concentration of nitrate (mg/L) + kdnit_tc: Denitrification rate corrected for temperature (1/d) + KsOxdn: Half-saturation oxygen inhibition constant for denitrification (mg-O2/L) + ralkden: Ratio translating NO3 denitrification into Alk (eq/mg-N) + use_NO3: Option to use nitrate + use_DOX: Option to use dissolved oxygen + """ + da: xr.DataArray = xr.where(use_NO3 == True, xr.where(use_DOX == True, r_alkden * (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3, r_alkden * kdnit_tc * NO3), 0) + + return da + + +def Alk_nitrification( + DOX: xr.DataArray, + NH4: xr.DataArray, + knit_tc: xr.DataArray, + KNR: xr.DataArray, + r_alkn: xr.DataArray, + use_NH4: xr.DataArray, + use_DOX: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to nitrification of ammonium + + Args: + DOX: Concentration of dissolved oxygen (mg/L) + NH4: Concentration of ammonia/ammonium (mg/L) + knit_tc: Nitrification rate corrected for temperature (1/d) + KNR: Oxygen inhibition factor for nitrification (mg-O2/L) + r_alkn: Ratio translating NH4 nitrification into Alk (eq/mg-N) + use_NH4: Option to use ammonium + use_DOX: Option to use dissolved oxygen + """ + da: xr.DataArray = xr.where(use_NH4 == True, xr.where(use_DOX == True, r_alkn * (1 - math.exp(-KNR * DOX)) * knit_tc * NH4, knit_tc * NH4), 0) + + return da + + +def Alk_algal_growth( + ApGrowth: xr.DataArray, + r_alkaa: xr.DataArray, + r_alkan: xr.DataArray, + ApUptakeFr_NH4 : xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to algal growth + + Args: + ApGrowth: Algal photosynthesis calculated in algae module (ug-Chla/L/d) + r_alkaa: Ratio translating algal growth into Alk if NH4 is the N source (eq/ug-Chla) + r_alkan: Ratio translating algal growth into Alk if NO3 is the N source (eq/ug-Chla) + ApUptakeFr_NH4 : Preference fraction of algal N uptake from NH4 + use_Algae: Option to use algae + """ + da: xr.DataArray = xr.where(use_Algae == True, (r_alkaa * ApUptakeFr_NH4 - r_alkan * (1 - ApUptakeFr_NH4 )) * ApGrowth, 0) + + return da + + +def Alk_algal_respiration( + ApRespiration: xr.DataArray, + r_alkaa: xr.DataArray, + use_Algae: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to algal respiration + + Args: + ApRespiration: Algae respiration calculated in algae module (ug-Chla/L/d) + r_alkaa: Ratio translating algal growth into Alk if NH4 is the N source (eq/ug-Chla) + use_Algae: Option to use algae + """ + da: xr.DataArray = xr.where(use_Algae == True, ApRespiration * r_alkaa, 0) + + return da + + +def Alk_benthic_algae_growth( + AbGrowth: xr.DataArray, + depth: xr.DataArray, + r_alkba: xr.DataArray, + r_alkbn: xr.DataArray, + AbUptakeFr_NH4 : xr.DataArray, + Fb: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to algal growth + + Args: + ApGrowth: Algal photosynthesis calculated in algae module (ug-Chla/L/d) + depth: Depth of water (m) + r_alkaa: Ratio translating algal growth into Alk if NH4 is the N source (eq/ug-Chla) + r_alkan: Ratio translating algal growth into Alk if NO3 is the N source (eq/ug-Chla) + AbUptakeFr_NH4 : Preference fraction of benthic algae N uptake from NH4 + Fb: Fraction of bottom area available for benthic algae growth + use_Balgae: Option to use benthic algae + """ + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) *(r_alkba * AbUptakeFr_NH4 - r_alkbn * (1 - AbUptakeFr_NH4 )) * AbGrowth * Fb, 0) + + return da + + +def Alk_benthic_algae_respiration( + AbRespiration: xr.DataArray, + depth: xr.DataArray, + r_alkba: xr.DataArray, + Fb: xr.DataArray, + use_Balgae: xr.DataArray +) -> xr.DataArray: + """Calculate the alkalinity concentration change due to algal respiration + + Args: + ApRespiration: Algae respiration calculated in algae module (ug-Chla/L/d) + r_alkaa: Ratio translating algal growth into Alk if NH4 is the N source (eq/ug-Chla) + Fb: Fraction of bottom area available for benthic algae growth + use_Balgae: Option to use betnhic algae + """ + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * r_alkba * AbRespiration * Fb, 0) + + return da + + +@numba.njit +def dAlkdt( + Alk_denitrification: xr.DataArray, + Alk_nitrification: xr.DataArray, + Alk_algal_growth: xr.DataArray, + Alk_algal_respiration: xr.DataArray, + Alk_benthic_algae_growth: xr.DataArray, + Alk_benthic_algae_respiration: xr.DataArray +) -> xr.DataArray: + """Computes the change in alkalinity for timestep + + Args: + Alk_denitrification: xr.DataArray, + Alk_nitrification: xr.DataArray, + Alk_algal_growth: xr.DataArray, + Alk_algal_respiration: xr.DataArray, + Alk_benthic_algae_growth: xr.DataArray, + Alk_benthic_algae_respiration: xr.DataArray + """ + return Alk_denitrification - Alk_nitrification - Alk_algal_growth + Alk_algal_respiration - Alk_benthic_algae_growth + Alk_benthic_algae_respiration + + +@numba.njit +def Alk( + Alk: xr.DataArray, + dAlkdt: xr.DataArray, + timestep: xr.DataArray, +) -> xr.DataArray: + """Computes the alkalinity concentration at the next timestep + + Args: + Alk: Concentration of alkalinity from previous timestep (mg/L) + dAlkdt: Change in concentration of alkalinity for current timestep (mg/L/d) + timestep: Current iteration timestep (d) + """ + return Alk + dAlkdt * timestep + +##################################### From N2 + + +@numba.njit +def KHN2_tc( + TwaterK : xr.DataArray, +) -> xr.DataArray : + + """Calculate Henry's law constant (mol/L/atm) + + Constant values found on NIST + + Args: + TwaterK: water temperature kelvin (K) + Henry's law constant for solubility in water at 298.15K: 0.00065 (mol/(kg*bar)) + Temperature dependence constant: 1300 (K) + Reference temperature: 298.15 (K) + """ + + return 0.00065 * math.exp(1300.0 * (1.0 / TwaterK - 1 / 298.15)) + +@numba.njit +def P_wv( + TwaterK : xr.DataArray, +) -> xr.DataArray : + + """Calculate partial pressure water vapor (atm) + + Constant values found in documentation + + Args: + TwaterK: water temperature kelvin (K) + + """ + return math.exp(11.8571 - (3840.70 / TwaterK) - (216961.0 / (TwaterK**2))) + +@numba.njit + +def N2sat( + KHN2_tc : xr.DataArray, + pressure_atm: xr.DataArray, + P_wv: xr.DataArray +) -> xr.DataArray: + + """Calculate N2 at saturation f(Twater and atm pressure) (mg-N/L) + + Args: + KHN2_tc: Henry's law constant (mol/L/atm) + pressure_atm: atmosphric pressure in atm (atm) + P_wv: Partial pressure of water vapor (atm) + """ + + N2sat = 2.8E+4 * KHN2_tc * 0.79 * (pressure_atm - P_wv) + N2sat = xr.where(N2sat < 0.0,0.0,N2sat) #Trap saturation concentration to ensure never negative + + return N2sat + +@numba.njit +def dN2dt( + ka_tc : xr.DataArray, + N2sat : xr.DataArray, + N2: xr.DataArray, +) -> xr.DataArray: + + """Calculate change in N2 air concentration (mg-N/L/d) + + Args: + ka_tc: Oxygen re-aeration rate (1/d) + N2sat: N2 at saturation f(Twater and atm pressure) (mg-N/L) + N2: Nitrogen concentration air (mg-N/L) + """ + + return 1.034 * ka_tc * (N2sat - N2) + +@numba.njit +def N2( + N2: xr.DataArray, + dN2dt : xr.DataArray, + timestep: xr.DataArray +) -> xr.DataArray: + + """Calculate change in N2 air concentration (mg-N/L/d) + + Args: + N2: Nitrogen concentration air (mg-N/L) + dN2dt: Change in nitrogen concentration air + timestep: Current iteration timestep (d) + """ + + return N2 + dN2dt * timestep + +@numba.njit +def TDG( + N2: xr.DataArray, + N2sat : xr.DataArray, + DOX: xr.DataArray, + DOX_sat: xr.DataArray, + use_DOX: bool, +) -> xr.DataArray: + + """Calculate total dissolved gas (%) + + Args: + N2: Nitrogen concentration air (mg-N/L) + N2sat: N2 at saturation f(Twater and atm pressure) (mg-N/L) + DOX: Dissolved oxygen concentration (mg-O2/L) + DOX_sat: O2 at saturation f(Twater and atm pressure) (mg-O2/L) + use_DOX: true/false use dissolved oxygen module (true/false) + """ + + return xr.where(use_DOX,(79.0 * N2 / N2sat) + (21.0 * DOX / DOX_sat), N2/N2sat) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/state_variables.py b/src/clearwater_modules/nsm1/state_variables.py index b986abd..2cb76e0 100644 --- a/src/clearwater_modules/nsm1/state_variables.py +++ b/src/clearwater_modules/nsm1/state_variables.py @@ -1,17 +1,6 @@ from clearwater_modules import base from clearwater_modules.nsm1.model import NutrientBudget -import clearwater_modules.nsm1.algae.processes as algae_processes -import clearwater_modules.nsm1.alkalinity.processes as alkalinity_processes -import clearwater_modules.nsm1.balgae.processes as balgae_processes -import clearwater_modules.nsm1.carbon.processes as carbon_processes -import clearwater_modules.nsm1.CBOD.processes as CBOD_processes -import clearwater_modules.nsm1.DOX.processes as DOX_processes -import clearwater_modules.nsm1.n2.processes as n2_processes -import clearwater_modules.nsm1.nitrogen.processes as nitrogen_processes -import clearwater_modules.nsm1.pathogens.processes as pathogens_processes -import clearwater_modules.nsm1.phosphorus.processes as phosphorus_processes -import clearwater_modules.nsm1.POM.processes as POM_processes -import clearwater_modules.shared.processes as shared_processes +import clearwater_modules.nsm1.processes as processes @base.register_variable(models=NutrientBudget) @@ -23,15 +12,13 @@ class Variable(base.Variable): def mock_equation(water_temp_c: float) -> float: return water_temp_c ** 2 -# TODO: import state variables from CWR such as surface_area volume, and timestep, as well as kah inputs - Variable( name='Ap', long_name='Algae Concentration', units='ug-Chla/L', description='Algal Concentration', use='state', - process=algae_processes.Ap + process=processes.Ap ) Variable( @@ -40,7 +27,7 @@ def mock_equation(water_temp_c: float) -> float: units='g-D/m^2', description='Benthic Algae Concentration', use='state', - process=balgae_processes.Ab + process=processes.Ab ) Variable( @@ -49,7 +36,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-N/L', description='Ammonium Concentration', use='state', - process=nitrogen_processes.NH4 + process=processes.NH4 ) Variable( @@ -58,7 +45,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-N/L', description='Nitrate Concentration', use='state', - process=nitrogen_processes.NO3 + process=processes.NO3 ) Variable( @@ -67,7 +54,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-N/L', description='Organic Nitrogen Concentration', use='state', - process=nitrogen_processes.OrgN + process=processes.OrgN ) Variable( @@ -76,7 +63,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-N/L', description='Nitrogen concentration air', use='state', - process=n2_processes.N2 + process=processes.N2 ) Variable( @@ -85,7 +72,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-P/L', description='Total Inorganic Phosphorus Concentration', use='state', - process=phosphorus_processes.TIP + process=processes.TIP ) Variable( @@ -94,7 +81,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-P/L', description='Total Organic Phosphorus Concentration', use='state', - process=phosphorus_processes.OrgP + process=processes.OrgP ) Variable( @@ -103,7 +90,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-C/L', description='Particulate Organic Carbon Concentration', use='state', - process=carbon_processes.POC + process=processes.POC ) Variable( @@ -112,7 +99,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-C/L', description='Dissolved Organic Carbon Concentration', use='state', - process=carbon_processes.DOC + process=processes.DOC ) Variable( @@ -121,7 +108,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-C/L', description='Dissolved Inorganic Carbon Concentration', use='state', - process=carbon_processes.DIC + process=processes.DIC ) Variable( @@ -130,16 +117,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-D/L', description='Particulate Organic Matter Concentration', use='state', - process=POM_processes.POM -) - -Variable( - name='POM2', - long_name='Sediment Particulate Organic Matter', - units='mg-D/L', - description='Sediment Particulate Organic Matter Concentration', - use='state', - process=mock_equation#TODO might be Sedflux + process=processes.POM ) Variable( @@ -148,7 +126,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-O2/L', description='Carbonaceous Biochemical Oxygen Demand Concentration', use='state', - process=CBOD_processes.CBOD + process=processes.CBOD ) Variable( @@ -157,7 +135,7 @@ def mock_equation(water_temp_c: float) -> float: units='mg-O2/L', description='Dissolved Oxygen', use='state', - process=DOX_processes.DOX + process=processes.DOX ) Variable( @@ -166,7 +144,7 @@ def mock_equation(water_temp_c: float) -> float: units='cfu/100mL', description='Pathogen concentration', use='state', - process=pathogens_processes.PX + process=processes.PX ) Variable( @@ -175,5 +153,5 @@ def mock_equation(water_temp_c: float) -> float: units='mg-CaCO3/L', description='Alkalinity concentration', use='state', - process=alkalinity_processes.Alk + process=processes.Alk ) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/static_variables.py b/src/clearwater_modules/nsm1/static_variables.py new file mode 100644 index 0000000..b0efccd --- /dev/null +++ b/src/clearwater_modules/nsm1/static_variables.py @@ -0,0 +1,928 @@ +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +############################################ From static_variables_global +Variable( + name='vson', + long_name='Organic N settling velocity', + units='m/d', + description='Organic N settling velocity', + use='static', +) + +Variable( + name='vsoc', + long_name='POC settling velocity', + units='m/d', + description='POC settling velocity', + use='static' +) + +Variable( + name='vsop', + long_name='Organic phosphorus settling velocity', + units='m/d', + description='Organic phosphorus settling velocity', + use='static' +) + +Variable( + name='vs', + long_name='Sediment settling velocity', + units='m/d', + description='Sediment settling velocity', + use='static' +) + +Variable( + name='SOD_20', + long_name='Sediment oxygen demand at 20 degrees C', + units='g-O2/m/d', + description='Sediment oxygen demand at 20 degrees C', + use='static' +) + +Variable( + name='SOD_theta', + long_name='Arrhenius coefficient for sediment oxygen demand', + units='unitless', + description='Arrhenius coefficient for sediment oxygen demand', + use='static' +) + +Variable( + name='fcom', + long_name='Fraction of carbon in organic matter', + units='mg-C/mg-D', + description='Fraction of carbon in organic matter', + use='static' +) + +Variable( + name='vb', + long_name='Burial velocity', + units='m/d', + description='Rate at which constituents are buried on the bottom', + use='static' +) + +Variable( + name='kaw_20_user', + long_name='Wind oxygen reaeration velocity at 20C', + units='m/d', + description='Wind oxygen reaeration velocity at 20C', + use='static' +) + +Variable( + name='kah_20_user', + long_name='Hydraulic oxygen reaeration rate at 20C', + units='1/d', + description='Hydraulic oxygen reaeration rate at 20C', + use='static' +) + +Variable( + name='hydraulic_reaeration_option', + long_name='Option for chosing the method by which O2 reaeration rate is calculated', + units='unitless', + description='Selects method for computing O2 reaeration rate', + use='static' +) + +Variable( + name='wind_reaeration_option', + long_name='Option for chosing the method by which wind reaeration is calculated', + units='unitless', + description='Selects method for computing O2 reaeration due to wind', + use='static' +) + +Variable( + name='use_NH4', + long_name='Use ammonium module', + units='unitless', + description='True/False use ammonium module', + use='static', +) + +Variable( + name='use_NO3', + long_name='Use nitrate module', + units='unitless', + description='True/False use nitrate module', + use='static', +) + +Variable( + name='use_OrgN', + long_name='Use organic nitrogen module', + units='unitless', + description='True/False use organic nitrogen module', + use='static', +) + +Variable( + name='use_SedFlux', + long_name='Use sediment flux module', + units='unitless', + description='True/False use sediment flux module', + use='static', +) + +Variable( + name='use_DOX', + long_name='Use dissolved oxygen module', + units='unitless', + description='True/False use dissolved oxygen module', + use='static', +) + +Variable( + name='use_Algae', + long_name='Use algae module', + units='unitless', + description='True/False use algae module', + use='static', +) + +Variable( + name='use_Balgae', + long_name='Use benthic algae module', + units='unitless', + description='True/False use benthic algae module', + use='static', +) + +Variable( + name='use_TIP', + long_name='Use total inorganic phosphorus module', + units='unitless', + description='True/False use total inorganic phosphorus module', + use='static', +) + +Variable( + name='use_OrgP', + long_name='Use total organic phosphorus module', + units='unitless', + description='True/False use total organic phosphorus module', + use='static', +) + +Variable( + name='use_POC', + long_name='Use particulate organic carbon module', + units='unitless', + description='True/False use particulate organic carbon module', + use='static', +) + +Variable( + name='use_DOC', + long_name='Use dissolved organic carbon module', + units='unitless', + description='True/False use dissolved organic carbon module', + use='static', +) + +Variable( + name='use_DIC', + long_name='Use dissolved inorganic carbon module', + units='unitless', + description='True/False use dissolved inorganic carbon module', + use='static', +) + +Variable( + name='use_N2', + long_name='Use dissolved N2 module', + units='unitless', + description='True/False use N2 module', + use='static', +) + +Variable( + name='use_Pathogen', + long_name='Use pathogen module', + units='unitless', + description='True/False use pathogen module', + use='static', +) + +Variable( + name='use_Alk', + long_name='Use alkalinity module', + units='unitless', + description='True/False use alkalinity module', + use='static', +) + +Variable( + name='use_POM', + long_name='Use particulate organic matter module', + units='unitless', + description='True/False use particulate organic matter module', + use='static', +) + +Variable( + name='timestep', + long_name='timestep', + units='d', + description='calculation timestep', + use='static', +) + +Variable( + name='TwaterC', + long_name='Water temperature in celsius', + units='degrees C', + description='Water temperature in celsius', + use='static', +) + +Variable( + name='velocity', + long_name='velocity', + units='m/s', + description='Average water velocity in cell', + use='static', +) + +Variable( + name='flow', + long_name='flow', + units='m3/s', + description='Average flow rate in cell', + use='static', +) + +Variable( + name='topwidth', + long_name='topwidth', + units='m', + description='Average topwidth of cell', + use='static', +) + +#TODO find units for slope +Variable( + name='slope', + long_name='slope', + units='TODO', + description='Average slope of bottom surface', + use='static', +) + +Variable( + name='shear_velocity', + long_name='shear_velocity', + units='TODO', + description='Average shear velocity on bottom surface', + use='static', +) + +Variable( + name='pressure_atm', + long_name='pressure_atm', + units='TODO', + description='atmospheric pressure in atm', + use='static', +) + +Variable( + name='wind_speed', + long_name='Wind speed at 10 meters above the water surface', + units='m/s', + description='Wind speed at 10 meters above the water surface', + use='static', +) + +Variable( + name='q_solar', + long_name='Incident short-wave solar radiation', + units='W/m2', + description='Incident short-wave solar radiation', + use='static', +) + +#TODO figure out what Solid is +Variable( + name='Solid', + long_name='Solid reaeration option', + units='Unknown', + description='Solid', + use='static', +) + +############################################ From algae +Variable( + name='AWd', + long_name='Algal Dry Weight', + units='mg', + description='Algal Dry Weight', + use='static', +) + +Variable( + name='AWc', + long_name='Carbon Weight', + units='mg', + description='Carbon Weight', + use='static', +) + +Variable( + name='AWn', + long_name='Nitrogen Weight', + units='mg', + description='Nitrogen Weight', + use='static', +) + +Variable( + name='AWp', + long_name='Phosphorus Weight', + units='mg', + description='Phosphorus Weight', + use='static', +) + +Variable( + name='AWa', + long_name='Algal Chlorophyll', + units='ug Chla', + description='Algal Chlorophyll', + use='static', +) + +Variable( + name='KL', + long_name='Light Limiting Constant for Algal Growth', + units='W/m^2', + description='Light Limiting Constant for Algal Growth', + use='static', +) + +Variable( + name='KsN', + long_name='Half-Saturation N Limiting Constant for Algal Growth', + units='mg-N/L', + description='Half-Saturation N Limiting Constant for Algal Growth', + use='static', +) + +Variable( + name='KsP', + long_name='Half-Saturation P Limiting Constant for Algal Growth', + units='mg-P/L', + description='Half-Saturation P Limiting Constant for Algal Growth', + use='static', +) + +Variable( + name='mu_max_20', + long_name='Max Algae Growth', + units='1/d', + description='Max Algae Growth at 20C', + use='static', +) + +Variable( + name='kdp_20', + long_name='Algal Mortality Rate', + units='1/d', + description='Algal Mortality Rate at 20C', + use='static', +) + +Variable( + name='krp_20', + long_name='Algal Respiration Rate', + units='1/d', + description='Algal Respiration Rate at 20C', + use='static', +) + +Variable( + name='vsap', + long_name='Algal Setting Velocity', + units='m/d', + description='Algal Setting Velocity', + use='static', +) + +Variable( + name='growth_rate_option', + long_name='Growth Rate Option', + units='1/d', + description='Algal growth rate option 1) multiplicative, 2) Limiting Nutrient, 3) Harmonic Mean Option', + use='static', +) + +Variable( + name='light_limitation_option', + long_name='Light Limitation Option', + units='1/d', + description='Algal light limitation 1) half-saturation, 2) Smith model, 3) Steele model', + use='static', +) + +Variable( + name='lambda0', + long_name='lambda0', + units='1/m', + description='background portion', + use='static', +) + +Variable( + name='lambda1', + long_name='lambda1', + units='1/m/(ug Chla/L)', + description='linear self shading', + use='static', +) + +Variable( + name='lambda2', + long_name='lambda2', + units='unitless', + description='nonlinear', + use='static', +) + +Variable( + name='lambdas', + long_name='lambdas', + units='L/mg/m', + description='ISS portion', + use='static', +) + +Variable( + name='lambdam', + long_name='lambdam', + units='L/mg/m', + description='POM portion', + use='static', +) + +Variable( + name='Fr_PAR', + long_name='fraction PAR', + units='unitless', + description='fraction of solar radiation within the PAR of the spectrum', + use='static', +) + +############################################ From benthic algae +Variable( + name='Fw', + long_name='Fraction of benthic algae mortality into water column', + units='unitless', + description='Fraction of benthic algae mortality into water column', + use='static', +) + +Variable( + name='Fb', + long_name='Fraction of bottom area available for benthic algae', + units='unitless', + description='Fraction of bottom area available for benthic algae', + use='static', +) + +Variable( + name='BWd', + long_name='Benthic algae dry weight', + units='unitless', + description='Benthic algae dry weight', + use='static', +) + +Variable( + name='BWc', + long_name='Benthic algae carbon', + units='unitless', + description='Benthic algae carbon', + use='static', +) + +Variable( + name='BWn', + long_name='Benthic algae nitrogen', + units='unitless', + description='Benthic algae nitrogen', + use='static', +) + +Variable( + name='BWp', + long_name='Benthic algae phosphorus', + units='unitless', + description='Benthic algae phosphorus', + use='static', +) + +Variable( + name='BWa', + long_name='Benthic algae Chla', + units='unitless', + description='Benthic algae Chla', + use='static', +) + +Variable( + name='KLb', + long_name='Light limiting constant for benthic algae growth', + units='W/m^2', + description='Light limiting constant for benthic algae growth', + use='static', +) + +Variable( + name='KsNb', + long_name='Half-Saturation N limiting constant for Benthic algae', + units='mg-N/L', + description='Half-Saturation N limiting constant for Benthic algae', + use='static', +) + +Variable( + name='KsPb', + long_name='Half-Saturation P limiting constant for Benthic algae', + units='mg-P/L', + description='Half-Saturation P limiting constant for Benthic algae', + use='static', +) + +Variable( + name='Ksb', + long_name='Half-Saturation density constant for benthic algae growth', + units='g-D/m^2', + description='Half-Saturation density constant for benthic algae growth', + use='static', +) + +Variable( + name='mub_max_20', + long_name='Maximum benthic algal growth rate', + units='1/d', + description='maximum benthic algal growth rate', + use='static', +) + +Variable( + name='krb_20', + long_name='Benthic algal respiration rate', + units='1/d', + description='Benthic algal respiration rate', + use='static', +) + +Variable( + name='kdb_20', + long_name='Benthic algal mortality rate', + units='1/d', + description='Benthic algal mortality rate', + use='static', +) + +Variable( + name='b_growth_rate_option', + long_name='Benthic Algal growth rate options', + units='unitless', + description='Benthic Algal growth rate with two options: 1) Multiplicative, 2) Limiting Nutritent', + use='static', +) + +Variable( + name='b_light_limitation_option', + long_name='Benthic Algal light limitation rate options', + units='unitless', + description='Benthic Algal light limitation rate with three options: 1) Half-saturation formulation, 2) Smiths Model, 3) Steeles Model', + use='static', +) + +Variable( + name='Fb', + long_name='Fraction of bottom area available for benthic algae growth', + units='unitless', + description='Fraction of bottom area available for benthic algae growth', + use='static' +) + +Variable( + name='Fw', + long_name='Fraction of benthic algae mortality into water column', + units='unitless', + description='Fraction of benthic algae mortality into water column', + use='static' +) + +############################################ From nitrogen +Variable( + name='KNR', + long_name='Oxygen inhabitation factor for nitrification', + units='mg-O2/L', + description='Oxygen inhabitation factor for nitrification', + use='static', +) + +Variable( + name='knit_20', + long_name='Nitrification Rate Ammonia decay at 20C', + units='1/d', + description='Nitrification Rate Ammonia NH4 -> NO3 decay at 20C', + use='static', +) + +Variable( + name='kon_20', + long_name='Decay Rate of OrgN to NH4 at 20C', + units='1/d', + description='Decay Rate of OrgN to NH4 at 20C', + use='static', +) + +Variable( + name='kdnit_20', + long_name='Denitrification rate at 20C', + units='1/d', + description='Denitrification rate at 20C', + use='static', +) + +Variable( + name='rnh4_20', + long_name='Sediment release rate of NH4 at 20C', + units='g-N/m^2/d', + description='Sediment release rate of NH4 at 20C', + use='static' +) + +Variable( + name='vno3_20', + long_name='Sediment denitrification velocity at 20C', + units='m/d', + description='Sediment denitrification velocity at 20C', + use='static', +) + +Variable( + name='KsOxdn', + long_name='Half-saturation oxygen inhibition constant for denitrification', + units='mg-O2/L', + description='Half-saturation oxygen inhibition constant for denitrification', + use='static', +) + +Variable( + name='PN', + long_name='NH4 preference factor algae', + units='unitless', + description='NH4 preference factor algae (1=full NH4, 0=full NO3)', + use='static', +) + +Variable( + name='PNb', + long_name='NH4 preference factor benthic algae', + units='unitless', + description='NH4 preference factor benthic algae (1=full NH4, 0=full NO3)', + use='static', +) + +############################################ From phosphorus +Variable( + name='kop_20', + long_name='Decay rate of organic P to DIP', + units='1/d', + description='Decay rate of organic P to DIP', + use='static', +) + +Variable( + name='rpo4_20', + long_name='Benthic sediment release rate of DIP', + units='g-P/m^2/d', + description='Benthic sediment release rate of DIP', + use='static', +) + +Variable( + name='kdpo4', + long_name='solid partitioning coeff. of PO4', + units='L/kg', + description='solid partitioning coeff. of PO4', + use='static', +) + +############################################ From POM +Variable( + name='kpom_20', + long_name='POM dissolution rate at 20C', + units='1/d', + description='POM dissolution rate at 20C', + use='static' +) + +############################################ From CBOD +Variable( + name='kbod_20', + long_name='CBOD oxidation rate at 20C', + units='1/d', + description='CBOD oxidation rate at 20C', + use='static' +) + +Variable( + name='ksbod_20', + long_name='CBOD sedimentation rate at 20C', + units='m/d', + description='CBOD sedimentation rate at 20C', + use='static' +) + +Variable( + name='KsOxbod', + long_name='Half saturation oxygen attenuation constant for CBOD oxidation', + units='mg-O2/L', + description='Half saturation oxygen attenuation constant for CBOD oxidation', + use='static' +) + +############################################ From Carbon +Variable( + name='f_pocp', + long_name='Fraction of algal mortality into POC', + units='unitless', + description='Fraction of dead algae that converts to particulate organic carbon', + use='static' +) + +Variable( + name='kdoc_20', + long_name='Dissolved organic carbon oxidation rate', + units='1/d', + description='Dissolved organic carbon oxidation rate', + use='static' +) + +Variable( + name='f_pocb', + long_name='fraction of benthic algal mortality into POC', + units='unitless', + description='fraction of benthic algal mortality into POC', + use='static' +) + +Variable( + name='kpoc_20', + long_name='POC hydrolysis rate at 20 degrees Celsius', + units='1/d', + description='POC hydrolysis rate at 20 degrees Celsius', + use='static' +) + +Variable( + name='KsOxmc', + long_name='half saturation oxygen attenuation constant for DOC oxidation rate', + units='mg-O2/L', + description='half saturation oxygen attenuation constant for DOC oxidation rate', + use='static' +) + +Variable( + name='pCO2', + long_name='partial atmospheric CO2 pressure', + units='ppm', + description='partial pressure of CO2 in the atmosphere', + use='static' +) + +Variable( + name='FCO2', + long_name='CO2 reaeration rate', + units='1/d', + description='CO2 reaeration rate', + use='static' +) + +Variable( + name='roc', + long_name='O2:C ratio for carbon oxidation', + units='mg-O2/mg-C', + description='O2:C ratio for carbon oxidation (32/12)', + use='static' +) + +############################################ From DOX +Variable( + name='ron', + long_name='O2:N ratio for nitrification', + units='mg-O2/mg-N', + description='O2:N ratio for nitrification (2*32/14)', + use='static' +) + +Variable( + name='KsSOD', + long_name='half saturation oxygen attenuation constant for SOD', + units='mg/L', + description='half saturation oxygen attenuation constant for SOD', + use='static' +) + +############################################ From Pathogen +Variable( + name='kdx_20', + long_name='Pathogen death rate at 20C', + units='1/d', + description='Pathogen death rate at 20C', + use='static', +) + +Variable( + name='apx', + long_name='Light efficiency factor for pathogen decay', + units='unitless', + description='Light efficiency factor for pathogen decay', + use='static', +) + +Variable( + name='vx', + long_name='Pathogen net settling velocity', + units='unitless', + description='Pathogen net settling velocity', + use='static', +) + +############################################ From Alkalinity +Variable( + name='r_alkaa', + long_name='Ratio translating algal growth into Alk if NH4 is the N source', + units='eq/ug-Chla', + description='Ratio translating algal growth into Alk if NH4 is the N source', + use='static' +) + +Variable( + name='r_alkan', + long_name='Ratio translating algal growth into Alk if NO3 is the N source', + units='eq/ug-Chla', + description='Ratio translating algal growth into Alk if NO3 is the N source', + use='static' +) + +Variable( + name='r_alkn', + long_name='Ratio translating NH4 nitrification into Alk', + units='eq/mg-N', + description='Ratio translating NH4 nitrification into Alk', + use='static' +) + +Variable( + name='r_alkden', + long_name='Ratio translating NO3 denitrification into Alk', + units='eq/mg-N', + description='Ratio translating NO3 denitrification into Alk', + use='static' +) + +Variable( + name='r_alkba', + long_name='Ratio translating benthic algae growth into Alk if NH4 is the N source', + units='eq/mg-D', + description='Ratio translating benthic algae growth into Alk if NH4 is the N source', + use='static' +) + +Variable( + name='r_alkbn', + long_name='Ratio translating benthic algae growth into Alk if NO3 is the N source', + units='eq/mg-D', + description='Ratio translating benthic algae growth into Alk if NO3 is the N source', + use='static' +) + + + + + + + + + + + + From 02db5085dc709423780f93bf904ba5a0feab6439 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:53:48 -0600 Subject: [PATCH 02/20] Corrected BWn constant --- examples/model_architecture_nsm.ipynb | 13 +++++++------ src/clearwater_modules/nsm1/constants.py | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index 1966b8f..c928f62 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -72,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "3bce5192", "metadata": {}, "outputs": [ @@ -85,16 +85,17 @@ }, { "ename": "ValueError", - "evalue": "No initial value found for state variable: POM2.", + "evalue": "No initial value found for static variable: BWn.", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[6], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", + "Cell \u001b[1;32mIn[3], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\model.py:170\u001b[0m, in \u001b[0;36mNutrientBudget.__init__\u001b[1;34m(self, initial_state_values, updateable_static_variables, algae_parameters, alkalinity_parameters, balgae_parameters, carbon_parameters, CBOD_parameters, DOX_parameters, nitrogen_parameters, POM_parameters, N2_parameters, phosphorus_parameters, pathogen_parameters, global_parameters, global_vars, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 152\u001b[0m static_variable_values \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 153\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__algae_parameters,\n\u001b[0;32m 154\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__alkalinity_parameters,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 164\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_parameters,\n\u001b[0;32m 165\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_vars}\n\u001b[0;32m 167\u001b[0m \u001b[38;5;66;03m# TODO: make sure this feature works -> test it, but post demo\u001b[39;00m\n\u001b[0;32m 168\u001b[0m \u001b[38;5;66;03m#static_variable_values['use_sed_temp'] = use_sed_temp\u001b[39;00m\n\u001b[1;32m--> 170\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[0;32m 171\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 174\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhotstart_dataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_dim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:74\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minitial_state_values, \u001b[38;5;28mdict\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstatic_variable_values, \u001b[38;5;28mdict\u001b[39m):\n\u001b[0;32m 73\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from dicts...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m---> 74\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_dataset_from_dicts\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 75\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 76\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 77\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 78\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 80\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(hotstart_dataset, xr\u001b[38;5;241m.\u001b[39mDataset):\n\u001b[0;32m 81\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from hotstart dataset...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:113\u001b[0m, in \u001b[0;36mModel._init_dataset_from_dicts\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables)\u001b[0m\n\u001b[0;32m 111\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m state_var \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstate_variables:\n\u001b[0;32m 112\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m state_var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m initial_state_values\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[1;32m--> 113\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 114\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo initial value found for state variable: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mstate_var\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 115\u001b[0m )\n\u001b[0;32m 117\u001b[0m \u001b[38;5;66;03m# reassign updateable_static_variables to state variables\u001b[39;00m\n\u001b[0;32m 118\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m static \u001b[38;5;129;01min\u001b[39;00m updateable_static_variables:\n", - "\u001b[1;31mValueError\u001b[0m: No initial value found for state variable: POM2." + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:129\u001b[0m, in \u001b[0;36mModel._init_dataset_from_dicts\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables)\u001b[0m\n\u001b[0;32m 127\u001b[0m \u001b[38;5;66;03m# initialize the main model dataset\u001b[39;00m\n\u001b[0;32m 128\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_init_state_arrays(initial_state_values)\n\u001b[1;32m--> 129\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_static_arrays\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 130\u001b[0m \u001b[43m \u001b[49m\u001b[43mdataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 131\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 132\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 134\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mModel initialized from input dicts successfully!.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 135\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m dataset\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:210\u001b[0m, in \u001b[0;36mModel._init_static_arrays\u001b[1;34m(self, dataset, static_variable_values)\u001b[0m\n\u001b[0;32m 208\u001b[0m \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[0;32m 209\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m static_variable_values\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[1;32m--> 210\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 211\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo initial value found for static variable: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 212\u001b[0m )\n\u001b[0;32m 213\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01min\u001b[39;00m dataset\u001b[38;5;241m.\u001b[39mcoords\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[0;32m 214\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 215\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariable name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m already exists in coords.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 216\u001b[0m )\n", + "\u001b[1;31mValueError\u001b[0m: No initial value found for static variable: BWn." ] } ], @@ -153,7 +154,7 @@ "balgae_parameters = {\n", " 'BWd': 100,\n", " 'BWc': 40,\n", - " 'Bwn': 7.2,\n", + " 'BWn': 7.2,\n", " 'BWp': 1,\n", " 'BWa': 3500,\n", "\n", diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index dbc27e4..fe0ea3c 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -70,7 +70,7 @@ class AlkalinityStaticVariables(TypedDict): class BalgaeStaticVariables(TypedDict): BWd: float BWc: float - Bwn: float + BWn: float BWp: float BWa: float @@ -89,7 +89,7 @@ class BalgaeStaticVariables(TypedDict): DEFAULT_BALGAE = BalgaeStaticVariables( BWd = 100, BWc= 40, - Bwn=7.2, + BWn=7.2, BWp= 1, BWa= 3500, From 05fd9fc2d1c845f4b1e0f85a03f0205c631686d0 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:56:38 -0600 Subject: [PATCH 03/20] Corrected KsOxbod --- examples/model_architecture_nsm.ipynb | 50 ++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index c928f62..d9c9127 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -72,10 +72,50 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "id": "3bce5192", "metadata": {}, "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, { "name": "stdout", "output_type": "stream", @@ -85,17 +125,17 @@ }, { "ename": "ValueError", - "evalue": "No initial value found for static variable: BWn.", + "evalue": "No initial value found for static variable: KsOxbod.", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[3], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", + "Cell \u001b[1;32mIn[1], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\model.py:170\u001b[0m, in \u001b[0;36mNutrientBudget.__init__\u001b[1;34m(self, initial_state_values, updateable_static_variables, algae_parameters, alkalinity_parameters, balgae_parameters, carbon_parameters, CBOD_parameters, DOX_parameters, nitrogen_parameters, POM_parameters, N2_parameters, phosphorus_parameters, pathogen_parameters, global_parameters, global_vars, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 152\u001b[0m static_variable_values \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 153\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__algae_parameters,\n\u001b[0;32m 154\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__alkalinity_parameters,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 164\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_parameters,\n\u001b[0;32m 165\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_vars}\n\u001b[0;32m 167\u001b[0m \u001b[38;5;66;03m# TODO: make sure this feature works -> test it, but post demo\u001b[39;00m\n\u001b[0;32m 168\u001b[0m \u001b[38;5;66;03m#static_variable_values['use_sed_temp'] = use_sed_temp\u001b[39;00m\n\u001b[1;32m--> 170\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[0;32m 171\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 174\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhotstart_dataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_dim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:74\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minitial_state_values, \u001b[38;5;28mdict\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstatic_variable_values, \u001b[38;5;28mdict\u001b[39m):\n\u001b[0;32m 73\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from dicts...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m---> 74\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_dataset_from_dicts\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 75\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 76\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 77\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 78\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 80\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(hotstart_dataset, xr\u001b[38;5;241m.\u001b[39mDataset):\n\u001b[0;32m 81\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from hotstart dataset...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:129\u001b[0m, in \u001b[0;36mModel._init_dataset_from_dicts\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables)\u001b[0m\n\u001b[0;32m 127\u001b[0m \u001b[38;5;66;03m# initialize the main model dataset\u001b[39;00m\n\u001b[0;32m 128\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_init_state_arrays(initial_state_values)\n\u001b[1;32m--> 129\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_static_arrays\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 130\u001b[0m \u001b[43m \u001b[49m\u001b[43mdataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 131\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 132\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 134\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mModel initialized from input dicts successfully!.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 135\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m dataset\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:210\u001b[0m, in \u001b[0;36mModel._init_static_arrays\u001b[1;34m(self, dataset, static_variable_values)\u001b[0m\n\u001b[0;32m 208\u001b[0m \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[0;32m 209\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m static_variable_values\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[1;32m--> 210\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 211\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo initial value found for static variable: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 212\u001b[0m )\n\u001b[0;32m 213\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01min\u001b[39;00m dataset\u001b[38;5;241m.\u001b[39mcoords\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[0;32m 214\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 215\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariable name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m already exists in coords.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 216\u001b[0m )\n", - "\u001b[1;31mValueError\u001b[0m: No initial value found for static variable: BWn." + "\u001b[1;31mValueError\u001b[0m: No initial value found for static variable: KsOxbod." ] } ], @@ -195,7 +235,7 @@ "CBOD_parameters = {\n", " 'kbod_20': 0.12,\n", " 'ksbod_20': 0,\n", - " 'ksOxbod': 0.5\n", + " 'KsOxbod': 0.5\n", "}\n", "\n", "carbon_parameters = {\n", From 26626682811ad0bdf0a62888b087e7cbc520030b Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:16:17 -0600 Subject: [PATCH 04/20] Updated nsm constants file to remove duplicates --- examples/model_architecture_nsm.ipynb | 4 +- src/clearwater_modules/nsm1/constants.py | 83 ++---------------------- 2 files changed, 7 insertions(+), 80 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index d9c9127..2aa4dc6 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -233,9 +233,9 @@ "}\n", "\n", "CBOD_parameters = {\n", + " 'KsOxbod': 0.5,\n", " 'kbod_20': 0.12,\n", - " 'ksbod_20': 0,\n", - " 'KsOxbod': 0.5\n", + " 'ksbod_20': 0\n", "}\n", "\n", "carbon_parameters = {\n", diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index fe0ea3c..1128d16 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -57,7 +57,7 @@ class AlkalinityStaticVariables(TypedDict): r_alkba: float r_alkbn: float -DEFAULT_Alkalinity = AlkalinityStaticVariables( +DEFAULT_ALKALINITY = AlkalinityStaticVariables( r_alkaa = 14.0 / 106.0 / 12.0 / 1000.0, r_alkan= 18.0 / 106.0 / 12.0 / 1000.0, r_alkn = 2.0 / 14.0 / 1000.0, @@ -137,12 +137,11 @@ class CarbonStaticVariables(TypedDict): f_pocb: float kpoc_20: float KsOxmc: float - kac_20: float pCO2: float FCO2: float roc: float -DEFAULT_Carbon = CarbonStaticVariables( +DEFAULT_CARBON = CarbonStaticVariables( f_pocp = 0.9, kdoc_20= 0.01, f_pocb=0.9, @@ -154,14 +153,14 @@ class CarbonStaticVariables(TypedDict): ) class CBODStaticVariables(TypedDict): + KsOxbod: float kbod_20: float ksbod_20: float - KsOxbod: float DEFAULT_CBOD = CBODStaticVariables( + KsOxbod = 0.5, kbod_20 = 0.12, - ksbod_20 = 0.0, - KsOxbod = 0.5 + ksbod_20 = 0.0 ) class DOXStaticVariables(TypedDict): @@ -180,15 +179,6 @@ class N2StaticVariables(TypedDict): ) -class PhosphorusStaticVariables(TypedDict): - kop_20: float - rpo4_20: float - -DEFAULT_PHOSPHORUS = PhosphorusStaticVariables( - kop_20 = 0.1, - rpo4_20 = 0 -) - class POMStaticVariables(TypedDict): kpom_20: float @@ -198,46 +188,6 @@ class POMStaticVariables(TypedDict): ) -class CBODStaticVariables(TypedDict): - kbod_20: float - ksbod_20: float - ksOxbod: float - -DEFAULT_CBOD = CBODStaticVariables( - kbod_20 = 0.12, - ksbod_20 = 0, - ksOxbod = 0.5 -) - - -class CarbonStaticVariables(TypedDict): - F_pocp: float - kdoc_20: float - F_pocb: float - kpoc_20: float - K_sOxmc: float - pCO2: float - FCO2: float - -DEFAULT_CARBON = CarbonStaticVariables( - F_pocp = 0.9, - kdoc_20 = 0.01, - F_pocb = 0.9, - kpoc_20 = 0.005, - K_sOxmc = 1, - pCO2 = 383, - FCO2 = 0.2 -) - - -class DOXStaticVariables(TypedDict): - ... - -DEFAULT_DOX = DOXStaticVariables( - -) - - class PathogenStaticVariables(TypedDict): kdx_20: float apx: float @@ -249,23 +199,6 @@ class PathogenStaticVariables(TypedDict): vx=1 ) -class AlkalinityStaticVariables(TypedDict): - r_alkaa: float - r_alkan: float - r_alkn: float - r_alkden: float - r_alkba: float - r_alkbn: float - -DEFAULT_ALKALINITY = AlkalinityStaticVariables( - r_alkaa = 1, - r_alkan = 1, - r_alkn = 1, - r_alkden = 1, - r_alkba = 1, - r_alkbn = 1 -) - class PhosphorusStaticVariables(TypedDict): kop_20: float rpo4_20: float @@ -277,12 +210,6 @@ class PhosphorusStaticVariables(TypedDict): kdpo4 = 0.0, ) -class POMStaticVariables(TypedDict): - kpom_20: float - -DEFAULT_POM = POMStaticVariables( - kpom_20 = 0.01, -) class GlobalParameters(TypedDict): use_NH4 : bool From acf6203e98f66b2d41f103a3d6a4d718858f219b Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:49:46 -0600 Subject: [PATCH 05/20] Updated dynamic variables that were coming up as circular, solved all but dDOXdt --- examples/model_architecture_nsm.ipynb | 34 +++-- src/clearwater_modules/nsm1/constants.py | 5 +- .../nsm1/dynamic_variables.py | 34 ++--- src/clearwater_modules/nsm1/processes.py | 117 +++++------------- .../nsm1/static_variables.py | 18 ++- 5 files changed, 84 insertions(+), 124 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index 2aa4dc6..bd095fa 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -120,22 +120,24 @@ "name": "stdout", "output_type": "stream", "text": [ - "Initializing from dicts...\n" + "Initializing from dicts...\n", + "Model initialized from input dicts successfully!.\n", + "Variable | Inputs\n", + "------------------\n" ] }, { "ename": "ValueError", - "evalue": "No initial value found for static variable: KsOxbod.", + "evalue": "Circular dependency detected in dynamic/state variables! Variables remaining: ['dDOXdt', 'DOX']", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 174\u001b[0m\n\u001b[0;32m 170\u001b[0m DOX_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 171\u001b[0m N2_parameters \u001b[38;5;241m=\u001b[39m {}\n\u001b[1;32m--> 174\u001b[0m nsm_model \u001b[38;5;241m=\u001b[39m \u001b[43mNutrientBudget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mandatory\u001b[39;49;00m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43malgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43malkalinity_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43malkalinity_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 178\u001b[0m \u001b[43m \u001b[49m\u001b[43mbalgae_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbalgae_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 179\u001b[0m \u001b[43m \u001b[49m\u001b[43mcarbon_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcarbon_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 180\u001b[0m \u001b[43m \u001b[49m\u001b[43mCBOD_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCBOD_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43mDOX_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mDOX_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnitrogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOM_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPOM_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 184\u001b[0m \u001b[43m \u001b[49m\u001b[43mN2_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mN2_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 185\u001b[0m \u001b[43m \u001b[49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mphosphorus_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 186\u001b[0m \u001b[43m \u001b[49m\u001b[43mpathogen_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpathogen_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 187\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_parameters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[43m \u001b[49m\u001b[43mglobal_vars\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mglobal_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 189\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is true\u001b[39;49;00m\n\u001b[0;32m 190\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is None\u001b[39;49;00m\n\u001b[0;32m 191\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43myear\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# default is \"timestep\"\u001b[39;49;00m\n\u001b[0;32m 192\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 194\u001b[0m \u001b[38;5;66;03m#print(tsm_model.get_state_variables())\u001b[39;00m\n\u001b[0;32m 195\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\model.py:170\u001b[0m, in \u001b[0;36mNutrientBudget.__init__\u001b[1;34m(self, initial_state_values, updateable_static_variables, algae_parameters, alkalinity_parameters, balgae_parameters, carbon_parameters, CBOD_parameters, DOX_parameters, nitrogen_parameters, POM_parameters, N2_parameters, phosphorus_parameters, pathogen_parameters, global_parameters, global_vars, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 152\u001b[0m static_variable_values \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 153\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__algae_parameters,\n\u001b[0;32m 154\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__alkalinity_parameters,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 164\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_parameters,\n\u001b[0;32m 165\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__global_vars}\n\u001b[0;32m 167\u001b[0m \u001b[38;5;66;03m# TODO: make sure this feature works -> test it, but post demo\u001b[39;00m\n\u001b[0;32m 168\u001b[0m \u001b[38;5;66;03m#static_variable_values['use_sed_temp'] = use_sed_temp\u001b[39;00m\n\u001b[1;32m--> 170\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[0;32m 171\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[0;32m 174\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrack_dynamic_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43mhotstart_dataset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhotstart_dataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43mtime_dim\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_dim\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 177\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:74\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables, track_dynamic_variables, hotstart_dataset, time_dim)\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minitial_state_values, \u001b[38;5;28mdict\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstatic_variable_values, \u001b[38;5;28mdict\u001b[39m):\n\u001b[0;32m 73\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from dicts...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m---> 74\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_dataset_from_dicts\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 75\u001b[0m \u001b[43m \u001b[49m\u001b[43minitial_state_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minitial_state_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 76\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 77\u001b[0m \u001b[43m \u001b[49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupdateable_static_variables\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 78\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 80\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(hotstart_dataset, xr\u001b[38;5;241m.\u001b[39mDataset):\n\u001b[0;32m 81\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mInitializing from hotstart dataset...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:129\u001b[0m, in \u001b[0;36mModel._init_dataset_from_dicts\u001b[1;34m(self, initial_state_values, static_variable_values, updateable_static_variables)\u001b[0m\n\u001b[0;32m 127\u001b[0m \u001b[38;5;66;03m# initialize the main model dataset\u001b[39;00m\n\u001b[0;32m 128\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_init_state_arrays(initial_state_values)\n\u001b[1;32m--> 129\u001b[0m dataset: xr\u001b[38;5;241m.\u001b[39mDataset \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_static_arrays\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 130\u001b[0m \u001b[43m \u001b[49m\u001b[43mdataset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 131\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatic_variable_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 132\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 134\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mModel initialized from input dicts successfully!.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 135\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m dataset\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:210\u001b[0m, in \u001b[0;36mModel._init_static_arrays\u001b[1;34m(self, dataset, static_variable_values)\u001b[0m\n\u001b[0;32m 208\u001b[0m \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[0;32m 209\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m static_variable_values\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[1;32m--> 210\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 211\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo initial value found for static variable: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 212\u001b[0m )\n\u001b[0;32m 213\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m var\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01min\u001b[39;00m dataset\u001b[38;5;241m.\u001b[39mcoords\u001b[38;5;241m.\u001b[39mkeys():\n\u001b[0;32m 214\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 215\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariable name \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvar\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m already exists in coords.\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 216\u001b[0m )\n", - "\u001b[1;31mValueError\u001b[0m: No initial value found for static variable: KsOxbod." + "Cell \u001b[1;32mIn[1], line 200\u001b[0m\n\u001b[0;32m 197\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n\u001b[0;32m 199\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariable | Inputs\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m------------------\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m--> 200\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[43mnsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcomputation_order\u001b[49m:\n\u001b[0;32m 201\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mi\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m | \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msorter\u001b[38;5;241m.\u001b[39mget_process_args(i\u001b[38;5;241m.\u001b[39mprocess)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:309\u001b[0m, in \u001b[0;36mModel.computation_order\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 307\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Return a list of variables to compute in order (dynamic + state).\"\"\"\u001b[39;00m\n\u001b[0;32m 308\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m--> 309\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables \u001b[38;5;241m=\u001b[39m \u001b[43msorter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msort_variables_for_computation\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 310\u001b[0m \u001b[43m \u001b[49m\u001b[43msorter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit_variables\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mall_variables\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 311\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 312\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\sorter.py:83\u001b[0m, in \u001b[0;36msort_variables_for_computation\u001b[1;34m(variables_dict)\u001b[0m\n\u001b[0;32m 81\u001b[0m arg_names\u001b[38;5;241m.\u001b[39mremove(var\u001b[38;5;241m.\u001b[39mname)\n\u001b[0;32m 82\u001b[0m variable_args[var\u001b[38;5;241m.\u001b[39mname] \u001b[38;5;241m=\u001b[39m (var, arg_names)\n\u001b[1;32m---> 83\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m__rapid_sort\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstatic_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstate_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_args\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\sorter.py:55\u001b[0m, in \u001b[0;36m__rapid_sort\u001b[1;34m(static_vars, state_vars, variable_args_dict)\u001b[0m\n\u001b[0;32m 53\u001b[0m variable_args_dict\u001b[38;5;241m.\u001b[39mpop(key)\n\u001b[0;32m 54\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(variable_args_dict) \u001b[38;5;241m==\u001b[39m previous_len:\n\u001b[1;32m---> 55\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 56\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCircular dependency detected in dynamic/state variables! \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 57\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariables remaining: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(variable_args_dict\u001b[38;5;241m.\u001b[39mkeys())\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 58\u001b[0m )\n\u001b[0;32m 59\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 60\u001b[0m previous_len \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlen\u001b[39m(variable_args_dict)\n", + "\u001b[1;31mValueError\u001b[0m: Circular dependency detected in dynamic/state variables! Variables remaining: ['dDOXdt', 'DOX']" ] } ], @@ -239,9 +241,9 @@ "}\n", "\n", "carbon_parameters = {\n", - " 'F_pocp': 0.9,\n", + " 'f_pocp': 0.9,\n", " 'kdoc_20': 0.01,\n", - " 'F_pocb': 0.9,\n", + " 'f_pocb': 0.9,\n", " 'kpoc_20': 0.005,\n", " 'K_sOxmc': 1,\n", " 'pCO2': 383,\n", @@ -268,7 +270,7 @@ " 'use_NO3': True, \n", " 'use_OrgN': True,\n", " 'use_TIP': True, \n", - " 'use_SedFlux': True,\n", + " 'use_SedFlux': False,\n", " 'use_DOX': True,\n", " 'use_Algae': True,\n", " 'use_Balgae': True,\n", @@ -297,7 +299,9 @@ " 'hydraulic_reaeration_option': 2,\n", " 'wind_reaeration_option': 2, \n", " 'timestep': 86400,\n", + " 'depth': 1,\n", " 'TwaterC': 20,\n", + " 'theta': 1.047,\n", " 'velocity': 1,\n", " 'flow': 2,\n", " 'topwidth': 1,\n", @@ -333,8 +337,12 @@ " time_dim='year', # default is \"timestep\"\n", ")\n", "\n", - "#print(tsm_model.get_state_variables())\n", - "nsm_model.dataset" + "#nsm_model.increment_timestep()\n", + "nsm_model.dataset\n", + "\n", + "print('Variable | Inputs\\n------------------')\n", + "for i in nsm_model.computation_order:\n", + " print(f'{i.name} | {sorter.get_process_args(i.process)}')" ] }, { diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index 1128d16..ec0aa4b 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -249,7 +249,6 @@ class GlobalParameters(TypedDict): use_POM = True ) - class GlobalVars(TypedDict): vson: float vsoc: float @@ -264,7 +263,9 @@ class GlobalVars(TypedDict): hydraulic_reaeration_option: int wind_reaeration_option: int timestep: float + depth: float TwaterC: float + theta: float velocity: float flow: float topwidth: float @@ -290,7 +291,9 @@ class GlobalVars(TypedDict): hydraulic_reaeration_option = 2, wind_reaeration_option = 2, timestep = 86400, + depth = 1, TwaterC = 20, + theta = 1.047, velocity = 1, flow = 2, topwidth = 1, diff --git a/src/clearwater_modules/nsm1/dynamic_variables.py b/src/clearwater_modules/nsm1/dynamic_variables.py index cabe5eb..6e711b6 100644 --- a/src/clearwater_modules/nsm1/dynamic_variables.py +++ b/src/clearwater_modules/nsm1/dynamic_variables.py @@ -8,14 +8,6 @@ class Variable(base.Variable): ... ############################################ From dynamic_variables_global -Variable( - name='depth', - long_name='Average water depth in cell', - units='m', - description='Average water depth in cell computed by dividing volume by surface area', - use='dynamic', - process=processes.compute_depth -) Variable( name='TwaterK', @@ -750,15 +742,6 @@ class Variable(base.Variable): process=processes.dOrgPdt ) -Variable( - name='DIPfromBed_SedFlux', - long_name='Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules', - units='mg-P/L/d', - description='Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules', - use='dynamic', - process=processes.DIPfromBed_SedFlux -) - Variable(#TODO: find correct process name='DIPfromBed', long_name='Dissolved Organic Phosphorus coming from Bed calculated without SedFlux modules', @@ -1051,12 +1034,12 @@ class Variable(base.Variable): ) Variable( - name='DOC_oxidation', + name='DOC_DIC_oxidation', long_name='DOC concentration lost to cell due to oxidation', units='mg/L/d', description='DOC concentration lost to cell due to oxidation', use='dynamic', - process=processes.DOC_oxidation + process=processes.DOC_DIC_oxidation ) Variable( @@ -1131,6 +1114,7 @@ class Variable(base.Variable): process=processes.DIC_CBOD_oxidation ) + Variable( name='DIC_sed_release', long_name='DIC concentration change due to sediment release', @@ -1186,7 +1170,6 @@ class Variable(base.Variable): process=processes.Atm_O2_reaeration ) -# TODO: UPDATE BASED ON FORTRAN Variable( name='DOX_ApGrowth', long_name='Dissolved oxygen flux due to algal photosynthesis', @@ -1196,9 +1179,8 @@ class Variable(base.Variable): process=processes.DOX_ApGrowth ) -# TODO: UPDATE BASED ON FORTRAN Variable( - name='DOX_algal_respiration', + name='DOX_ApRespiration', long_name='Dissolved oxygen flux due to algal respiration', units='mg/L/d', description='Dissolved oxygen flux due to algal respiration', @@ -1216,21 +1198,21 @@ class Variable(base.Variable): ) Variable( - name='DOX_DOC_Oxidation', + name='DOX_DOC_oxidation', long_name='Dissolved oxygen flux due to DOC oxidation', units='mg/L/d', description='Dissolved oxygen flux due to DOC oxidation', use='dynamic', - process=processes.DOX_DOC_Oxidation + process=processes.DOX_DOC_oxidation ) Variable( - name='DOX_CBOD_Oxidation', + name='DOX_CBOD_oxidation', long_name='Dissolved oxygen flux due to CBOD oxidation', units='mg/L/d', description='Dissolved oxygen flux due to CBOD oxidation', use='dynamic', - process=processes.DOX_CBOD_Oxidation + process=processes.DOX_CBOD_oxidation ) Variable( diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 2403161..9ee7aa7 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -40,18 +40,6 @@ def arrhenius_correction( """ return rc20 * theta**(TwaterC - 20.0) -@numba.njit -def compute_depth( - surface_area: xr.DataArray, - volume: xr.DataArray -) -> xr.DataArray: - """Compute depth of a computation cell - - Args: - surface_area: state variable for surface area of computational cell provided by CWR engine - volume: state variable for volume of computational cell provided by CWR engine - """ - return volume / surface_area @numba.njit def TwaterK( @@ -182,7 +170,7 @@ def ka_tc( def SOD_tc( SOD_20: xr.DataArray, TwaterC: xr.DataArray, - theta: xr.DataArray, + SOD_theta: xr.DataArray, DOX: xr.DataArray, KsSOD: xr.DataArray, use_DOX: xr.DataArray @@ -195,7 +183,7 @@ def SOD_tc( theta: Arrhenius coefficient use_DOX: Option to consider DOX concentration in water in calculation of sediment oxygen demand """ - SOD_tc = arrhenius_correction(TwaterC, SOD_20, theta) + SOD_tc = arrhenius_correction(TwaterC, SOD_20, SOD_theta) da: xr.DataArray = xr.where(use_DOX == True, SOD_tc * DOX / (DOX + KsSOD), SOD_tc) @@ -1219,8 +1207,6 @@ def NH4_Nitrification( @numba.njit def NH4fromBed( - use_SedFlux: bool, - JNH4: xr.DataArray, depth: xr.DataArray, rnh4_tc: xr.DataArray, @@ -1228,14 +1214,12 @@ def NH4fromBed( """Calculate NH4fromBed: bed -> NH4 (diffusion) (mg-N/L/day) Args: - use_SedFlux: true/false to use sediment flux module (unitless), depth: water depth (m), - JNH4: Sediment water flux of ammonium (g-N/m^2/d), rnh4_tc: Sediment release rate of NH4 temperature correction(1/d). """ - return xr.where(use_SedFlux, JNH4 / depth, rnh4_tc / depth) + return rnh4_tc / depth @numba.njit def NH4_ApRespiration( @@ -1391,8 +1375,6 @@ def NO3_Denit( @numba.njit def NO3_BedDenit( - use_SedFlux: bool, - JNO3: xr.DataArray, depth: xr.DataArray, vno3_tc: xr.DataArray, NO3: xr.DataArray, @@ -1401,15 +1383,13 @@ def NO3_BedDenit( """Calculate NO3_BedDenit: Sediment denitrification (mg-N/L/day) Args: - use_SedFlux: true/false to use sediment flux module (unitless), depth: water depth (m), - NO3: Nitrate concentration (mg-N/L), - JNO3: Sediment water flux of nitrate (g-N/m^2/d), + NO3: Nitrate concentration (mg-N/L) vno3_tc: Sediment denitrification velocity temperature correction (m/d) """ - return xr.where(use_SedFlux, JNO3 / depth,vno3_tc * NO3 / depth) + return vno3_tc * NO3 / depth @numba.njit def NO3_ApGrowth( @@ -1717,23 +1697,6 @@ def dOrgPdt( """ return xr.where(use_OrgP, -OrgP_DIP_decay-OrgP_Settling + ApDeath_OrgP + AbDeath_OrgP, 0) - -#TODO will this be a problem if use_SedFlux is False -def DIPfromBed_SedFlux( - use_SedFlux: bool, - JDIP: xr.DataArray, - depth:xr.DataArray, - rpo4_tc: xr.DataArray, -) -> xr.DataArray : - """Calculate DIPfromBed_SedFlux: Dissolved Organic Phosphorus coming from Bed calculated using SedFlux modules (mg-P/L/d). - - Args: - use_SedFlux: true/false to use the sediment flux module (unitless) - JDIP: Sediment-water flux of phosphate (g-P/m^2/d) - depth: water depth (m) - rpo4_tc: Benthic sediment release rate of DIP temperature correction(g-P/m2/d) - """ - return xr.where(use_SedFlux, JDIP / depth, rpo4_tc/depth) @numba.njit def DIPfromBed( @@ -2016,7 +1979,7 @@ def POM_POC_settling( POC: xr.DataArray, vsoc: xr.DataArray, depth: xr.DataArray, - focm: xr.DataArray, + fcom: xr.DataArray, use_POC: xr.DataArray ) -> xr.DataArray: """Calculates particulate organic matter concentration change due to POM settling @@ -2028,7 +1991,7 @@ def POM_POC_settling( fcom: Fraction of carbon in organic matter (mg-C/mg-D) use_POC: Option to consider particulate organic carbon """ - da: xr.DataArray = xr.where(use_POC == True, vsoc * POC / depth / focm, 0) + da: xr.DataArray = xr.where(use_POC == True, vsoc * POC / depth / fcom, 0) return da @@ -2277,7 +2240,7 @@ def POC_algal_mortality( def POC_benthic_algae_mortality( depth: xr.DataArray, - F_pocb: xr.DataArray, + f_pocb: xr.DataArray, kdb_tc: xr.DataArray, rcb: xr.DataArray, Ab: xr.DataArray, @@ -2289,7 +2252,7 @@ def POC_benthic_algae_mortality( Args: depth: Water depth in cell (m) - F_pocb: Fraction of benthic algal mortality into POC + f_pocb: Fraction of benthic algal mortality into POC kdb_tc: Benthic algae death rate (1/d) rcb: Benthic algae C to biomass weight ratio (mg-C/mg-D) Ab: Benthic algae concentration (mg/L) @@ -2297,7 +2260,7 @@ def POC_benthic_algae_mortality( Fw: Fraction of benthic algae mortality into water column use_Balgae: Option for considering benthic algae in POC budget (boolean) """ - da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * F_pocb * kdb_tc * rcb * Ab * Fb * Fw, 0) + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * f_pocb * kdb_tc * rcb * Ab * Fb * Fw, 0) return da @@ -2358,7 +2321,7 @@ def DOC_algal_mortality( def DOC_benthic_algae_mortality( depth: xr.DataArray, - F_pocb: xr.DataArray, + f_pocb: xr.DataArray, kdb_tc: xr.DataArray, rcb: xr.DataArray, Ab: xr.DataArray, @@ -2378,7 +2341,7 @@ def DOC_benthic_algae_mortality( Fw: Fraction of benthic algae mortality into water column use_Balgae: Option for considering benthic algae in DOC budget (boolean) """ - da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * (1 - F_pocb) * kdb_tc * rcb * Ab * Fb * Fw, 0) + da: xr.DataArray = xr.where(use_Balgae == True, (1 / depth) * (1 - f_pocb) * kdb_tc * rcb * Ab * Fb * Fw, 0) return da @@ -2397,7 +2360,7 @@ def kdoc_tc( return arrhenius_correction(TwaterC, kdoc_20, 1.047) -def DOC_oxidation( +def DOC_DIC_oxidation( DOX: xr.DataArray, KsOxmc: xr.DataArray, kdoc_tc: xr.DataArray, @@ -2420,7 +2383,7 @@ def DOC_oxidation( @numba.njit def dDOCdt( - DOC_oxidation: xr.DataArray, + DOC_DIC_oxidation: xr.DataArray, POC_hydrolysis: xr.DataArray, DOC_algal_mortality: xr.DataArray, DOC_benthic_algae_mortality: xr.DataArray @@ -2435,7 +2398,7 @@ def dDOCdt( DOC_benthic_algae_mortality: DOC concentration change due to benthic algae mortality (mg/L/d) DOC_oxidation: DOC concentration change due to DOC oxidation (mg/L/d) """ - return POC_hydrolysis + DOC_algal_mortality + DOC_benthic_algae_mortality - DOC_oxidation + return POC_hydrolysis + DOC_algal_mortality + DOC_benthic_algae_mortality - DOC_DIC_oxidation @numba.njit @@ -2589,8 +2552,7 @@ def DIC_sed_release( SOD_tc: xr.DataArray, roc: xr.DataArray, depth: xr.DataArray, - JDIC: xr.DataArray, - use_SedFlux: xr.DataArray + ) -> xr.DataArray: """Computes the sediment release of DIC @@ -2598,12 +2560,8 @@ def DIC_sed_release( SOD_tc: Sediment oxygen demand adjusted for water temperature (mg-O2/L/d) roc: Ratio of O2 to carbon for carbon oxidation (mg-O2/mg-C) depth: Water depth (m) - JDIC: Sediment-water flux of dissolved inorganic carbon (g-C/m2/d) - use_SedFlux: Option to consider full sediment flux budget in DIC sediment contribution (bool) """ - da: xr.DataArray = xr.where(use_SedFlux == True, JDIC / depth, SOD_tc / roc / depth) - - return da + return SOD_tc / roc / depth @numba.njit @@ -2613,7 +2571,6 @@ def dDICdt( DIC_algal_photosynthesis: xr.DataArray, DIC_benthic_algae_respiration: xr.DataArray, DIC_benthic_algae_photosynthesis: xr.DataArray, - DIC_DOC_oxidation: xr.DataArray, DIC_CBOD_oxidation: xr.DataArray, DIC_sed_release: xr.DataArray ) -> xr.DataArray: @@ -2628,7 +2585,7 @@ def dDICdt( DIC_CBOD_oxidation: DIC concentration change due to CBOD oxidation (mg/L/d) DIC_sed_release: DIC concentration change due to sediment release (mg/L/d) """ - return Atm_CO2_reaeration + DIC_algal_respiration + DIC_benthic_algae_respiration + DIC_DOC_oxidation + DIC_CBOD_oxidation + DIC_sed_release - DIC_algal_photosynthesis - DIC_benthic_algae_photosynthesis + return Atm_CO2_reaeration + DIC_algal_respiration + DIC_benthic_algae_respiration + DIC_CBOD_oxidation + DIC_sed_release - DIC_algal_photosynthesis - DIC_benthic_algae_photosynthesis @numba.njit @@ -2775,25 +2732,25 @@ def DOX_Nitrification( return da -def DOX_DOC_Oxidation( - DOC_Oxidation: xr.DataArray, +def DOX_DOC_oxidation( + DOC_DIC_oxidation: xr.DataArray, roc: xr.DataArray, use_DOC: xr.DataArray ) -> xr.DataArray: """Computes dissolved oxygen flux due to oxidation of dissolved organic carbon Args: - DOC_Oxidation: Dissolved organic carbon oxidation, calculated in carbon module (mg/L/d) + DOC_DIC_Oxidation: Dissolved organic carbon oxidation, calculated in carbon module (mg/L/d) roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) """ - da: xr.DataArray = xr.where(use_DOC == True, roc * DOC_Oxidation, 0) + da: xr.DataArray = xr.where(use_DOC == True, roc * DOC_DIC_oxidation, 0) return da @numba.njit -def DOX_CBOD_Oxidation( - DIC_CBOD_Oxidation: xr.DataArray, +def DOX_CBOD_oxidation( + DIC_CBOD_oxidation: xr.DataArray, roc: xr.DataArray ) -> xr.DataArray: """Compute dissolved oxygen flux due to CBOD oxidation @@ -2802,7 +2759,7 @@ def DOX_CBOD_Oxidation( DIC_CBOD_Oxidation: Carbonaceous biochemical oxygen demand oxidation, calculated in CBOD module (mg/L/d) roc: Ratio of oxygen to carbon for carbon oxidation (mg-O2/mg-C) """ - return DIC_CBOD_Oxidation * roc + return DIC_CBOD_oxidation * roc def DOX_AbGrowth( @@ -2836,7 +2793,7 @@ def DOX_AbRespiration( AbRespiration: xr.DataArray, Fb: xr.DataArray, depth: xr.DataArray, - use_BAlgae: xr.DataArray + use_Balgae: xr.DataArray ) -> xr.DataArray: """Compute dissolved oxygen flux due to benthic algae respiration @@ -2849,29 +2806,23 @@ def DOX_AbRespiration( use_BAlgae: Option to consider benthic algae in the DOX budget """ - da: xr.DataArray = xr.where(use_BAlgae == True, roc * rcb * AbRespiration * Fb / depth, 0) + da: xr.DataArray = xr.where(use_Balgae == True, roc * rcb * AbRespiration * Fb / depth, 0) return da def DOX_SOD( - SOD_Bed: xr.DataArray, depth: xr.DataArray, - SOD_tc: xr.DataArray, - use_SedFlux: xr.DataArray + SOD_tc: xr.DataArray ) -> xr.DataArray: """Compute dissolved oxygen flux due to sediment oxygen demand Args: - SOD_Bed: Sediment oxygen demand if calculated using the SedFlux module (mg-O2/m2) depth: Water depth (m) SOD_tc: Sediment oxygen demand not considering the SedFlux budget (mg-O2/m2) - use_SedFlux: Option to consider sediment flux in DOX budget (boolean) """ - da: xr.DataArray = xr.where(use_SedFlux == 1, SOD_Bed / depth, SOD_tc / depth) - - return da + return SOD_tc / depth @numba.njit def dDOXdt( @@ -2879,8 +2830,8 @@ def dDOXdt( DOX_ApGrowth: xr.DataArray, DOX_ApRespiration: xr.DataArray, DOX_Nitrification: xr.DataArray, - DOX_DOC_Oxidation: xr.DataArray, - DOX_CBOD_Oxidation: xr.DataArray, + DOX_DOC_oxidation: xr.DataArray, + DOX_CBOD_oxidation: xr.DataArray, DOX_AbGrowth: xr.DataArray, DOX_AbRespiration: xr.DataArray, DOX_SOD: xr.DataArray @@ -2892,13 +2843,13 @@ def dDOXdt( DOX_ApGrowth: DOX concentration change due to algal photosynthesis (mg/L/d) DOX_ApRespiration: DOX concentration change due to algal respiration (mg/L/d) DOX_Nitrification: DOX concentration change due to nitrification (mg/L/d) - DOX_DOC_Oxidation: DOX concentration change due to DOC oxidation (mg/L/d) - DOX_CBOD_Oxidation: DOX concentration change due to CBOD oxidation (mg/L/d) + DOX_DOC_oxidation: DOX concentration change due to DOC oxidation (mg/L/d) + DOX_CBOD_oxidation: DOX concentration change due to CBOD oxidation (mg/L/d) DOX_AbGrowth: DOX concentration change due to benthic algae photosynthesis (mg/L/d) DOX_AbRespiration: DOX concentration change due to benthic algae respiration (mg/L/d) DOX_SOD: DOX concentration change due to sediment oxygen demand (mg/L/d) """ - return Atm_O2_reaeration + DOX_ApGrowth - DOX_ApRespiration - DOX_Nitrification - DOX_DOC_Oxidation - DOX_CBOD_Oxidation + DOX_AbGrowth - DOX_AbRespiration - DOX_SOD + return Atm_O2_reaeration + DOX_ApGrowth - DOX_ApRespiration - DOX_Nitrification - DOX_DOC_oxidation - DOX_CBOD_oxidation + DOX_AbGrowth - DOX_AbRespiration - DOX_SOD @numba.njit diff --git a/src/clearwater_modules/nsm1/static_variables.py b/src/clearwater_modules/nsm1/static_variables.py index b0efccd..0d0cabc 100644 --- a/src/clearwater_modules/nsm1/static_variables.py +++ b/src/clearwater_modules/nsm1/static_variables.py @@ -239,12 +239,28 @@ class Variable(base.Variable): use='static', ) +Variable( + name='depth', + long_name='Depth of water in cell', + units='m', + description='Depth of water in cell', + use='static', +) + Variable( name='TwaterC', long_name='Water temperature in celsius', units='degrees C', description='Water temperature in celsius', - use='static', + use='static' +) + +Variable( + name='theta', + long_name='Water temperature theta adjustment factor', + units='unitless', + description='Water temperature theta adjustment factor', + use='static' ) Variable( From 9accaddea5fc8c3e242a52f27ba56717525c0ec7 Mon Sep 17 00:00:00 2001 From: Sarah Jordan Date: Tue, 5 Mar 2024 16:46:16 -0600 Subject: [PATCH 06/20] fix variables and processes DOX_ApGrowth, DOX_AbGrowth, and use_Balgae --- examples/dev_sandbox/prof_nsm.py | 217 +++++++++ examples/model_architecture_nsm.ipynb | 423 +++++++++++++++++- .../nsm1/dynamic_variables.py | 6 +- src/clearwater_modules/nsm1/processes.py | 2 +- 4 files changed, 624 insertions(+), 24 deletions(-) create mode 100644 examples/dev_sandbox/prof_nsm.py diff --git a/examples/dev_sandbox/prof_nsm.py b/examples/dev_sandbox/prof_nsm.py new file mode 100644 index 0000000..68a85db --- /dev/null +++ b/examples/dev_sandbox/prof_nsm.py @@ -0,0 +1,217 @@ +"""A script to allow for debugging of the NSM module.""" +import time +import sys +import clearwater_modules as cwm +from clearwater_modules.nsm1.model import NutrientBudget + + + + +initial_state_values = { + 'Ap': 1, + 'Ab': 1, + 'NH4': 1, + 'NO3': 1, + 'OrgN': 1, + 'N2': 1, + 'TIP': 1, + 'OrgP': 1, + 'POC': 1, + 'DOC': 1, + 'DIC': 1, + 'POM': 1, + 'CBOD': 1, + 'DOX': 1, + 'PX': 1, + 'Alk': 1 +} + +algae_parameters = { + 'AWd': 100, + 'AWc': 40, + 'AWn': 7.2, + 'AWp': 1, + 'AWa': 1000, + 'KL': 10, + 'KsN': 0.04, + 'KsP': 0.0012, + 'mu_max_20': 1, + 'kdp_20': 0.15, + 'krp_20': 0.2, + 'vsap': 0.15, + 'growth_rate_option': 1, + 'light_limitation_option': 1, + 'lambda0': .5, + 'lambda1': .5, + 'lambda2': .5, + 'lambdas': .5, + 'lambdam': .5, + 'Fr_PAR': .5 +} + +balgae_parameters = { + 'BWd': 100, + 'BWc': 40, + 'BWn': 7.2, + 'BWp': 1, + 'BWa': 3500, + + 'KLb': 10, + 'KsNb': 0.25, + 'KsPb': 0.125, + 'Ksb': 10, + 'mub_max_20': 0.4, + 'krb_20': 0.2, + 'kdb_20': 0.3, + 'b_growth_rate_option': 1, + 'b_light_limitation_option': 1, + 'Fw': 0.9, + 'Fb': 0.9 +} + +nitrogen_parameters = { + 'KNR': 0.6, + 'knit_20': 0.1, + 'kon_20': 0.1, + 'kdnit_20': 0.002, + 'rnh4_20': 0, + 'vno3_20': 0, + 'KsOxdn': 0.1, + 'PN': 0.5, + 'PNb': 0.5 +} + +phosphorus_parameters = { + 'kop_20': 0.1, + 'rpo4_20': 0 +} + +POM_parameters = { + 'kpom_20': 0.1 +} + +CBOD_parameters = { + 'KsOxbod': 0.5, + 'kbod_20': 0.12, + 'ksbod_20': 0 +} + +carbon_parameters = { + 'f_pocp': 0.9, + 'kdoc_20': 0.01, + 'f_pocb': 0.9, + 'kpoc_20': 0.005, + 'K_sOxmc': 1, + 'pCO2': 383, + 'FCO2': 0.2 +} + +pathogen_parameters = { + 'kdx': 0.8, + 'apx': 1, + 'vx': 1 +} + +alkalinity_parameters = { + 'r_alkaa': 1, + 'r_alkan': 1, + 'r_alkn': 1, + 'r_alkden': 1, + 'r_alkba': 1, + 'r_alkbn': 1 +} + +global_parameters = { + 'use_NH4': True, + 'use_NO3': True, + 'use_OrgN': True, + 'use_TIP': True, + 'use_SedFlux': False, + 'use_DOX': True, + 'use_Algae': True, + 'use_Balgae': True, + 'use_OrgP': True, + 'use_POC': True, + 'use_DOC': True, + 'use_DIC': True, + 'use_N2': True, + 'use_Pathogen': True, + 'use_Alk': True, + 'use_POM': True +} + + +global_vars = { + 'vson': 0.01, + 'vsoc': 0.01, + 'vsop': 999, + 'vs': 999, + 'SOD_20': 999, + 'SOD_theta': 999, + 'vb': 0.01, + 'fcom': 0.4, + 'kaw_20_user': 999, + 'kah_20_user': 999, + 'hydraulic_reaeration_option': 2, + 'wind_reaeration_option': 2, + 'timestep': 86400, + 'depth': 1, + 'TwaterC': 20, + 'theta': 1.047, + 'velocity': 1, + 'flow': 2, + 'topwidth': 1, + 'slope': 2, + 'shear_velocity': 4, + 'pressure_atm': 2, + 'wind_speed': 4, + 'q_solar': 4, + 'Solid': 1, +} + +DOX_parameters = { + 'DOX': 6.5, +} +N2_parameters = {} + +def main(iters: int): + ti = time.time() + # define starting state values + nsm_model = NutrientBudget( + initial_state_values=initial_state_values, # mandatory + algae_parameters=algae_parameters, + alkalinity_parameters=alkalinity_parameters, + balgae_parameters=balgae_parameters, + carbon_parameters=carbon_parameters, + CBOD_parameters=CBOD_parameters, + DOX_parameters=DOX_parameters, + nitrogen_parameters=nitrogen_parameters, + POM_parameters=POM_parameters, + N2_parameters=N2_parameters, + phosphorus_parameters=phosphorus_parameters, + pathogen_parameters=pathogen_parameters, + global_parameters=global_parameters, + global_vars=global_vars, + track_dynamic_variables=True, # default is true + hotstart_dataset=None, # default is None + time_dim='year', # default is "timestep" + ) + # print(nsm_model.get_variable_names()) + print(nsm_model.dynamic_variables_names) + + for _ in range(iters): + nsm_model.increment_timestep() + + +if __name__ == '__main__': + if len(sys.argv) > 1: + try: + iters = int(sys.argv[1]) + print(f'Running {iters} iterations.') + except ValueError: + raise ValueError('Argument must be an integer # of iterations.') + else: + print('No argument given, defaulting to 100 iteration.') + iters = 100 + + main(iters=iters) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index bd095fa..0555e1b 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -41,12 +41,132 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "663a1e5a-4311-42e7-babc-6e254a5ff9cf", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.1.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
    \n", + "
    \n", + "
    \n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" + } + ], "source": [ "import clearwater_modules as cwm\n", "import clearwater_modules.sorter as sorter\n", @@ -59,12 +179,38 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "01c71150", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['__builtins__',\n", + " '__cached__',\n", + " '__doc__',\n", + " '__file__',\n", + " '__loader__',\n", + " '__name__',\n", + " '__package__',\n", + " '__path__',\n", + " '__spec__',\n", + " '__version__',\n", + " 'base',\n", + " 'nsm1',\n", + " 'shared',\n", + " 'sorter',\n", + " 'tsm',\n", + " 'utils']" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Confirm that sub-modules are imported\n", "dir(cwm)" @@ -78,7 +224,7 @@ "outputs": [ { "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.1.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, @@ -116,28 +262,263 @@ "metadata": {}, "output_type": "display_data" }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
    \n", + "
    \n", + "
    \n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" + }, { "name": "stdout", "output_type": "stream", "text": [ "Initializing from dicts...\n", "Model initialized from input dicts successfully!.\n", + "['TwaterK', 'SOD_tc', 'kah_20', 'kah_tc', 'kaw_20', 'kaw_tc', 'ka_tc', 'L', 'PAR', 'fdp', 'rna', 'rpa', 'rca', 'rda', 'mu_max_tc', 'krp_tc', 'kdp_tc', 'FL', 'FN', 'FP', 'mu', 'ApGrowth', 'ApRespiration', 'ApDeath', 'ApSettling', 'dApdt', 'mub_max_tc', 'krb_tc', 'kdb_tc', 'rnb', 'rpb', 'rcb', 'rab', 'FLb', 'FNb', 'FPb', 'FSb', 'mub', 'AbGrowth', 'AbRespiration', 'AbDeath', 'dAbdt', 'Chlb', 'knit_tc', 'rnh4_tc', 'vno3_tc', 'kon_tc', 'kdnit_tc', 'ApUptakeFr_NH4', 'ApUptakeFr_NO3', 'AbUptakeFr_NH4', 'AbUptakeFr_NO3', 'ApDeath_OrgN', 'AbDeath_OrgN', 'OrgN_NH4_Decay', 'OrgN_Settling', 'dOrgNdt', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth', 'dNH4dt', 'NO3_Denit', 'NO3_BedDenit', 'NO3_ApGrowth', 'NO3_AbGrowth', 'dNO3dt', 'DIN', 'TON', 'TKN', 'TN', 'NitrificationInhibition', 'kop_tc', 'rpo4_tc', 'OrgP_DIP_decay', 'OrgP_Settling', 'ApDeath_OrgP', 'AbDeath_OrgP', 'dOrgPdt', 'DIPfromBed', 'TIP_Settling', 'DIP_ApRespiration', 'DIP_ApGrowth', 'DIP_AbRespiration', 'DIP_AbGrowth', 'dTIPdt', 'TOP', 'TP', 'DIP', 'kpom_tc', 'POM_algal_settling', 'POM_dissolution', 'POM_POC_settling', 'POM_benthic_algae_mortality', 'POM_burial', 'dPOMdt', 'kbod_tc', 'ksbod_tc', 'CBOD_oxidation', 'CBOD_sedimentation', 'dCBODdt', 'kpoc_tc', 'POC_settling', 'POC_hydrolysis', 'POC_algal_mortality', 'POC_benthic_algae_mortality', 'dPOCdt', 'kdoc_tc', 'DOC_algal_mortality', 'DOC_benthic_algae_mortality', 'DOC_DIC_oxidation', 'dDOCdt', 'K_H', 'Atm_CO2_reaeration', 'DIC_algal_respiration', 'DIC_algal_photosynthesis', 'DIC_benthic_algae_respiration', 'DIC_benthic_algae_photosynthesis', 'DIC_CBOD_oxidation', 'DIC_sed_release', 'dDICdt', 'DOX_sat', 'pwv', 'DOs_atm_alpha', 'Atm_O2_reaeration', 'DOX_ApGrowth', 'DOX_ApRespiration', 'DOX_Nitrification', 'DOX_DOC_oxidation', 'DOX_CBOD_oxidation', 'DOX_AbGrowth', 'DOX_AbRespiration', 'DOX_SOD', 'dDOXdt', 'kdx_tc', 'PathogenDeath', 'PathogenDecay', 'PathogenSettling', 'dPXdt', 'Alk_denitrification', 'Alk_nitrification', 'Alk_algal_growth', 'Alk_algal_respiration', 'Alk_benthic_algae_growth', 'Alk_benthic_algae_respiration', 'dAlkdt', 'KHN2_tc', 'P_wv', 'N2sat', 'dN2dt', 'TDG']\n", "Variable | Inputs\n", - "------------------\n" - ] - }, - { - "ename": "ValueError", - "evalue": "Circular dependency detected in dynamic/state variables! Variables remaining: ['dDOXdt', 'DOX']", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 200\u001b[0m\n\u001b[0;32m 197\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n\u001b[0;32m 199\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariable | Inputs\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m------------------\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m--> 200\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[43mnsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcomputation_order\u001b[49m:\n\u001b[0;32m 201\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mi\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m | \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msorter\u001b[38;5;241m.\u001b[39mget_process_args(i\u001b[38;5;241m.\u001b[39mprocess)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m)\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:309\u001b[0m, in \u001b[0;36mModel.computation_order\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 307\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Return a list of variables to compute in order (dynamic + state).\"\"\"\u001b[39;00m\n\u001b[0;32m 308\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m--> 309\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables \u001b[38;5;241m=\u001b[39m \u001b[43msorter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msort_variables_for_computation\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 310\u001b[0m \u001b[43m \u001b[49m\u001b[43msorter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit_variables\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mall_variables\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 311\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 312\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sorted_variables\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\sorter.py:83\u001b[0m, in \u001b[0;36msort_variables_for_computation\u001b[1;34m(variables_dict)\u001b[0m\n\u001b[0;32m 81\u001b[0m arg_names\u001b[38;5;241m.\u001b[39mremove(var\u001b[38;5;241m.\u001b[39mname)\n\u001b[0;32m 82\u001b[0m variable_args[var\u001b[38;5;241m.\u001b[39mname] \u001b[38;5;241m=\u001b[39m (var, arg_names)\n\u001b[1;32m---> 83\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m__rapid_sort\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstatic_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstate_vars\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvariable_args\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\sorter.py:55\u001b[0m, in \u001b[0;36m__rapid_sort\u001b[1;34m(static_vars, state_vars, variable_args_dict)\u001b[0m\n\u001b[0;32m 53\u001b[0m variable_args_dict\u001b[38;5;241m.\u001b[39mpop(key)\n\u001b[0;32m 54\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(variable_args_dict) \u001b[38;5;241m==\u001b[39m previous_len:\n\u001b[1;32m---> 55\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 56\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCircular dependency detected in dynamic/state variables! \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 57\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVariables remaining: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(variable_args_dict\u001b[38;5;241m.\u001b[39mkeys())\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m 58\u001b[0m )\n\u001b[0;32m 59\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 60\u001b[0m previous_len \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlen\u001b[39m(variable_args_dict)\n", - "\u001b[1;31mValueError\u001b[0m: Circular dependency detected in dynamic/state variables! Variables remaining: ['dDOXdt', 'DOX']" + "------------------\n", + "TwaterK | ['TwaterC']\n", + "SOD_tc | ['SOD_20', 'TwaterC', 'SOD_theta', 'DOX', 'KsSOD', 'use_DOX']\n", + "kah_20 | ['kah_20_user', 'hydraulic_reaeration_option', 'velocity', 'depth', 'flow', 'topwidth', 'slope', 'shear_velocity']\n", + "kah_tc | ['TwaterC', 'kah_20', 'theta']\n", + "kaw_20 | ['kaw_20_user', 'wind_speed', 'wind_reaeration_option']\n", + "kaw_tc | ['TwaterC', 'kaw_20', 'theta']\n", + "ka_tc | ['kah_tc', 'kaw_tc', 'depth']\n", + "L | ['lambda0', 'lambda1', 'lambda2', 'lambdas', 'lambdam', 'Solid', 'POC', 'fcom', 'use_Algae', 'use_POC', 'Ap']\n", + "PAR | ['use_Algae', 'use_Balgae', 'q_solar', 'Fr_PAR']\n", + "fdp | ['use_TIP', 'Solid', 'kdpo4']\n", + "rna | ['AWn', 'AWa']\n", + "rpa | ['AWp', 'AWa']\n", + "rca | ['AWc', 'AWa']\n", + "rda | ['AWd', 'AWa']\n", + "mu_max_tc | ['TwaterC', 'mu_max_20']\n", + "krp_tc | ['TwaterC', 'krp_20']\n", + "kdp_tc | ['TwaterC', 'kdp_20']\n", + "FL | ['L', 'depth', 'Ap', 'PAR', 'light_limitation_option', 'KL']\n", + "FN | ['use_NH4', 'use_NO3', 'NH4', 'NO3', 'KsN']\n", + "FP | ['fdp', 'TIP', 'use_TIP', 'KsP']\n", + "mu | ['mu_max_tc', 'growth_rate_option', 'FL', 'FP', 'FN']\n", + "ApGrowth | ['mu', 'Ap']\n", + "ApRespiration | ['krp_tc', 'Ap']\n", + "ApDeath | ['kdp_tc', 'Ap']\n", + "ApSettling | ['vsap', 'Ap', 'depth']\n", + "dApdt | ['ApGrowth', 'ApRespiration', 'ApDeath', 'ApSettling']\n", + "mub_max_tc | ['mub_max_20', 'TwaterC']\n", + "krb_tc | ['krb_20', 'TwaterC']\n", + "kdb_tc | ['kdb_20', 'TwaterC']\n", + "rnb | ['BWn', 'BWd']\n", + "rpb | ['BWp', 'BWd']\n", + "rcb | ['BWc', 'BWd']\n", + "rab | ['BWa', 'BWd']\n", + "FLb | ['L', 'depth', 'Ab', 'PAR', 'b_light_limitation_option', 'KLb']\n", + "FNb | ['use_NH4', 'use_NO3', 'NH4', 'NO3', 'KsNb']\n", + "FPb | ['fdp', 'TIP', 'use_TIP', 'KsPb']\n", + "FSb | ['Ab', 'Ksb']\n", + "mub | ['mub_max_tc', 'b_growth_rate_option', 'FLb', 'FPb', 'FNb', 'FSb']\n", + "AbGrowth | ['mub', 'Ab']\n", + "AbRespiration | ['krb_tc', 'Ab']\n", + "AbDeath | ['kdb_tc', 'Ab']\n", + "dAbdt | ['AbGrowth', 'AbRespiration', 'AbDeath']\n", + "Chlb | ['rab', 'Ab']\n", + "knit_tc | ['TwaterC', 'knit_20']\n", + "rnh4_tc | ['TwaterC', 'rnh4_20']\n", + "vno3_tc | ['TwaterC', 'vno3_20']\n", + "kon_tc | ['TwaterC', 'kon_20']\n", + "kdnit_tc | ['TwaterC', 'kdnit_20']\n", + "ApUptakeFr_NH4 | ['use_NH4', 'use_NO3', 'use_Algae', 'PN', 'NH4', 'NO3']\n", + "ApUptakeFr_NO3 | ['ApUptakeFr_NH4']\n", + "AbUptakeFr_NH4 | ['use_NH4', 'use_NO3', 'use_Balgae', 'PNb', 'NH4', 'NO3']\n", + "AbUptakeFr_NO3 | ['AbUptakeFr_NH4']\n", + "ApDeath_OrgN | ['use_Algae', 'rna', 'ApDeath']\n", + "AbDeath_OrgN | ['use_Balgae', 'rnb', 'Fw', 'Fb', 'depth', 'AbDeath']\n", + "OrgN_NH4_Decay | ['kon_tc', 'OrgN', 'use_OrgN']\n", + "OrgN_Settling | ['vson', 'depth', 'OrgN']\n", + "dOrgNdt | ['use_OrgN', 'ApDeath_OrgN', 'AbDeath_OrgN', 'OrgN_NH4_Decay', 'OrgN_Settling']\n", + "NH4fromBed | ['depth', 'rnh4_tc']\n", + "NH4_ApRespiration | ['use_Algae', 'ApRespiration', 'rna']\n", + "NH4_ApGrowth | ['use_Algae', 'ApGrowth', 'rna', 'ApUptakeFr_NH4']\n", + "NH4_AbRespiration | ['use_Balgae', 'rnb', 'AbRespiration']\n", + "NH4_AbGrowth | ['use_Balgae', 'rnb', 'AbGrowth', 'AbUptakeFr_NH4', 'Fb', 'depth']\n", + "NO3_Denit | ['use_DOX', 'DOX', 'KsOxdn', 'kdnit_tc', 'NO3']\n", + "NO3_BedDenit | ['depth', 'vno3_tc', 'NO3']\n", + "NO3_ApGrowth | ['use_Algae', 'ApUptakeFr_NO3', 'rna', 'ApGrowth']\n", + "NO3_AbGrowth | ['use_Balgae', 'AbUptakeFr_NO3', 'rnb', 'Fb', 'AbGrowth', 'depth']\n", + "DIN | ['use_NH4', 'use_NO3', 'NH4', 'NO3']\n", + "TON | ['use_OrgN', 'use_Algae', 'OrgN', 'rna', 'Ap']\n", + "TKN | ['use_NH4', 'NH4', 'TON']\n", + "TN | ['DIN', 'TON']\n", + "NitrificationInhibition | ['use_DOX', 'KNR', 'DOX']\n", + "kop_tc | ['TwaterC', 'kop_20']\n", + "rpo4_tc | ['TwaterC', 'rpo4_20']\n", + "OrgP_DIP_decay | ['kop_tc', 'OrgP', 'use_OrgP']\n", + "OrgP_Settling | ['vsop', 'depth', 'OrgP']\n", + "ApDeath_OrgP | ['rpa', 'ApDeath', 'use_Algae']\n", + "AbDeath_OrgP | ['rpb', 'AbDeath', 'Fw', 'Fb', 'depth', 'use_Balgae']\n", + "dOrgPdt | ['ApDeath_OrgP', 'AbDeath_OrgP', 'OrgP_DIP_decay', 'OrgP_Settling', 'use_OrgP']\n", + "DIPfromBed | ['depth', 'rpo4_tc']\n", + "TIP_Settling | ['vs', 'depth', 'fdp', 'TIP']\n", + "DIP_ApRespiration | ['rpa', 'ApRespiration', 'use_Algae']\n", + "DIP_ApGrowth | ['rpa', 'ApGrowth', 'use_Algae']\n", + "DIP_AbRespiration | ['rpb', 'AbRespiration', 'use_Balgae']\n", + "DIP_AbGrowth | ['rpb', 'AbGrowth', 'Fb', 'depth', 'use_Balgae']\n", + "dTIPdt | ['OrgP_DIP_decay', 'TIP_Settling', 'DIPfromBed', 'DIP_ApRespiration', 'DIP_ApGrowth', 'DIP_AbRespiration', 'DIP_AbGrowth', 'use_TIP']\n", + "TOP | ['use_OrgP', 'OrgP', 'use_Algae', 'rpa', 'Ap']\n", + "TP | ['use_TIP', 'TOP', 'TIP']\n", + "DIP | ['fdp', 'TIP']\n", + "kpom_tc | ['TwaterC', 'kpom_20']\n", + "POM_algal_settling | ['Ap', 'vsap', 'rda', 'depth', 'use_Algae']\n", + "POM_dissolution | ['POM', 'kpom_tc']\n", + "POM_POC_settling | ['POC', 'vsoc', 'depth', 'fcom', 'use_POC']\n", + "POM_benthic_algae_mortality | ['Ab', 'kdb_tc', 'Fb', 'Fw', 'depth', 'use_Balgae']\n", + "POM_burial | ['vb', 'POM', 'depth']\n", + "dPOMdt | ['POM_algal_settling', 'POM_dissolution', 'POM_POC_settling', 'POM_benthic_algae_mortality', 'POM_burial']\n", + "kbod_tc | ['TwaterC', 'kbod_20']\n", + "ksbod_tc | ['TwaterC', 'ksbod_20']\n", + "CBOD_oxidation | ['DOX', 'CBOD', 'kbod_tc', 'KsOxbod', 'use_DOX']\n", + "CBOD_sedimentation | ['CBOD', 'ksbod_tc']\n", + "dCBODdt | ['CBOD_oxidation', 'CBOD_sedimentation']\n", + "kpoc_tc | ['TwaterC', 'kpoc_20']\n", + "POC_settling | ['vsoc', 'depth', 'POC']\n", + "POC_hydrolysis | ['kpoc_tc', 'POC']\n", + "POC_algal_mortality | ['f_pocp', 'kdp_tc', 'rca', 'Ap', 'use_Algae']\n", + "POC_benthic_algae_mortality | ['depth', 'f_pocb', 'kdb_tc', 'rcb', 'Ab', 'Fb', 'Fw', 'use_Balgae']\n", + "dPOCdt | ['POC_settling', 'POC_hydrolysis', 'POC_algal_mortality', 'POC_benthic_algae_mortality']\n", + "kdoc_tc | ['TwaterC', 'kdoc_20']\n", + "DOC_algal_mortality | ['f_pocp', 'kdp_tc', 'rca', 'Ap', 'use_Algae']\n", + "DOC_benthic_algae_mortality | ['depth', 'f_pocb', 'kdb_tc', 'rcb', 'Ab', 'Fb', 'Fw', 'use_Balgae']\n", + "DOC_DIC_oxidation | ['DOX', 'KsOxmc', 'kdoc_tc', 'DOC', 'use_DOX']\n", + "dDOCdt | ['DOC_DIC_oxidation', 'POC_hydrolysis', 'DOC_algal_mortality', 'DOC_benthic_algae_mortality']\n", + "K_H | ['TwaterC']\n", + "Atm_CO2_reaeration | ['ka_tc', 'K_H', 'pCO2', 'FCO2', 'DIC']\n", + "DIC_algal_respiration | ['ApRespiration', 'rca', 'use_Algae']\n", + "DIC_algal_photosynthesis | ['ApGrowth', 'rca', 'use_Algae']\n", + "DIC_benthic_algae_respiration | ['AbRespiration', 'rcb', 'Fb', 'depth', 'use_Balgae']\n", + "DIC_benthic_algae_photosynthesis | ['AbGrowth', 'rcb', 'Fb', 'depth', 'use_Balgae']\n", + "DIC_CBOD_oxidation | ['DOX', 'CBOD', 'roc', 'kbod_tc', 'KsOxbod', 'use_DOX']\n", + "DIC_sed_release | ['SOD_tc', 'roc', 'depth']\n", + "dDICdt | ['Atm_CO2_reaeration', 'DIC_algal_respiration', 'DIC_algal_photosynthesis', 'DIC_benthic_algae_respiration', 'DIC_benthic_algae_photosynthesis', 'DIC_CBOD_oxidation', 'DIC_sed_release']\n", + "pwv | ['TwaterK']\n", + "DOs_atm_alpha | ['TwaterK']\n", + "DOX_ApGrowth | ['ApGrowth', 'rca', 'roc', 'ApUptakeFr_NH4', 'use_Algae']\n", + "DOX_ApRespiration | ['ApRespiration', 'rca', 'roc', 'use_Algae']\n", + "DOX_Nitrification | ['KNR', 'DOX', 'ron', 'knit_tc', 'NH4', 'use_NH4']\n", + "DOX_DOC_oxidation | ['DOC_DIC_oxidation', 'roc', 'use_DOC']\n", + "DOX_CBOD_oxidation | ['DIC_CBOD_oxidation', 'roc']\n", + "DOX_AbGrowth | ['AbUptakeFr_NH4', 'roc', 'rcb', 'AbGrowth', 'Fb', 'depth', 'use_Balgae']\n", + "DOX_AbRespiration | ['roc', 'rcb', 'AbRespiration', 'Fb', 'depth', 'use_Balgae']\n", + "DOX_SOD | ['depth', 'SOD_tc']\n", + "kdx_tc | ['TwaterC', 'kdx_20']\n", + "PathogenDeath | ['kdx_tc', 'PX']\n", + "PathogenDecay | ['apx', 'q_solar', 'L', 'depth', 'PX']\n", + "PathogenSettling | ['vx', 'depth', 'PX']\n", + "dPXdt | ['PathogenDeath', 'PathogenDecay', 'PathogenSettling']\n", + "Alk_denitrification | ['DOX', 'NO3', 'kdnit_tc', 'KsOxdn', 'r_alkden', 'use_NO3', 'use_DOX']\n", + "Alk_nitrification | ['DOX', 'NH4', 'knit_tc', 'KNR', 'r_alkn', 'use_NH4', 'use_DOX']\n", + "Alk_algal_growth | ['ApGrowth', 'r_alkaa', 'r_alkan', 'ApUptakeFr_NH4', 'use_Algae']\n", + "Alk_algal_respiration | ['ApRespiration', 'r_alkaa', 'use_Algae']\n", + "Alk_benthic_algae_growth | ['AbGrowth', 'depth', 'r_alkba', 'r_alkbn', 'AbUptakeFr_NH4', 'Fb', 'use_Balgae']\n", + "Alk_benthic_algae_respiration | ['AbRespiration', 'depth', 'r_alkba', 'Fb', 'use_Balgae']\n", + "dAlkdt | ['Alk_denitrification', 'Alk_nitrification', 'Alk_algal_growth', 'Alk_algal_respiration', 'Alk_benthic_algae_growth', 'Alk_benthic_algae_respiration']\n", + "KHN2_tc | ['TwaterK']\n", + "P_wv | ['TwaterK']\n", + "N2sat | ['KHN2_tc', 'pressure_atm', 'P_wv']\n", + "dN2dt | ['ka_tc', 'N2sat', 'N2']\n", + "Ap | ['Ap', 'dApdt', 'timestep']\n", + "Ab | ['Ab', 'dAbdt', 'timestep']\n", + "OrgN | ['OrgN', 'dOrgNdt', 'timestep']\n", + "N2 | ['N2', 'dN2dt', 'timestep']\n", + "TIP | ['TIP', 'dTIPdt', 'timestep']\n", + "OrgP | ['OrgP', 'dOrgPdt', 'timestep']\n", + "POC | ['POC', 'dPOCdt', 'timestep']\n", + "DOC | ['DOC', 'dDOCdt', 'timestep']\n", + "DIC | ['DIC', 'dDICdt', 'timestep']\n", + "POM | ['dPOMdt', 'POM', 'timestep']\n", + "CBOD | ['CBOD', 'dCBODdt', 'timestep']\n", + "PX | ['PX', 'dPXdt', 'timestep']\n", + "Alk | ['Alk', 'dAlkdt', 'timestep']\n", + "NH4_Nitrification | ['NitrificationInhibition', 'NH4', 'knit_tc', 'use_NH4']\n", + "dNH4dt | ['use_NH4', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth']\n", + "dNO3dt | ['use_NO3', 'NH4_Nitrification', 'NO3_Denit', 'NO3_BedDenit', 'NO3_ApGrowth', 'NO3_AbGrowth']\n", + "DOX_sat | ['TwaterK', 'pressure_atm', 'pwv', 'DOs_atm_alpha']\n", + "Atm_O2_reaeration | ['ka_tc', 'DOX_sat', 'DOX']\n", + "dDOXdt | ['Atm_O2_reaeration', 'DOX_ApGrowth', 'DOX_ApRespiration', 'DOX_Nitrification', 'DOX_DOC_oxidation', 'DOX_CBOD_oxidation', 'DOX_AbGrowth', 'DOX_AbRespiration', 'DOX_SOD']\n", + "TDG | ['N2', 'N2sat', 'DOX', 'DOX_sat', 'use_DOX']\n", + "NH4 | ['NH4', 'dNH4dt', 'timestep']\n", + "NO3 | ['NO3', 'dNO3dt', 'timestep']\n", + "DOX | ['DOX', 'dDOXdt', 'timestep']\n" ] } ], @@ -337,6 +718,8 @@ " time_dim='year', # default is \"timestep\"\n", ")\n", "\n", + "print(nsm_model.dynamic_variables_names)\n", + "\n", "#nsm_model.increment_timestep()\n", "nsm_model.dataset\n", "\n", diff --git a/src/clearwater_modules/nsm1/dynamic_variables.py b/src/clearwater_modules/nsm1/dynamic_variables.py index 6e711b6..6d925ef 100644 --- a/src/clearwater_modules/nsm1/dynamic_variables.py +++ b/src/clearwater_modules/nsm1/dynamic_variables.py @@ -1175,7 +1175,7 @@ class Variable(base.Variable): long_name='Dissolved oxygen flux due to algal photosynthesis', units='mg/L/d', description='Dissolved oxygen flux due to algal photosynthesis', - use='dynamics', + use='dynamic', process=processes.DOX_ApGrowth ) @@ -1220,7 +1220,7 @@ class Variable(base.Variable): long_name='Dissolved oxygen flux due to benthic algae photosynthesis', units='mg/L/d', description='Dissolved oxygen flux due to benthic algae photosynthesis', - use='dynamics', + use='dynamic', process=processes.DOX_AbGrowth ) @@ -1405,4 +1405,4 @@ class Variable(base.Variable): description='Total dissolved gas', use='dynamic', process=processes.TDG -) \ No newline at end of file +) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 9ee7aa7..472a296 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -2769,7 +2769,7 @@ def DOX_AbGrowth( AbGrowth: xr.DataArray, Fb: xr.DataArray, depth: xr.DataArray, - use_BAlgae: xr.DataArray + use_Balgae: xr.DataArray ) -> xr.DataArray: """Compute dissolved oxygen flux due to benthic algae growth From fd5f224dc34dfbb527a048ddf8b638ea2031c9b4 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:16:05 -0600 Subject: [PATCH 07/20] Corrected use_Balgae argument, had to make "a" not capitalized --- src/clearwater_modules/nsm1/processes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 472a296..064a8cc 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -2780,9 +2780,9 @@ def DOX_AbGrowth( AbGrowth: Benthic algae photosynthesis, calculated in benthic algae module (mg/L/d) Fb: Fraction of bottom area available for benthic algae growth depth: Water depth (m) - use_BAlgae: Option to consider benthic algae in the DOX budget + use_Balgae: Option to consider benthic algae in the DOX budget """ - da: xr.DataArray = xr.where(use_BAlgae == True, (138 / 106 - 32 / 106 * AbUptakeFr_NH4) * roc * rcb * AbGrowth * Fb / depth, 0) + da: xr.DataArray = xr.where(use_Balgae == True, (138 / 106 - 32 / 106 * AbUptakeFr_NH4) * roc * rcb * AbGrowth * Fb / depth, 0) return da From 88f0556f9e4bf379e9b7ce275c18014be5d551f0 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:27:27 -0600 Subject: [PATCH 08/20] Changed the L var xr.where implementation to match the `var: xr.DataArray = ` set up. --- src/clearwater_modules/nsm1/processes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 064a8cc..c3df837 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -219,10 +219,10 @@ def L( use_POC: true/falseo use particulate organic carbon module (t/f) Ap: algae concentration (ug-Chla/L) """ - L=lambda0 + lambdas * Solid + L = lambda0 + lambdas * Solid - L=xr.where (use_POC, L+lambdam*POC/fcom, L) - L=xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**0.66667, L) + L: xr.DataArray = xr.where (use_POC, L+lambdam*POC/fcom, L) + L: xr.DataArray = xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**0.66667, L) return L From c9aa3391c96f152118a8cfd7f57ab993baf8b9c0 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:56:17 -0500 Subject: [PATCH 09/20] Removed njit from xr.where and replaced nested xr.where with np.select for kah_20. --- examples/model_architecture_nsm.ipynb | 108 ++++++----------------- src/clearwater_modules/nsm1/processes.py | 80 +++++++---------- 2 files changed, 60 insertions(+), 128 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index 0555e1b..c186530 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -224,7 +224,7 @@ "outputs": [ { "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.1.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", "application/vnd.holoviews_load.v0+json": "" }, "metadata": {}, @@ -262,85 +262,6 @@ "metadata": {}, "output_type": "display_data" }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
    \n", - "
    \n", - "
    \n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "p1002" - } - }, - "output_type": "display_data" - }, { "name": "stdout", "output_type": "stream", @@ -728,6 +649,33 @@ " print(f'{i.name} | {sorter.get_process_args(i.process)}')" ] }, + { + "cell_type": "code", + "execution_count": 2, + "id": "32673258", + "metadata": {}, + "outputs": [ + { + "ename": "TypingError", + "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\n\u001b[1m\u001b[1mnon-precise type array(pyobject, 2d, C)\u001b[0m\n\u001b[0m\u001b[1mDuring: typing of argument at C:\\Users\\b2edhijm\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py (469)\u001b[0m\n\u001b[1m\nFile \"..\\src\\clearwater_modules\\nsm1\\processes.py\", line 469:\u001b[0m\n\u001b[1mdef mu(\n \n\n\u001b[1m@numba.njit\n\u001b[0m\u001b[1m^\u001b[0m\u001b[0m\n", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypingError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mnsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement_timestep\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:356\u001b[0m, in \u001b[0;36mModel.increment_timestep\u001b[1;34m(self, update_state_values)\u001b[0m\n\u001b[0;32m 353\u001b[0m timestep_ds[var_name] \u001b[38;5;241m=\u001b[39m value\n\u001b[0;32m 355\u001b[0m \u001b[38;5;66;03m# compute the dynamic variables in order\u001b[39;00m\n\u001b[1;32m--> 356\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m \u001b[43mutils\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miter_computations\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 357\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep_ds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 358\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcomputation_order\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 359\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 360\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtrack_dynamic_variables:\n\u001b[0;32m 361\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m timestep_ds\u001b[38;5;241m.\u001b[39mdrop_vars(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdynamic_variables_names)\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\utils.py:62\u001b[0m, in \u001b[0;36miter_computations\u001b[1;34m(input_dataset, compute_order)\u001b[0m\n\u001b[0;32m 59\u001b[0m dims \u001b[38;5;241m=\u001b[39m input_dataset\u001b[38;5;241m.\u001b[39mdims\n\u001b[0;32m 61\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, func, arrays \u001b[38;5;129;01min\u001b[39;00m inputs:\n\u001b[1;32m---> 62\u001b[0m array: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43marrays\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 63\u001b[0m input_dataset[name] \u001b[38;5;241m=\u001b[39m (dims, array)\n\u001b[0;32m 65\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m input_dataset\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\numba\\core\\dispatcher.py:468\u001b[0m, in \u001b[0;36m_DispatcherBase._compile_for_args\u001b[1;34m(self, *args, **kws)\u001b[0m\n\u001b[0;32m 464\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;241m.\u001b[39mrstrip()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124mThis error may have been caused \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 465\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mby the following argument(s):\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00margs_str\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 466\u001b[0m e\u001b[38;5;241m.\u001b[39mpatch_message(msg)\n\u001b[1;32m--> 468\u001b[0m \u001b[43merror_rewrite\u001b[49m\u001b[43m(\u001b[49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mtyping\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 469\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m errors\u001b[38;5;241m.\u001b[39mUnsupportedError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m 470\u001b[0m \u001b[38;5;66;03m# Something unsupported is present in the user code, add help info\u001b[39;00m\n\u001b[0;32m 471\u001b[0m error_rewrite(e, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124munsupported_error\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\numba\\core\\dispatcher.py:409\u001b[0m, in \u001b[0;36m_DispatcherBase._compile_for_args..error_rewrite\u001b[1;34m(e, issue_type)\u001b[0m\n\u001b[0;32m 407\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[0;32m 408\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 409\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\u001b[38;5;241m.\u001b[39mwith_traceback(\u001b[38;5;28;01mNone\u001b[39;00m)\n", + "\u001b[1;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\n\u001b[1m\u001b[1mnon-precise type array(pyobject, 2d, C)\u001b[0m\n\u001b[0m\u001b[1mDuring: typing of argument at C:\\Users\\b2edhijm\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py (469)\u001b[0m\n\u001b[1m\nFile \"..\\src\\clearwater_modules\\nsm1\\processes.py\", line 469:\u001b[0m\n\u001b[1mdef mu(\n \n\n\u001b[1m@numba.njit\n\u001b[0m\u001b[1m^\u001b[0m\u001b[0m\n" + ] + } + ], + "source": [ + "nsm_model.increment_timestep()\n", + "nsm_model.dataset" + ] + }, { "cell_type": "markdown", "id": "234fa8ec", diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index c3df837..df778b4 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -74,6 +74,36 @@ def kah_20( slope: Average slope of bottom surface shear_velocity: Average shear velocity on bottom surface (m/s) """ + condlist = [hydraulic_reaeration_option == 1, + hydraulic_reaeration_option == 2, + hydraulic_reaeration_option == 3, + hydraulic_reaeration_option == 4, + hydraulic_reaeration_option == 5 & depth < 0.61, + hydraulic_reaeration_option == 5 & depth > 0.61, + hydraulic_reaeration_option == 5 & depth == 0.61, + hydraulic_reaeration_option == 6 & flow < 0.556, + hydraulic_reaeration_option == 6 & flow >= 0.556, + hydraulic_reaeration_option == 7 & flow < 0.556, + hydraulic_reaeration_option == 7 & flow >= 0.556, + hydraulic_reaeration_option == 8 & flow < 0.425, + hydraulic_reaeration_option == 8 & flow >= 0.425, + hydraulic_reaeration_option == 9] + + choicelist = [kah_20_user, + (3.93 * velocity**0.5) / (depth**1.5), + (5.32 * velocity**0.67) / (depth**1.85), + (5.026 * velocity) / (depth**1.67), + (5.32 * velocity**0.67) / (depth**1.85), + (3.93 * velocity**0.5) / (depth**1.5), + (5.026 * velocity) / (depth**1.67), + 517 * (velocity * slope)**0.524 * flow**-0.242, + 596 * (velocity * slope)**0.528 * flow**-0.136, + 88 * (velocity * slope)**0.313 * depth**-0.353, + 142 * (velocity * slope)**0.333 * depth**-0.66 * topwidth**-0.243, + 31183 * velocity * slope, + 15308 * velocity * slope, + 2.16 * (1 + 9 * (velocity / (9.81 * depth)**0.5)**0.25) * shear_velocity / depth + ] da: xr.DataArray = xr.where(hydraulic_reaeration_option == 1, kah_20_user, xr.where(hydraulic_reaeration_option == 2, (3.93 * velocity**0.5) / (depth**1.5), @@ -189,7 +219,6 @@ def SOD_tc( return da -@numba.njit def L( lambda0: xr.DataArray, lambda1: xr.DataArray, @@ -226,7 +255,6 @@ def L( return L -@numba.njit def PAR( use_Algae : bool, use_Balgae: bool, @@ -240,10 +268,9 @@ def PAR( q_solar: solar radiation (1/d), Fr_PAR: fraction of solar radiation within the PAR of the spectrum """ - return xr.where (use_Algae or use_Balgae, q_solar * Fr_PAR) + return xr.where (use_Algae or use_Balgae, q_solar * Fr_PAR, 0) -@numba.njit def fdp( use_TIP: bool, Solid : xr.DataArray, @@ -363,7 +390,6 @@ def kdp_tc( return arrhenius_correction(TwaterC, kdp_20, 1.047) -@numba.njit def FL( L: xr.DataArray, depth: xr.DataArray, @@ -399,7 +425,6 @@ def FL( return FL -@numba.njit def FN( use_NH4: bool, use_NO3: bool, @@ -425,7 +450,6 @@ def FN( return FN -@numba.njit def FP( fdp: xr.DataArray, TIP: xr.DataArray, @@ -448,7 +472,6 @@ def FP( return FP -@numba.njit def mu( mu_max_tc: xr.DataArray, growth_rate_option: int, @@ -666,7 +689,6 @@ def rab( return BWa/BWd -@numba.njit def FLb( L: xr.DataArray, depth: xr.DataArray, @@ -703,7 +725,6 @@ def FLb( return FLb -@numba.njit def FNb( use_NH4: bool, use_NO3: bool, @@ -728,7 +749,6 @@ def FNb( return FNb -@numba.njit def FPb( fdp: xr.DataArray, TIP: xr.DataArray, @@ -751,7 +771,6 @@ def FPb( return FPb -@numba.njit def FSb( Ab: xr.DataArray, Ksb: xr.DataArray, @@ -771,8 +790,6 @@ def FSb( return FSb - -@numba.njit def mub( mub_max_tc: xr.DataArray, b_growth_rate_option: int, @@ -970,7 +987,6 @@ def kdnit_tc( return arrhenius_correction(TwaterC, kdnit_20, 1.045) -@numba.njit def ApUptakeFr_NH4( use_NH4: bool, use_NO3: bool, @@ -1017,7 +1033,6 @@ def ApUptakeFr_NO3( return 1 - ApUptakeFr_NH4 -@numba.njit def AbUptakeFr_NH4( use_NH4: bool, use_NO3: bool, @@ -1060,7 +1075,6 @@ def AbUptakeFr_NO3( return 1 - AbUptakeFr_NH4 -@numba.njit def OrgN_NH4_Decay( kon_tc: xr.DataArray, OrgN: xr.DataArray, @@ -1091,7 +1105,6 @@ def OrgN_Settling( return vson / depth * OrgN -@numba.njit def ApDeath_OrgN( use_Algae: bool, rna: xr.DataArray, @@ -1107,7 +1120,6 @@ def ApDeath_OrgN( return xr.where(use_Algae, rna * ApDeath, 0.0) -@numba.njit def AbDeath_OrgN( use_Balgae: bool, rnb: xr.DataArray, @@ -1129,7 +1141,6 @@ def AbDeath_OrgN( return xr.where(use_Balgae, rnb * Fw * Fb * AbDeath / depth, 0.0) -@numba.njit def dOrgNdt( use_OrgN: bool, ApDeath_OrgN: xr.DataArray, @@ -1169,7 +1180,6 @@ def OrgN( return OrgN + dOrgNdt * timestep -@numba.njit def NitrificationInhibition( use_DOX: bool, KNR: xr.DataArray, @@ -1187,7 +1197,6 @@ def NitrificationInhibition( return xr.where (use_DOX, 1.0 - math.exp(-KNR * DOX), 1.0) -@numba.njit def NH4_Nitrification( NitrificationInhibition: xr.DataArray, NH4: xr.DataArray, @@ -1221,7 +1230,6 @@ def NH4fromBed( return rnh4_tc / depth -@numba.njit def NH4_ApRespiration( use_Algae: bool, ApRespiration: xr.DataArray, @@ -1238,7 +1246,6 @@ def NH4_ApRespiration( return xr.where (use_Algae, rna * ApRespiration, 0.0) -@numba.njit def NH4_ApGrowth( use_Algae: bool, ApGrowth: xr.DataArray, @@ -1257,7 +1264,6 @@ def NH4_ApGrowth( return xr.where(use_Algae, ApUptakeFr_NH4 * rna * ApGrowth, 0.0) -@numba.njit def NH4_AbRespiration( use_Balgae: bool, rnb: xr.DataArray, @@ -1275,7 +1281,6 @@ def NH4_AbRespiration( return xr.where(use_Balgae, rnb * AbRespiration, 0.0 ) -@numba.njit def NH4_AbGrowth( use_Balgae: bool, rnb: xr.DataArray, @@ -1298,7 +1303,6 @@ def NH4_AbGrowth( return xr.where(use_Balgae,(AbUptakeFr_NH4 * rnb * Fb * AbGrowth) / depth, 0.0 ) -@numba.njit def dNH4dt( use_NH4: bool, NH4_Nitrification: xr.DataArray, @@ -1352,7 +1356,6 @@ def NH4( return NH4 + dNH4dt * timestep -@numba.njit def NO3_Denit( use_DOX: bool, DOX: xr.DataArray, @@ -1391,7 +1394,6 @@ def NO3_BedDenit( return vno3_tc * NO3 / depth -@numba.njit def NO3_ApGrowth( use_Algae: bool, ApUptakeFr_NO3: xr.DataArray, @@ -1412,7 +1414,6 @@ def NO3_ApGrowth( return xr.where(use_Algae, ApUptakeFr_NO3 * rna * ApGrowth, 0.0) -@numba.njit def NO3_AbGrowth( use_Balgae: bool, AbUptakeFr_NO3: xr.DataArray, @@ -1436,7 +1437,6 @@ def NO3_AbGrowth( return xr.where(use_Balgae, (AbUptakeFr_NO3 * rnb * Fb * AbGrowth) / depth, 0.0) -@numba.njit def dNO3dt( use_NO3: bool, NH4_Nitrification: xr.DataArray, @@ -1487,7 +1487,6 @@ def NO3( return NO3 + dNO3dt * timestep -@numba.njit def DIN( use_NH4: bool, use_NO3: bool, @@ -1510,7 +1509,6 @@ def DIN( return DIN -@numba.njit def TON( use_OrgN: bool, use_Algae: bool, @@ -1536,7 +1534,6 @@ def TON( return TON -@numba.njit def TKN( use_NH4: bool, NH4: xr.DataArray, @@ -1602,7 +1599,6 @@ def rpo4_tc( return arrhenius_correction(TwaterC, rpo4_20, 1.074) -@numba.njit def OrgP_DIP_decay( kop_tc : xr.DataArray, OrgP: xr.DataArray, @@ -1634,7 +1630,6 @@ def OrgP_Settling( """ return (vsop / depth) * OrgP -@numba.njit def ApDeath_OrgP( rpa : xr.DataArray, ApDeath: xr.DataArray, @@ -1652,7 +1647,6 @@ def ApDeath_OrgP( return xr.where(use_Algae, rpa * ApDeath,0) -@numba.njit def AbDeath_OrgP( rpb : xr.DataArray, AbDeath: xr.DataArray, @@ -1676,7 +1670,6 @@ def AbDeath_OrgP( return xr.where(use_Balgae, (rpb * Fw *Fb * AbDeath) / depth,0) -@numba.njit def dOrgPdt( ApDeath_OrgP : xr.DataArray, AbDeath_OrgP: xr.DataArray, @@ -1730,7 +1723,6 @@ def TIP_Settling( """ return vs / depth * (1.0 - fdp) * TIP -@numba.njit def DIP_ApRespiration( rpa: xr.DataArray, ApRespiration: xr.DataArray, @@ -1746,7 +1738,6 @@ def DIP_ApRespiration( """ return xr.where(use_Algae, rpa * ApRespiration,0) -@numba.njit def DIP_ApGrowth( rpa: xr.DataArray, ApGrowth: xr.DataArray, @@ -1762,7 +1753,6 @@ def DIP_ApGrowth( """ return xr.where(use_Algae, rpa * ApGrowth,0) -@numba.njit def DIP_AbRespiration( rpb: xr.DataArray, AbRespiration: xr.DataArray, @@ -1778,7 +1768,6 @@ def DIP_AbRespiration( """ return xr.where(use_Balgae, rpb * AbRespiration,0) -@numba.njit def DIP_AbGrowth( rpb: xr.DataArray, AbGrowth: xr.DataArray, @@ -1798,7 +1787,6 @@ def DIP_AbGrowth( """ return xr.where(use_Balgae, rpb * Fb * AbGrowth / depth,0) -@numba.njit def dTIPdt( OrgP_DIP_decay: xr.DataArray, TIP_Settling: xr.DataArray, @@ -1867,7 +1855,6 @@ def OrgP( """ return OrgP + dOrgPdt * timestep -@numba.njit def TOP( use_OrgP: bool, OrgP: xr.DataArray, @@ -1892,7 +1879,6 @@ def TOP( return TOP -@numba.njit def TP( use_TIP: bool, TOP: xr.DataArray, @@ -3180,8 +3166,7 @@ def P_wv( """ return math.exp(11.8571 - (3840.70 / TwaterK) - (216961.0 / (TwaterK**2))) - -@numba.njit + def N2sat( KHN2_tc : xr.DataArray, @@ -3236,7 +3221,6 @@ def N2( return N2 + dN2dt * timestep -@numba.njit def TDG( N2: xr.DataArray, N2sat : xr.DataArray, From 3c053d4ed16548fa5d3b502554430c1414506468 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:08:12 -0500 Subject: [PATCH 10/20] Made some np.select updates --- src/clearwater_modules/nsm1/processes.py | 136 +++++++++++++++-------- 1 file changed, 92 insertions(+), 44 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index df778b4..a54ee5c 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -74,22 +74,23 @@ def kah_20( slope: Average slope of bottom surface shear_velocity: Average shear velocity on bottom surface (m/s) """ - condlist = [hydraulic_reaeration_option == 1, + da: np.ndarray = np.select( + condlist = [hydraulic_reaeration_option == 1, hydraulic_reaeration_option == 2, hydraulic_reaeration_option == 3, hydraulic_reaeration_option == 4, - hydraulic_reaeration_option == 5 & depth < 0.61, - hydraulic_reaeration_option == 5 & depth > 0.61, - hydraulic_reaeration_option == 5 & depth == 0.61, - hydraulic_reaeration_option == 6 & flow < 0.556, - hydraulic_reaeration_option == 6 & flow >= 0.556, - hydraulic_reaeration_option == 7 & flow < 0.556, - hydraulic_reaeration_option == 7 & flow >= 0.556, - hydraulic_reaeration_option == 8 & flow < 0.425, - hydraulic_reaeration_option == 8 & flow >= 0.425, - hydraulic_reaeration_option == 9] + hydraulic_reaeration_option == 5 and depth < 0.61, + hydraulic_reaeration_option == 5 and depth > 0.61, + hydraulic_reaeration_option == 5 and depth == 0.61, + hydraulic_reaeration_option == 6 and flow < 0.556, + hydraulic_reaeration_option == 6 and flow >= 0.556, + hydraulic_reaeration_option == 7 and flow < 0.556, + hydraulic_reaeration_option == 7 and flow >= 0.556, + hydraulic_reaeration_option == 8 and flow < 0.425, + hydraulic_reaeration_option == 8 and flow >= 0.425, + hydraulic_reaeration_option == 9], - choicelist = [kah_20_user, + choicelist = [kah_20_user, (3.93 * velocity**0.5) / (depth**1.5), (5.32 * velocity**0.67) / (depth**1.85), (5.026 * velocity) / (depth**1.67), @@ -103,18 +104,10 @@ def kah_20( 31183 * velocity * slope, 15308 * velocity * slope, 2.16 * (1 + 9 * (velocity / (9.81 * depth)**0.5)**0.25) * shear_velocity / depth - ] - - da: xr.DataArray = xr.where(hydraulic_reaeration_option == 1, kah_20_user, - xr.where(hydraulic_reaeration_option == 2, (3.93 * velocity**0.5) / (depth**1.5), - xr.where(hydraulic_reaeration_option == 3, (5.32 * velocity**0.67) / (depth**1.85), - xr.where(hydraulic_reaeration_option == 4, (5.026 * velocity) / (depth**1.67), - xr.where(hydraulic_reaeration_option == 5, xr.where(depth < 0.61, (5.32 * velocity**0.67) / (depth**1.85), xr.where(depth > 0.61, (3.93 * velocity**0.5) / (depth**1.5), (5.026 * velocity) / (depth**1.67))), - xr.where(hydraulic_reaeration_option == 6, xr.where(flow < 0.556, 517 * (velocity * slope)**0.524 * flow**-0.242, 596 * (velocity * slope)**0.528 * flow**-0.136), - xr.where(hydraulic_reaeration_option == 7, xr.where(flow < 0.556, 88 * (velocity * slope)**0.313 * depth**-0.353, 142 * (velocity * slope)**0.333 * depth**-0.66 * topwidth**-0.243), - xr.where(hydraulic_reaeration_option == 8, xr.where(flow < 0.425, 31183 * velocity * slope, 15308 * velocity * slope), - xr.where(hydraulic_reaeration_option == 9, 2.16 * (1 + 9 * (velocity / (9.81 * depth)**0.5)**0.25) * shear_velocity / depth, -9999 - ))))))))) + ], + default = kah_20_user, + ) + return da @@ -148,20 +141,48 @@ def kaw_20( """ Uw10 = wind_speed * (10 / 2)**0.143 - da: xr.DataArray = xr.where(wind_reaeration_option == 1, kaw_20_user, - xr.where(wind_reaeration_option == 2, 0.864 * Uw10, - xr.where(wind_reaeration_option == 3, xr.where(Uw10 <= 3.5, 0.2 * Uw10, 0.057 * Uw10**2), - xr.where(wind_reaeration_option == 4, 0.728 * Uw10**0.5 - 0.317 * Uw10 + 0.0372 * Uw10**2, - xr.where(wind_reaeration_option == 5, 0.0986 * Uw10**1.64, - xr.where(wind_reaeration_option == 6, 0.5 + 0.05 * Uw10**2, - xr.where(wind_reaeration_option == 7, xr.where(Uw10 <= 5.5, 0.362 * Uw10**0.5, 0.0277 * Uw10**2), - xr.where(wind_reaeration_option == 8, 0.64 + 0.128 * Uw10**2, - xr.where(wind_reaeration_option == 9, xr.where(Uw10 <= 4.1, 0.156 * Uw10**0.63, 0.0269 * Uw10**1.9), - xr.where(wind_reaeration_option == 10, 0.0276 * Uw10**2, - xr.where(wind_reaeration_option == 11, 0.0432 * Uw10**2, - xr.where(wind_reaeration_option == 12, 0.319 * Uw10, - xr.where(wind_reaeration_option == 13, xr.where(Uw10 < 1.6, 0.398, 0.155 * Uw10**2), -9999 - ))))))))))))) + da: np.ndarray = np.select( + condlist = [ + wind_reaeration_option == 1, + wind_reaeration_option == 2, + wind_reaeration_option == 3 and Uw10 <= 3.5, + wind_reaeration_option == 3 and Uw10 > 3.5, + wind_reaeration_option == 4, + wind_reaeration_option == 5, + wind_reaeration_option == 6, + wind_reaeration_option == 7 and Uw10 <= 5.5, + wind_reaeration_option == 7 and Uw10 > 5.5, + wind_reaeration_option == 8, + wind_reaeration_option == 9 and Uw10 <= 4.1, + wind_reaeration_option == 9 and Uw10 > 4.1, + wind_reaeration_option == 10, + wind_reaeration_option == 11, + wind_reaeration_option == 12, + wind_reaeration_option == 13 and Uw10 < 1.6, + wind_reaeration_option == 13 and Uw10 >= 1.6, + ], + + choicelist = [ + kaw_20_user, + 0.864 * Uw10, + 0.2 * Uw10, + 0.057 * Uw10**2, + 0.728 * Uw10**0.5 - 0.317 * Uw10 + 0.0372 * Uw10**2, + 0.0986 * Uw10**1.64, + 0.5 + 0.05 * Uw10**2, + 0.362 * Uw10**0.5, + 0.0277 * Uw10**2, + 0.64 + 0.128 * Uw10**2, + 0.156 * Uw10**0.63, + 0.0269 * Uw10**1.9, + 0.0276 * Uw10**2, + 0.0432 * Uw10**2, + 0.319 * Uw10, + 0.398, + 0.155 * Uw10**2 + ], + default = kaw_20_user, + ) return da @@ -411,12 +432,39 @@ def FL( KEXT = L * depth - FL = xr.where(Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, 0, - xr.where(light_limitation_option==1, (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), - xr.where(light_limitation_option==2, - xr.where(abs(KL)<0.0000000001, 1, (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5)))), - xr.where(light_limitation_option==3, - xr.where(abs(KL)<0.0000000001,0,(2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL))), "NaN")))) + FL: np.ndarray = np.select( + condlist = [ + Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, + light_limitation_option == 1, + light_limitation_option == 2 and abs(KL) < 0.0000000001, + light_limitation_option == 2 and abs(KL) >= 0.0000000001, + light_limitation_option == 3 and abs(KL) < 0.0000000001, + light_limitation_option == 3 and abs(KL) >= 0.0000000001, + ], + + choicelist = [ + 0, + (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), + 1, + (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5))), + 0, + (2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL)) + ], + default = "NaN", + ) + + FL: np.ndarray = np.select( + condlist = [ + FL > 1.0, + FL < 0.0, + ] + + choicelist = [ + 1.0, + 0.0 + ] + default = FL + ) FL= xr.where(FL > 1.0, 1.0, From e4221789813283743d9d05549f9d5488d8d73eea Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:10:03 -0500 Subject: [PATCH 11/20] Updated FL np.select --- src/clearwater_modules/nsm1/processes.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index a54ee5c..92449ed 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -432,7 +432,7 @@ def FL( KEXT = L * depth - FL: np.ndarray = np.select( + FL_orig: np.ndarray = np.select( condlist = [ Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, light_limitation_option == 1, @@ -450,20 +450,22 @@ def FL( 0, (2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL)) ], - default = "NaN", + + default = "NaN" ) FL: np.ndarray = np.select( condlist = [ - FL > 1.0, - FL < 0.0, - ] + FL_orig > 1.0, + FL_orig < 0.0, + ], choicelist = [ 1.0, 0.0 - ] - default = FL + ], + + default = FL_orig ) From 03162eca895313d4125f450c0048fa8dea3dc836 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:44:52 -0500 Subject: [PATCH 12/20] Replaced all nested xr.where with np.select. --- examples/model_architecture.ipynb | 50 ++--- examples/model_architecture_nsm.ipynb | 13 +- src/clearwater_modules/nsm1/processes.py | 258 +++++++++++++++++++---- 3 files changed, 244 insertions(+), 77 deletions(-) diff --git a/examples/model_architecture.ipynb b/examples/model_architecture.ipynb index f94a812..9e9b0d6 100644 --- a/examples/model_architecture.ipynb +++ b/examples/model_architecture.ipynb @@ -618,55 +618,55 @@ " q_longwave_down (year, x, y) float64 nan 337.8\n", " q_longwave_up (year, x, y) float64 nan 406.2\n", " q_net (year, x, y) float64 nan -151.1\n", - " dTdt_water_c (year, x, y) float64 nan -3.619e-05
    • year
      PandasIndex
      PandasIndex(Index([0, 1], dtype='int32', name='year'))
    • x
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='x'))
    • y
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='y'))
  • " ], "text/plain": [ "\n", diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index c186530..c796e9f 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -431,7 +431,7 @@ "PX | ['PX', 'dPXdt', 'timestep']\n", "Alk | ['Alk', 'dAlkdt', 'timestep']\n", "NH4_Nitrification | ['NitrificationInhibition', 'NH4', 'knit_tc', 'use_NH4']\n", - "dNH4dt | ['use_NH4', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth']\n", + "dNH4dt | ['use_NH4', 'OrgN_NH4_Decay', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth']\n", "dNO3dt | ['use_NO3', 'NH4_Nitrification', 'NO3_Denit', 'NO3_BedDenit', 'NO3_ApGrowth', 'NO3_AbGrowth']\n", "DOX_sat | ['TwaterK', 'pressure_atm', 'pwv', 'DOs_atm_alpha']\n", "Atm_O2_reaeration | ['ka_tc', 'DOX_sat', 'DOX']\n", @@ -656,18 +656,17 @@ "metadata": {}, "outputs": [ { - "ename": "TypingError", - "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\n\u001b[1m\u001b[1mnon-precise type array(pyobject, 2d, C)\u001b[0m\n\u001b[0m\u001b[1mDuring: typing of argument at C:\\Users\\b2edhijm\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py (469)\u001b[0m\n\u001b[1m\nFile \"..\\src\\clearwater_modules\\nsm1\\processes.py\", line 469:\u001b[0m\n\u001b[1mdef mu(\n \n\n\u001b[1m@numba.njit\n\u001b[0m\u001b[1m^\u001b[0m\u001b[0m\n", + "ename": "TypeError", + "evalue": "'>' not supported between instances of 'numpy.ndarray' and 'float'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypingError\u001b[0m Traceback (most recent call last)", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mnsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement_timestep\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:356\u001b[0m, in \u001b[0;36mModel.increment_timestep\u001b[1;34m(self, update_state_values)\u001b[0m\n\u001b[0;32m 353\u001b[0m timestep_ds[var_name] \u001b[38;5;241m=\u001b[39m value\n\u001b[0;32m 355\u001b[0m \u001b[38;5;66;03m# compute the dynamic variables in order\u001b[39;00m\n\u001b[1;32m--> 356\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m \u001b[43mutils\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miter_computations\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 357\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep_ds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 358\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcomputation_order\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 359\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 360\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtrack_dynamic_variables:\n\u001b[0;32m 361\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m timestep_ds\u001b[38;5;241m.\u001b[39mdrop_vars(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdynamic_variables_names)\n", "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\utils.py:62\u001b[0m, in \u001b[0;36miter_computations\u001b[1;34m(input_dataset, compute_order)\u001b[0m\n\u001b[0;32m 59\u001b[0m dims \u001b[38;5;241m=\u001b[39m input_dataset\u001b[38;5;241m.\u001b[39mdims\n\u001b[0;32m 61\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, func, arrays \u001b[38;5;129;01min\u001b[39;00m inputs:\n\u001b[1;32m---> 62\u001b[0m array: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43marrays\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 63\u001b[0m input_dataset[name] \u001b[38;5;241m=\u001b[39m (dims, array)\n\u001b[0;32m 65\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m input_dataset\n", - "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\numba\\core\\dispatcher.py:468\u001b[0m, in \u001b[0;36m_DispatcherBase._compile_for_args\u001b[1;34m(self, *args, **kws)\u001b[0m\n\u001b[0;32m 464\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;241m.\u001b[39mrstrip()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124mThis error may have been caused \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 465\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mby the following argument(s):\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00margs_str\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 466\u001b[0m e\u001b[38;5;241m.\u001b[39mpatch_message(msg)\n\u001b[1;32m--> 468\u001b[0m \u001b[43merror_rewrite\u001b[49m\u001b[43m(\u001b[49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mtyping\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 469\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m errors\u001b[38;5;241m.\u001b[39mUnsupportedError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m 470\u001b[0m \u001b[38;5;66;03m# Something unsupported is present in the user code, add help info\u001b[39;00m\n\u001b[0;32m 471\u001b[0m error_rewrite(e, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124munsupported_error\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\numba\\core\\dispatcher.py:409\u001b[0m, in \u001b[0;36m_DispatcherBase._compile_for_args..error_rewrite\u001b[1;34m(e, issue_type)\u001b[0m\n\u001b[0;32m 407\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[0;32m 408\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 409\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m e\u001b[38;5;241m.\u001b[39mwith_traceback(\u001b[38;5;28;01mNone\u001b[39;00m)\n", - "\u001b[1;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\n\u001b[1m\u001b[1mnon-precise type array(pyobject, 2d, C)\u001b[0m\n\u001b[0m\u001b[1mDuring: typing of argument at C:\\Users\\b2edhijm\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py (469)\u001b[0m\n\u001b[1m\nFile \"..\\src\\clearwater_modules\\nsm1\\processes.py\", line 469:\u001b[0m\n\u001b[1mdef mu(\n \n\n\u001b[1m@numba.njit\n\u001b[0m\u001b[1m^\u001b[0m\u001b[0m\n" + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py:467\u001b[0m, in \u001b[0;36mFL\u001b[1;34m(L, depth, Ap, PAR, light_limitation_option, KL)\u001b[0m\n\u001b[0;32m 433\u001b[0m KEXT \u001b[38;5;241m=\u001b[39m L \u001b[38;5;241m*\u001b[39m depth\n\u001b[0;32m 435\u001b[0m FL_orig: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mselect(\n\u001b[0;32m 436\u001b[0m condlist \u001b[38;5;241m=\u001b[39m [\n\u001b[0;32m 437\u001b[0m Ap \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m KEXT \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m PAR \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 462\u001b[0m default \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNaN\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 463\u001b[0m )\n\u001b[0;32m 465\u001b[0m FL: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mselect(\n\u001b[0;32m 466\u001b[0m condlist \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m--> 467\u001b[0m \u001b[43mFL_orig\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m>\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1.0\u001b[39;49m,\n\u001b[0;32m 468\u001b[0m FL_orig \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0.0\u001b[39m,\n\u001b[0;32m 469\u001b[0m ],\n\u001b[0;32m 470\u001b[0m \n\u001b[0;32m 471\u001b[0m choicelist \u001b[38;5;241m=\u001b[39m [\n\u001b[0;32m 472\u001b[0m \u001b[38;5;241m1.0\u001b[39m,\n\u001b[0;32m 473\u001b[0m \u001b[38;5;241m0.0\u001b[39m\n\u001b[0;32m 474\u001b[0m ],\n\u001b[0;32m 475\u001b[0m \n\u001b[0;32m 476\u001b[0m default \u001b[38;5;241m=\u001b[39m FL_orig\n\u001b[0;32m 477\u001b[0m )\n\u001b[0;32m 479\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m FL\n", + "\u001b[1;31mTypeError\u001b[0m: '>' not supported between instances of 'numpy.ndarray' and 'float'" ] } ], diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 92449ed..ac901eb 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -441,7 +441,7 @@ def FL( light_limitation_option == 3 and abs(KL) < 0.0000000001, light_limitation_option == 3 and abs(KL) >= 0.0000000001, ], - + choicelist = [ 0, (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), @@ -467,10 +467,6 @@ def FL( default = FL_orig ) - - - FL= xr.where(FL > 1.0, 1.0, - xr.where(FL<0.0, 0.0, FL)) return FL @@ -493,10 +489,23 @@ def FN( KsN: Michaelis-Menton half-saturation constant relating inorganic N to algal growth (mg-N/L) """ - FN = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsN + NH4 + NO3), 1) - FN = xr.where(math.isnan(FN), 0, - xr.where(FN>1.0,1.0,FN)) + FN_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsN + NH4 + NO3), 1) + + FN: np.ndarray = np.select( + condlist= [ + math.isnan(FN_orig), + FN_orig > 1.0 + ], + + choicelist= [ + 0, + 1.0 + ], + + default = FN_orig + ) + return FN @@ -515,9 +524,21 @@ def FP( fdp: Fraction P dissolved (unitless) """ - FP = xr.where(use_TIP, fdp * TIP / (KsP + fdp * TIP), 1.0) - FP = xr.where(math.isnan(FP), 0, - xr.where(FP>1.0, 1, FP)) + FP_orig = xr.where(use_TIP, fdp * TIP / (KsP + fdp * TIP), 1.0) + + FP: np.ndarray = np.select( + condlist= [ + math.isnan(FP_orig), + FP_orig > 1.0 + ], + + choicelist= [ + 0, + 1.0 + ], + + default = FP_orig + ) return FP @@ -540,10 +561,25 @@ def mu( FN: Algae nitrogen limitation factor (unitless) """ - return xr.where(growth_rate_option == 1, mu_max_tc * FL * FP * FN, - xr.where(growth_rate_option == 2, mu_max_tc * FL * min(FP, FN), - xr.where(growth_rate_option == 3, - xr.where(FN==0.0 or FP==0.0, 0.0, mu_max_tc * FL * 2.0 / (1.0 / FN + 1.0 / FP)), "NaN"))) + mu: np.ndarray = np.select( + condlist = [ + growth_rate_option == 1, + growth_rate_option == 2, + growth_rate_option == 3 and (FN == 0.0 or FP == 0.0), + growth_rate_option == 3 and FN != 0 and FP != 0 + ], + + choicelist = [ + mu_max_tc * FL * FP * FN, + mu_max_tc * FL * min(FP, FN), + 0, + mu_max_tc * FL * 2.0 / (1.0 / FN + 1.0 / FP) + ], + + default = 'NaN' + ) + + return mu @numba.njit @@ -762,16 +798,41 @@ def FLb( # Note that KENT is defined differently here than it was for the algal equations. # The equations are different, this expression is more convenient here. KEXT = math.exp(-L*depth) + + FLb_orig: np.ndarray = np.select( + condlist = [ + Ab <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, + b_light_limitation_option == 1, + b_light_limitation_option == 2, + b_light_limitation_option == 3 and abs(KLb) < 1.0E-10, + b_light_limitation_option == 3 and abs(KLb) >= 1.0E-10 + ], + + choicelist = [ + 0.0, + PAR * KEXT / (KLb + PAR * KEXT), + PAR * KEXT / ((KLb**2.0 + (PAR * KEXT)**2.0)**0.5), + 0.0, + PAR * KEXT / KLb * math.exp(1.0 - PAR * KEXT / KLb) + ], + + default = 'NaN' + ) - FLb = xr.where(Ab <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, 0.0, - xr.where(b_light_limitation_option == 1, PAR * KEXT / (KLb + PAR * KEXT), - xr.where(b_light_limitation_option == 2, PAR * KEXT / ((KLb**2.0 + (PAR * KEXT)**2.0)**0.5), - xr.where(b_light_limitation_option == 3, - xr.where(abs(KLb) < 1.0E-10, 0.0, PAR * KEXT / KLb * math.exp(1.0 - PAR * KEXT / KLb)), "NaN" - )))) - FLb = xr.where(FLb > 1.0, 1.0, - xr.where(FLb < 0.0, 0.0, FLb)) - + FLb: np.ndarray = np.select( + condlist = [ + FLb_orig > 1.0, + FLb_orig < 0.0 + ], + + choicelist = [ + 1.0, + 0.0 + ], + + default = FLb_orig + ) + return FLb @@ -792,10 +853,23 @@ def FNb( NO3: Nitrate concentration (mg-N/L) KsNb: Michaelis-Menton half-saturation constant relating inorganic N to benthic algal growth (mg-N/L) """ - FNb = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsNb + NH4 + NO3),1) - FNb = xr.where(math.isnan(FNb),0.0, - xr.where(FNb < 1.0, 1, FNb)) + FNb_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsNb + NH4 + NO3),1) + + FNb: np.ndarray = np.select( + condlist= [ + math.isnan(FNb_orig), + FNb_orig > 1.0 + ], + + choicelist= [ + 0.0, + 1.0 + ], + + default = FNb_orig + ) + return FNb @@ -814,10 +888,22 @@ def FPb( fdp: Fraction P dissolved (unitless) """ - FPb = xr.where(use_TIP, fdp * TIP / (KsPb + fdp * TIP),1.0) - FPb = xr.where(math.isnan(FPb),0.0, - xr.where(FPb > 1.0, 1.0, FPb)) + FPb_orig = xr.where(use_TIP, fdp * TIP / (KsPb + fdp * TIP),1.0) + FPb: np.ndarray = np.select( + condlist= [ + math.isnan(FPb_orig), + FPb_orig > 1.0 + ], + + choicelist= [ + 0.0, + 1.0 + ], + + default = FPb_orig + ) + return FPb @@ -834,9 +920,21 @@ def FSb( """ - FSb = 1.0 - (Ab / (Ab + Ksb)) - FSb = xr.where(math.isnan(FSb), 1.0, - xr.where(FSb > 1.0, 1.0, FSb)) + FSb_orig = 1.0 - (Ab / (Ab + Ksb)) + + FSb: np.ndarray = np.select( + condlist= [ + math.isnan(FSb_orig), + FSb_orig > 1.0 + ], + + choicelist= [ + 0.0, + 1.0 + ], + + default = FSb_orig + ) return FSb @@ -1059,10 +1157,23 @@ def ApUptakeFr_NH4( ApUptakeFr_NH4 = 0 # set value of UptakeFr_NH4/NO3 for special conditions - ApUptakeFr_NH4 = xr.where(use_NH4 and not use_NO3, 1.0, - xr.where(not use_NH4 and use_NO3, 0.0, - xr.where(not use_NH4 and not use_NO3, 0.5, - xr.where(use_Algae and use_NH4 and use_NO3, PN * NH4 / (PN * NH4 + (1.0 - PN) * NO3), "NaN")))) + ApUptakeFr_NH4: np.ndarray = np.select( + choicelist = [ + use_NH4 and not use_NO3, + not use_NH4 and use_NO3, + not use_NH4 and not use_NO3, + use_Algae and use_NH4 and use_NO3 + ], + + condlist = [ + 1.0, + 0.0, + 0.5, + PN * NH4 / (PN * NH4 + (1.0 - PN) * NO3) + ], + + default = 'NaN' + ) # Check for case when NH4 and NO3 are very small. If so, force uptake_fractions appropriately. ApUptakeFr_NH4 = xr.where(math.isnan(ApUptakeFr_NH4),PN,ApUptakeFr_NH4) @@ -1103,10 +1214,24 @@ def AbUptakeFr_NH4( NO3: Nitrate water concentration (mg-N/L) """ AbUptakeFr_NH4 = 0 - AbUptakeFr_NH4 = xr.where(use_NH4 and not use_NO3, 1.0, - xr.where(not use_NH4 and use_NO3, 0.0, - xr.where(not use_NH4 and not use_NO3, 0.5, - xr.where(use_Balgae and use_NH4 and use_NO3, (PNb * NH4) / (PNb * NH4 + (1.0 - PNb) * NO3), "NaN")))) + + AbUptakeFr_NH4: np.ndarray = np.select( + choicelist = [ + use_NH4 and not use_NO3, + not use_NH4 and use_NO3, + not use_NH4 and not use_NO3, + use_Balgae and use_NH4 and use_NO3 + ], + + condlist = [ + 1.0, + 0.0, + 0.5, + (PNb * NH4) / (PNb * NH4 + (1.0 - PNb) * NO3) + ], + + default = 'NaN' + ) AbUptakeFr_NH4 = xr.where(math.isnan(AbUptakeFr_NH4),PNb,AbUptakeFr_NH4) @@ -1355,6 +1480,7 @@ def NH4_AbGrowth( def dNH4dt( use_NH4: bool, + OrgN_NH4_Decay: xr.DataArray, NH4_Nitrification: xr.DataArray, NH4fromBed: xr.DataArray, NH4_ApRespiration: xr.DataArray, @@ -1369,6 +1495,7 @@ def dNH4dt( Args: use_OrgN: true/false to use organic nitrogen module (unitless), use_NH4: true/false to use ammonium module (unitless), + OrgN_NH4_Decay: OrgN -> NH4 (mg-N/L/d) NH4_Nitrification: NH4 -> NO3 Nitrification (mg-N/L/day) NH4fromBed: bed -> NH4 (diffusion) (mg-N/L/day) NH4_ApRespiration: Floating algae -> NH4 (mg-N/L/day) @@ -1424,7 +1551,22 @@ def NO3_Denit( kdnit_tc: Denitrification rate temperature correction (1/d) """ - return xr.where(use_DOX,xr.where(math.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3),kdnit_tc * NO3,(1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3),0.0) + + NO3_Denit: np.ndarray = np.select( + choicelist = [ + use_DOX and math.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3), + use_DOX + ], + + condlist = [ + kdnit_tc * NO3, + (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3 + ], + + default = 0.0 + ) + + return NO3_Denit @numba.njit def NO3_BedDenit( @@ -3031,7 +3173,20 @@ def Alk_denitrification( use_NO3: Option to use nitrate use_DOX: Option to use dissolved oxygen """ - da: xr.DataArray = xr.where(use_NO3 == True, xr.where(use_DOX == True, r_alkden * (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3, r_alkden * kdnit_tc * NO3), 0) + + da: np.ndarray = np.select( + choicelist = [ + use_NO3 == True and use_DOX == True, + use_NO3 == True + ], + + condlist = [ + r_alkden * (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3, + r_alkden * kdnit_tc * NO3 + ], + + default = 0 + ) return da @@ -3056,8 +3211,21 @@ def Alk_nitrification( use_NH4: Option to use ammonium use_DOX: Option to use dissolved oxygen """ - da: xr.DataArray = xr.where(use_NH4 == True, xr.where(use_DOX == True, r_alkn * (1 - math.exp(-KNR * DOX)) * knit_tc * NH4, knit_tc * NH4), 0) - + + da: np.ndarray = np.select( + choicelist = [ + use_NH4 == True and use_DOX == True, + use_NH4 == True + ], + + condlist = [ + r_alkn * (1 - math.exp(-KNR * DOX)) * knit_tc * NH4, + knit_tc * NH4 + ], + + default = 0 + ) + return da From 6c406b02526e6b493d4b884471d12846a918cbb1 Mon Sep 17 00:00:00 2001 From: Sarah Jordan Date: Mon, 18 Mar 2024 12:27:44 -0500 Subject: [PATCH 13/20] troubleshooting updates "NaN" to np.nan, reverse condlist/choicelist, np.exp --- src/clearwater_modules/nsm1/processes.py | 69 +++++++++++------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index ac901eb..c6e5869 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -418,7 +418,7 @@ def FL( PAR: xr.DataArray, light_limitation_option: int, KL: xr.DataArray, -) -> xr.DataArray: +) -> np.ndarray: """Calculate Algal light limitation: FL (unitless). Args: @@ -451,7 +451,7 @@ def FL( (2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL)) ], - default = "NaN" + default = np.nan ) FL: np.ndarray = np.select( @@ -576,7 +576,7 @@ def mu( mu_max_tc * FL * 2.0 / (1.0 / FN + 1.0 / FP) ], - default = 'NaN' + default = np.nan ) return mu @@ -816,7 +816,7 @@ def FLb( PAR * KEXT / KLb * math.exp(1.0 - PAR * KEXT / KLb) ], - default = 'NaN' + default = np.nan ) FLb: np.ndarray = np.select( @@ -1154,25 +1154,23 @@ def ApUptakeFr_NH4( NH4: Ammonium water concentration (mg-N/L) NO3: Nitrate water concentration (mg-N/L) """ - ApUptakeFr_NH4 = 0 - # set value of UptakeFr_NH4/NO3 for special conditions ApUptakeFr_NH4: np.ndarray = np.select( - choicelist = [ - use_NH4 and not use_NO3, - not use_NH4 and use_NO3, - not use_NH4 and not use_NO3, - use_Algae and use_NH4 and use_NO3 + condlist = [ + use_NH4 & ~use_NO3, + ~use_NH4 & use_NO3, + ~use_NH4 & ~use_NO3, + use_Algae & use_NH4 & use_NO3 ], - condlist = [ + choicelist = [ 1.0, 0.0, 0.5, PN * NH4 / (PN * NH4 + (1.0 - PN) * NO3) ], - default = 'NaN' + default = np.nan ) # Check for case when NH4 and NO3 are very small. If so, force uptake_fractions appropriately. @@ -1212,25 +1210,23 @@ def AbUptakeFr_NH4( PNb: NH4 preference factor benthic algae (unitless) NH4: Ammonium water concentration (mg-N/L) NO3: Nitrate water concentration (mg-N/L) - """ - AbUptakeFr_NH4 = 0 - + """ AbUptakeFr_NH4: np.ndarray = np.select( - choicelist = [ + condlist = [ use_NH4 and not use_NO3, not use_NH4 and use_NO3, not use_NH4 and not use_NO3, use_Balgae and use_NH4 and use_NO3 ], - condlist = [ + choicelist = [ 1.0, 0.0, 0.5, (PNb * NH4) / (PNb * NH4 + (1.0 - PNb) * NO3) ], - default = 'NaN' + default = np.nan ) AbUptakeFr_NH4 = xr.where(math.isnan(AbUptakeFr_NH4),PNb,AbUptakeFr_NH4) @@ -1370,7 +1366,7 @@ def NitrificationInhibition( """ - return xr.where (use_DOX, 1.0 - math.exp(-KNR * DOX), 1.0) + return xr.where (use_DOX, 1.0 - np.exp(-KNR * DOX), 1.0) def NH4_Nitrification( NitrificationInhibition: xr.DataArray, @@ -1553,12 +1549,12 @@ def NO3_Denit( """ NO3_Denit: np.ndarray = np.select( - choicelist = [ + condlist = [ use_DOX and math.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3), use_DOX ], - condlist = [ + choicelist = [ kdnit_tc * NO3, (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3 ], @@ -2086,6 +2082,7 @@ def TP( """ TP = TOP TP = xr.where(use_TIP,TP + TIP,TP) + return TP @numba.njit def DIP( @@ -3078,7 +3075,6 @@ def PathogenDeath( """ return kdx_tc * PX -@numba.njit def PathogenDecay( apx: xr.DataArray, q_solar: xr.DataArray, @@ -3097,7 +3093,7 @@ def PathogenDecay( PX: Pathogen concentration (cfu/100mL) """ - return apx * q_solar / (L * depth) * (1 - math.exp(-L * depth)) * PX + return apx * q_solar / (L * depth) * (1 - np.exp(-L * depth)) * PX @numba.njit def PathogenSettling( @@ -3175,12 +3171,12 @@ def Alk_denitrification( """ da: np.ndarray = np.select( - choicelist = [ - use_NO3 == True and use_DOX == True, - use_NO3 == True + condlist = [ + use_NO3 and use_DOX, + use_NO3 ], - condlist = [ + choicelist = [ r_alkden * (1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3, r_alkden * kdnit_tc * NO3 ], @@ -3213,13 +3209,13 @@ def Alk_nitrification( """ da: np.ndarray = np.select( - choicelist = [ - use_NH4 == True and use_DOX == True, - use_NH4 == True + condlist = [ + use_NH4 and use_DOX, + use_NH4 ], - condlist = [ - r_alkn * (1 - math.exp(-KNR * DOX)) * knit_tc * NH4, + choicelist = [ + r_alkn * (1 - np.exp(-KNR * DOX)) * knit_tc * NH4, knit_tc * NH4 ], @@ -3352,7 +3348,6 @@ def Alk( ##################################### From N2 -@numba.njit def KHN2_tc( TwaterK : xr.DataArray, ) -> xr.DataArray : @@ -3368,9 +3363,9 @@ def KHN2_tc( Reference temperature: 298.15 (K) """ - return 0.00065 * math.exp(1300.0 * (1.0 / TwaterK - 1 / 298.15)) + return 0.00065 * np.exp(1300.0 * (1.0 / TwaterK - 1 / 298.15)) -@numba.njit + def P_wv( TwaterK : xr.DataArray, ) -> xr.DataArray : @@ -3383,7 +3378,7 @@ def P_wv( TwaterK: water temperature kelvin (K) """ - return math.exp(11.8571 - (3840.70 / TwaterK) - (216961.0 / (TwaterK**2))) + return np.exp(11.8571 - (3840.70 / TwaterK) - (216961.0 / (TwaterK**2))) def N2sat( From 9c26236ebf9eb3cbf1582fddf2a00e740b81d277 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:28:36 -0500 Subject: [PATCH 14/20] Removed all numba.njit. --- examples/model_architecture_nsm.ipynb | 762 ++++++++++++++++++++++- src/clearwater_modules/nsm1/processes.py | 186 +++--- 2 files changed, 843 insertions(+), 105 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index c796e9f..e1a98f4 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -656,18 +656,756 @@ "metadata": {}, "outputs": [ { - "ename": "TypeError", - "evalue": "'>' not supported between instances of 'numpy.ndarray' and 'float'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mnsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement_timestep\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2\u001b[0m nsm_model\u001b[38;5;241m.\u001b[39mdataset\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:356\u001b[0m, in \u001b[0;36mModel.increment_timestep\u001b[1;34m(self, update_state_values)\u001b[0m\n\u001b[0;32m 353\u001b[0m timestep_ds[var_name] \u001b[38;5;241m=\u001b[39m value\n\u001b[0;32m 355\u001b[0m \u001b[38;5;66;03m# compute the dynamic variables in order\u001b[39;00m\n\u001b[1;32m--> 356\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m \u001b[43mutils\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miter_computations\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 357\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestep_ds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 358\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcomputation_order\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 359\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 360\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtrack_dynamic_variables:\n\u001b[0;32m 361\u001b[0m timestep_ds \u001b[38;5;241m=\u001b[39m timestep_ds\u001b[38;5;241m.\u001b[39mdrop_vars(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdynamic_variables_names)\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\utils.py:62\u001b[0m, in \u001b[0;36miter_computations\u001b[1;34m(input_dataset, compute_order)\u001b[0m\n\u001b[0;32m 59\u001b[0m dims \u001b[38;5;241m=\u001b[39m input_dataset\u001b[38;5;241m.\u001b[39mdims\n\u001b[0;32m 61\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, func, arrays \u001b[38;5;129;01min\u001b[39;00m inputs:\n\u001b[1;32m---> 62\u001b[0m array: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43marrays\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 63\u001b[0m input_dataset[name] \u001b[38;5;241m=\u001b[39m (dims, array)\n\u001b[0;32m 65\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m input_dataset\n", - "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py:467\u001b[0m, in \u001b[0;36mFL\u001b[1;34m(L, depth, Ap, PAR, light_limitation_option, KL)\u001b[0m\n\u001b[0;32m 433\u001b[0m KEXT \u001b[38;5;241m=\u001b[39m L \u001b[38;5;241m*\u001b[39m depth\n\u001b[0;32m 435\u001b[0m FL_orig: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mselect(\n\u001b[0;32m 436\u001b[0m condlist \u001b[38;5;241m=\u001b[39m [\n\u001b[0;32m 437\u001b[0m Ap \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m KEXT \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m PAR \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.0\u001b[39m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 462\u001b[0m default \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNaN\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 463\u001b[0m )\n\u001b[0;32m 465\u001b[0m FL: np\u001b[38;5;241m.\u001b[39mndarray \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mselect(\n\u001b[0;32m 466\u001b[0m condlist \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m--> 467\u001b[0m \u001b[43mFL_orig\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m>\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1.0\u001b[39;49m,\n\u001b[0;32m 468\u001b[0m FL_orig \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0.0\u001b[39m,\n\u001b[0;32m 469\u001b[0m ],\n\u001b[0;32m 470\u001b[0m \n\u001b[0;32m 471\u001b[0m choicelist \u001b[38;5;241m=\u001b[39m [\n\u001b[0;32m 472\u001b[0m \u001b[38;5;241m1.0\u001b[39m,\n\u001b[0;32m 473\u001b[0m \u001b[38;5;241m0.0\u001b[39m\n\u001b[0;32m 474\u001b[0m ],\n\u001b[0;32m 475\u001b[0m \n\u001b[0;32m 476\u001b[0m default \u001b[38;5;241m=\u001b[39m FL_orig\n\u001b[0;32m 477\u001b[0m )\n\u001b[0;32m 479\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m FL\n", - "\u001b[1;31mTypeError\u001b[0m: '>' not supported between instances of 'numpy.ndarray' and 'float'" - ] + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
    <xarray.Dataset>\n",
    +       "Dimensions:                           (year: 2, x: 1, y: 1)\n",
    +       "Coordinates:\n",
    +       "  * year                              (year) int32 0 1\n",
    +       "  * x                                 (x) float64 1.0\n",
    +       "  * y                                 (y) float64 1.0\n",
    +       "Data variables: (12/281)\n",
    +       "    Ap                                (year, x, y) float64 1.0 -3.865e+04\n",
    +       "    Ab                                (year, x, y) float64 1.0 -4.301e+04\n",
    +       "    NH4                               (year, x, y) float64 1.0 6.089e+03\n",
    +       "    NO3                               (year, x, y) float64 1.0 3.861e+03\n",
    +       "    OrgN                              (year, x, y) float64 1.0 -7.898e+03\n",
    +       "    N2                                (year, x, y) float64 1.0 2.191e+07\n",
    +       "    ...                                ...\n",
    +       "    dNH4dt                            (year, x, y) float64 nan 0.07046\n",
    +       "    dNO3dt                            (year, x, y) float64 nan 0.04468\n",
    +       "    DOX_sat                           (year, x, y) float64 nan 0.0\n",
    +       "    Atm_O2_reaeration                 (year, x, y) float64 nan -8.28\n",
    +       "    dDOXdt                            (year, x, y) float64 nan -508.3\n",
    +       "    TDG                               (year, x, y) float64 nan inf
    " + ], + "text/plain": [ + "\n", + "Dimensions: (year: 2, x: 1, y: 1)\n", + "Coordinates:\n", + " * year (year) int32 0 1\n", + " * x (x) float64 1.0\n", + " * y (y) float64 1.0\n", + "Data variables: (12/281)\n", + " Ap (year, x, y) float64 1.0 -3.865e+04\n", + " Ab (year, x, y) float64 1.0 -4.301e+04\n", + " NH4 (year, x, y) float64 1.0 6.089e+03\n", + " NO3 (year, x, y) float64 1.0 3.861e+03\n", + " OrgN (year, x, y) float64 1.0 -7.898e+03\n", + " N2 (year, x, y) float64 1.0 2.191e+07\n", + " ... ...\n", + " dNH4dt (year, x, y) float64 nan 0.07046\n", + " dNO3dt (year, x, y) float64 nan 0.04468\n", + " DOX_sat (year, x, y) float64 nan 0.0\n", + " Atm_O2_reaeration (year, x, y) float64 nan -8.28\n", + " dDOXdt (year, x, y) float64 nan -508.3\n", + " TDG (year, x, y) float64 nan inf" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index c6e5869..5a5a7c1 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -5,16 +5,16 @@ import math ############################################ From shared processes -@numba.njit + def celsius_to_kelvin(tempc: xr.DataArray) -> xr.DataArray: return tempc + 273.16 -@numba.njit + def kelvin_to_celsius(tempk: xr.DataArray) -> xr.DataArray: return tempk - 273.16 -@numba.njit + def arrhenius_correction( TwaterC: xr.DataArray, rc20: xr.DataArray, @@ -41,7 +41,7 @@ def arrhenius_correction( return rc20 * theta**(TwaterC - 20.0) -@numba.njit + def TwaterK( TwaterC : xr.DataArray, ) -> xr.DataArray : @@ -111,7 +111,7 @@ def kah_20( return da -@numba.njit + def kah_tc( TwaterC: xr.DataArray, kah_20: xr.DataArray, @@ -187,7 +187,7 @@ def kaw_20( return da -@numba.njit + def kaw_tc( TwaterC: xr.DataArray, kaw_20: xr.DataArray, @@ -203,7 +203,7 @@ def kaw_tc( return arrhenius_correction(TwaterC, kaw_20, theta) -@numba.njit + def ka_tc( kah_tc: xr.DataArray, kaw_tc: xr.DataArray, @@ -309,7 +309,7 @@ def fdp( return xr.where(use_TIP, 1/(1+kdpo4 * Solid/0.000001), 0) ############################################ From algae -@numba.njit + def rna( AWn: xr.DataArray, AWa: xr.DataArray @@ -323,7 +323,7 @@ def rna( return AWn/AWa -@numba.njit + def rpa( AWp: xr.DataArray, AWa: xr.DataArray @@ -338,7 +338,7 @@ def rpa( return AWp/AWa -@numba.njit + def rca( AWc: xr.DataArray, AWa: xr.DataArray @@ -352,7 +352,7 @@ def rca( return AWc/AWa -@numba.njit + def rda( AWd: xr.DataArray, AWa: xr.DataArray @@ -366,7 +366,7 @@ def rda( return AWd/AWa -@numba.njit + def mu_max_tc( TwaterC: xr.DataArray, mu_max_20: xr.DataArray @@ -381,7 +381,7 @@ def mu_max_tc( return arrhenius_correction(TwaterC, mu_max_20, 1.047) -@numba.njit + def krp_tc( TwaterC: xr.DataArray, krp_20: xr.DataArray @@ -396,7 +396,7 @@ def krp_tc( return arrhenius_correction(TwaterC, krp_20, 1.047) -@numba.njit + def kdp_tc( TwaterC: xr.DataArray, kdp_20: xr.DataArray @@ -582,7 +582,7 @@ def mu( return mu -@numba.njit + def ApGrowth( mu: xr.DataArray, Ap: xr.DataArray @@ -597,7 +597,7 @@ def ApGrowth( return mu * Ap -@numba.njit + def ApRespiration( krp_tc: xr.DataArray, Ap: xr.DataArray @@ -612,7 +612,7 @@ def ApRespiration( return krp_tc * Ap -@numba.njit + def ApDeath( kdp_tc: xr.DataArray, Ap: xr.DataArray @@ -626,7 +626,7 @@ def ApDeath( return kdp_tc * Ap -@numba.njit + def ApSettling( vsap: xr.DataArray, Ap: xr.DataArray, @@ -642,7 +642,7 @@ def ApSettling( return vsap / depth * Ap -@numba.njit + def dApdt( ApGrowth: xr.DataArray, ApRespiration: xr.DataArray, @@ -661,7 +661,7 @@ def dApdt( return ApGrowth - ApRespiration - ApDeath - ApSettling -@numba.njit + def Ap( Ap: xr.DataArray, dApdt: xr.DataArray, @@ -677,7 +677,7 @@ def Ap( return Ap + dApdt * timestep ############################################ From benthic algae -@numba.njit + def mub_max_tc( mub_max_20: xr.DataArray, TwaterC: xr.DataArray @@ -691,7 +691,7 @@ def mub_max_tc( return arrhenius_correction(TwaterC, mub_max_20, 1.047) -@numba.njit + def krb_tc( krb_20: xr.DataArray, TwaterC: xr.DataArray @@ -705,7 +705,7 @@ def krb_tc( return arrhenius_correction(TwaterC, krb_20, 1.06) -@numba.njit + def kdb_tc( kdb_20: xr.DataArray, TwaterC: xr.DataArray @@ -719,7 +719,7 @@ def kdb_tc( return arrhenius_correction(TwaterC, kdb_20, 1.047) -@numba.njit + def rnb( BWn: xr.DataArray, BWd: xr.DataArray @@ -733,7 +733,7 @@ def rnb( return BWn/BWd -@numba.njit + def rpb( BWp: xr.DataArray, BWd: xr.DataArray @@ -747,7 +747,7 @@ def rpb( return BWp/BWd -@numba.njit + def rcb( BWc: xr.DataArray, BWd: xr.DataArray @@ -761,7 +761,7 @@ def rcb( return BWc/BWd -@numba.njit + def rab( BWa: xr.DataArray, BWd: xr.DataArray @@ -963,7 +963,7 @@ def mub( -@numba.njit + def AbGrowth( mub: xr.DataArray, Ab: xr.DataArray @@ -978,7 +978,7 @@ def AbGrowth( return mub * Ab -@numba.njit + def AbRespiration( krb_tc: xr.DataArray, Ab: xr.DataArray @@ -992,7 +992,7 @@ def AbRespiration( return krb_tc * Ab -@numba.njit + def AbDeath( kdb_tc: xr.DataArray, Ab: xr.DataArray @@ -1007,7 +1007,7 @@ def AbDeath( return kdb_tc * Ab -@numba.njit + def dAbdt( AbGrowth: xr.DataArray, AbRespiration: xr.DataArray, @@ -1024,7 +1024,7 @@ def dAbdt( return AbGrowth - AbRespiration - AbDeath -@numba.njit + def Ab( Ab: xr.DataArray, dAbdt: xr.DataArray, @@ -1042,7 +1042,7 @@ def Ab( return Ab + dAbdt * timestep -@numba.njit + def Chlb( rab: xr.DataArray, Ab: xr.DataArray, @@ -1060,7 +1060,7 @@ def Chlb( ############################################ From nitrogen -@numba.njit + def knit_tc( TwaterC: xr.DataArray, knit_20: xr.DataArray @@ -1075,7 +1075,7 @@ def knit_tc( return arrhenius_correction(TwaterC, knit_20, 1.083) -@numba.njit + def rnh4_tc( TwaterC: xr.DataArray, rnh4_20: xr.DataArray @@ -1090,7 +1090,7 @@ def rnh4_tc( return arrhenius_correction(TwaterC, rnh4_20, 1.074) -@numba.njit + def vno3_tc( TwaterC: xr.DataArray, vno3_20: xr.DataArray @@ -1105,7 +1105,7 @@ def vno3_tc( return arrhenius_correction(TwaterC, vno3_20, 1.08) -@numba.njit + def kon_tc( TwaterC: xr.DataArray, kon_20: xr.DataArray @@ -1120,7 +1120,7 @@ def kon_tc( return arrhenius_correction(TwaterC, kon_20, 1.074) -@numba.njit + def kdnit_tc( TwaterC: xr.DataArray, kdnit_20: xr.DataArray @@ -1179,7 +1179,7 @@ def ApUptakeFr_NH4( return ApUptakeFr_NH4 -@numba.njit + def ApUptakeFr_NO3( ApUptakeFr_NH4: xr.DataArray ) -> xr.DataArray: @@ -1234,7 +1234,7 @@ def AbUptakeFr_NH4( return AbUptakeFr_NH4 -@numba.njit + def AbUptakeFr_NO3( AbUptakeFr_NH4: xr.DataArray ) -> xr.DataArray: @@ -1261,7 +1261,7 @@ def OrgN_NH4_Decay( return xr.where(use_OrgN, kon_tc * OrgN,0) -@numba.njit + def OrgN_Settling( vson: xr.DataArray, depth: xr.DataArray, @@ -1333,7 +1333,7 @@ def dOrgNdt( return xr.where(use_OrgN, ApDeath_OrgN + AbDeath_OrgN - OrgN_NH4_Decay - OrgN_Settling,0) -@numba.njit + def OrgN( OrgN: xr.DataArray, dOrgNdt: xr.DataArray, @@ -1385,7 +1385,7 @@ def NH4_Nitrification( return xr.where(use_NH4,NitrificationInhibition * knit_tc * NH4,0) -@numba.njit + def NH4fromBed( depth: xr.DataArray, rnh4_tc: xr.DataArray, @@ -1511,7 +1511,7 @@ def dNH4dt( return xr.where(use_NH4, OrgN_NH4_Decay - NH4_Nitrification + NH4fromBed + NH4_ApRespiration - NH4_ApGrowth + NH4_AbRespiration - NH4_AbGrowth, 0.0) -@numba.njit + def NH4( NH4: xr.DataArray, dNH4dt: xr.DataArray, @@ -1564,7 +1564,7 @@ def NO3_Denit( return NO3_Denit -@numba.njit + def NO3_BedDenit( depth: xr.DataArray, vno3_tc: xr.DataArray, @@ -1656,7 +1656,7 @@ def dNO3dt( return xr.where(use_NO3, NH4_Nitrification - NO3_Denit - NO3_BedDenit - NO3_ApGrowth - NO3_AbGrowth ,0) -@numba.njit + def NO3( NO3: xr.DataArray, dNO3dt: xr.DataArray, @@ -1741,7 +1741,7 @@ def TKN( return TKN + TON -@numba.njit + def TN( DIN: xr.DataArray, TON: xr.DataArray, @@ -1757,7 +1757,7 @@ def TN( return DIN + TON ################################### From phosphorus -@numba.njit + def kop_tc( TwaterC : xr.DataArray, kop_20: xr.DataArray @@ -1772,7 +1772,7 @@ def kop_tc( return arrhenius_correction(TwaterC, kop_20, 1.047) -@numba.njit + def rpo4_tc( TwaterC : xr.DataArray, rpo4_20: xr.DataArray @@ -1802,7 +1802,7 @@ def OrgP_DIP_decay( """ return xr.where(use_OrgP,kop_tc * OrgP,0) -@numba.njit + def OrgP_Settling( vsop : xr.DataArray, depth: xr.DataArray, @@ -1879,7 +1879,7 @@ def dOrgPdt( return xr.where(use_OrgP, -OrgP_DIP_decay-OrgP_Settling + ApDeath_OrgP + AbDeath_OrgP, 0) -@numba.njit + def DIPfromBed( depth:xr.DataArray, rpo4_tc: xr.DataArray, @@ -1893,7 +1893,7 @@ def DIPfromBed( return rpo4_tc / depth #TODO calcuate fdp? -@numba.njit + def TIP_Settling( vs: xr.DataArray, depth: xr.DataArray, @@ -2011,7 +2011,7 @@ def dTIPdt( return xr.where(use_TIP, - TIP_Settling + DIPfromBed + OrgP_DIP_decay + DIP_ApRespiration - DIP_ApGrowth + DIP_AbRespiration - DIP_AbGrowth, 0) -@numba.njit + def TIP( TIP: xr.DataArray, dTIPdt: xr.DataArray, @@ -2027,7 +2027,7 @@ def TIP( """ return TIP + dTIPdt * timestep -@numba.njit + def OrgP( OrgP: xr.DataArray, dOrgPdt: xr.DataArray, @@ -2084,7 +2084,7 @@ def TP( TP = xr.where(use_TIP,TP + TIP,TP) return TP -@numba.njit + def DIP( fdp: xr.DataArray, TIP: xr.DataArray @@ -2100,7 +2100,7 @@ def DIP( ################################### From POM -@numba.njit + def kpom_tc( TwaterC: float, kpom_20: float, @@ -2135,7 +2135,7 @@ def POM_algal_settling( return da -@numba.njit + def POM_dissolution( POM: xr.DataArray, kpom_tc: xr.DataArray @@ -2194,7 +2194,7 @@ def POM_benthic_algae_mortality( return da -@numba.njit + def POM_burial( vb: xr.DataArray, POM: xr.DataArray, @@ -2210,7 +2210,7 @@ def POM_burial( return vb * POM / depth -@numba.njit + def dPOMdt( POM_algal_settling: xr.DataArray, POM_dissolution: xr.DataArray, @@ -2230,7 +2230,7 @@ def dPOMdt( return POM_algal_settling - POM_dissolution + POM_POC_settling + POM_benthic_algae_mortality - POM_burial -@numba.njit + def POM( dPOMdt: xr.DataArray, POM: xr.DataArray, @@ -2247,7 +2247,7 @@ def POM( ################################## From CBOD -@numba.njit + def kbod_tc( TwaterC: xr.DataArray, kbod_20: xr.DataArray, @@ -2263,7 +2263,7 @@ def kbod_tc( return kbod_tc -@numba.njit + def ksbod_tc( TwaterC: xr.DataArray, ksbod_20: xr.DataArray, @@ -2301,7 +2301,7 @@ def CBOD_oxidation( return da -@numba.njit + def CBOD_sedimentation( CBOD: xr.DataArray, ksbod_tc: xr.DataArray @@ -2317,7 +2317,7 @@ def CBOD_sedimentation( return CBOD_sedimentation -@numba.njit + def dCBODdt( CBOD_oxidation: xr.DataArray, CBOD_sedimentation: xr.DataArray @@ -2331,7 +2331,7 @@ def dCBODdt( return - CBOD_oxidation - CBOD_sedimentation -@numba.njit + def CBOD( CBOD: xr.DataArray, dCBODdt: xr.DataArray, @@ -2348,7 +2348,7 @@ def CBOD( ############################### From Carbon -@numba.njit + def kpoc_tc( TwaterC: xr.DataArray, kpoc_20: xr.DataArray, @@ -2362,7 +2362,7 @@ def kpoc_tc( return arrhenius_correction(TwaterC, kpoc_20, 1.047) -@numba.njit + def POC_hydrolysis( kpoc_tc: xr.DataArray, POC: xr.DataArray, @@ -2376,7 +2376,7 @@ def POC_hydrolysis( return kpoc_tc * POC -@numba.njit + def POC_settling( vsoc: xr.DataArray, depth: xr.DataArray, @@ -2439,7 +2439,7 @@ def POC_benthic_algae_mortality( return da -@numba.njit + def dPOCdt( POC_settling: xr.DataArray, POC_hydrolysis: xr.DataArray, @@ -2457,7 +2457,7 @@ def dPOCdt( return POC_algal_mortality + POC_benthic_algae_mortality - POC_settling - POC_hydrolysis -@numba.njit + def POC( POC: xr.DataArray, dPOCdt: xr.DataArray, @@ -2521,7 +2521,7 @@ def DOC_benthic_algae_mortality( return da -@numba.njit + def kdoc_tc( TwaterC: xr.DataArray, kdoc_20: xr.DataArray, @@ -2556,7 +2556,7 @@ def DOC_DIC_oxidation( return da -@numba.njit + def dDOCdt( DOC_DIC_oxidation: xr.DataArray, POC_hydrolysis: xr.DataArray, @@ -2576,7 +2576,7 @@ def dDOCdt( return POC_hydrolysis + DOC_algal_mortality + DOC_benthic_algae_mortality - DOC_DIC_oxidation -@numba.njit + def DOC( DOC: xr.DataArray, dDOCdt: xr.DataArray, @@ -2592,7 +2592,7 @@ def DOC( return DOC + dDOCdt * timestep -@numba.njit + def Henrys_k( TwaterC: xr.DataArray ) -> xr.DataArray: @@ -2603,7 +2603,7 @@ def Henrys_k( """ return 10**(2385.73 / (TwaterC + 273.15) + .0152642 * (TwaterC + 273.15) - 14.0184) -@numba.njit + def Atmospheric_CO2_reaeration( ka_tc: xr.DataArray, K_H: xr.DataArray, @@ -2739,7 +2739,7 @@ def DIC_sed_release( return SOD_tc / roc / depth -@numba.njit + def dDICdt( Atm_CO2_reaeration: xr.DataArray, DIC_algal_respiration: xr.DataArray, @@ -2763,7 +2763,7 @@ def dDICdt( return Atm_CO2_reaeration + DIC_algal_respiration + DIC_benthic_algae_respiration + DIC_CBOD_oxidation + DIC_sed_release - DIC_algal_photosynthesis - DIC_benthic_algae_photosynthesis -@numba.njit + def DIC( DIC: xr.DataArray, dDICdt: xr.DataArray, @@ -2783,7 +2783,7 @@ def DIC( #TODO: make sure np.exp will work here... -@numba.njit + def pwv( TwaterK: xr.DataArray ) -> xr.DataArray: @@ -2795,7 +2795,7 @@ def pwv( return np.exp(11.8571 - 3840.70 / TwaterK - 216961 / TwaterK ** 2) -@numba.njit + def DOs_atm_alpha( TwaterK: xr.DataArray ) -> xr.DataArray: @@ -2807,7 +2807,7 @@ def DOs_atm_alpha( return .000975 - 1.426 * 10 ** -5 * TwaterK + 6.436 * 10 ** -8 * TwaterK ** 2 -@numba.njit + def DOX_sat( TwaterK: xr.DataArray, pressure_atm: xr.DataArray, @@ -2831,7 +2831,7 @@ def DOX_sat( return DOX_sat_corrected -@numba.njit + def Atm_O2_reaeration( ka_tc: xr.DataArray, DOX_sat: xr.DataArray, @@ -2923,7 +2923,7 @@ def DOX_DOC_oxidation( return da -@numba.njit + def DOX_CBOD_oxidation( DIC_CBOD_oxidation: xr.DataArray, roc: xr.DataArray @@ -2999,7 +2999,7 @@ def DOX_SOD( return SOD_tc / depth -@numba.njit + def dDOXdt( Atm_O2_reaeration: xr.DataArray, DOX_ApGrowth: xr.DataArray, @@ -3027,7 +3027,7 @@ def dDOXdt( return Atm_O2_reaeration + DOX_ApGrowth - DOX_ApRespiration - DOX_Nitrification - DOX_DOC_oxidation - DOX_CBOD_oxidation + DOX_AbGrowth - DOX_AbRespiration - DOX_SOD -@numba.njit + def DOX( DOX: xr.DataArray, dDOXdt: xr.DataArray, @@ -3045,7 +3045,7 @@ def DOX( ######################################### From pathogen -@numba.njit + def kdx_tc( TwaterC : xr.DataArray, kdx_20: xr.DataArray @@ -3060,7 +3060,7 @@ def kdx_tc( return arrhenius_correction(TwaterC, kdx_20, 1.07) -@numba.njit + def PathogenDeath( kdx_tc : xr.DataArray, PX: xr.DataArray @@ -3095,7 +3095,7 @@ def PathogenDecay( """ return apx * q_solar / (L * depth) * (1 - np.exp(-L * depth)) * PX -@numba.njit + def PathogenSettling( vx: xr.DataArray, depth: xr.DataArray, @@ -3111,7 +3111,7 @@ def PathogenSettling( """ return vx/depth*PX -@numba.njit + def dPXdt( PathogenDeath: xr.DataArray, PathogenDecay: xr.DataArray, @@ -3129,7 +3129,7 @@ def dPXdt( """ return -PathogenDeath - PathogenDecay - PathogenSettling -@numba.njit + def PX( PX:xr.DataArray, dPXdt: xr.DataArray, @@ -3308,7 +3308,7 @@ def Alk_benthic_algae_respiration( return da -@numba.njit + def dAlkdt( Alk_denitrification: xr.DataArray, Alk_nitrification: xr.DataArray, @@ -3330,7 +3330,7 @@ def dAlkdt( return Alk_denitrification - Alk_nitrification - Alk_algal_growth + Alk_algal_respiration - Alk_benthic_algae_growth + Alk_benthic_algae_respiration -@numba.njit + def Alk( Alk: xr.DataArray, dAlkdt: xr.DataArray, @@ -3400,7 +3400,7 @@ def N2sat( return N2sat -@numba.njit + def dN2dt( ka_tc : xr.DataArray, N2sat : xr.DataArray, @@ -3417,7 +3417,7 @@ def dN2dt( return 1.034 * ka_tc * (N2sat - N2) -@numba.njit + def N2( N2: xr.DataArray, dN2dt : xr.DataArray, From d0706dd8c0c7b6d6a03efce8bd1519191dcbfd93 Mon Sep 17 00:00:00 2001 From: kewalak Date: Mon, 18 Mar 2024 16:52:17 -0700 Subject: [PATCH 15/20] Start Algae Testing --- examples/model_architecture_nsm.ipynb | 128 +----- src/clearwater_modules/nsm1/constants.py | 33 +- src/clearwater_modules/nsm1/processes.py | 2 +- tests/test_6_nsm_module.py | 134 ++++++ tests/test_7_nsm_algae_calculations.py | 504 +++++++++++++++++++++++ 5 files changed, 666 insertions(+), 135 deletions(-) create mode 100644 tests/test_6_nsm_module.py create mode 100644 tests/test_7_nsm_algae_calculations.py diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index c796e9f..ccac85b 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -48,123 +48,15 @@ }, "outputs": [ { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.1.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
    \n", - "
    \n", - "
    \n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "p1002" - } - }, - "output_type": "display_data" + "ename": "ModuleNotFoundError", + "evalue": "No module named 'clearwater_modules'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mclearwater_modules\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mcwm\u001b[39;00m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mclearwater_modules\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01msorter\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01msorter\u001b[39;00m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumba\u001b[39;00m\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'clearwater_modules'" + ] } ], "source": [ @@ -1441,7 +1333,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.10.13" }, "toc-autonumbering": true }, diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index ec0aa4b..5d6cc6d 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -19,12 +19,6 @@ class AlgaeStaticVariables(TypedDict): vsap: float growth_rate_option: int light_limitation_option: int - lambda0: float - lambda1: float - lambda2: float - lambdas: float - lambdam: float - Fr_PAR: float DEFAULT_ALGAE = AlgaeStaticVariables( AWd = 100, @@ -41,12 +35,6 @@ class AlgaeStaticVariables(TypedDict): vsap= 0.15, growth_rate_option = 1, light_limitation_option = 1, - lambda0 = .5, - lambda1 = .5, - lambda2 = .5, - lambdas = .5, - lambdam = .5, - Fr_PAR = .5 ) class AlkalinityStaticVariables(TypedDict): @@ -275,6 +263,13 @@ class GlobalVars(TypedDict): wind_speed: float q_solar: float Solid: int + lambda0: float + lambda1: float + lambda2: float + lambdas: float + lambdam: float + Fr_PAR: float + DEFAULT_GLOBALVARS = GlobalVars( @@ -290,8 +285,8 @@ class GlobalVars(TypedDict): kah_20_user = 999, hydraulic_reaeration_option = 2, wind_reaeration_option = 2, - timestep = 86400, - depth = 1, + timestep = 86400, #TODO Dynamic or static? + depth = 1.5, #TODO Dynamic or static? TwaterC = 20, theta = 1.047, velocity = 1, @@ -301,6 +296,12 @@ class GlobalVars(TypedDict): shear_velocity = 4, pressure_atm = 2, wind_speed = 4, - q_solar = 4, - Solid = 1 + q_solar = 500, + Solid = 1, + lambda0 = .02, + lambda1 = .0088, + lambda2 = .054, + lambdas = .052, + lambdam = .0174, + Fr_PAR = .47 ) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index ac901eb..b5557ed 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -269,7 +269,7 @@ def L( use_POC: true/falseo use particulate organic carbon module (t/f) Ap: algae concentration (ug-Chla/L) """ - L = lambda0 + lambdas * Solid + L = lambda0 #+ lambdas * Solid L: xr.DataArray = xr.where (use_POC, L+lambdam*POC/fcom, L) L: xr.DataArray = xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**0.66667, L) diff --git a/tests/test_6_nsm_module.py b/tests/test_6_nsm_module.py new file mode 100644 index 0000000..25c0f1c --- /dev/null +++ b/tests/test_6_nsm_module.py @@ -0,0 +1,134 @@ +import numpy as np +import pytest + +from clearwater_modules.nsm1.model import ( + NutrientBudget +) + +from clearwater_modules.nsm1.constants import ( + DEFAULT_ALGAE, + DEFAULT_ALKALINITY, + DEFAULT_BALGAE, + DEFAULT_NITROGEN, + DEFAULT_CARBON, + DEFAULT_CBOD, + DEFAULT_DOX, + DEFAULT_N2, + DEFAULT_POM, + DEFAULT_PATHOGEN, + DEFAULT_PHOSPHORUS, + DEFAULT_GLOBALPARAMETERS, + DEFAULT_GLOBALVARS + +) + + +@pytest.fixture(scope='module') +def initial_nsm1_state(initial_array) -> dict[str, float]: + """Return initial state values for the model.""" + return { + 'Ap': initial_array, + 'Ab': initial_array, + 'NH4': initial_array, + 'NO3': initial_array, + 'OrgN': initial_array, + 'N2': initial_array, + 'TIP': initial_array, + 'OrgP': initial_array, + 'POC': initial_array, + 'DOC': initial_array, + 'DIC': initial_array, + 'POM': initial_array, + 'CBOD': initial_array, + 'DOX': initial_array, + 'PX': initial_array, + 'Alk': initial_array, + } + + +@pytest.fixture(scope='module') +def time_steps() -> int: + return 1 + + +@pytest.fixture(scope='module') +def nsm1_state_variable_names(initial_state_values) -> list[str]: + """Return the names of the state variables.""" + return list(initial_state_values.keys()) + + +@pytest.fixture(scope='module') +def nutrient_budget_instance( + time_steps, + initial_nsm1_state +) -> NutrientBudget: + """Return an instance of the NSM1 class.""" + return NutrientBudget( + time_steps=time_steps, + initial_state_values=initial_nsm1_state, + updateable_static_variables=['a0'], + time_dim='tsm_time_step', + ) + + +def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: + """Checks that all NSM1 variables are present.""" + assert nutrient_budget_instance.time_dim == 'tsm_time_step' + assert isinstance(nutrient_budget_instance.algae_parameters, dict) + assert isinstance(nutrient_budget_instance.alkalinity_parameters, dict) + assert isinstance(nutrient_budget_instance.Balgae_parameters, dict) + assert isinstance(nutrient_budget_instance.nitrogen_parameters, dict) + assert isinstance(nutrient_budget_instance.carbon_parameters, dict) + assert isinstance(nutrient_budget_instance.CBOD_parameters, dict) + assert isinstance(nutrient_budget_instance.DOX_parameters, dict) + assert isinstance(nutrient_budget_instance.N2_parameters, dict) + assert isinstance(nutrient_budget_instance.POM_parameters, dict) + assert isinstance(nutrient_budget_instance.pathogen_parameters, dict) + assert isinstance(nutrient_budget_instance.phosphorus_parameters, dict) + assert isinstance(nutrient_budget_instance.gp_parameters, dict) + assert isinstance(nutrient_budget_instance.gvars_parameters, dict) + + assert nutrient_budget_instance.updateable_static_variables == ['a0'] + + assert nutrient_budget_instance.algae_parameters == DEFAULT_ALGAE + assert nutrient_budget_instance.alkalinity_parameters == DEFAULT_ALKALINITY + assert nutrient_budget_instance.Balgae_parameters == DEFAULT_BALGAE + assert nutrient_budget_instance.nitrogen_parameters == DEFAULT_NITROGEN + assert nutrient_budget_instance.carbon_parameters == DEFAULT_CARBON + assert nutrient_budget_instance.CBOD_parameters == DEFAULT_CBOD + assert nutrient_budget_instance.DOX_parameters == DEFAULT_DOX + assert nutrient_budget_instance.N2_parameters == DEFAULT_N2 + assert nutrient_budget_instance.POM_parameters == DEFAULT_POM + assert nutrient_budget_instance.pathogen_parameters == DEFAULT_PATHOGEN + assert nutrient_budget_instance.phosphorus_parameters == DEFAULT_PHOSPHORUS + assert nutrient_budget_instance.gp_parameters == DEFAULT_GLOBALPARAMETERS + assert nutrient_budget_instance.gvars_parameters == DEFAULT_GLOBALVARS + +def test_nsm1_variable_sorting(nutrient_budget_instance) -> None: + """Checks that we can auto-sort our NSM1 variable""" + assert isinstance(nutrient_budget_instance.computation_order, list) + assert nutrient_budget_instance.computation_order[-1].name == 'water_temp_c' #TODO what is first? + + +def test_nsm1_timestep(nutrient_budget_instance) -> None: + """Checks that we can auto-sort our NSM1 variable""" + nutrient_budget_instance.increment_timestep() + assert len(nutrient_budget_instance.dataset.tsm_time_step) == 2 + assert nutrient_budget_instance.dataset.sel(tsm_time_step=1).isnull().any() == False + + +#TODO do we need this for NSM? +def test_use_sed_temp( + initial_tsm_state, + time_steps, +) -> None: + """Tests that when we set use_sed_temp to False we get a False boolean array.""" + if 'a0' in initial_tsm_state: + del initial_tsm_state['a0'] + no_sed_temp = NutrientBudget( + time_steps=time_steps, + initial_state_values=initial_tsm_state, + use_sed_temp=False, + ) + assert no_sed_temp.dataset.use_sed_temp.dtype == bool + assert bool(np.all(no_sed_temp.dataset.use_sed_temp == False)) diff --git a/tests/test_7_nsm_algae_calculations.py b/tests/test_7_nsm_algae_calculations.py new file mode 100644 index 0000000..077d4b6 --- /dev/null +++ b/tests/test_7_nsm_algae_calculations.py @@ -0,0 +1,504 @@ +from numba import ( + types, + typed, +) +import pytest + +from clearwater_modules.nsm1 import NutrientBudget +from clearwater_modules.nsm1.constants import ( + AlgaeStaticVariables, + AlkalinityStaticVariables, + BalgaeStaticVariables, + NitrogenStaticVariables, + CarbonStaticVariables, + CBODStaticVariables, + DOXStaticVariables, + N2StaticVariables, + POMStaticVariables, + PathogenStaticVariables, + PhosphorusStaticVariables, + GlobalParameters, + GlobalVars +) + + +@pytest.fixture(scope='function') +def initial_nsm1_state() -> dict[str, float]: + """Return initial state values for the model.""" + return { + + 'Ap': 40, + 'Ab': 24, + 'NH4': 0.05, + 'NO3': 5, + 'OrgN': 1.7, + 'N2': 1, + 'TIP': 0.07, + 'OrgP': 0.25, + 'POC': 4, + 'DOC': 1, + 'DIC': 1, + 'POM': 10, + 'CBOD': 5, + 'DOX': 8, + 'PX': 1, + 'Alk': 1 + + } + +@pytest.fixture(scope='module') +def time_steps() -> int: + return 1 + + +@pytest.fixture(scope='function') +def default_algae_params() -> AlgaeStaticVariables: + """Returns default algae static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return AlgaeStaticVariables( + AWd = 100, + AWc= 40, + AWn= 7.2, + AWp= 1, + AWa= 1000, + KL= 10, + KsN= 0.04, + KsP= 0.0012, + mu_max_20= 1, + kdp_20= 0.15, + krp_20= 0.2, + vsap= 0.15, + growth_rate_option = 1, + light_limitation_option = 1, + ) + +@pytest.fixture(scope='function') +def default_alkalinity_params() -> AlkalinityStaticVariables: + """Returns default alkalinity static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return AlkalinityStaticVariables( + r_alkaa = 14.0 / 106.0 / 12.0 / 1000.0, + r_alkan= 18.0 / 106.0 / 12.0 / 1000.0, + r_alkn = 2.0 / 14.0 / 1000.0, + r_alkden = 4.0 / 14.0 / 1000.0, + r_alkba = 14.0 / 106.0 / 12.0 / 1000.0, + r_alkbn =18.0 / 106.0 / 12.0 / 1000.0 + ) + +def default_Balgae_params() -> BalgaeStaticVariables: + """Returns default Benthic Algae static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return BalgaeStaticVariables( + BWd = 100, + BWc= 40, + BWn=7.2, + BWp= 1, + BWa= 3500, + + KLb= 10, + KsNb= 0.25, + KsPb=0.125, + Ksb=10, + mub_max_20=0.4, + krb_20=0.2, + kdb_20=0.3, + b_growth_rate_option=1, + b_light_limitation_option=1, + Fw=0.9, + Fb=0.9 + ) + +def default_nitrogen_params() -> NitrogenStaticVariables: + """Returns default nitrogen static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return NitrogenStaticVariables( + KNR= 0.6 , + knit_20= 0.1, + kon_20=0.1, + kdnit_20=0.002, + rnh4_20=0, + vno3_20=0, + KsOxdn=0.1, + PN=0.5, + PNb=0.5 + ) + +def default_carbon_params() -> CarbonStaticVariables: + """Returns default carbon static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return CarbonStaticVariables( + f_pocp = 0.9, + kdoc_20= 0.01, + f_pocb=0.9, + kpoc_20= 0.005, + KsOxmc=1.0, + pCO2 = 383.0, + FCO2 = 0.2, + roc = 32.0/12.0 + ) + +def default_CBOD_params() -> CBODStaticVariables: + """Returns default CBOD static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return CBODStaticVariables( + KsOxbod = 0.5, + kbod_20 = 0.12, + ksbod_20 = 0.0 + ) + +def default_DOX_params() -> DOXStaticVariables: + """Returns default DOX static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return DOXStaticVariables( + ron = 2.0 * 32.0 / 14.0, + KsSOD =1, + ) + +def default_N2_params() -> N2StaticVariables: + """Returns default N2 static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return N2StaticVariables( + + ) + +def default_POM_params() -> POMStaticVariables: + """Returns default POM static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return POMStaticVariables( + kpom_20 = 0.1 + ) + +def default_pathogens_params() -> PathogenStaticVariables: + """Returns default Pathogens static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return PathogenStaticVariables( + kdx_20=0.8, + apx=1, + vx=1 + ) + +def default_phosphorus_params() -> PhosphorusStaticVariables: + """Returns default phosphorus static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return PhosphorusStaticVariables( + kop_20 = 0.1, + rpo4_20 =0, + kdpo4 = 0.0, + ) + +def default_gp_params() -> GlobalParameters: + """Returns default global parameter static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return GlobalParameters( + use_NH4= True, + use_NO3= True, + use_OrgN= True, + use_OrgP = True, + use_TIP= True, + use_SedFlux= False, + use_POC = True, + use_DOC = True, + use_DOX= True, + use_DIC= True, + use_Algae= True, + use_Balgae= True, + use_N2 = True, + use_Pathogen = True, + use_Alk = True, + use_POM = True + ) + +def default_gvars_params() -> GlobalVars: + """Returns default global variables static variable values for the model. + + NOTE: As of now (3/18/2022) these match the built in defaults, but are + copied here to allow for easy modification of the defaults in the future. + + Returns a typed dictionary, with string keys and float values. + """ + return GlobalVars( + vson = 0.01, + vsoc = 0.01, + vsop = 999, + vs = 999, + SOD_20 = 999, + SOD_theta = 999, + vb = 0.01, + fcom = 0.4, + kaw_20_user = 999, + kah_20_user = 999, + hydraulic_reaeration_option = 2, + wind_reaeration_option = 2, + timestep = 86400, #TODO Dynamic or static? + depth = 1.5, #TODO Dynamic or static? + TwaterC = 20, + theta = 1.047, + velocity = 1, + flow = 2, + topwidth = 1, + slope = 2, + shear_velocity = 4, + pressure_atm = 2, + wind_speed = 4, + q_solar = 500, + Solid = 1, + lambda0 = .02, + lambda1 = .0088, + lambda2 = .054, + lambdas = .052, + lambdam = .0174, + Fr_PAR = .47 + ) + +def get_nutrient_budget_instance( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_Balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + use_sed_temp: bool = False, + +) -> NutrientBudget: + """Return an instance of the NSM1 class.""" + return NutrientBudget( + time_steps=time_steps, + initial_state_values=initial_nsm1_state, + algae_parameters=default_algae_params, + alkalinity_parameters=default_alkalinity_params, + Balgae_parameters=default_Balgae_params, + nitrogen_parameters=default_nitrogen_params, + carbon_parameters=default_carbon_params, + CBOD_parameters=default_CBOD_params, + DOX_parameters=default_DOX_params, + N2_parameters=default_N2_params, + POM_parameters=default_POM_params, + pathogen_parameters=default_pathogen_params, + phosphorus_parameters=default_phosphorus_params, + global_parameters=default_gp_params, + global_vars=default_gvars_params, + + use_sed_temp=use_sed_temp, + time_dim='nsm1_time_step', + ) + + +@pytest.fixture(scope='module') +def tolerance() -> float: + """Controls the precision of the pytest.approx() function.""" + return 0.0000001 + + +def test_defaults( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_Balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_Balgae_params=default_Balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel(nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 53.19609 + +def test_changed_Ap( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_Balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + initial_state_dict['Ap'] = 60.0 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_Balgae_params=default_Balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 75.57808 + +def test_changed_NH4( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_Balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + initial_state_dict['NH4'] = 0.3 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_Balgae_params=default_Balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 75.59588 + From 69bbfefb49c1544fac08176c0effe984a5eeca7e Mon Sep 17 00:00:00 2001 From: kewalak Date: Tue, 26 Mar 2024 16:02:24 -0700 Subject: [PATCH 16/20] Algae Testing 13 passing tests --- examples/model_architecture_nsm.ipynb | 601 ++++++++++-------- .../nsm1/algae/processes.py | 8 +- src/clearwater_modules/nsm1/model.py | 2 + src/clearwater_modules/nsm1/processes.py | 33 +- tests/test_6_nsm_module.py | 38 +- tests/test_7_nsm_algae_calculations.py | 545 +++++++++++++++- 6 files changed, 901 insertions(+), 326 deletions(-) diff --git a/examples/model_architecture_nsm.ipynb b/examples/model_architecture_nsm.ipynb index 84b6f56..0bf5dbb 100644 --- a/examples/model_architecture_nsm.ipynb +++ b/examples/model_architecture_nsm.ipynb @@ -48,15 +48,122 @@ }, "outputs": [ { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'clearwater_modules'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mclearwater_modules\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mcwm\u001b[39;00m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mclearwater_modules\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01msorter\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01msorter\u001b[39;00m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumba\u001b[39;00m\n", - "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'clearwater_modules'" - ] + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.4'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.4.min.js\", \"https://cdn.holoviz.org/panel/1.3.8/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
    \n", + "
    \n", + "
    \n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "p1002" + } + }, + "output_type": "display_data" } ], "source": [ @@ -110,57 +217,31 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 13, "id": "3bce5192", "metadata": {}, "outputs": [ { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" + "name": "stdout", + "output_type": "stream", + "text": [ + "Initializing from dicts...\n", + "Model initialized from input dicts successfully!.\n", + "['TwaterK', 'SOD_tc', 'kah_20', 'kah_tc', 'kaw_20', 'kaw_tc', 'ka_tc', 'L', 'PAR', 'fdp', 'rna', 'rpa', 'rca', 'rda', 'mu_max_tc', 'krp_tc', 'kdp_tc', 'FL', 'FN', 'FP', 'mu', 'ApGrowth', 'ApRespiration', 'ApDeath', 'ApSettling', 'dApdt', 'mub_max_tc', 'krb_tc', 'kdb_tc', 'rnb', 'rpb', 'rcb', 'rab', 'FLb', 'FNb', 'FPb', 'FSb', 'mub', 'AbGrowth', 'AbRespiration', 'AbDeath', 'dAbdt', 'Chlb', 'knit_tc', 'rnh4_tc', 'vno3_tc', 'kon_tc', 'kdnit_tc', 'ApUptakeFr_NH4', 'ApUptakeFr_NO3', 'AbUptakeFr_NH4', 'AbUptakeFr_NO3', 'ApDeath_OrgN', 'AbDeath_OrgN', 'OrgN_NH4_Decay', 'OrgN_Settling', 'dOrgNdt', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth', 'dNH4dt', 'NO3_Denit', 'NO3_BedDenit', 'NO3_ApGrowth', 'NO3_AbGrowth', 'dNO3dt', 'DIN', 'TON', 'TKN', 'TN', 'NitrificationInhibition', 'kop_tc', 'rpo4_tc', 'OrgP_DIP_decay', 'OrgP_Settling', 'ApDeath_OrgP', 'AbDeath_OrgP', 'dOrgPdt', 'DIPfromBed', 'TIP_Settling', 'DIP_ApRespiration', 'DIP_ApGrowth', 'DIP_AbRespiration', 'DIP_AbGrowth', 'dTIPdt', 'TOP', 'TP', 'DIP', 'kpom_tc', 'POM_algal_settling', 'POM_dissolution', 'POM_POC_settling', 'POM_benthic_algae_mortality', 'POM_burial', 'dPOMdt', 'kbod_tc', 'ksbod_tc', 'CBOD_oxidation', 'CBOD_sedimentation', 'dCBODdt', 'kpoc_tc', 'POC_settling', 'POC_hydrolysis', 'POC_algal_mortality', 'POC_benthic_algae_mortality', 'dPOCdt', 'kdoc_tc', 'DOC_algal_mortality', 'DOC_benthic_algae_mortality', 'DOC_DIC_oxidation', 'dDOCdt', 'K_H', 'Atm_CO2_reaeration', 'DIC_algal_respiration', 'DIC_algal_photosynthesis', 'DIC_benthic_algae_respiration', 'DIC_benthic_algae_photosynthesis', 'DIC_CBOD_oxidation', 'DIC_sed_release', 'dDICdt', 'DOX_sat', 'pwv', 'DOs_atm_alpha', 'Atm_O2_reaeration', 'DOX_ApGrowth', 'DOX_ApRespiration', 'DOX_Nitrification', 'DOX_DOC_oxidation', 'DOX_CBOD_oxidation', 'DOX_AbGrowth', 'DOX_AbRespiration', 'DOX_SOD', 'dDOXdt', 'kdx_tc', 'PathogenDeath', 'PathogenDecay', 'PathogenSettling', 'dPXdt', 'Alk_denitrification', 'Alk_nitrification', 'Alk_algal_growth', 'Alk_algal_respiration', 'Alk_benthic_algae_growth', 'Alk_benthic_algae_respiration', 'dAlkdt', 'KHN2_tc', 'P_wv', 'N2sat', 'dN2dt', 'TDG']\n" + ] }, { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\l2edeknw\\Documents\\Projects\\ToddERDC\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py:3454: RuntimeWarning: divide by zero encountered in divide\n", + " return xr.where(use_DOX,(79.0 * N2 / N2sat) + (21.0 * DOX / DOX_sat), N2/N2sat)\n" + ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Initializing from dicts...\n", - "Model initialized from input dicts successfully!.\n", - "['TwaterK', 'SOD_tc', 'kah_20', 'kah_tc', 'kaw_20', 'kaw_tc', 'ka_tc', 'L', 'PAR', 'fdp', 'rna', 'rpa', 'rca', 'rda', 'mu_max_tc', 'krp_tc', 'kdp_tc', 'FL', 'FN', 'FP', 'mu', 'ApGrowth', 'ApRespiration', 'ApDeath', 'ApSettling', 'dApdt', 'mub_max_tc', 'krb_tc', 'kdb_tc', 'rnb', 'rpb', 'rcb', 'rab', 'FLb', 'FNb', 'FPb', 'FSb', 'mub', 'AbGrowth', 'AbRespiration', 'AbDeath', 'dAbdt', 'Chlb', 'knit_tc', 'rnh4_tc', 'vno3_tc', 'kon_tc', 'kdnit_tc', 'ApUptakeFr_NH4', 'ApUptakeFr_NO3', 'AbUptakeFr_NH4', 'AbUptakeFr_NO3', 'ApDeath_OrgN', 'AbDeath_OrgN', 'OrgN_NH4_Decay', 'OrgN_Settling', 'dOrgNdt', 'NH4_Nitrification', 'NH4fromBed', 'NH4_ApRespiration', 'NH4_ApGrowth', 'NH4_AbRespiration', 'NH4_AbGrowth', 'dNH4dt', 'NO3_Denit', 'NO3_BedDenit', 'NO3_ApGrowth', 'NO3_AbGrowth', 'dNO3dt', 'DIN', 'TON', 'TKN', 'TN', 'NitrificationInhibition', 'kop_tc', 'rpo4_tc', 'OrgP_DIP_decay', 'OrgP_Settling', 'ApDeath_OrgP', 'AbDeath_OrgP', 'dOrgPdt', 'DIPfromBed', 'TIP_Settling', 'DIP_ApRespiration', 'DIP_ApGrowth', 'DIP_AbRespiration', 'DIP_AbGrowth', 'dTIPdt', 'TOP', 'TP', 'DIP', 'kpom_tc', 'POM_algal_settling', 'POM_dissolution', 'POM_POC_settling', 'POM_benthic_algae_mortality', 'POM_burial', 'dPOMdt', 'kbod_tc', 'ksbod_tc', 'CBOD_oxidation', 'CBOD_sedimentation', 'dCBODdt', 'kpoc_tc', 'POC_settling', 'POC_hydrolysis', 'POC_algal_mortality', 'POC_benthic_algae_mortality', 'dPOCdt', 'kdoc_tc', 'DOC_algal_mortality', 'DOC_benthic_algae_mortality', 'DOC_DIC_oxidation', 'dDOCdt', 'K_H', 'Atm_CO2_reaeration', 'DIC_algal_respiration', 'DIC_algal_photosynthesis', 'DIC_benthic_algae_respiration', 'DIC_benthic_algae_photosynthesis', 'DIC_CBOD_oxidation', 'DIC_sed_release', 'dDICdt', 'DOX_sat', 'pwv', 'DOs_atm_alpha', 'Atm_O2_reaeration', 'DOX_ApGrowth', 'DOX_ApRespiration', 'DOX_Nitrification', 'DOX_DOC_oxidation', 'DOX_CBOD_oxidation', 'DOX_AbGrowth', 'DOX_AbRespiration', 'DOX_SOD', 'dDOXdt', 'kdx_tc', 'PathogenDeath', 'PathogenDecay', 'PathogenSettling', 'dPXdt', 'Alk_denitrification', 'Alk_nitrification', 'Alk_algal_growth', 'Alk_algal_respiration', 'Alk_benthic_algae_growth', 'Alk_benthic_algae_respiration', 'dAlkdt', 'KHN2_tc', 'P_wv', 'N2sat', 'dN2dt', 'TDG']\n", "Variable | Inputs\n", "------------------\n", "TwaterK | ['TwaterC']\n", @@ -510,8 +591,10 @@ "DOX_parameters = {}\n", "N2_parameters = {}\n", "\n", + "time_steps=1 \n", "\n", "nsm_model = NutrientBudget(\n", + " time_steps=time_steps,\n", " initial_state_values=initial_state_values, # mandatory\n", " algae_parameters=algae_parameters,\n", " alkalinity_parameters=alkalinity_parameters,\n", @@ -533,7 +616,7 @@ "\n", "print(nsm_model.dynamic_variables_names)\n", "\n", - "#nsm_model.increment_timestep()\n", + "nsm_model.increment_timestep()\n", "nsm_model.dataset\n", "\n", "print('Variable | Inputs\\n------------------')\n", @@ -543,10 +626,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "id": "32673258", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\l2edeknw\\Documents\\Projects\\ToddERDC\\ClearWater-modules\\src\\clearwater_modules\\nsm1\\processes.py:3454: RuntimeWarning: divide by zero encountered in divide\n", + " return xr.where(use_DOX,(79.0 * N2 / N2sat) + (21.0 * DOX / DOX_sat), N2/N2sat)\n" + ] + }, { "data": { "text/html": [ @@ -913,389 +1004,389 @@ " stroke: currentColor;\n", " fill: currentColor;\n", "}\n", - "
    <xarray.Dataset>\n",
    +       "
    <xarray.Dataset> Size: 3kB\n",
            "Dimensions:                           (year: 2, x: 1, y: 1)\n",
            "Coordinates:\n",
    -       "  * year                              (year) int32 0 1\n",
    -       "  * x                                 (x) float64 1.0\n",
    -       "  * y                                 (y) float64 1.0\n",
    +       "  * year                              (year) int32 8B 0 1\n",
    +       "  * x                                 (x) float64 8B 1.0\n",
    +       "  * y                                 (y) float64 8B 1.0\n",
            "Data variables: (12/281)\n",
    -       "    Ap                                (year, x, y) float64 1.0 -3.865e+04\n",
    -       "    Ab                                (year, x, y) float64 1.0 -4.301e+04\n",
    -       "    NH4                               (year, x, y) float64 1.0 6.089e+03\n",
    -       "    NO3                               (year, x, y) float64 1.0 3.861e+03\n",
    -       "    OrgN                              (year, x, y) float64 1.0 -7.898e+03\n",
    -       "    N2                                (year, x, y) float64 1.0 2.191e+07\n",
    +       "    Ap                                (year, x, y) float64 16B 1.0 -3.05e+04\n",
    +       "    Ab                                (year, x, y) float64 16B 1.0 -3.967e+04\n",
    +       "    NH4                               (year, x, y) float64 16B 1.0 5.951e+03\n",
    +       "    NO3                               (year, x, y) float64 16B 1.0 3.724e+03\n",
    +       "    OrgN                              (year, x, y) float64 16B 1.0 -7.898e+03\n",
    +       "    N2                                (year, x, y) float64 16B 1.0 2.191e+07\n",
            "    ...                                ...\n",
    -       "    dNH4dt                            (year, x, y) float64 nan 0.07046\n",
    -       "    dNO3dt                            (year, x, y) float64 nan 0.04468\n",
    -       "    DOX_sat                           (year, x, y) float64 nan 0.0\n",
    -       "    Atm_O2_reaeration                 (year, x, y) float64 nan -8.28\n",
    -       "    dDOXdt                            (year, x, y) float64 nan -508.3\n",
    -       "    TDG                               (year, x, y) float64 nan inf
    • year
      PandasIndex
      PandasIndex(Index([0, 1], dtype='int32', name='year'))
    • x
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='x'))
    • y
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='y'))
  • " ], "text/plain": [ - "\n", + " Size: 3kB\n", "Dimensions: (year: 2, x: 1, y: 1)\n", "Coordinates:\n", - " * year (year) int32 0 1\n", - " * x (x) float64 1.0\n", - " * y (y) float64 1.0\n", + " * year (year) int32 8B 0 1\n", + " * x (x) float64 8B 1.0\n", + " * y (y) float64 8B 1.0\n", "Data variables: (12/281)\n", - " Ap (year, x, y) float64 1.0 -3.865e+04\n", - " Ab (year, x, y) float64 1.0 -4.301e+04\n", - " NH4 (year, x, y) float64 1.0 6.089e+03\n", - " NO3 (year, x, y) float64 1.0 3.861e+03\n", - " OrgN (year, x, y) float64 1.0 -7.898e+03\n", - " N2 (year, x, y) float64 1.0 2.191e+07\n", + " Ap (year, x, y) float64 16B 1.0 -3.05e+04\n", + " Ab (year, x, y) float64 16B 1.0 -3.967e+04\n", + " NH4 (year, x, y) float64 16B 1.0 5.951e+03\n", + " NO3 (year, x, y) float64 16B 1.0 3.724e+03\n", + " OrgN (year, x, y) float64 16B 1.0 -7.898e+03\n", + " N2 (year, x, y) float64 16B 1.0 2.191e+07\n", " ... ...\n", - " dNH4dt (year, x, y) float64 nan 0.07046\n", - " dNO3dt (year, x, y) float64 nan 0.04468\n", - " DOX_sat (year, x, y) float64 nan 0.0\n", - " Atm_O2_reaeration (year, x, y) float64 nan -8.28\n", - " dDOXdt (year, x, y) float64 nan -508.3\n", - " TDG (year, x, y) float64 nan inf" + " dAlkdt (year, x, y) float64 16B nan 0.3351\n", + " KHN2_tc (year, x, y) float64 16B nan 0.0007001\n", + " P_wv (year, x, y) float64 16B nan 0.02309\n", + " N2sat (year, x, y) float64 16B nan 30.61\n", + " dN2dt (year, x, y) float64 16B nan 253.6\n", + " TDG (year, x, y) float64 16B nan inf" ] }, - "execution_count": 2, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -1347,7 +1438,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "a5d34d2d-03a6-41e1-92fc-9e6fba72d6f5", "metadata": { "tags": [] @@ -2071,7 +2162,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.11.8" }, "toc-autonumbering": true }, diff --git a/src/clearwater_modules/nsm1/algae/processes.py b/src/clearwater_modules/nsm1/algae/processes.py index e232666..852460f 100644 --- a/src/clearwater_modules/nsm1/algae/processes.py +++ b/src/clearwater_modules/nsm1/algae/processes.py @@ -3,6 +3,7 @@ """ import numba import xarray as xr +import numpy as np from clearwater_modules.shared.processes import arrhenius_correction import math @@ -116,7 +117,7 @@ def FL( Ap: xr.DataArray, PAR: xr.DataArray, light_limitation_option: int, - KL: xr.DataArray, + KL: int, ) -> xr.DataArray: """Calculate Algal light limitation: FL (unitless). @@ -131,12 +132,13 @@ def FL( KEXT = L * depth + FL = xr.where(Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, 0, xr.where(light_limitation_option==1, (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), xr.where(light_limitation_option==2, - xr.where(abs(KL)<0.0000000001, 1, (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5)))), + xr.where(abs(KL)< 0.0000000001, 1, (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5)))), xr.where(light_limitation_option==3, - xr.where(abs(KL)<0.0000000001,0,(2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL))), "NaN")))) + xr.where(abs(KL)< 0.0000000001,0,(2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL))), "NaN")))) FL= xr.where(FL > 1.0, 1.0, diff --git a/src/clearwater_modules/nsm1/model.py b/src/clearwater_modules/nsm1/model.py index 1da9c1d..2bc1121 100644 --- a/src/clearwater_modules/nsm1/model.py +++ b/src/clearwater_modules/nsm1/model.py @@ -18,6 +18,7 @@ class NutrientBudget(base.Model): def __init__( self, + time_steps: int, initial_state_values: Optional[base.InitialVariablesDict] = None, updateable_static_variables: Optional[list[str]] = None, algae_parameters: Optional[dict[str, float]] = None, @@ -168,6 +169,7 @@ def __init__( #static_variable_values['use_sed_temp'] = use_sed_temp super().__init__( + time_steps=time_steps, initial_state_values=initial_state_values, static_variable_values=static_variable_values, updateable_static_variables=updateable_static_variables, diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 982e58a..1ab795b 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -269,10 +269,10 @@ def L( use_POC: true/falseo use particulate organic carbon module (t/f) Ap: algae concentration (ug-Chla/L) """ - L = lambda0 #+ lambdas * Solid + L: xr.DataArray = lambda0 #+ lambdas * Solid - L: xr.DataArray = xr.where (use_POC, L+lambdam*POC/fcom, L) - L: xr.DataArray = xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**0.66667, L) + L: xr.DataArray = xr.where (use_POC, L+lambdam*(POC/fcom), L) + L: xr.DataArray = xr.where (use_Algae, L+lambda1*Ap + lambda2*Ap**(2/3), L) return L @@ -291,7 +291,7 @@ def PAR( """ return xr.where (use_Algae or use_Balgae, q_solar * Fr_PAR, 0) - +#TODO does not appear HEC-RAS actually uses Solid in any calculations def fdp( use_TIP: bool, Solid : xr.DataArray, @@ -306,7 +306,7 @@ def fdp( kdpo4: solid partitioning coeff. of PO4 (L/kg) """ - return xr.where(use_TIP, 1/(1+kdpo4 * Solid/0.000001), 0) + return xr.where(use_TIP, 1, 0) ############################################ From algae @@ -416,7 +416,7 @@ def FL( depth: xr.DataArray, Ap: xr.DataArray, PAR: xr.DataArray, - light_limitation_option: int, + light_limitation_option: xr.DataArray, KL: xr.DataArray, ) -> np.ndarray: """Calculate Algal light limitation: FL (unitless). @@ -429,26 +429,25 @@ def FL( light_limitation_option: Algal light limitation option 1) Half-saturation, 2) Smith model, 3) Steele model (unitless) KL: Light limitation constant for algal growth (W/m^2) """ - - KEXT = L * depth + warnings.filterwarnings("ignore", category=RuntimeWarning) FL_orig: np.ndarray = np.select( condlist = [ - Ap <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, + Ap <= 0.0 or (L * depth) <= 0.0 or PAR <= 0.0, light_limitation_option == 1, - light_limitation_option == 2 and abs(KL) < 0.0000000001, - light_limitation_option == 2 and abs(KL) >= 0.0000000001, - light_limitation_option == 3 and abs(KL) < 0.0000000001, - light_limitation_option == 3 and abs(KL) >= 0.0000000001, + light_limitation_option == 2 and np.abs(KL) < 0.0000000001, + light_limitation_option == 2 and np.abs(KL) >= 0.0000000001, + light_limitation_option == 3 and np.abs(KL) < 0.0000000001, + light_limitation_option == 3 and np.abs(KL) >= 0.0000000001, ], choicelist = [ 0, - (1.0 / KEXT) * math.log((KL + PAR) /(KL + PAR * math.exp(-KEXT))), + (1.0 / (L * depth)) * np.log((KL + PAR) /(KL + PAR * np.exp(-(L * depth)))), 1, - (1.0 / KEXT) * math.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * math.exp(-KEXT) / KL + ((1.0 + (PAR * math.exp(-KEXT) / KL)**2.0)**0.5))), + (1.0 / (L * depth)) * np.log( (PAR / KL + ((1.0 + (PAR / KL)**2.0)**0.5)) / (PAR * np.exp(-(L * depth)) / KL + ((1.0 + (PAR * np.exp(-(L * depth)) / KL)**2.0)**0.5))), 0, - (2.718/KEXT) * (math.exp(-PAR/KL * math.exp(-KEXT)) - math.exp(-PAR/KL)) + (2.718/(L * depth)) * (np.exp(-PAR/KL * np.exp(-(L * depth))) - np.exp(-PAR/KL)) ], default = np.nan @@ -467,7 +466,7 @@ def FL( default = FL_orig ) - + warnings.filterwarnings("default", category=RuntimeWarning) return FL diff --git a/tests/test_6_nsm_module.py b/tests/test_6_nsm_module.py index 25c0f1c..e5afaf0 100644 --- a/tests/test_6_nsm_module.py +++ b/tests/test_6_nsm_module.py @@ -19,7 +19,6 @@ DEFAULT_PHOSPHORUS, DEFAULT_GLOBALPARAMETERS, DEFAULT_GLOBALVARS - ) @@ -67,16 +66,16 @@ def nutrient_budget_instance( time_steps=time_steps, initial_state_values=initial_nsm1_state, updateable_static_variables=['a0'], - time_dim='tsm_time_step', + time_dim='nsm1_time_step', ) def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: """Checks that all NSM1 variables are present.""" - assert nutrient_budget_instance.time_dim == 'tsm_time_step' + assert nutrient_budget_instance.time_dim == 'nsm1_time_step' assert isinstance(nutrient_budget_instance.algae_parameters, dict) assert isinstance(nutrient_budget_instance.alkalinity_parameters, dict) - assert isinstance(nutrient_budget_instance.Balgae_parameters, dict) + assert isinstance(nutrient_budget_instance.balgae_parameters, dict) assert isinstance(nutrient_budget_instance.nitrogen_parameters, dict) assert isinstance(nutrient_budget_instance.carbon_parameters, dict) assert isinstance(nutrient_budget_instance.CBOD_parameters, dict) @@ -85,14 +84,14 @@ def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: assert isinstance(nutrient_budget_instance.POM_parameters, dict) assert isinstance(nutrient_budget_instance.pathogen_parameters, dict) assert isinstance(nutrient_budget_instance.phosphorus_parameters, dict) - assert isinstance(nutrient_budget_instance.gp_parameters, dict) - assert isinstance(nutrient_budget_instance.gvars_parameters, dict) + assert isinstance(nutrient_budget_instance.global_parameters, dict) + assert isinstance(nutrient_budget_instance.global_vars, dict) assert nutrient_budget_instance.updateable_static_variables == ['a0'] assert nutrient_budget_instance.algae_parameters == DEFAULT_ALGAE assert nutrient_budget_instance.alkalinity_parameters == DEFAULT_ALKALINITY - assert nutrient_budget_instance.Balgae_parameters == DEFAULT_BALGAE + assert nutrient_budget_instance.balgae_parameters == DEFAULT_BALGAE assert nutrient_budget_instance.nitrogen_parameters == DEFAULT_NITROGEN assert nutrient_budget_instance.carbon_parameters == DEFAULT_CARBON assert nutrient_budget_instance.CBOD_parameters == DEFAULT_CBOD @@ -101,34 +100,19 @@ def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: assert nutrient_budget_instance.POM_parameters == DEFAULT_POM assert nutrient_budget_instance.pathogen_parameters == DEFAULT_PATHOGEN assert nutrient_budget_instance.phosphorus_parameters == DEFAULT_PHOSPHORUS - assert nutrient_budget_instance.gp_parameters == DEFAULT_GLOBALPARAMETERS - assert nutrient_budget_instance.gvars_parameters == DEFAULT_GLOBALVARS + assert nutrient_budget_instance.global_parameters == DEFAULT_GLOBALPARAMETERS + assert nutrient_budget_instance.global_vars == DEFAULT_GLOBALVARS def test_nsm1_variable_sorting(nutrient_budget_instance) -> None: """Checks that we can auto-sort our NSM1 variable""" assert isinstance(nutrient_budget_instance.computation_order, list) - assert nutrient_budget_instance.computation_order[-1].name == 'water_temp_c' #TODO what is first? + assert nutrient_budget_instance.computation_order[-1].name == 'DOX' #TODO what is first? def test_nsm1_timestep(nutrient_budget_instance) -> None: """Checks that we can auto-sort our NSM1 variable""" nutrient_budget_instance.increment_timestep() - assert len(nutrient_budget_instance.dataset.tsm_time_step) == 2 - assert nutrient_budget_instance.dataset.sel(tsm_time_step=1).isnull().any() == False + assert len(nutrient_budget_instance.dataset.nsm1_time_step) == 2 + assert nutrient_budget_instance.dataset.sel(nsm1_time_step=1).isnull().any() == False -#TODO do we need this for NSM? -def test_use_sed_temp( - initial_tsm_state, - time_steps, -) -> None: - """Tests that when we set use_sed_temp to False we get a False boolean array.""" - if 'a0' in initial_tsm_state: - del initial_tsm_state['a0'] - no_sed_temp = NutrientBudget( - time_steps=time_steps, - initial_state_values=initial_tsm_state, - use_sed_temp=False, - ) - assert no_sed_temp.dataset.use_sed_temp.dtype == bool - assert bool(np.all(no_sed_temp.dataset.use_sed_temp == False)) diff --git a/tests/test_7_nsm_algae_calculations.py b/tests/test_7_nsm_algae_calculations.py index 077d4b6..d77ab9a 100644 --- a/tests/test_7_nsm_algae_calculations.py +++ b/tests/test_7_nsm_algae_calculations.py @@ -50,7 +50,6 @@ def initial_nsm1_state() -> dict[str, float]: def time_steps() -> int: return 1 - @pytest.fixture(scope='function') def default_algae_params() -> AlgaeStaticVariables: """Returns default algae static variable values for the model. @@ -95,7 +94,8 @@ def default_alkalinity_params() -> AlkalinityStaticVariables: r_alkbn =18.0 / 106.0 / 12.0 / 1000.0 ) -def default_Balgae_params() -> BalgaeStaticVariables: +@pytest.fixture(scope='function') +def default_balgae_params() -> BalgaeStaticVariables: """Returns default Benthic Algae static variable values for the model. NOTE: As of now (3/18/2022) these match the built in defaults, but are @@ -109,7 +109,6 @@ def default_Balgae_params() -> BalgaeStaticVariables: BWn=7.2, BWp= 1, BWa= 3500, - KLb= 10, KsNb= 0.25, KsPb=0.125, @@ -123,6 +122,7 @@ def default_Balgae_params() -> BalgaeStaticVariables: Fb=0.9 ) +@pytest.fixture(scope='function') def default_nitrogen_params() -> NitrogenStaticVariables: """Returns default nitrogen static variable values for the model. @@ -143,6 +143,7 @@ def default_nitrogen_params() -> NitrogenStaticVariables: PNb=0.5 ) +@pytest.fixture(scope='function') def default_carbon_params() -> CarbonStaticVariables: """Returns default carbon static variable values for the model. @@ -162,6 +163,7 @@ def default_carbon_params() -> CarbonStaticVariables: roc = 32.0/12.0 ) +@pytest.fixture(scope='function') def default_CBOD_params() -> CBODStaticVariables: """Returns default CBOD static variable values for the model. @@ -176,6 +178,7 @@ def default_CBOD_params() -> CBODStaticVariables: ksbod_20 = 0.0 ) +@pytest.fixture(scope='function') def default_DOX_params() -> DOXStaticVariables: """Returns default DOX static variable values for the model. @@ -189,6 +192,7 @@ def default_DOX_params() -> DOXStaticVariables: KsSOD =1, ) +@pytest.fixture(scope='function') def default_N2_params() -> N2StaticVariables: """Returns default N2 static variable values for the model. @@ -201,6 +205,7 @@ def default_N2_params() -> N2StaticVariables: ) +@pytest.fixture(scope='function') def default_POM_params() -> POMStaticVariables: """Returns default POM static variable values for the model. @@ -213,7 +218,8 @@ def default_POM_params() -> POMStaticVariables: kpom_20 = 0.1 ) -def default_pathogens_params() -> PathogenStaticVariables: +@pytest.fixture(scope='function') +def default_pathogen_params() -> PathogenStaticVariables: """Returns default Pathogens static variable values for the model. NOTE: As of now (3/18/2022) these match the built in defaults, but are @@ -227,6 +233,7 @@ def default_pathogens_params() -> PathogenStaticVariables: vx=1 ) +@pytest.fixture(scope='function') def default_phosphorus_params() -> PhosphorusStaticVariables: """Returns default phosphorus static variable values for the model. @@ -241,6 +248,7 @@ def default_phosphorus_params() -> PhosphorusStaticVariables: kdpo4 = 0.0, ) +@pytest.fixture(scope='function') def default_gp_params() -> GlobalParameters: """Returns default global parameter static variable values for the model. @@ -268,6 +276,7 @@ def default_gp_params() -> GlobalParameters: use_POM = True ) +@pytest.fixture(scope='function') def default_gvars_params() -> GlobalVars: """Returns default global variables static variable values for the model. @@ -289,9 +298,9 @@ def default_gvars_params() -> GlobalVars: kah_20_user = 999, hydraulic_reaeration_option = 2, wind_reaeration_option = 2, - timestep = 86400, #TODO Dynamic or static? + timestep = 1, #TODO Dynamic or static? depth = 1.5, #TODO Dynamic or static? - TwaterC = 20, + TwaterC = 25, theta = 1.047, velocity = 1, flow = 2, @@ -306,7 +315,7 @@ def default_gvars_params() -> GlobalVars: lambda1 = .0088, lambda2 = .054, lambdas = .052, - lambdam = .0174, + lambdam = .174, Fr_PAR = .47 ) @@ -315,7 +324,7 @@ def get_nutrient_budget_instance( initial_nsm1_state, default_algae_params, default_alkalinity_params, - default_Balgae_params, + default_balgae_params, default_nitrogen_params, default_carbon_params, default_CBOD_params, @@ -326,7 +335,6 @@ def get_nutrient_budget_instance( default_phosphorus_params, default_gp_params, default_gvars_params, - use_sed_temp: bool = False, ) -> NutrientBudget: """Return an instance of the NSM1 class.""" @@ -335,7 +343,7 @@ def get_nutrient_budget_instance( initial_state_values=initial_nsm1_state, algae_parameters=default_algae_params, alkalinity_parameters=default_alkalinity_params, - Balgae_parameters=default_Balgae_params, + balgae_parameters=default_balgae_params, nitrogen_parameters=default_nitrogen_params, carbon_parameters=default_carbon_params, CBOD_parameters=default_CBOD_params, @@ -346,24 +354,20 @@ def get_nutrient_budget_instance( phosphorus_parameters=default_phosphorus_params, global_parameters=default_gp_params, global_vars=default_gvars_params, - - use_sed_temp=use_sed_temp, time_dim='nsm1_time_step', ) - @pytest.fixture(scope='module') def tolerance() -> float: """Controls the precision of the pytest.approx() function.""" - return 0.0000001 - + return 0.001 def test_defaults( time_steps, initial_nsm1_state, default_algae_params, default_alkalinity_params, - default_Balgae_params, + default_balgae_params, default_nitrogen_params, default_carbon_params, default_CBOD_params, @@ -385,7 +389,7 @@ def test_defaults( initial_nsm1_state=initial_nsm1_state, default_algae_params=default_algae_params, default_alkalinity_params=default_alkalinity_params, - default_Balgae_params=default_Balgae_params, + default_balgae_params=default_balgae_params, default_nitrogen_params=default_nitrogen_params, default_carbon_params=default_carbon_params, default_CBOD_params=default_CBOD_params, @@ -401,15 +405,16 @@ def test_defaults( # Run the model nsm1.increment_timestep() Ap = nsm1.dataset.isel(nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 53.19609 + assert pytest.approx(Ap, tolerance) == 52.668 def test_changed_Ap( time_steps, initial_nsm1_state, default_algae_params, default_alkalinity_params, - default_Balgae_params, + default_balgae_params, default_nitrogen_params, default_carbon_params, default_CBOD_params, @@ -433,7 +438,7 @@ def test_changed_Ap( initial_nsm1_state=initial_nsm1_state, default_algae_params=default_algae_params, default_alkalinity_params=default_alkalinity_params, - default_Balgae_params=default_Balgae_params, + default_balgae_params=default_balgae_params, default_nitrogen_params=default_nitrogen_params, default_carbon_params=default_carbon_params, default_CBOD_params=default_CBOD_params, @@ -451,14 +456,14 @@ def test_changed_Ap( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 75.57808 + assert pytest.approx(Ap, tolerance) == 74.850 def test_changed_NH4( time_steps, initial_nsm1_state, default_algae_params, default_alkalinity_params, - default_Balgae_params, + default_balgae_params, default_nitrogen_params, default_carbon_params, default_CBOD_params, @@ -482,7 +487,498 @@ def test_changed_NH4( initial_nsm1_state=initial_nsm1_state, default_algae_params=default_algae_params, default_alkalinity_params=default_alkalinity_params, - default_Balgae_params=default_Balgae_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.681 + +def test_changed_KL( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['KL'] = 15 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 49.229 + +def test_changed_KsN( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['KsN'] = 0.02 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.803 + +def test_changed_KsP( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['KsP'] = 0.005 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 50.931 + +def test_changed_mu_max( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['mu_max_20'] = 1.5 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 69.809 + +def test_changed_kdp( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['kdp_20'] = 0.09 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 55.688 + +def test_changed_krp( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['krp_20'] = 0.09 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 58.204 + +def test_changed_vsap( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['vsap'] = 0.2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 51.335 + +def test_changed_NO3( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + initial_state_dict['NO3'] = 10 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.803 + +def test_changed_TIP( + + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + initial_state_dict['TIP'] = 0.1 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.842 + +def test_changed_TwaterC( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['TwaterC'] = 35 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, default_nitrogen_params=default_nitrogen_params, default_carbon_params=default_carbon_params, default_CBOD_params=default_CBOD_params, @@ -500,5 +996,6 @@ def test_changed_NH4( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 75.59588 + assert pytest.approx(Ap, tolerance) == 62.385 + \ No newline at end of file From db5ab9a8136f383c5fb01cebdc4cba885668820e Mon Sep 17 00:00:00 2001 From: kewalak Date: Wed, 27 Mar 2024 10:54:19 -0700 Subject: [PATCH 17/20] Finished Algae Tests --- src/clearwater_modules/nsm1/processes.py | 40 +- tests/test_7_nsm_algae_calculations.py | 938 ++++++++++++++++++++++- 2 files changed, 961 insertions(+), 17 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 1ab795b..7421312 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -488,7 +488,25 @@ def FN( KsN: Michaelis-Menton half-saturation constant relating inorganic N to algal growth (mg-N/L) """ - FN_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsN + NH4 + NO3), 1) + #FN_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsN + NH4 + NO3), 1) + + FN_orig: np.ndarray = np.select( + condlist= [ + use_NH4 == True and use_NO3 == True, + use_NH4 == False and use_NO3 == True, + use_NH4 == True and use_NO3 == False, + use_NH4 == False and use_NO3 == False, + ], + + choicelist= [ + (NH4 + NO3) / (KsN + NH4 + NO3), + (NO3) / (KsN + NO3), + (NH4) / (KsN + NH4), + 1 + ], + + default = 1 + ) FN: np.ndarray = np.select( @@ -853,8 +871,26 @@ def FNb( KsNb: Michaelis-Menton half-saturation constant relating inorganic N to benthic algal growth (mg-N/L) """ - FNb_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsNb + NH4 + NO3),1) + #FNb_orig = xr.where(use_NH4 or use_NO3, (NH4 + NO3) / (KsNb + NH4 + NO3),1) + FNb_orig: np.ndarray = np.select( + condlist= [ + use_NH4 == True and use_NO3 == True, + use_NH4 == True and use_NO3 == False, + use_NH4 == False and use_NO3 == True, + use_NH4 == False and use_NO3 == False, + ], + + choicelist= [ + (NH4 + NO3) / (KsNb + NH4 + NO3), + (NH4) / (KsNb + NH4), + (NO3) / (KsNb + NO3), + 1 + ], + + default = 1 + ) + FNb: np.ndarray = np.select( condlist= [ math.isnan(FNb_orig), diff --git a/tests/test_7_nsm_algae_calculations.py b/tests/test_7_nsm_algae_calculations.py index d77ab9a..79dbfb6 100644 --- a/tests/test_7_nsm_algae_calculations.py +++ b/tests/test_7_nsm_algae_calculations.py @@ -360,7 +360,7 @@ def get_nutrient_budget_instance( @pytest.fixture(scope='module') def tolerance() -> float: """Controls the precision of the pytest.approx() function.""" - return 0.001 + return 0.000001 def test_defaults( time_steps, @@ -407,7 +407,7 @@ def test_defaults( Ap = nsm1.dataset.isel(nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 52.668 + assert pytest.approx(Ap, tolerance) == 52.668069 def test_changed_Ap( time_steps, @@ -456,7 +456,7 @@ def test_changed_Ap( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 74.850 + assert pytest.approx(Ap, tolerance) == 74.849998 def test_changed_NH4( time_steps, @@ -505,7 +505,7 @@ def test_changed_NH4( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 52.681 + assert pytest.approx(Ap, tolerance) == 52.680781 def test_changed_KL( time_steps, @@ -554,7 +554,7 @@ def test_changed_KL( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 49.229 + assert pytest.approx(Ap, tolerance) == 49.229049 def test_changed_KsN( time_steps, @@ -603,7 +603,7 @@ def test_changed_KsN( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 52.803 + assert pytest.approx(Ap, tolerance) == 52.803304 def test_changed_KsP( time_steps, @@ -652,7 +652,7 @@ def test_changed_KsP( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 50.931 + assert pytest.approx(Ap, tolerance) == 50.931103 def test_changed_mu_max( time_steps, @@ -701,7 +701,7 @@ def test_changed_mu_max( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 69.809 + assert pytest.approx(Ap, tolerance) == 69.809173 def test_changed_kdp( time_steps, @@ -750,7 +750,7 @@ def test_changed_kdp( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 55.688 + assert pytest.approx(Ap, tolerance) == 55.687635 def test_changed_krp( time_steps, @@ -799,7 +799,7 @@ def test_changed_krp( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 58.204 + assert pytest.approx(Ap, tolerance) == 58.203941 def test_changed_vsap( time_steps, @@ -848,7 +848,7 @@ def test_changed_vsap( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 51.335 + assert pytest.approx(Ap, tolerance) == 51.334735 def test_changed_NO3( time_steps, @@ -897,7 +897,7 @@ def test_changed_NO3( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 52.803 + assert pytest.approx(Ap, tolerance) == 52.802629 def test_changed_TIP( @@ -947,7 +947,7 @@ def test_changed_TIP( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 52.842 + assert pytest.approx(Ap, tolerance) == 52.842286 def test_changed_TwaterC( time_steps, @@ -996,6 +996,914 @@ def test_changed_TwaterC( Ap = nsm1.dataset.isel( nsm1_time_step=-1).Ap.values.item() assert isinstance(Ap, float) - assert pytest.approx(Ap, tolerance) == 62.385 + assert pytest.approx(Ap, tolerance) == 62.384696 - \ No newline at end of file +def test_changed_depth( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['depth'] = 2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 47.171170 + +def test_changed_q_solar( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['q_solar'] = 250 + +def test_changed_Fr_PAR( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['Fr_PAR'] = 0.2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 45.185221 + +def test_changed_use_NH4( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gp_params['use_NH4'] = False + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.665375 + +def test_changed_use_NO3( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gp_params['use_NO3'] = False + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 37.582388 + +def test_changed_use_TIP( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gp_params['use_TIP'] = False + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 53.255764 + +def test_changed_g2_l1( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['growth_rate_option'] = 2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 52.939611 + +def test_changed_g3_l1( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['growth_rate_option'] = 3 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 53.096967 + +def test_changed_g1_l2( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + #default_algae_params['growth_rate_option'] = 3 + default_algae_params['light_limitation_option'] = 2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 59.847275 + +def test_changed_g2_l2( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['growth_rate_option'] = 2 + default_algae_params['light_limitation_option'] = 2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 60.175682 + +def test_changed_g3_l2( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['growth_rate_option'] = 3 + default_algae_params['light_limitation_option'] = 2 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 60.365992 + +def test_changed_g1_l3( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_algae_params['growth_rate_option'] = 1 + default_algae_params['light_limitation_option'] = 3 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 40.479472 + +def test_changed_lambda0( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['lambda0'] = 5 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 31.938218 + +def test_changed_lambda1( + + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['lambda1'] = 0.03 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 46.601473 + +def test_changed_lambda2( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['lambda2'] = 0.02 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 55.635473 + +def test_changed_lambdam( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['lambdam'] = 0.009 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 62.784764 + +def test_changed_use_POC( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gp_params['use_POC'] = False + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 63.113783 + +def test_changed_POC( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + initial_state_dict['POC'] = 6 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 46.458270 + +def test_changed_fcom( + time_steps, + initial_nsm1_state, + default_algae_params, + default_alkalinity_params, + default_balgae_params, + default_nitrogen_params, + default_carbon_params, + default_CBOD_params, + default_DOX_params, + default_N2_params, + default_POM_params, + default_pathogen_params, + default_phosphorus_params, + default_gp_params, + default_gvars_params, + tolerance, +) -> None: + """Test the model with default parameters.""" + # alter parameters as necessary + initial_state_dict = initial_nsm1_state + default_gvars_params['fcom'] = 0.6 + + # instantiate the model + nsm1: NutrientBudget = get_nutrient_budget_instance( + time_steps=time_steps, + initial_nsm1_state=initial_nsm1_state, + default_algae_params=default_algae_params, + default_alkalinity_params=default_alkalinity_params, + default_balgae_params=default_balgae_params, + default_nitrogen_params=default_nitrogen_params, + default_carbon_params=default_carbon_params, + default_CBOD_params=default_CBOD_params, + default_DOX_params=default_DOX_params, + default_N2_params=default_N2_params, + default_POM_params=default_POM_params, + default_pathogen_params=default_pathogen_params, + default_phosphorus_params=default_phosphorus_params, + default_gp_params=default_gp_params, + default_gvars_params=default_gvars_params + ) + + # Run the model + nsm1.increment_timestep() + Ap = nsm1.dataset.isel( + nsm1_time_step=-1).Ap.values.item() + assert isinstance(Ap, float) + assert pytest.approx(Ap, tolerance) == 56.937679 \ No newline at end of file From 77ac3f7521b602b0e104d4e1069c2756b83a7f7d Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Thu, 28 Mar 2024 09:56:37 -0500 Subject: [PATCH 18/20] Corrected np.select syntax in the processes.py file, troubleshooted time_dim error and other processes issues with math.isnan and min. --- examples/model_architecture.ipynb | 181 ++++++++++++----------- src/clearwater_modules/nsm1/constants.py | 2 +- src/clearwater_modules/nsm1/processes.py | 58 ++++---- tests/test_6_nsm_module.py | 1 - 4 files changed, 122 insertions(+), 120 deletions(-) diff --git a/examples/model_architecture.ipynb b/examples/model_architecture.ipynb index 1737146..4a9f8bd 100644 --- a/examples/model_architecture.ipynb +++ b/examples/model_architecture.ipynb @@ -170,52 +170,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "a5d34d2d-03a6-41e1-92fc-9e6fba72d6f5", "metadata": { "tags": [] }, "outputs": [ - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.2.2'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.2.3/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.2.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.holoviz.org/panel/1.2.3/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, { "name": "stdout", "output_type": "stream", @@ -591,98 +551,98 @@ " fill: currentColor;\n", "}\n", "
    <xarray.Dataset>\n",
    -       "Dimensions:            (year: 2, x: 1, y: 1)\n",
    +       "Dimensions:            (tsm_time_step: 2, x: 1, y: 1)\n",
            "Coordinates:\n",
    -       "  * year               (year) int32 0 1\n",
    +       "  * tsm_time_step      (tsm_time_step) int32 0 1\n",
            "  * x                  (x) float64 1.0\n",
            "  * y                  (y) float64 1.0\n",
            "Data variables: (12/52)\n",
    -       "    water_temp_c       (year, x, y) float64 20.0 20.0\n",
    -       "    surface_area       (year, x, y) int32 1 1\n",
    -       "    volume             (year, x, y) int32 1 1\n",
    +       "    water_temp_c       (tsm_time_step, x, y) float64 20.0 20.0\n",
    +       "    surface_area       (tsm_time_step, x, y) float64 1.0 1.0\n",
    +       "    volume             (tsm_time_step, x, y) float64 1.0 1.0\n",
            "    use_sed_temp       (x, y) bool True\n",
            "    stefan_boltzmann   (x, y) float64 5.67e-08\n",
            "    cp_air             (x, y) int32 1005\n",
            "    ...                 ...\n",
    -       "    q_sediment         (year, x, y) float64 nan -401.5\n",
    -       "    dTdt_sediment_c    (year, x, y) float64 nan 129.6\n",
    -       "    q_longwave_down    (year, x, y) float64 nan 337.8\n",
    -       "    q_longwave_up      (year, x, y) float64 nan 406.2\n",
    -       "    q_net              (year, x, y) float64 nan -151.1\n",
    -       "    dTdt_water_c       (year, x, y) float64 nan -3.619e-05
    • tsm_time_step
      PandasIndex
      PandasIndex(Index([0, 1], dtype='int32', name='tsm_time_step'))
    • x
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='x'))
    • y
      PandasIndex
      PandasIndex(Index([1.0], dtype='float64', name='y'))
  • " ], "text/plain": [ "\n", - "Dimensions: (year: 2, x: 1, y: 1)\n", + "Dimensions: (tsm_time_step: 2, x: 1, y: 1)\n", "Coordinates:\n", - " * year (year) int32 0 1\n", + " * tsm_time_step (tsm_time_step) int32 0 1\n", " * x (x) float64 1.0\n", " * y (y) float64 1.0\n", "Data variables: (12/52)\n", - " water_temp_c (year, x, y) float64 20.0 20.0\n", - " surface_area (year, x, y) int32 1 1\n", - " volume (year, x, y) int32 1 1\n", + " water_temp_c (tsm_time_step, x, y) float64 20.0 20.0\n", + " surface_area (tsm_time_step, x, y) float64 1.0 1.0\n", + " volume (tsm_time_step, x, y) float64 1.0 1.0\n", " use_sed_temp (x, y) bool True\n", " stefan_boltzmann (x, y) float64 5.67e-08\n", " cp_air (x, y) int32 1005\n", " ... ...\n", - " q_sediment (year, x, y) float64 nan -401.5\n", - " dTdt_sediment_c (year, x, y) float64 nan 129.6\n", - " q_longwave_down (year, x, y) float64 nan 337.8\n", - " q_longwave_up (year, x, y) float64 nan 406.2\n", - " q_net (year, x, y) float64 nan -151.1\n", - " dTdt_water_c (year, x, y) float64 nan -3.619e-05" + " q_sediment (tsm_time_step, x, y) float64 nan -401.5\n", + " dTdt_sediment_c (tsm_time_step, x, y) float64 nan 129.6\n", + " q_net (tsm_time_step, x, y) float64 nan -151.1\n", + " q_longwave_down (tsm_time_step, x, y) float64 nan 337.8\n", + " q_longwave_up (tsm_time_step, x, y) float64 nan 406.2\n", + " dTdt_water_c (tsm_time_step, x, y) float64 nan -3.619e-05" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -731,15 +691,58 @@ " 'richardson_option': True\n", "}\n", "\n", + "time_step = 1\n", + "\n", "tsm_model = cwm.tsm.EnergyBudget(\n", + " time_steps=time_step,\n", " initial_state_values=initial_state_values, # mandatory\n", " temp_parameters=temp_parameters,\n", " meteo_parameters=meteo_parameters,\n", " track_dynamic_variables=True, # default is true\n", " hotstart_dataset=None, # default is None\n", - " time_dim='year', # default is \"timestep\"\n", + " time_dim='tsm_time_step', # default is \"timestep\"\n", ")\n", "\n", + "tsm_model.increment_timestep()\n", + "tsm_model.dataset\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "644f6baf", + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "\"not all values found in index 'tsm_time_step'. Try setting the `method` keyword argument (example: method='nearest').\"", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3790\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3789\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 3790\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 3791\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[1;32mindex.pyx:152\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mindex.pyx:181\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mpandas\\_libs\\hashtable_class_helper.pxi:4484\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.Int32HashTable.get_item\u001b[1;34m()\u001b[0m\n", + "File \u001b[1;32mpandas\\_libs\\hashtable_class_helper.pxi:4508\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.Int32HashTable.get_item\u001b[1;34m()\u001b[0m\n", + "\u001b[1;31mKeyError\u001b[0m: 2", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\xarray\\core\\indexes.py:772\u001b[0m, in \u001b[0;36mPandasIndex.sel\u001b[1;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[0;32m 771\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 772\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabel_value\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 773\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:3797\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 3796\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[1;32m-> 3797\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[0;32m 3798\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m 3799\u001b[0m \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[0;32m 3800\u001b[0m \u001b[38;5;66;03m# InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[0;32m 3801\u001b[0m \u001b[38;5;66;03m# the TypeError.\u001b[39;00m\n", + "\u001b[1;31mKeyError\u001b[0m: 2", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[3], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mtsm_model\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement_timestep\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2\u001b[0m tsm_model\u001b[38;5;241m.\u001b[39mdataset\n", + "File \u001b[1;32m~\\Documents\\GitHub\\ClearWater-modules\\src\\clearwater_modules\\base.py:530\u001b[0m, in \u001b[0;36mModel.increment_timestep\u001b[1;34m(self, update_state_values)\u001b[0m\n\u001b[0;32m 523\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimestep_ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimestep_ds\u001b[38;5;241m.\u001b[39mdrop_vars(\n\u001b[0;32m 524\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdynamic_variables_names\n\u001b[0;32m 525\u001b[0m )\n\u001b[0;32m 526\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimestep_ds \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimestep_ds\u001b[38;5;241m.\u001b[39mdrop_vars(\n\u001b[0;32m 527\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_non_updateable_static_variables\n\u001b[0;32m 528\u001b[0m )\n\u001b[1;32m--> 530\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtemporal_variables\u001b[49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mloc\u001b[49m\u001b[43m[\u001b[49m\n\u001b[0;32m 531\u001b[0m \u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtime_dim\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimestep\u001b[49m\u001b[43m}\u001b[49m\n\u001b[0;32m 532\u001b[0m \u001b[43m\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimestep_ds\n\u001b[0;32m 534\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\xarray\\core\\dataset.py:510\u001b[0m, in \u001b[0;36m_LocIndexer.__setitem__\u001b[1;34m(self, key, value)\u001b[0m\n\u001b[0;32m 504\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[0;32m 505\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcan only set locations defined by dictionaries from Dataset.loc.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 506\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m Got: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 507\u001b[0m )\n\u001b[0;32m 509\u001b[0m \u001b[38;5;66;03m# set new values\u001b[39;00m\n\u001b[1;32m--> 510\u001b[0m dim_indexers \u001b[38;5;241m=\u001b[39m \u001b[43mmap_index_queries\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mdim_indexers\n\u001b[0;32m 511\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset[dim_indexers] \u001b[38;5;241m=\u001b[39m value\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\xarray\\core\\indexing.py:193\u001b[0m, in \u001b[0;36mmap_index_queries\u001b[1;34m(obj, indexers, method, tolerance, **indexers_kwargs)\u001b[0m\n\u001b[0;32m 191\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(IndexSelResult(labels))\n\u001b[0;32m 192\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 193\u001b[0m results\u001b[38;5;241m.\u001b[39mappend(\u001b[43mindex\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[0;32m 195\u001b[0m merged \u001b[38;5;241m=\u001b[39m merge_sel_results(results)\n\u001b[0;32m 197\u001b[0m \u001b[38;5;66;03m# drop dimension coordinates found in dimension indexers\u001b[39;00m\n\u001b[0;32m 198\u001b[0m \u001b[38;5;66;03m# (also drop multi-index if any)\u001b[39;00m\n\u001b[0;32m 199\u001b[0m \u001b[38;5;66;03m# (.sel() already ensures alignment)\u001b[39;00m\n", + "File \u001b[1;32mc:\\Anaconda3\\envs\\clearwater_dev_env\\Lib\\site-packages\\xarray\\core\\indexes.py:774\u001b[0m, in \u001b[0;36mPandasIndex.sel\u001b[1;34m(self, labels, method, tolerance)\u001b[0m\n\u001b[0;32m 772\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex\u001b[38;5;241m.\u001b[39mget_loc(label_value)\n\u001b[0;32m 773\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m--> 774\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\n\u001b[0;32m 775\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnot all values found in index \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcoord_name\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 776\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTry setting the `method` keyword argument (example: method=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnearest\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 777\u001b[0m ) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n\u001b[0;32m 779\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m label_array\u001b[38;5;241m.\u001b[39mdtype\u001b[38;5;241m.\u001b[39mkind \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m 780\u001b[0m indexer \u001b[38;5;241m=\u001b[39m label_array\n", + "\u001b[1;31mKeyError\u001b[0m: \"not all values found in index 'tsm_time_step'. Try setting the `method` keyword argument (example: method='nearest').\"" + ] + } + ], + "source": [ "tsm_model.increment_timestep()\n", "tsm_model.dataset" ] diff --git a/src/clearwater_modules/nsm1/constants.py b/src/clearwater_modules/nsm1/constants.py index 5d6cc6d..14af78b 100644 --- a/src/clearwater_modules/nsm1/constants.py +++ b/src/clearwater_modules/nsm1/constants.py @@ -285,7 +285,7 @@ class GlobalVars(TypedDict): kah_20_user = 999, hydraulic_reaeration_option = 2, wind_reaeration_option = 2, - timestep = 86400, #TODO Dynamic or static? + timestep = 1, #TODO Dynamic or static? depth = 1.5, #TODO Dynamic or static? TwaterC = 20, theta = 1.047, diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index 7421312..e27f167 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -79,15 +79,15 @@ def kah_20( hydraulic_reaeration_option == 2, hydraulic_reaeration_option == 3, hydraulic_reaeration_option == 4, - hydraulic_reaeration_option == 5 and depth < 0.61, - hydraulic_reaeration_option == 5 and depth > 0.61, - hydraulic_reaeration_option == 5 and depth == 0.61, - hydraulic_reaeration_option == 6 and flow < 0.556, - hydraulic_reaeration_option == 6 and flow >= 0.556, - hydraulic_reaeration_option == 7 and flow < 0.556, - hydraulic_reaeration_option == 7 and flow >= 0.556, - hydraulic_reaeration_option == 8 and flow < 0.425, - hydraulic_reaeration_option == 8 and flow >= 0.425, + (hydraulic_reaeration_option == 5) & (depth < 0.61), + (hydraulic_reaeration_option == 5) & (depth > 0.61), + (hydraulic_reaeration_option == 5) & (depth == 0.61), + (hydraulic_reaeration_option == 6) & (flow < 0.556), + (hydraulic_reaeration_option == 6) & (flow >= 0.556), + (hydraulic_reaeration_option == 7) & (flow < 0.556), + (hydraulic_reaeration_option == 7) & (flow >= 0.556), + (hydraulic_reaeration_option == 8) & (flow < 0.425), + (hydraulic_reaeration_option == 8) & (flow >= 0.425), hydraulic_reaeration_option == 9], choicelist = [kah_20_user, @@ -145,21 +145,21 @@ def kaw_20( condlist = [ wind_reaeration_option == 1, wind_reaeration_option == 2, - wind_reaeration_option == 3 and Uw10 <= 3.5, - wind_reaeration_option == 3 and Uw10 > 3.5, + (wind_reaeration_option == 3) & (Uw10 <= 3.5), + (wind_reaeration_option == 3) & (Uw10 > 3.5), wind_reaeration_option == 4, wind_reaeration_option == 5, wind_reaeration_option == 6, - wind_reaeration_option == 7 and Uw10 <= 5.5, - wind_reaeration_option == 7 and Uw10 > 5.5, + (wind_reaeration_option == 7) & (Uw10 <= 5.5), + (wind_reaeration_option == 7) & (Uw10 > 5.5), wind_reaeration_option == 8, - wind_reaeration_option == 9 and Uw10 <= 4.1, - wind_reaeration_option == 9 and Uw10 > 4.1, + (wind_reaeration_option == 9) & (Uw10 <= 4.1), + (wind_reaeration_option == 9) & (Uw10 > 4.1), wind_reaeration_option == 10, wind_reaeration_option == 11, wind_reaeration_option == 12, - wind_reaeration_option == 13 and Uw10 < 1.6, - wind_reaeration_option == 13 and Uw10 >= 1.6, + (wind_reaeration_option == 13) & (Uw10 < 1.6), + (wind_reaeration_option == 13) & (Uw10 >= 1.6), ], choicelist = [ @@ -289,7 +289,7 @@ def PAR( q_solar: solar radiation (1/d), Fr_PAR: fraction of solar radiation within the PAR of the spectrum """ - return xr.where (use_Algae or use_Balgae, q_solar * Fr_PAR, 0) + return xr.where ((use_Algae) | (use_Balgae), q_solar * Fr_PAR, 0) #TODO does not appear HEC-RAS actually uses Solid in any calculations def fdp( @@ -433,12 +433,12 @@ def FL( FL_orig: np.ndarray = np.select( condlist = [ - Ap <= 0.0 or (L * depth) <= 0.0 or PAR <= 0.0, + (Ap <= 0.0) | (L * depth <= 0.0) | (PAR <= 0.0), light_limitation_option == 1, - light_limitation_option == 2 and np.abs(KL) < 0.0000000001, - light_limitation_option == 2 and np.abs(KL) >= 0.0000000001, - light_limitation_option == 3 and np.abs(KL) < 0.0000000001, - light_limitation_option == 3 and np.abs(KL) >= 0.0000000001, + (light_limitation_option == 2) & (np.abs(KL) < 0.0000000001), + (light_limitation_option == 2) & (np.abs(KL) >= 0.0000000001), + (light_limitation_option == 3) & (np.abs(KL) < 0.0000000001), + (light_limitation_option == 3) & (np.abs(KL) >= 0.0000000001), ], choicelist = [ @@ -492,10 +492,10 @@ def FN( FN_orig: np.ndarray = np.select( condlist= [ - use_NH4 == True and use_NO3 == True, - use_NH4 == False and use_NO3 == True, - use_NH4 == True and use_NO3 == False, - use_NH4 == False and use_NO3 == False, + (use_NH4 == True) & (use_NO3 == True), + (use_NH4 == False) & (use_NO3 == True), + (use_NH4 == True) & (use_NO3 == False), + (use_NH4 == False) & (use_NO3 == False), ], choicelist= [ @@ -582,8 +582,8 @@ def mu( condlist = [ growth_rate_option == 1, growth_rate_option == 2, - growth_rate_option == 3 and (FN == 0.0 or FP == 0.0), - growth_rate_option == 3 and FN != 0 and FP != 0 + (growth_rate_option == 3) & ((FN == 0.0) | (FP == 0.0)), + (growth_rate_option == 3) & (FN != 0) & (FP != 0) ], choicelist = [ diff --git a/tests/test_6_nsm_module.py b/tests/test_6_nsm_module.py index e5afaf0..c3af4c7 100644 --- a/tests/test_6_nsm_module.py +++ b/tests/test_6_nsm_module.py @@ -112,7 +112,6 @@ def test_nsm1_variable_sorting(nutrient_budget_instance) -> None: def test_nsm1_timestep(nutrient_budget_instance) -> None: """Checks that we can auto-sort our NSM1 variable""" nutrient_budget_instance.increment_timestep() - assert len(nutrient_budget_instance.dataset.nsm1_time_step) == 2 assert nutrient_budget_instance.dataset.sel(nsm1_time_step=1).isnull().any() == False From 33a748fbd5987bbd92ca27614b229e459bdd0e47 Mon Sep 17 00:00:00 2001 From: Isaac Mudge <66634423+imscw95@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:19:03 -0500 Subject: [PATCH 19/20] Corrected all processes.py syntax and functions to work with test_6 --- src/clearwater_modules/nsm1/processes.py | 73 +++++++++++++++--------- tests/test_6_nsm_module.py | 4 +- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index e27f167..3837b07 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -511,7 +511,7 @@ def FN( FN: np.ndarray = np.select( condlist= [ - math.isnan(FN_orig), + np.isnan(FN_orig), FN_orig > 1.0 ], @@ -545,7 +545,7 @@ def FP( FP: np.ndarray = np.select( condlist= [ - math.isnan(FP_orig), + np.isnan(FP_orig), FP_orig > 1.0 ], @@ -581,14 +581,16 @@ def mu( mu: np.ndarray = np.select( condlist = [ growth_rate_option == 1, - growth_rate_option == 2, + (growth_rate_option == 2) & (FP > FN), + (growth_rate_option == 2) & (FN > FP), (growth_rate_option == 3) & ((FN == 0.0) | (FP == 0.0)), (growth_rate_option == 3) & (FN != 0) & (FP != 0) ], choicelist = [ mu_max_tc * FL * FP * FN, - mu_max_tc * FL * min(FP, FN), + mu_max_tc * FL * FN, + mu_max_tc * FL * FP, 0, mu_max_tc * FL * 2.0 / (1.0 / FN + 1.0 / FP) ], @@ -814,15 +816,15 @@ def FLb( # Note that KENT is defined differently here than it was for the algal equations. # The equations are different, this expression is more convenient here. - KEXT = math.exp(-L*depth) + KEXT = np.exp(-L*depth) FLb_orig: np.ndarray = np.select( condlist = [ - Ab <= 0.0 or KEXT <= 0.0 or PAR <= 0.0, + (Ab <= 0.0) | (KEXT <= 0.0) | (PAR <= 0.0), b_light_limitation_option == 1, b_light_limitation_option == 2, - b_light_limitation_option == 3 and abs(KLb) < 1.0E-10, - b_light_limitation_option == 3 and abs(KLb) >= 1.0E-10 + (b_light_limitation_option == 3) & (abs(KLb) < 1.0E-10), + (b_light_limitation_option == 3) & (abs(KLb) >= 1.0E-10) ], choicelist = [ @@ -830,7 +832,7 @@ def FLb( PAR * KEXT / (KLb + PAR * KEXT), PAR * KEXT / ((KLb**2.0 + (PAR * KEXT)**2.0)**0.5), 0.0, - PAR * KEXT / KLb * math.exp(1.0 - PAR * KEXT / KLb) + PAR * KEXT / KLb * np.exp(1.0 - PAR * KEXT / KLb) ], default = np.nan @@ -875,10 +877,10 @@ def FNb( FNb_orig: np.ndarray = np.select( condlist= [ - use_NH4 == True and use_NO3 == True, - use_NH4 == True and use_NO3 == False, - use_NH4 == False and use_NO3 == True, - use_NH4 == False and use_NO3 == False, + (use_NH4 == True) & (use_NO3 == True), + (use_NH4 == True) & (use_NO3 == False), + (use_NH4 == False) & (use_NO3 == True), + (use_NH4 == False) & (use_NO3 == False), ], choicelist= [ @@ -893,7 +895,7 @@ def FNb( FNb: np.ndarray = np.select( condlist= [ - math.isnan(FNb_orig), + np.isnan(FNb_orig), FNb_orig > 1.0 ], @@ -927,7 +929,7 @@ def FPb( FPb: np.ndarray = np.select( condlist= [ - math.isnan(FPb_orig), + np.isnan(FPb_orig), FPb_orig > 1.0 ], @@ -959,7 +961,7 @@ def FSb( FSb: np.ndarray = np.select( condlist= [ - math.isnan(FSb_orig), + np.isnan(FSb_orig), FSb_orig > 1.0 ], @@ -994,9 +996,24 @@ def mub( """ # Benthic Local Specific Growth Rate - return xr.where(b_growth_rate_option == 1, mub_max_tc * FLb * FPb * FNb * FSb, mub_max_tc * FLb * FSb * min(FPb, FNb)) - - + + mub: np.ndarray = np.select( + condlist= [ + b_growth_rate_option == 1, + (b_growth_rate_option != 1) & (FPb > FNb), + (b_growth_rate_option != 1) & (FNb > FPb) + ], + + choicelist= [ + mub_max_tc * FLb * FPb * FNb * FSb, + mub_max_tc * FLb * FSb * FNb, + mub_max_tc * FLb * FSb * FPb + ], + + default = 0 + ) + + return mub def AbGrowth( @@ -1209,7 +1226,7 @@ def ApUptakeFr_NH4( ) # Check for case when NH4 and NO3 are very small. If so, force uptake_fractions appropriately. - ApUptakeFr_NH4 = xr.where(math.isnan(ApUptakeFr_NH4),PN,ApUptakeFr_NH4) + ApUptakeFr_NH4 = xr.where(np.isnan(ApUptakeFr_NH4),PN,ApUptakeFr_NH4) return ApUptakeFr_NH4 @@ -1248,10 +1265,10 @@ def AbUptakeFr_NH4( """ AbUptakeFr_NH4: np.ndarray = np.select( condlist = [ - use_NH4 and not use_NO3, - not use_NH4 and use_NO3, - not use_NH4 and not use_NO3, - use_Balgae and use_NH4 and use_NO3 + (use_NH4) & (~use_NO3), + (~use_NH4) & (use_NO3), + (~use_NH4) & (~use_NO3), + (use_Balgae) & (use_NH4) & (use_NO3) ], choicelist = [ @@ -1264,7 +1281,7 @@ def AbUptakeFr_NH4( default = np.nan ) - AbUptakeFr_NH4 = xr.where(math.isnan(AbUptakeFr_NH4),PNb,AbUptakeFr_NH4) + AbUptakeFr_NH4 = xr.where(np.isnan(AbUptakeFr_NH4),PNb,AbUptakeFr_NH4) return AbUptakeFr_NH4 @@ -1585,7 +1602,7 @@ def NO3_Denit( NO3_Denit: np.ndarray = np.select( condlist = [ - use_DOX and math.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3), + (use_DOX) & (np.isnan((1.0 - (DOX / (DOX + KsOxdn))) * kdnit_tc * NO3)), use_DOX ], @@ -3207,7 +3224,7 @@ def Alk_denitrification( da: np.ndarray = np.select( condlist = [ - use_NO3 and use_DOX, + (use_NO3) & (use_DOX), use_NO3 ], @@ -3245,7 +3262,7 @@ def Alk_nitrification( da: np.ndarray = np.select( condlist = [ - use_NH4 and use_DOX, + (use_NH4) & (use_DOX), use_NH4 ], diff --git a/tests/test_6_nsm_module.py b/tests/test_6_nsm_module.py index c3af4c7..144816c 100644 --- a/tests/test_6_nsm_module.py +++ b/tests/test_6_nsm_module.py @@ -65,7 +65,7 @@ def nutrient_budget_instance( return NutrientBudget( time_steps=time_steps, initial_state_values=initial_nsm1_state, - updateable_static_variables=['a0'], + updateable_static_variables=['a10'], time_dim='nsm1_time_step', ) @@ -87,7 +87,7 @@ def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: assert isinstance(nutrient_budget_instance.global_parameters, dict) assert isinstance(nutrient_budget_instance.global_vars, dict) - assert nutrient_budget_instance.updateable_static_variables == ['a0'] + assert nutrient_budget_instance.updateable_static_variables == ['a10'] assert nutrient_budget_instance.algae_parameters == DEFAULT_ALGAE assert nutrient_budget_instance.alkalinity_parameters == DEFAULT_ALKALINITY From 82a7ba9a0921a077ebab4d17636372126bbb4883 Mon Sep 17 00:00:00 2001 From: Sarah Jordan Date: Tue, 23 Apr 2024 11:32:10 -0500 Subject: [PATCH 20/20] change updateable static variable --- tests/test_6_nsm_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_6_nsm_module.py b/tests/test_6_nsm_module.py index 144816c..93daf42 100644 --- a/tests/test_6_nsm_module.py +++ b/tests/test_6_nsm_module.py @@ -65,7 +65,7 @@ def nutrient_budget_instance( return NutrientBudget( time_steps=time_steps, initial_state_values=initial_nsm1_state, - updateable_static_variables=['a10'], + updateable_static_variables=['vson'], time_dim='nsm1_time_step', ) @@ -87,7 +87,7 @@ def test_nsm1_specific_attributes(nutrient_budget_instance) -> None: assert isinstance(nutrient_budget_instance.global_parameters, dict) assert isinstance(nutrient_budget_instance.global_vars, dict) - assert nutrient_budget_instance.updateable_static_variables == ['a10'] + assert nutrient_budget_instance.updateable_static_variables == ['vson'] assert nutrient_budget_instance.algae_parameters == DEFAULT_ALGAE assert nutrient_budget_instance.alkalinity_parameters == DEFAULT_ALKALINITY