diff --git a/src/clearwater_modules/nsm1/old/CBOD/dynamic_variables.py b/src/clearwater_modules/nsm1/old/CBOD/dynamic_variables.py new file mode 100644 index 0000000..7c81a2a --- /dev/null +++ b/src/clearwater_modules/nsm1/old/CBOD/dynamic_variables.py @@ -0,0 +1,59 @@ +""" +File contains dynamic variables related to the CBOD module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.CBOD.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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 +) diff --git a/src/clearwater_modules/nsm1/old/CBOD/processes.py b/src/clearwater_modules/nsm1/old/CBOD/processes.py new file mode 100644 index 0000000..0ea2729 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/CBOD/processes.py @@ -0,0 +1,107 @@ +""" +File contains process to calculate new CBOD concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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 diff --git a/src/clearwater_modules/nsm1/old/CBOD/static_variables.py b/src/clearwater_modules/nsm1/old/CBOD/static_variables.py new file mode 100644 index 0000000..dfeebd5 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/CBOD/static_variables.py @@ -0,0 +1,37 @@ +""" +File contains static variables related to the CBOD module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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' +) + diff --git a/src/clearwater_modules/nsm1/old/DOX/dynamic_variables.py b/src/clearwater_modules/nsm1/old/DOX/dynamic_variables.py new file mode 100644 index 0000000..87ae512 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/DOX/dynamic_variables.py @@ -0,0 +1,132 @@ +# TODO: figure out imports + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.DOX.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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 +) diff --git a/src/clearwater_modules/nsm1/old/DOX/processes.py b/src/clearwater_modules/nsm1/old/DOX/processes.py new file mode 100644 index 0000000..0dd2f9e --- /dev/null +++ b/src/clearwater_modules/nsm1/old/DOX/processes.py @@ -0,0 +1,275 @@ +""" +File contains dynamic variables related to the DOX module +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + + +#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 diff --git a/src/clearwater_modules/nsm1/old/DOX/static_variables.py b/src/clearwater_modules/nsm1/old/DOX/static_variables.py new file mode 100644 index 0000000..2a3397c --- /dev/null +++ b/src/clearwater_modules/nsm1/old/DOX/static_variables.py @@ -0,0 +1,29 @@ +""" +File contains static variables related to the DOX module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +Variable( + name='ron', + long_name='O2:N ratio for nitrification', + units='mg-O2/mg-N', + description='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' +) diff --git a/src/clearwater_modules/nsm1/old/POM/dynamic_variables.py b/src/clearwater_modules/nsm1/old/POM/dynamic_variables.py new file mode 100644 index 0000000..7df4dbf --- /dev/null +++ b/src/clearwater_modules/nsm1/old/POM/dynamic_variables.py @@ -0,0 +1,72 @@ +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.POM.processes as processes +import clearwater_modules.shared.processes as shared_processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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 +) diff --git a/src/clearwater_modules/nsm1/old/POM/processes.py b/src/clearwater_modules/nsm1/old/POM/processes.py new file mode 100644 index 0000000..eed5b1a --- /dev/null +++ b/src/clearwater_modules/nsm1/old/POM/processes.py @@ -0,0 +1,157 @@ +""" +File contains process to calculate new POM concentration and associated dependent variables +""" +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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 + + + + + diff --git a/src/clearwater_modules/nsm1/old/POM/static_variables.py b/src/clearwater_modules/nsm1/old/POM/static_variables.py new file mode 100644 index 0000000..7645f64 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/POM/static_variables.py @@ -0,0 +1,21 @@ +""" +File contains static variables related to the POM module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +Variable( + name='kpom_20', + long_name='POM dissolution rate at 20C', + units='1/d', + description='POM dissolution rate at 20C', + use='static' +) + diff --git a/src/clearwater_modules/nsm1/old/algae/dynamic_variables.py b/src/clearwater_modules/nsm1/old/algae/dynamic_variables.py new file mode 100644 index 0000000..029d534 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/algae/dynamic_variables.py @@ -0,0 +1,166 @@ +""" +File contains dynamic variables related to the Algae module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.algae.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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, +) + +Variable( + name='Ap', + long_name='New algal biomass concentration', + units='ug-Chala/L/d', + description='New algal biomass concentration', + use='dynamic', + process=processes.Ap, +) diff --git a/src/clearwater_modules/nsm1/old/algae/processes.py b/src/clearwater_modules/nsm1/old/algae/processes.py new file mode 100644 index 0000000..852460f --- /dev/null +++ b/src/clearwater_modules/nsm1/old/algae/processes.py @@ -0,0 +1,316 @@ +""" +File contains process to calculate new algae biomass concentration and associated dependent variables +""" +import numba +import xarray as xr +import numpy as np +from clearwater_modules.shared.processes import arrhenius_correction +import math + + +@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: int, +) -> 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 diff --git a/src/clearwater_modules/nsm1/old/algae/static_variables.py b/src/clearwater_modules/nsm1/old/algae/static_variables.py new file mode 100644 index 0000000..7b0c027 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/algae/static_variables.py @@ -0,0 +1,174 @@ +""" +File contains static variables related to the Algae module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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', +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/alkalinity/dynamic_variables.py b/src/clearwater_modules/nsm1/old/alkalinity/dynamic_variables.py new file mode 100644 index 0000000..29da0ab --- /dev/null +++ b/src/clearwater_modules/nsm1/old/alkalinity/dynamic_variables.py @@ -0,0 +1,79 @@ +""" +File contains dynamic variables related to the alkalinity module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.alkalinity.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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 +) + + + diff --git a/src/clearwater_modules/nsm1/old/alkalinity/processes.py b/src/clearwater_modules/nsm1/old/alkalinity/processes.py new file mode 100644 index 0000000..2da53bd --- /dev/null +++ b/src/clearwater_modules/nsm1/old/alkalinity/processes.py @@ -0,0 +1,178 @@ +""" +File contains process to calculate new alkalinity concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +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 \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/alkalinity/static_variables.py b/src/clearwater_modules/nsm1/old/alkalinity/static_variables.py new file mode 100644 index 0000000..2cce845 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/alkalinity/static_variables.py @@ -0,0 +1,61 @@ +""" +File contains static variables related to the Alkalinity module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + + +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' +) diff --git a/src/clearwater_modules/nsm1/old/balgae/dynamic_variables.py b/src/clearwater_modules/nsm1/old/balgae/dynamic_variables.py new file mode 100644 index 0000000..bff3bca --- /dev/null +++ b/src/clearwater_modules/nsm1/old/balgae/dynamic_variables.py @@ -0,0 +1,166 @@ +""" +File contains dynamic variables related to the benthic algae module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.balgae.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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( + name='Chlb', + long_name='Chlorophyll-a concentration', + units='mg-Chla/m^2', + description='Chlorophyll-a concentration', + use='dynamic', + process=processes.Chlb +) diff --git a/src/clearwater_modules/nsm1/old/balgae/processes.py b/src/clearwater_modules/nsm1/old/balgae/processes.py new file mode 100644 index 0000000..abcb67c --- /dev/null +++ b/src/clearwater_modules/nsm1/old/balgae/processes.py @@ -0,0 +1,345 @@ +""" +File contains process to calculate new benthic algae biomass concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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: + mub_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)) + +#TODO RAS WQ has an option for harmonic which the FORTAN code does not have + +@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 + +) -> xr.DataArray: + """Calculate new benthic algae concentration (g/m^2/d) + + Args: + Ab: Benthic algae concentration (g/m^2) + dAbdt: Change in benthic algae concentration (g/m^2/d) + """ + return Ab + dAbdt + +@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 diff --git a/src/clearwater_modules/nsm1/old/balgae/static_variables.py b/src/clearwater_modules/nsm1/old/balgae/static_variables.py new file mode 100644 index 0000000..91a7ff5 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/balgae/static_variables.py @@ -0,0 +1,154 @@ +""" +File contains static variables related to the Benthic Algae module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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' +) diff --git a/src/clearwater_modules/nsm1/old/carbon/dynamic_variables.py b/src/clearwater_modules/nsm1/old/carbon/dynamic_variables.py new file mode 100644 index 0000000..28a859e --- /dev/null +++ b/src/clearwater_modules/nsm1/old/carbon/dynamic_variables.py @@ -0,0 +1,202 @@ +""" +File contains dynamic variables related to the Carbon module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.carbon.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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='kac_tc', + long_name='temperature dependent CO2 reaeration rate', + units='1/d', + description='temperature dependent CO2 reaeration rate', + use='dynamic', + process=processes.kac_tc +) + +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 +) diff --git a/src/clearwater_modules/nsm1/old/carbon/processes.py b/src/clearwater_modules/nsm1/old/carbon/processes.py new file mode 100644 index 0000000..0063797 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/carbon/processes.py @@ -0,0 +1,445 @@ +""" +File contains process to calculate new carbon concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + + +@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 diff --git a/src/clearwater_modules/nsm1/old/carbon/static_variables.py b/src/clearwater_modules/nsm1/old/carbon/static_variables.py new file mode 100644 index 0000000..ad5bcfe --- /dev/null +++ b/src/clearwater_modules/nsm1/old/carbon/static_variables.py @@ -0,0 +1,77 @@ +""" +File contains static variables related to the Carbon module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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' +) + +#TODO define roc long name and description +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' +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/n2/dynamic_variables.py b/src/clearwater_modules/nsm1/old/n2/dynamic_variables.py new file mode 100644 index 0000000..9734417 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/n2/dynamic_variables.py @@ -0,0 +1,58 @@ +""" +File includes dynamic variables computed in N2 module. Dynamic variables may be accessed by other modules. +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.n2.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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/old/n2/processes.py b/src/clearwater_modules/nsm1/old/n2/processes.py new file mode 100644 index 0000000..5e6005b --- /dev/null +++ b/src/clearwater_modules/nsm1/old/n2/processes.py @@ -0,0 +1,117 @@ +""" +File contains dynamic variables related to the N2 module +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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/old/n2/static_variables.py b/src/clearwater_modules/nsm1/old/n2/static_variables.py new file mode 100644 index 0000000..2a0da2e --- /dev/null +++ b/src/clearwater_modules/nsm1/old/n2/static_variables.py @@ -0,0 +1,12 @@ +""" +File contains static variables related to the N2 module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + diff --git a/src/clearwater_modules/nsm1/old/nitrogen/dynamic_variables.py b/src/clearwater_modules/nsm1/old/nitrogen/dynamic_variables.py new file mode 100644 index 0000000..1135f2d --- /dev/null +++ b/src/clearwater_modules/nsm1/old/nitrogen/dynamic_variables.py @@ -0,0 +1,295 @@ +""" +File contains dynamic variables related to the Nitrogen module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.nitrogen.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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 +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/nitrogen/processes.py b/src/clearwater_modules/nsm1/old/nitrogen/processes.py new file mode 100644 index 0000000..32f7409 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/nitrogen/processes.py @@ -0,0 +1,719 @@ +""" +File contains process to calculate nitrogen species concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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 NH4( + dNH4dt: xr.DataArray, + NH4: xr.DataArray + +) -> xr.DataArray: + """Calculates new ammonia concentration + + Args: + dNH4dt: Change in ammonia concentration over the timestep (mg-N/L/d) + NH4: Ammonia concentration (mg-N/L) + """ + return NH4 + dNH4dt + + +@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 NO3( + dNO3dt: xr.DataArray, + NO3: xr.DataArray + +) -> xr.DataArray: + """Calculates new organic nitrogen concentration + + Args: + dNO3dt: Change in nitrate concentration over the timestep (mg-N/L/d) + NO3: Nitrate concentration (mg-N/L) + """ + return NO3 + dNO3dt + +@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 diff --git a/src/clearwater_modules/nsm1/old/nitrogen/static_variables.py b/src/clearwater_modules/nsm1/old/nitrogen/static_variables.py new file mode 100644 index 0000000..52934db --- /dev/null +++ b/src/clearwater_modules/nsm1/old/nitrogen/static_variables.py @@ -0,0 +1,86 @@ +""" +File contains static variables related to the Nitrogen module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + + +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', +) diff --git a/src/clearwater_modules/nsm1/old/pathogens/dynamic_variables.py b/src/clearwater_modules/nsm1/old/pathogens/dynamic_variables.py new file mode 100644 index 0000000..5522925 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/pathogens/dynamic_variables.py @@ -0,0 +1,67 @@ +""" +File contains dynamic variables related to the Pathogens module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.pathogens.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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 +) + +Variable( + name='PX', + long_name='New pathogen concentration', + units='cfu/100mL', + description='New pathogen concentration', + use='dynamic', + process=processes.PX +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/pathogens/processes.py b/src/clearwater_modules/nsm1/old/pathogens/processes.py new file mode 100644 index 0000000..2488f49 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/pathogens/processes.py @@ -0,0 +1,110 @@ +""" +File contains process to calculate new pathogen concentration and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +@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 \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/pathogens/static_variables.py b/src/clearwater_modules/nsm1/old/pathogens/static_variables.py new file mode 100644 index 0000000..7281d45 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/pathogens/static_variables.py @@ -0,0 +1,37 @@ +""" +File contains static variables related to the Pathogens module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + + +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', +) diff --git a/src/clearwater_modules/nsm1/old/phosphorus/dynamic_variables.py b/src/clearwater_modules/nsm1/old/phosphorus/dynamic_variables.py new file mode 100644 index 0000000..bbe19de --- /dev/null +++ b/src/clearwater_modules/nsm1/old/phosphorus/dynamic_variables.py @@ -0,0 +1,185 @@ +""" +File contains dynamic variables related to the Phosphorus module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +import clearwater_modules.nsm1.phosphorus.processes as processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + +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 inorganich phosphorus', + units='mg-P/L', + description='Dissolve inorganich phosphorus', + use='dynamic', + process=processes.DIP +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/phosphorus/processes.py b/src/clearwater_modules/nsm1/old/phosphorus/processes.py new file mode 100644 index 0000000..640a869 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/phosphorus/processes.py @@ -0,0 +1,378 @@ +""" +File contains process to calculate new phosphorus concentration and associated dependent variables +""" +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + + + +@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 + diff --git a/src/clearwater_modules/nsm1/old/phosphorus/static_variables.py b/src/clearwater_modules/nsm1/old/phosphorus/static_variables.py new file mode 100644 index 0000000..c990184 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/phosphorus/static_variables.py @@ -0,0 +1,36 @@ +""" +File contains static variables related to the Phosphorus module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +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', +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/sedflux/dynamic_variables.py b/src/clearwater_modules/nsm1/old/sedflux/dynamic_variables.py new file mode 100644 index 0000000..8bc80f1 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/sedflux/dynamic_variables.py @@ -0,0 +1,46 @@ +""" +File contains dynamic variables related to the SedFlux module +""" + +import clearwater_modules.shared.processes as shared_processes +from clearwater_modules import base +from clearwater_modules.nsm1.model import NutrientBudget +from clearwater_modules.nsm1.sedflux import processes + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + +def mock_equation(water_temp_c: float) -> float: + return water_temp_c ** 2 + + +Variable( + name='JNH4', + long_name='Sediment water flux of ammonia', + units='g-N/m^2/d', + description='Sediment water flux of ammonia', + use='dynamic', + process=mock_equation # TODO this depends on sedflux module +) + +Variable( + name='JNO3', + long_name='Sediment water flux of nitrate', + units='g-N/m^2/d', + description='Sediment water flux of nitrate', + use='dynamic', + process=mock_equation # TODO this depends on sedflux module +) + + +Variable( + name='JDIP', + long_name='Sediment water flux of phosphate', + units='g-P/m^2/d', + description='Sediment water flux of phosphate', + use='dynamic', + process=mock_equation #TODO this depends on sedflux module +) \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/sedflux/processes.py b/src/clearwater_modules/nsm1/old/sedflux/processes.py new file mode 100644 index 0000000..9faec09 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/sedflux/processes.py @@ -0,0 +1,4597 @@ +""" +File contains process to calculate sediment flux and associated dependent variables +""" + +import numba +import xarray as xr +from clearwater_modules.shared.processes import arrhenius_correction +import math + +# Note: OrgN, NH4, NO3, OrgP, TIP, POC and DOX must be on for SedFlux. + +@numba.njit +def DOX_max( + DOX: xr.DataArray, +) -> xr.DataArray: + """Calculate DOX_max just to make sure DOX is 0.01 or greater (mg-O2/L). + + Args: + DOX: Dissolve oxygen (mg-O2//L) + """ + return xr.where(DOX>0.01, DOX, 0.01) + +""" + POC2=[0]*3 #concentration of sediment particulate organic carbon + PON2=[0]*3 #concentration of sediment particulate organic nitrogen + POP2=[0]*3 #concentration of sediment particulate organic phosphrous + + POC2[1] = self.global_vars_sedflux['POC2_1'] + POC2[2] = self.global_vars_sedflux['POC2_2'] + POC2[3] = self.global_vars_sedflux['POC2_3'] + + PON2[1] = self.global_vars_sedflux['PON2_1'] + PON2[2] = self.global_vars_sedflux['PON2_2'] + PON2[3] = self.global_vars_sedflux['PON2_3'] + + POP2[1] = self.global_vars_sedflux['POP2_1'] + POP2[2] = self.global_vars_sedflux['POP2_2'] + POP2[3] = self.global_vars_sedflux['POP2_3'] + + KPON_tc=[0]*3 + KPOP_tc=[0]*3 + KPOC_tc = [0]*3 + +""" + +@numba.njit +def Dd_tc( + Dd: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d). + + Args: + Dd: pore-water diffusion coefficient between layer 1 and 2 (m2/d) + TsedC: sediment temperature (C) + """ + return arrhenius_correction(TsedC, Dd, 1.08) + +@numba.njit +def Dp_tc( + Dp: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate Dp_tc: particle mixing diffusion coefficient between layer 1 and 2 temperature corrected (m2/d). + + Args: + Dd: particle mixing diffusion coefficient between layer 1 and 2 (m2/d) + TsedC: sediment temperature (C) + """ + return arrhenius_correction(TsedC, Dp, 1.117) + +@numba.njit +def vnh41_tc( + vnh41: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vnh41_tc: nitrification reaction velocity in sediment layer 1 temperature corrected (m/d). + + Args: + vnh41: nitrification reaction velocity in sediment layer 1 (m/d) + TsedC: sediment temperature (C) + """ + return vnh41 * 1.123 * ((TsedC-20)/2) + +@numba.njit +def vno31_tc( + vno31: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vno31_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d). + + Args: + vnh41: denitrification reaction velocity in sediment layer 1 (m/d) + TsedC: sediment temperature (C) + """ + return vno31 * 1.08 * ((TsedC-20)/2) + +@numba.njit +def vch41_tc( + vch41: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vch41_tc: methane oxidation reaction velocity in sediment layer 1 temperature corrected (m/d). + + Args: + vch41: methane oxidation reaction velocity in sediment layer 1 (m/d) + TsedC: sediment temperature (C) + """ + return vch41 * 1.079 * ((TsedC-20)/2) + +@numba.njit +def vh2sd_tc( + vh2sd: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vh2sd_tc: dissolve sulfide oxidation reaction velocity in sediment layer 1 temperature corrected (m/d). + + Args: + vh2sd: dissolve sulfide oxidation reaction velocity in sediment layer 1 (m/d) + TsedC: sediment temperature (C) + """ + return vh2sd * 1.079 * ((TsedC-20)/2) + +@numba.njit +def vh2sp_tc( + vh2sp: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vh2sp_tc: particulate sulfide oxidation reaction veolcoity in sediment layer 1 (m/d). + + Args: + vh2sp: particulate sulfide oxidation reaction veolcoity in sediment layer 1 (m/d) + TsedC: sediment temperature (C) + """ + return vh2sp * 1.079 * ((TsedC-20)/2) + +@numba.njit +def vno32_tc( + vno32: xr.DataArray, + TsedC: xr.DataArray, +) -> xr.DataArray: + """Calculate vno32_tc: enitrification reaction velocity in sediment layer 3 temperature correction (m/d). + + Args: + vh2sp: enitrification reaction velocity in sediment layer 2 (m/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, vno32, 1.08) #TODO why is this different from vno31 + +@numba.njit +def KPON_1_tc( + KPONG1: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPON_1_tc: diagenesis rate of PON G1 in sediment layer 2 temperature corrected (1/d) + + Args: + KPONG1: diagenesis rate of PON G1 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, KPONG1, 1.1) + +@numba.njit +def KPON_2_tc( + KPONG2: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPON2__tc: diagenesis rate of PON G2 in sediment layer 2 temperature corrected (1/d) + + Args: + KPONG2: diagenesis rate of PON G2 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, KPONG2, 1.1) + +@numba.njit +def KPON_3_tc( + +) -> xr.DataArray: + """Calculate KPON_3_tc: diagenesis rate of PON G1 and G2 in sediment layer 2 temperature corrected (1/d) + + Args: + + """ + + return 0 #TODO should this be a static variable + +@numba.njit +def KPOP_1_tc( + KPOPG1: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPOP_1_tc: diagenesis rate of POP G1 in sediment layer 2 temperature corrected (1/d) + + Args: + KPOPG1: diagenesis rate of POP G1 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, KPOPG1, 1.1) + +@numba.njit +def KPOP_2_tc( + KPOPG2: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPOP_tc: diagenesis rate of POP G2 in sediment layer 2 temperature corrected (1/d) + + Args: + KPOPG2: diagenesis rate of POP G2 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + return arrhenius_correction(TsedC, KPOPG2, 1.15) + +@numba.njit +def KPOP_3_tc( + + +) -> xr.DataArray: + """Calculate KPOP_3_tc: diagenesis rate of POP in sediment layer 2 temperature corrected (1/d) + + Args: + + """ + return 0 #TODO should this be a static variable + +@numba.njit +def KPOC_1_tc( + KPOCG1: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPOC_1_c: diagenesis rate of POC G1 in sediment layer 2 temperature corrected (1/d) + + Args: + KPOCG1: diagenesis rate of POC G1 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, KPOCG1, 1.1) + +@numba.njit +def KPOC_2_tc( + KPOCG2: xr.DataArray, + TsedC: xr.DataArray, + +) -> xr.DataArray: + """Calculate KPOC_2_tc: diagenesis rate of POC G2 in sediment layer 2 temperature corrected (1/d) + + Args: + KPOCG2: diagenesis rate of POC G2 in sediment layer 2 (1/d) + TsedC: sediment temperature (C) + """ + + return arrhenius_correction(TsedC, KPOCG2, 1.15) + +@numba.njit +def KPOC_3_tc( + +) -> xr.DataArray: + """Calculate KPOC_tc: diagenesis rate of POC G3 in sediment layer 2 temperature corrected (1/d) + + Args: + + """ + + return 0 #TODO should this be a static variable + +@numba.njit +def JPOC_1( +vsoc: xr.DataArray, +POC: xr.DataArray, +FPOC1: xr.DataArray, +use_POC: xr.DataArray, + +ksbod_tc: xr.DataArray, +FCBOD1: xr.DataArray, +CBOD: xr.DataArray, +roc: xr.DataArray, + +use_Algae:xr.DataArray, +FAP1:xr.DataArray, +rca:xr.DataArray, +Ap:xr.DataArray, +vsap:xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rcb: xr.DataArray, +FAB1: xr.DataArray, + +use_CBOD: xr.DataArray + +) -> xr.DataArray: + """Calculate JPOC_1: total depositional flux to sediment of particulate organic matter G1 (g-C/m^2/d) + + Args: + vsoc: settling velocity of POC (m/d) + POC: Particulate organic carbon concentration (mg-C/L) + FPOC1: fraction of settled RPOC to sediment PCO G1 (unitless) + FPOC2: fraction of settled RPOC to sediment PCO G2 (unitless) + use_POC: true/false to use POC module (t/f) + + ksbod_tc: sedimentation rate (1/d) + FCBOD1: fraction of CBOD sedimentation to G1 (unitless) + FCBOD2: fraction of CBOD sedimentation to G2 (unitless) + CBOD: carbonaceous biochemical oxygen demand (mg-O2/L) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + + use_Algae: true/false to use algae module (t/f) + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rca: Algal C " Chla ratio (mg-C/ugChla) + Ap: Algal concentration (ugChla/L) + vsap: Algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f) + AbDeath: Balgal death rate (g/m^2/d) + Fw: Fraction of benthic algae mortality into water column (unitless) + rcb: Balgal C : Dry ratio (mg-C/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G1 (unitless) + + use_CBOD: true/false to use CBOD module (t/f) + + """ + + #TODO add use_CBOD make sure that is appropriate. + + return xr.where(use_POC, vsoc * POC * FPOC1 , 0) + \ + xr.where(use_CBOD, ksbod_tc * FCBOD1 * CBOD / roc, 0) + \ + xr.where(use_Algae, FAP1 * rca * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rcb * FAB1, 0) + +@numba.njit +def JPOC_2( +vsoc: xr.DataArray, +POC: xr.DataArray, +FPOC2: xr.DataArray, +use_POC: xr.DataArray, + +ksbod_tc: xr.DataArray, +FCBOD2: xr.DataArray, +CBOD: xr.DataArray, +roc: xr.DataArray, + +use_Algae:xr.DataArray, +FAP2: xr.DataArray, +rca:xr.DataArray, +Ap:xr.DataArray, +vsap:xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rcb: xr.DataArray, +FAB2: xr.DataArray, + +use_CBOD: xr.DataArray + +) -> xr.DataArray: + """Calculate JPOC_2: total depositional flux to sediment of particulate organic matter G2 (g-C/m^2/d) + + Args: + vsoc: settling velocity of POC (m/d) + POC: Particulate organic carbon concentration (mg-C/L) + FPOC1: fraction of settled RPOC to sediment PCO G1 (unitless) + FPOC2: fraction of settled RPOC to sediment PCO G2 (unitless) + use_POC: true/false to use POC module (t/f) + + ksbod_tc: sedimentation rate (1/d) + FCBOD1: fraction of CBOD sedimentation to G1 (unitless) + FCBOD2: fraction of CBOD sedimentation to G2 (unitless) + CBOD: carbonaceous biochemical oxygen demand (mg-O2/L) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + + use_Algae: true/false to use algae module (t/f) + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rca: Algal C " Chla ratio (mg-C/ugChla) + Ap: Algal concentration (ugChla/L) + vsap: Algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f) + AbDeath: Balgal death rate (g/m^2/d) + Fw: Fraction of benthic algae mortality into water column (unitless) + rcb: Balgal C : Dry ratio (mg-C/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G1 (unitless) + + use_CBOD: true/false to use CBOD module (t/f) + + """ + #TODO add use_CBOD make sure that is appropriate. + return xr.where(use_POC, vsoc * POC * FPOC2 , 0) + \ + xr.where(use_CBOD, ksbod_tc * FCBOD2 * CBOD / roc, 0) + \ + xr.where(use_Algae, FAP2 * rca * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rcb * FAB2, 0) + +@numba.njit +def JPOC_3( +vsoc: xr.DataArray, +POC: xr.DataArray, +FPOC1: xr.DataArray, +FPOC2: xr.DataArray, +use_POC: xr.DataArray, + +ksbod_tc: xr.DataArray, +FCBOD1: xr.DataArray, +FCBOD2: xr.DataArray, +CBOD: xr.DataArray, +roc: xr.DataArray, + +use_Algae:xr.DataArray, +FAP1:xr.DataArray, +FAP2: xr.DataArray, +rca:xr.DataArray, +Ap:xr.DataArray, +vsap:xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rcb: xr.DataArray, +FAB1: xr.DataArray, +FAB2: xr.DataArray, + +use_CBOD: xr.DataArray + +) -> xr.DataArray: + """Calculate JPOC_3: total depositional flux to sediment of particulate organic matter g3 (g-C/m^2/d) + + Args: + vsoc: settling velocity of POC (m/d) + POC: Particulate organic carbon concentration (mg-C/L) + FPOC1: fraction of settled RPOC to sediment PCO G1 (unitless) + FPOC2: fraction of settled RPOC to sediment PCO G2 (unitless) + use_POC: true/false to use POC module (t/f) + + ksbod_tc: sedimentation rate (1/d) + FCBOD1: fraction of CBOD sedimentation to G1 (unitless) + FCBOD2: fraction of CBOD sedimentation to G2 (unitless) + CBOD: carbonaceous biochemical oxygen demand (mg-O2/L) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + + use_Algae: true/false to use algae module (t/f) + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rca: Algal C " Chla ratio (mg-C/ugChla) + Ap: Algal concentration (ugChla/L) + vsap: Algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f) + AbDeath: Balgal death rate (g/m^2/d) + Fw: Fraction of benthic algae mortality into water column (unitless) + rcb: Balgal C : Dry ratio (mg-C/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G1 (unitless) + + use_CBOD: true/false to use CBOD module (t/f) + + """ + #TODO add use_CBOD make sure that is appropriate. + return xr.where(use_POC, vsoc * POC * (1 - FPOC1 - FPOC2), 0) + \ + xr.where(use_CBOD, ksbod_tc * (1.0 - FCBOD1 - FCBOD2) * CBOD / roc, 0) + \ + xr.where(use_Algae, (1.0 - FAP1 - FAP2) * rca * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rcb * (1.0 - FAB1 - FAB2), 0) + +@numba.njit +def JPON_1( +vson: xr.DataArray, +OrgN: xr.DataArray, +FPON1: xr.DataArray, +use_OrgN: xr.DataArray, + +use_Algae: xr.DataArray, +FAP1: xr.DataArray, +rna: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rnb: xr.DataArray, +FAB1: xr.DataArray, + + +) -> xr.DataArray: + """Calculate JPON_2: total depositional flux of PON G1 from overlying water column to bed sediment (g-N/m^2/d) + + Args: + vson: settling velocity of Organic Nitrogen (m/d) + OrgN: Organic nitrogen concentration (mg-N/L) + FPON1: fraction of settled RPON to sediment PON G1 (unitless) + FPON2: fraction of settled RPON to sediment PON G2 (unitless) + use_OrgN: true/false to use OrgN module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rna: Algal N: Chla ratio (mg-N/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rnb: Balgal N: Dry ratio (mg-N/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + + return xr.where(use_OrgN, vson * OrgN * FPON1, 0) + \ + xr.where(use_Algae, FAP1 * rna * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rnb * FAB1) + +@numba.njit +def JPON_2( +vson: xr.DataArray, +OrgN: xr.DataArray, +FPON2: xr.DataArray, +use_OrgN: xr.DataArray, + +use_Algae: xr.DataArray, +FAP2: xr.DataArray, +rna: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rnb: xr.DataArray, +FAB2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JPON_2: total depositional flux of PON G2 from overlying water column to bed sediment (g-N/m^2/d) + + Args: + vson: settling velocity of Organic Nitrogen (m/d) + OrgN: Organic nitrogen concentration (mg-N/L) + FPON1: fraction of settled RPON to sediment PON G1 (unitless) + FPON2: fraction of settled RPON to sediment PON G2 (unitless) + use_OrgN: true/false to use OrgN module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rna: Algal N: Chla ratio (mg-N/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rnb: Balgal N: Dry ratio (mg-N/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + + return xr.where(use_OrgN, vson * OrgN * FPON2, 0) + \ + xr.where(use_Algae, FAP2 * rna * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rnb * FAB2) + +@numba.njit +def JPON_3( +vson: xr.DataArray, +OrgN: xr.DataArray, +FPON1: xr.DataArray, +FPON2: xr.DataArray, +use_OrgN: xr.DataArray, + +use_Algae: xr.DataArray, +FAP1: xr.DataArray, +FAP2: xr.DataArray, +rna: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rnb: xr.DataArray, +FAB1: xr.DataArray, +FAB2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JPON_3: total depositional flux of PON G3 from overlying water column to bed sediment (g-N/m^2/d) + + Args: + vson: settling velocity of Organic Nitrogen (m/d) + OrgN: Organic nitrogen concentration (mg-N/L) + FPON1: fraction of settled RPON to sediment PON G1 (unitless) + FPON2: fraction of settled RPON to sediment PON G2 (unitless) + use_OrgN: true/false to use OrgN module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rna: Algal N: Chla ratio (mg-N/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rnb: Balgal N: Dry ratio (mg-N/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + return xr.where(use_OrgN, vson * OrgN * (1 - FPON1 - FPON2), 0) + \ + xr.where(use_Algae, (1.0 - FAP1 - FAP2) * rna * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rnb * (1.0 - FAB1 - FAB2), 0) + +@numba.njit +def JPOP_1( +vsop: xr.DataArray, +OrgP: xr.DataArray, +FPOP1: xr.DataArray, +use_OrgP: xr.DataArray, + +use_Algae: xr.DataArray, +FAP1: xr.DataArray, +rpa: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rpb: xr.DataArray, +FAB1: xr.DataArray, + +) -> xr.DataArray: + """Calculate JPOP_1: total depositional flux of POP G1 from overlying water column to bed sediment (g-P/m^2/d) + + Args: + vsop: settling velocity of Organic Phosphorus (m/d) + OrgP: Organic phosphorus concentration (mg-P/L) + FPOP1: fraction of settled RPOP to sediment POP G1 (unitless) + FPOP2: fraction of settled RPOP to sediment POP G2 (unitless) + use_OrgP: true/false to use OrgP module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rPa: Algal p: Chla ratio (mg-p/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rpb: Balgal P: Dry ratio (mg-P/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + + return xr.where(use_OrgP, vsop * OrgP * FPOP1, 0) + \ + xr.where(use_Algae, FAP1 * rpa * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rpb * FAB1, 0) + +@numba.njit +def JPOP_2( +vsop: xr.DataArray, +OrgP: xr.DataArray, +FPOP2: xr.DataArray, +use_OrgP: xr.DataArray, + +use_Algae: xr.DataArray, +FAP2: xr.DataArray, +rpa: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rpb: xr.DataArray, +FAB2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JPOP_2: total depositional flux of POP G1 from overlying water column to bed sediment (g-P/m^2/d) + + Args: + vsop: settling velocity of Organic Phosphorus (m/d) + OrgP: Organic phosphorus concentration (mg-P/L) + FPOP1: fraction of settled RPOP to sediment POP G1 (unitless) + FPOP2: fraction of settled RPOP to sediment POP G2 (unitless) + use_OrgP: true/false to use OrgP module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rPa: Algal p: Chla ratio (mg-p/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rpb: Balgal P: Dry ratio (mg-P/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + return xr.where(use_OrgP, vsop * OrgP * FPOP2, 0)+ \ + xr.where(use_Algae, FAP2 * rpa * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rpb * FAB2, 0) + +@numba.njit +def JPOP_3( +vsop: xr.DataArray, +OrgP: xr.DataArray, +FPOP1: xr.DataArray, +FPOP2: xr.DataArray, +use_OrgP: xr.DataArray, + +use_Algae: xr.DataArray, +FAP1: xr.DataArray, +FAP2: xr.DataArray, +rpa: xr.DataArray, +Ap: xr.DataArray, +vsap: xr.DataArray, + +use_Balgae: xr.DataArray, +AbDeath: xr.DataArray, +Fw: xr.DataArray, +rpb: xr.DataArray, +FAB1: xr.DataArray, +FAB2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JPOP_3: total depositional flux of POP G3 from overlying water column to bed sediment (g-P/m^2/d) + + Args: + vsop: settling velocity of Organic Phosphorus (m/d) + OrgP: Organic phosphorus concentration (mg-P/L) + FPOP1: fraction of settled RPOP to sediment POP G1 (unitless) + FPOP2: fraction of settled RPOP to sediment POP G2 (unitless) + use_OrgP: true/false to use OrgP module (t/f) + + use_Algae: true/false to use algae module (t/f), + FAP1: fraction of settled algae to G1 (unitless) + FAP2: fraction of settled algae to G2 (unitless) + rPa: Algal p: Chla ratio (mg-p/ugChla) + Ap: Algae concentration (ug-Chla/L) + vsap: algal settling velocity (m/d) + + use_Balgae: true/false to use Balgae module (t/f), + AbDeath: Balgal death rate (g/m2/d) + Fw: fraction of benthic algae mortality into water column (unitless) + rpb: Balgal P: Dry ratio (mg-P/mg-D) + FAB1: fraction of benthic algae death to G1 (unitless) + FAB2: fraction of benthic algae death to G2 (unitless) + + """ + + return xr.where(use_OrgP, vsop * OrgP * (1 - FPOP1 - FPOP2), 0)+ \ + xr.where(use_Algae, (1.0 - FAP1 - FAP2) * rpa * Ap * vsap, 0) + \ + xr.where(use_Balgae, AbDeath * (1.0 - Fw) * rpb * (1.0 - FAB1 - FAB2), 0) + +""" + #compute POC2/PON2/POP2, POC2/PON2/POP2 pathways and JC/JN/JP + POC2=[0]*3 #concentration of sediment particulate organic carbon + PON2=[0]*3 #concentration of sediment particulate organic nitrogen + POP2=[0]*3 #concentration of sediment particulate organic phosphrous + POC2_Diagenesis=[0]*3 + PON2_Diagenesis=[0]*3 + POP2_Diagenesis=[0]*3 + POC2_Burial=[0]*3 + PON2_Burial=[0]*3 + POP2_Burial=[0]*3 +""" + +@numba.njit +def POC2_1_new( +SedFlux_solution_option: xr.DataArray, +JPOC_1: xr.DataArray, +KPOC_1_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POC2_1: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_1_new: POC G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOC_1: otal depositional flux to sediment of particulate organic matter G1 (g-C/m^2/d) + KPOC_1_tc: diagenesis rate of POC G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + POC2_1: sediment POC layer 1 (mg-C/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOC_1 / (KPOC_1_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOC_1 + POC2_1 * h2 / dt),0) / (h2 / dt + KPOC_1_tc * h2 + vb),0)) + +@numba.njit +def POC2_2_new( +SedFlux_solution_option: xr.DataArray, +JPOC_2: xr.DataArray, +KPOC_2_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POC2_2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_2_new: POC G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOC_2: total depositional flux to sediment of particulate organic matter G2 (g-C/m^2/d) + KPOC_2_tc: diagenesis rate of POC G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + POC2_2: sediment POC layer 2 (mg-C/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOC_2 / (KPOC_2_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOC_2 + POC2_2 * h2 / dt),0) / (h2 / dt + KPOC_2_tc * h2 + vb),0)) + +@numba.njit +def POC2_3_new( +SedFlux_solution_option: xr.DataArray, +JPOC_3: xr.DataArray, +KPOC_3_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POC2_3: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_3_new: POC G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOC_3: total depositional flux to sediment of particulate organic matter G3 (g-C/m^2/d) + KPOC_3_tc: diagenesis rate of POC G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + POC2_3: sediment POC layer 2 (mg-C/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOC_3 / (KPOC_3_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOC_3 + POC2_3 * h2 / dt),0) / (h2 / dt + KPOC_3_tc * h2 + vb),0)) + +@numba.njit +def PON2_1_new( +SedFlux_solution_option: xr.DataArray, +JPON_1: xr.DataArray, +KPON_1_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +PON2_1: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_1_new: PON G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPON_1: total depositional flux to sediment of particulate organic nitrogen G1 (g-N/m^2/d) + KPON_1_tc: diagenesis rate of PON G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_1: sediment PON layer 2 (mg-N/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPON_1 / (KPON_1_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPON_1 + PON2_1 * h2 / dt),0) / (h2 / dt + KPON_1_tc * h2 + vb),0)) + +@numba.njit +def PON2_2_new( +SedFlux_solution_option: xr.DataArray, +JPON_2: xr.DataArray, +KPON_2_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +PON2_2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_2_new: PON G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPON_2: total depositional flux to sediment of particulate organic nitrogen G2 (g-N/m^2/d) + KPON_2_tc: diagenesis rate of PON G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_2: sediment PON layer 2 (mg-N/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPON_2 / (KPON_2_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPON_2 + PON2_2 * h2 / dt),0) / (h2 / dt + KPON_2_tc * h2 + vb),0)) + +@numba.njit +def PON2_3_new( +SedFlux_solution_option: xr.DataArray, +JPON_3: xr.DataArray, +KPON_3_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +PON2_3: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_3_new: PON G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPON_3: total depositional flux to sediment of particulate organic nitrogen G3 (g-N/m^2/d) + KPON_3_tc: diagenesis rate of PON G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_3: sediment PON layer 2 (mg-N/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPON_3 / (KPON_3_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPON_3 + PON2_3 * h2 / dt),0) / (h2 / dt + KPON_3_tc * h2 + vb),0)) + +@numba.njit +def POP2_1_new( +SedFlux_solution_option: xr.DataArray, +JPOP_1: xr.DataArray, +KPOP_1_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POP2_1: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_1_new: POP G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOP_1: total depositional flux to sediment of particulate organic phosphorus G1 (g-P/m^2/d) + KPOP_1_tc: diagenesis rate of POP G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_1: sediment POP layer 2 (mg-P/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOP_1 / (KPOP_1_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOP_1 + POP2_1 * h2 / dt),0) / (h2 / dt + KPOP_1_tc * h2 + vb),0)) + +@numba.njit +def POP2_2_new( +SedFlux_solution_option: xr.DataArray, +JPOP_2: xr.DataArray, +KPOP_2_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POP2_2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_2_new: POP G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOP_2: total depositional flux to sediment of particulate organic phosphorus G2 (g-P/m^2/d) + KPOP_2_tc: diagenesis rate of POP G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_2: sediment POP layer 2 (mg-P/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOP_2 / (KPOP_2_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOP_2 + POP2_2 * h2 / dt),0) / (h2 / dt + KPOP_2_tc * h2 + vb),0)) + +@numba.njit +def POP2_3_new( +SedFlux_solution_option: xr.DataArray, +JPOP_3: xr.DataArray, +KPOP_3_tc: xr.DataArray, +h2: xr.DataArray, +vb: xr.DataArray, +POP2_3: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_3_new: POP G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JPOP_3: total depositional flux to sediment of particulate organic phosphorus G3 (g-P/m^2/d) + KPOP_3_tc: diagenesis rate of POP G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + vb: burial velocity of POM2 in bed sediment (m/d) + PON2_3: sediment POP layer 2 (mg-P/L) + dt: time step (d) + + """ + + return xr.where(SedFlux_solution_option==1, max(JPOP_3 / (KPOP_3_tc * h2 + vb),0), xr.where(SedFlux_solution_option==2, max((JPOP_3 + POP2_3 * h2 / dt),0) / (h2 / dt + KPOP_3_tc * h2 + vb),0)) + +@numba.njit +def POC2_Diagenesis_1( +KPOC_1_tc: xr.DataArray, +h2: xr.DataArray, +POC2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Diagenesis_1: sediment diagenesis of POC G1 in sediment layer (g-C/m2/d) + + Args: + KPOC_1_tc: diagenesis rate of POC G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POC2_1_new: POC G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return KPOC_1_tc * h2 * POC2_1_new + +@numba.njit +def POC2_Diagenesis_2( +KPOC_2_tc: xr.DataArray, +h2: xr.DataArray, +POC2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Diagenesis_2: sediment diagenesis of POC G2 in sediment layer (g-C/m2/d) + + Args: + KPOC_2_tc: diagenesis rate of POC G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POC2_2_new: POC G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return KPOC_2_tc * h2 * POC2_2_new + +@numba.njit +def POC2_Diagenesis_3( +KPOC_3_tc: xr.DataArray, +h2: xr.DataArray, +POC2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Diagenesis_3: sediment diagenesis of POC G3 in sediment layer (g-C/m2/d) + + Args: + KPOC_3_tc: diagenesis rate of POC G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POC2_3_new: POC G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return KPOC_3_tc * h2 * POC2_3_new + +@numba.njit +def PON2_Diagenesis_1( +KPON_1_tc: xr.DataArray, +h2: xr.DataArray, +PON2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Diagenesis_1: sediment diagenesis of PON G1 in sediment layer (g-N/m2/d) + + Args: + KPON_1_tc: diagenesis rate of PON G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + PON2_1_new: PON G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return KPON_1_tc * h2 * PON2_1_new + +@numba.njit +def PON2_Diagenesis_2( +KPON_2_tc: xr.DataArray, +h2: xr.DataArray, +PON2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Diagenesis_2: sediment diagenesis of PON G2 in sediment layer (g-N/m2/d) + + Args: + KPON_2_tc: diagenesis rate of PON G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + PON2_2_new: PON G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return KPON_2_tc * h2 * PON2_2_new + +@numba.njit +def PON2_Diagenesis_3( +KPON_3_tc: xr.DataArray, +h2: xr.DataArray, +PON2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Diagenesis_3: sediment diagenesis of PON G3 in sediment layer (g-N/m2/d) + + Args: + KPON_3_tc: diagenesis rate of PON G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + PON2_3_new: PON G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return KPON_3_tc * h2 * PON2_3_new + +@numba.njit +def POP2_Diagenesis_1( +KPOP_1_tc: xr.DataArray, +h2: xr.DataArray, +POP2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Diagenesis_1: sediment diagenesis of PON G1 in sediment layer (g-P/m2/d) + + Args: + KPOP_1_tc: diagenesis rate of POP G1 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POP2_1_new: POP G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return KPOP_1_tc * h2 * POP2_1_new + +@numba.njit +def POP2_Diagenesis_2( +KPOP_2_tc: xr.DataArray, +h2: xr.DataArray, +POP2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Diagenesis_2: sediment diagenesis of PON G2 in sediment layer (g-P/m2/d) + + Args: + KPOP_2_tc: diagenesis rate of POP G2 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POP2_2_new: POP G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return KPOP_2_tc * h2 * POP2_2_new + +@numba.njit +def POP2_Diagenesis_3( +KPOP_3_tc: xr.DataArray, +h2: xr.DataArray, +POP2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Diagenesis_3: sediment diagenesis of PON G3 in sediment layer (g-P/m2/d) + + Args: + KPOP_3_tc: diagenesis rate of POP G3 in sediment layer 2 temperature corrected (1/d) + h2: active sediment layer (m) + POP2_3_new: POP G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return KPOP_3_tc * h2 * POP2_3_new + +@numba.njit +def POC2_Burial_1( +vb: xr.DataArray, +POC2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Burial_1: sediment diagenesis of POC G1 in sediment layer (g-C/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POC2_1_new: POC G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return vb * POC2_1_new + +@numba.njit +def POC2_Burial_2( +vb: xr.DataArray, +POC2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Burial_1: sediment diagenesis of POC G2 in sediment layer (g-C/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POC2_2_new: POC G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return vb * POC2_2_new + +@numba.njit +def POC2_Burial_3( +vb: xr.DataArray, +POC2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POC2_Burial_3: sediment diagenesis of POC G3 in sediment layer (g-C/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POC2_3_new: POC G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + + """ + + return vb * POC2_3_new + +@numba.njit +def PON2_Burial_1( +vb: xr.DataArray, +PON2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Burial_1: sediment diagenesis of PON G1 in sediment layer (g-N/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + PON2_1_new: PON G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return vb * PON2_1_new + +@numba.njit +def PON2_Burial_2( +vb: xr.DataArray, +PON2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Burial_2: sediment diagenesis of PON G2 in sediment layer (g-N/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + PON2_2_new: PON G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return vb * PON2_2_new + +@numba.njit +def PON2_Burial_3( +vb: xr.DataArray, +PON2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate PON2_Burial_3: sediment diagenesis of PON G3 in sediment layer (g-N/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + PON2_3_new: PON G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + + """ + + return vb * PON2_3_new + +@numba.njit +def POP2_Burial_1( +vb: xr.DataArray, +POP2_1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Burial_1: sediment diagenesis of POP G1 in sediment layer (g-P/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POP2_1_new: POP G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return vb * POP2_1_new + +@numba.njit +def POP2_Burial_2( +vb: xr.DataArray, +POP2_2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Burial_2: sediment diagenesis of POP G2 in sediment layer (g-P/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POP2_2_new: POP G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return vb * POP2_2_new + +@numba.njit +def POP2_Burial_3( +vb: xr.DataArray, +POP2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate POP2_Burial_3: sediment diagenesis of POP G3 in sediment layer (g-P/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + POP2_3_new: POP G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + + """ + + return vb * POP2_3_new + +@numba.njit +def JC( +POC2_Diagenesis_1: xr.DataArray, +POC2_Diagenesis_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JC: total sediment diagenesis flux of POC (g-C/m2/d) + + Args: + POC2_Diagenesis_1: sediment diagenesis of POC G1 in sediment layer (g-C/m2/d) + POC2_Diagenesis_2: sediment diagenesis of POC G2 in sediment layer (g-C/m2/d) + + """ + + return POC2_Diagenesis_1 + POC2_Diagenesis_2 + +@numba.njit +def JN( +PON2_Diagenesis_1: xr.DataArray, +PON2_Diagenesis_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JN: total sediment diagenesis flux of PON (g-N/m2/d) + + Args: + PON2_Diagenesis_1: sediment diagenesis of PON G1 in sediment layer (g-N/m2/d) + PON2_Diagenesis_2: sediment diagenesis of PON G2 in sediment layer (g-N/m2/d) + + """ + + return PON2_Diagenesis_1 + PON2_Diagenesis_2 + +@numba.njit +def JP( +POP2_Diagenesis_1: xr.DataArray, +POP2_Diagenesis_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JP: total sediment diagenesis flux of POP (g-P/m2/d) + + Args: + POP2_Diagenesis_1: sediment diagenesis of POP G1 in sediment layer (g-P/m2/d) + POP2_Diagenesis_2: sediment diagenesis of POP G2 in sediment layer (g-P/m2/d) + + """ + + return POP2_Diagenesis_1 + POP2_Diagenesis_2 + + +""" + # compute SOD + SOD_old =0 + # coefficients of a quadratic equation + ra2, ra1, ra0 =0 + #root of the quadratic equation + sn1, disc, r1, r2 =0 +""" + +@numba.njit +def BFORmax( +TsedC: xr.DataArray, +TempBen: xr.DataArray, +KsDp: xr.DataArray, +DOX: xr.DataArray, + +) -> xr.DataArray: + """Calculate BFORmax: maximum benthic stress oxygen correction coefficient (unitless) + + Args: + TsedC: sediment temperature (C) + TempBen: critical temperature for benthic stress (C) + KsDp: half-saturation constant for oxygen in particle mixing (mg-O2/L) + DOX: dissolved oxygen (mg-O/L) + """ + #TODO should this be 'new' + return xr.where (TsedC xr.DataArray: + """Calculate ST_new: Sediment Benthic Stress: Low DO will eliminate bioturbation. Particle phase mixing coefficient is modified (d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + TsedC: sediment temperature (C) + TempBen: critical temperature for benthic stress (C) + ST: Sediment Benthic Stress (d) + dt: timestep (d) + KsDp: half-saturation constant for oxygen in particle mixing (mg-O2/L) + DOX: dissolved oxygen (mg-O/L) + kst: decay rate of benthic stress (1/d) + BFORmax: maximum benthic stress oxygen correction coefficient (unitless) + """ + #TODO maybe a better way to do this. i do not even know if it is possible to get an nan value? + to_return = xr.where(SedFlux_solution_option == 1, 0.0, xr.where (TsedC xr.DataArray: + """Calculate w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + Dp_tc: particle mixing diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + h2: active sediment layer (m) + POC2_1_new: POC G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + POCr: reference POC G1 concentration for bioturbation (mg-C/L) + Css2: solids concentration in sediment layer 2 (kg/L) + TsedC: sediment temperature (C) + TempBen: critical temperature for benthic stress (C) + kst: decay rate of benthic stress (1/d) + ST_new: Sediment Benthic Stress: Low DO will eliminate bioturbation. Particle phase mixing coefficient is modified (d) + + """ + + to_return = xr.where(SedFlux_solution_option==1, Dp_tc/(0.5 *h2), xr.where(SedFlux_solution_option==2, Dp_tc / (0.5 * h2) * (POC2_1_new / (1000.0 * POCr * Css2),0))) + to_return = xr.where(TsedC>TempBen, to_return * (1-kst * ST_new),to_return) + to_return = xr.where(to_return <0, 0, to_return) + + #TODO the 1000 does not cancel with anything if that is what it is supposed to do + #TODO probably a better way to write this + return to_return + +@numba.njit +def KL12( +Dd_tc: xr.DataArray, +h2: xr.DataArray, + +) -> xr.DataArray: + """Calculate KL12: Dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + Args: + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + h2: active sediment layer (m) + + """ + + return xr.where(math.isnan(Dd_tc / (0.5 * h2)), 0 , Dd_tc / (0.5 * h2)) + +@numba.njit +def fds1( +Css1: xr.DataArray, +kdh2s2: xr.DataArray, + +) -> xr.DataArray: + """Calculate fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + + Args: + Css1: solids concentration in sediment layer 1 (kg/L) + kdh2s2: partition coefficient for sulfide in sediment layer 2 (L/kg) + + """ + + return 1.0 / (1.0 + Css1 * kdh2s2) + +@numba.njit +def fds2( +Css2: xr.DataArray, +kdh2s2: xr.DataArray, + +) -> xr.DataArray: + """Calculate fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + + Args: + Css2: solids concentration in sediment layer 1 (kg/L) + kdh2s2: partition coefficient for sulfide in sediment layer 2 (L/kg) + + """ + + return 1.0 / (1.0 + Css2 * kdh2s2) + +@numba.njit +def fps1( +fds1: xr.DataArray, + +) -> xr.DataArray: + """Calculate fps1: particulate fraction for H2S1 and H2S2 in layer 1 (unitless) + + Args: + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + + """ + + return 1.0 - fds1 + +@numba.njit +def fps2( +fds2: xr.DataArray, + +) -> xr.DataArray: + """Calculate fps2: particulate fraction for H2S1 and H2S2 in layer 2 (unitless) + + Args: + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + + """ + + return 1.0 - fds2 + +@numba.njit +def fdp2( +fds2: xr.DataArray, + +) -> xr.DataArray: + """Calculate fdp2: particulate fraction for H2S1 and H2S2 in layer 2 (unitless) + + Args: + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + + """ + + return 1.0 - fds2 + +@numba.njit +def fd1( +Css1: xr.DataArray, +kdnh42: xr.DataArray, + +) -> xr.DataArray: + """Calculate fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + + Args: + Css1: solids concentration in sediment layer 1 (kg/L) + kdnh42: partition coefficient for ammonium in sediment layer 2 (L/kg) + + """ + + return 1.0 / (1.0 + Css1 * kdnh42) + +@numba.njit +def fd2( +Css2: xr.DataArray, +kdnh42: xr.DataArray, + +) -> xr.DataArray: + """Calculate fd2: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 2 (unitless) + + Args: + Css2: solids concentration in sediment layer 2 (kg/L) + kdnh42: partition coefficient for ammonium in sediment layer 2 (L/kg) + + """ + + return 1.0 / (1.0 + Css2 * kdnh42) + +@numba.njit +def fp1( +fd1: xr.DataArray, + +) -> xr.DataArray: + """Calculate fp1: fraction of inorganic matter (ammonia, phosphate) in particulate form in sediment layer 1 (unitless) + + Args: + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + + """ + + return 1.0 - fd1 + +@numba.njit +def fp2( +fd2: xr.DataArray, + +) -> xr.DataArray: + """Calculate fp2: fraction of inorganic matter (ammonia, phosphate) in particulate form in sediment layer 2 (unitless) + + Args: + fd2: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 2 (unitless) + + """ + return 1.0 - fd2 + +@numba.njit +def TNH41( +NH41: xr.DataArray, +fd1: xr.DataArray, + +) -> xr.DataArray: + """Calculate THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + + Args: + NH41: NH4 seidment layer 1 (mg-N/L) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + + """ + return NH41 / fd1 + +@numba.njit +def TNH42( +NH42: xr.DataArray, +fd2: xr.DataArray, + +) -> xr.DataArray: + """Calculate THN42: total concentration NH4 dissolved layer 2 (mg-N/L) + + Args: + NH42: NH4 seidment layer 2 (mg-N/L) + fd2: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 2 (unitless) + + """ + return NH42 / fd2 + +@numba.njit +def FOxna( +DOX: xr.DataArray, +KsOxna1: xr.DataArray, + +) -> xr.DataArray: + """Calculate FOxna: nitrification attenuation due to low oxygen in layer 1 (unitless) + + Args: + DOX: dissolved oxgyen concentration (mg-O2/L) + KsOxna1: half-saturation oxygen constant for sediment nitrification (mg-O2/L) + + """ + return xr.where(math.isnan(DOX / (KsOxna1 * 2.0 + DOX)),0, DOX / (KsOxna1 * 2.0 + DOX)) + +@numba.njit +def con_nit( +vnh41_tc: xr.DataArray, +FOxna: xr.DataArray, +fd1: xr.DataArray, + +) -> xr.DataArray: + """Calculate con_nit: something nitrogen (m2/d2) #TODO define this + + Args: + vnh41_tc: nitrification reaction velocity in sediment layer 1 (m/d) + FOxna: nitrification attenuation due to low oxygen in layer 1 (unitless) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + + """ + return vnh41_tc * vnh41_tc * FOxna * fd1 + +@numba.njit +def a12_TNH4( +w12: xr.DataArray, +fp2: xr.DataArray, +KL12: xr.DataArray, +fd2: xr.DataArray, + +) -> xr.DataArray: + """Calculate a12_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + fp2: fraction of inorganic matter (ammonia, phosphate) in particulate form in sediment layer 2 (unitless) + KL12: KL12: Dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + fd2: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 2 (unitless) + + """ + return -w12 * fp2 - KL12 * fd2 + +@numba.njit +def a21_TNH4( +w12: xr.DataArray, +fp1: xr.DataArray, +KL12: xr.DataArray, +fd1: xr.DataArray, +vb: xr.DataArray, + +) -> xr.DataArray: + """Calculate a12_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + fp1: fraction of inorganic matter (ammonia, phosphate) in particulate form in sediment layer 1 (unitless) + KL12: KL12: Dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + """ + return -w12 * fp1 - KL12 * fd1 - vb + +@numba.njit +def a22_TNH4( +SedFlux_solution_option: xr.DataArray, +a12_TNH4: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +vb: xr.DataArray, + +) -> xr.DataArray: + """Calculate a22_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + a12_TNH4: coefficents for implicit finite difference form for TNH4 (m/d) + h2: active sediment layer (m) + dt: timestep (d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + """ + return xr.where(SedFlux_solution_option == 1, -a12_TNH4 + vb, -a12_TNH4 + vb + h2 / dt) + +@numba.njit +def b2_TNH4( +SedFlux_solution_option: xr.DataArray, +JN: xr.DataArray, +TNH42: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +vb: xr.DataArray, + +) -> xr.DataArray: + """Calculate b2_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JN: total sediment diagenesis flux of PON (g-N/m2/d) + THN42: total concentration NH4 dissolved layer 2 (mg-N/L) + h2: active sediment layer (m) + dt: timestep (d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + """ + return xr.where(SedFlux_solution_option == 1, JN, JN + h2 * TNH42 / dt) + +@numba.njit +def a12_NO3( +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate a12_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + KL12: issolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + return -KL12 + +@numba.njit +def a21_NO3( +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate a21_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + KL12: issolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + return -KL12 + +@numba.njit +def a22_NO3( +SedFlux_solution_option: xr.DataArray, +KL12: xr.DataArray, +vno32_tc: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate a22_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d)) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + h2: active sediment layer (m) + vno32_tc: nitrification reaction velocity in sediment layer 3 temperature correction (m/d). + dt: timestep (d) + KL12: issolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + return xr.where(SedFlux_solution_option == 1, KL12 + vno32_tc, KL12 + vno32_tc + h2 / dt) + +@numba.njit +def b2_NO3( +SedFlux_solution_option: xr.DataArray, +NO32: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate b2_NO3: coefficents for implicit finite difference form for No3 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + h2: active sediment layer (m) + dt: timestep (d) + NO32: nitrate concentration sediment layer 2 (mg-N/L) + + """ + return xr.where(SedFlux_solution_option == 1, 0.0, h2 * NO32 / dt) + +@numba.njit +def SO4( +Salinity: xr.DataArray, +roso4: xr.DataArray, +SO4_fresh: xr.DataArray, + +) -> xr.DataArray: + """Calculate SO4: estimate based on salinity for salt water (mg-O2/L) + + Args: + Salinity: water salinity (ppt) + roso4: oxygen stoichiometric coeff for sulfate SO4 (g-O2/g-SO4) + SO4_fresh: SO4 concentration of overlaying water column in freshwater. User-defined if not simulated for fresh water (mg-O2/L) + + """ + #TODO make sure this does not have to be SO4_new and that the units are correct + #TODO find the formula for if true + return xr.where(Salinity > 0.01, (20.0 + 27.0 / 190.0 * 607.445 * Salinity) * roso4, SO4_fresh) + +@numba.njit +def HSO4_new ( +POCdiagenesis_part_option: xr.DataArray, +t: xr.DataArray, +Dd_tc: xr.DataArray, +SO4: xr.DataArray, +h2: xr.DataArray, +roc: xr.DataArray, +JC: xr.DataArray, +JCc: xr.DataArray, + +) -> xr.DataArray: + """Calculate HSO4_new: previous timestep SO42 concentration in sediment layer 2 (mg-O/L) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + t: #TODO what is this time something? + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + SO4: SO4: estimate based on salinity for salt water (mg-O2/L) + h2: active sediment layer (m) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + JC: total sediment diagenesis flux of POC (g-C/m2/d) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + + """ + #TODO possibly better way to code + + to_return = xr.where(POCdiagenesis_part_option == 2 and t< 1.0E-10, math.sqrt(Dd_tc * SO4 * h2 / (max(roc * JC, 1.0E-10))), + xr.where(POCdiagenesis_part_option==1, math.sqrt(2.0 * Dd_tc * SO4 * h2 / JCc), "NaN")) + to_return = xr.where(to_return > h2, h2, to_return) + return to_return + +@numba.njit +def con_sox ( +vh2sd_tc: xr.DataArray, +fds1: xr.DataArray, +vh2sp_tc: xr.DataArray, +fps1: xr.DataArray, +DOX: xr.DataArray, +KSh2s: xr.DataArray, + +) -> xr.DataArray: + """Calculate con_sox: #TODO define that this is () + + Args: + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + vh2sd_Tc: dissolve sulfide oxidation reaction velocity in sediment layer 1 (m/d) + vh2sp_tc: particulate sulfide oxidation reaction veolcoity in sediment layer 1 (m/d) + fps1: particulate fraction for H2S1 and H2S2 in layer 1 (unitless) + DOX: dissolved oxgyen concentration (mg-O2/L) + KSh2s: sulfide oxidation normalization constant (mg-O2/L) + + + """ + #TODO possibly better way to code + + return xr.where(math.isnan((vh2sd_tc * vh2sd_tc * fds1 + vh2sp_tc * vh2sp_tc * fps1) * DOX / 2.0 / KSh2s), + (vh2sd_tc * vh2sd_tc * fds1 + vh2sp_tc * vh2sp_tc * fps1), + (vh2sd_tc * vh2sd_tc * fds1 + vh2sp_tc * vh2sp_tc * fps1) * DOX / 2.0 / KSh2s) + +@numba.njit +def a12_SO4 ( +KL12: xr.DataArray, + + +) -> xr.DataArray: + """Calculate a12_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + + """ + return -KL12 + +@numba.njit +def a21_SO4 ( +KL12: xr.DataArray, + + +) -> xr.DataArray: + """Calculate a12_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + + """ + return KL12 + +@numba.njit +def a22_SO4 ( +POCdiagenesis_part_option: xr.DataArray, +KL12: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate a22_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + h2: active sediment layer (m) + dt: timestep (d) + + """ + return xr.where(POCdiagenesis_part_option==2, + xr.where(SedFlux_solution_option == 1, -KL12, -KL12 - h2/dt), "NaN") + +@numba.njit +def a12_TH2S ( +POCdiagenesis_part_option: xr.DataArray, +w12: xr.DataArray, +fps2: xr.DataArray, +KL12: xr.DataArray, +fds2: xr.DataArray, + +) -> xr.DataArray: + """Calculate a12_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + fps2: particulate fraction for H2S1 and H2S2 in layer 2 (unitless) + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + """ + + return xr.where(POCdiagenesis_part_option==2, -w12 * fps2 - KL12 * fds2, "NaN") + +@numba.njit +def a21_TH2S ( +POCdiagenesis_part_option: xr.DataArray, +w12: xr.DataArray, +fps1: xr.DataArray, +KL12: xr.DataArray, +fds1: xr.DataArray, +vb: xr.DataArray, + +) -> xr.DataArray: + """Calculate a21_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + fps1: particulate fraction for H2S1 and H2S2 in layer 1 (unitless) + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + """ + + return xr.where(POCdiagenesis_part_option==2, -w12 * fps1 - KL12 * fds1 - vb, "NaN") + +@numba.njit +def a22_TH2S ( +SedFlux_solution_option: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, +vb: xr.DataArray, +a12_TH2S: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate a21_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + a12_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + h2: active sediment layer (m) + dt: timestep (d) + """ + + return xr.where(POCdiagenesis_part_option==2, + xr.where(SedFlux_solution_option==1, -a12_TH2S + vb, -a12_TH2S + vb + h2 / dt), "NaN") + + +""" +#TODO do I need preserve? +TH2S1_prev = TH2S1 +HSO4_prev = HSO4 +SO42_prev = SO42 +CH42_prev = CH42 +""" +@numba.njit +def CH4sat( +depth: xr.DataArray, +TsedC: xr.DataArray + +) -> xr.DataArray: + """Calculate CH4sat: saturated concentration of methane in oxygen equivalents (mg-O2/L) + + Args: + depth: water depth (m) + TsedC: temperature sediment (C) + """ + + return 100.0 * (1.0 + depth / 10.0) * 1.024**(20.0 - TsedC) + +@numba.njit +def FOxch( +Methane_solution_option: xr.DataArray, +DOX: xr.DataArray, +KsOxch: xr.DataArray, + +) -> xr.DataArray: + """Calculate FOxch: methane oxidation attenuation due to low oxygen in layer 1 (unitless) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) (unitless) + DOX: dissolved oxgyen concentration (mg-O2/L) + KsOxch: half-saturation coefficient for oxygen in oxidation of methane (mg-O2/L) + + """ + + return xr.where(Methane_solution_option ==2, + xr.where(math.nan(DOX / (KsOxch * 2.0 + DOX)), 0.0, DOX / (KsOxch * 2.0 + DOX))) + +@numba.njit +def con_cox( +Methane_solution_option: xr.DataArray, +vch41_tc: xr.DataArray, +FOxch: xr.DataArray, + +) -> xr.DataArray: + """Calculate con_cox: #TODO define that this is () + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) (unitless) + DOX: dissolved oxgyen concentration (mg-O2/L) + FOxch: methane oxidation attenuation due to low oxygen in layer 1 (unitless) + vch41_tc: methane oxidation reaction velocity in sediment layer 1 temperature corrected (m/d) + """ + + return xr.where(Methane_solution_option ==2,vch41_tc * vch41_tc * FOxch, "NaN") + +@numba.njit +def a12_CH4( +Methane_solution_option: xr.DataArray, +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate a12_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) (unitless) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + """ + + return xr.where(Methane_solution_option ==2,-KL12, "NaN") + +@numba.njit +def a21_CH4( +Methane_solution_option: xr.DataArray, +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate a21_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) (unitless) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + """ + + return xr.where(Methane_solution_option ==2,-KL12, "NaN") + +@numba.njit +def a22_CH4( +Methane_solution_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +KL12: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate a22_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + h2: active Sediment layer thickness (m) + dt: time (d) + """ + + return xr.where(Methane_solution_option ==2, + xr.where(SedFlux_solution_option == 1, KL12, KL12 + h2/dt), "NaN") #TODO make sure the NaN is appropriate since there is not alternative + + +""" + + #compute SOD + for i in (1, int(maxit)) : + #TNH41 and TNH42 +""" + +@numba.njit +def FNH4( +KsNh4: xr.DataArray, +fd1: xr.DataArray, +TNH41: xr.DataArray, + +) -> xr.DataArray: + """Calculate FNH4: modification of nitrification reaction in layer 1 (unitless) + + Args: + KsNh4: half-saturation ammonia constant for sediment nitrification (mg-N/L) + THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + + """ + return xr.where(KsNh4>0, KsNh4 / (KsNh4 + fd1 * TNH41), 1) + +#TODO is there a better way to do this, same calculation +@numba.njit +def TNH41_new( +TNH41: xr.DataArray, +TNH42: xr.DataArray, +a12_TNH4: xr.DataArray, +a21_TNH4: xr.DataArray, +a22_TNH4: xr.DataArray, +b2_TNH4: xr.DataArray, +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +fd1: xr.DataArray, +NH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + + Args: + THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + THN42: total concentration NH4 dissolved layer 2 (mg-N/L) + a12_TNH4: coefficents for implicit finite difference form for TNH4 (m/d) + a12_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + b2_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + con_nit: something nitrogen (m2/d2) #TODO define this + FNH4: modification of nitrification reaction in layer 1 (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + NH4: Ammonium water concentration (mg-N/L) + + """ + a11= a21_TNH4 + con_nit * FNH4 / KL01 + KL01 * fd1 + b1 = KL01 * NH4 + TNH41_new, TNH42_new = MatrixSolution(TNH41, TNH42, a11, a12_TNH4, b1, a21_TNH4, a22_TNH4, b2_TNH4) + + return max(TNH41_new,0.00) + +@numba.njit +def TNH42_new( +TNH41: xr.DataArray, +TNH42: xr.DataArray, +a12_TNH4: xr.DataArray, +a21_TNH4: xr.DataArray, +a22_TNH4: xr.DataArray, +b2_TNH4: xr.DataArray, +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +fd1: xr.DataArray, +NH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate THN42_new: total concentration NH4 dissolved layer 2 (mg-N/L) + + Args: + THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + THN42: total concentration NH4 dissolved layer 2 (mg-N/L) + a12_TNH4: coefficents for implicit finite difference form for TNH4 (m/d) + a12_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (m/d) + b2_TNH4: coefficents for implicit finite difference form for TNH4 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + con_nit: something nitrogen (m2/d2) #TODO define this + FNH4: modification of nitrification reaction in layer 1 (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + NH4: Ammonium water concentration (mg-N/L) + + """ + a11= a21_TNH4 + con_nit * FNH4 / KL01 + KL01 * fd1 + b1 = KL01 * NH4 + TNH41_new, TNH42_new = MatrixSolution(TNH41, TNH42, a11, a12_TNH4, b1, a21_TNH4, a22_TNH4, b2_TNH4) + + return max(TNH42_new,0.00) + +@numba.njit +def NO31_new( +NO31: xr.DataArray, +NO32: xr.DataArray, +TNH41: xr.DataArray, +a12_NO3: xr.DataArray, +a21_NO3: xr.DataArray, +a22_NO3: xr.DataArray, +b2_NO3: xr.DataArray, +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +NO3: xr.DataArray, +vno31_tc: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO31_new: new NO3 sediment layer 1 (mg-N/L) + Args: + THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + a12_NO3: coefficents for implicit finite difference form for NO3 (m/d) + a12_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + a22_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + b2_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + con_nit: something nitrogen (m2/d2) #TODO define this + FNH4: modification of nitrification reaction in layer 1 (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + NO3: Nitrate water concentration (mg-N/L) + vno31_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d) + NO31: NO3 sediment layer 1 (mg-N/L) + NO32: NO3 sediment layer 2 (mg-N/L) + + """ + a11 = -a21_NO3 + vno31_tc * vno31_tc / KL01 + KL01 + b1 = con_nit * FNH4 / KL01 * TNH41 + KL01 * NO3 + NO31_new, NO32_new = MatrixSolution(NO31, NO32, a11, a12_NO3, b1, a21_NO3, a22_NO3, b2_NO3) + + return max(NO31_new, 0.0) + +@numba.njit +def NO32_new( +NO31: xr.DataArray, +NO32: xr.DataArray, +TNH41: xr.DataArray, +a12_NO3: xr.DataArray, +a21_NO3: xr.DataArray, +a22_NO3: xr.DataArray, +b2_NO3: xr.DataArray, +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +NO3: xr.DataArray, +vno31_tc: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO32_new: new NO3 sediment layer 2 (mg-N/L) + + Args: + THN41: total concentration NH4 dissolved layer 1 (mg-N/L) + a12_NO3: coefficents for implicit finite difference form for NO3 (m/d) + a12_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + a22_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (m/d) + b2_NO3: coefficents for implicit finite difference form for NO3 (a11, a12, a21, a22, b1, b2) (g-N/m2/d) + con_nit: something nitrogen (m2/d2) #TODO define this + FNH4: modification of nitrification reaction in layer 1 (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + NO3: Nitrate water concentration (mg-N/L) + vno31_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d) + NO31: NO3 sediment layer 1 (mg-N/L) + NO32: NO3 sediment layer 2 (mg-N/L) + + """ + a11 = -a21_NO3 + vno31_tc * vno31_tc / KL01 + KL01 + b1 = con_nit * FNH4 / KL01 * TNH41 + KL01 * NO3 + NO31_new, NO32_new = MatrixSolution(NO31, NO32, a11, a12_NO3, b1, a21_NO3, a22_NO3, b2_NO3) + + return max(NO32_new, 0.0) + +@numba.njit +def JC_dn( +NO31: xr.DataArray, +rondn: xr.DataArray, +vno31_tc: xr.DataArray, +KL01: xr.DataArray, +vno32_tc: xr.DataArray, +NO32: xr.DataArray, + +) -> xr.DataArray: + """Calculate JC_dn: carbon (oxygen equivalents) consumbed by denitrification (g-O2/m2/d) + + Args: + NO31: NO3 sediment layer 1 (mg-N/L) + NO32: NO3 sediment layer 2 (mg-N/L) + vno31_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d) + vno32_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d) + rondn: oxygen stoichiometric coeff for denitrification (g-O2/g-N) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + """ + + return rondn * (vno31_tc * vno31_tc / KL01 * NO31 + vno32_tc * NO32) + +@numba.njit +def JCc( +roc: xr.DataArray, +JC: xr.DataArray, +JC_dn: xr.DataArray, + +) -> xr.DataArray: + """Calculate JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + + Args: + roc: oxygen stoichiometric coeff for organic carbon decay (g-O2/g-C) + JC: total sediment diagenesis flux of POC (g-C/m2/d) + JC_dn: carbon (oxygen equivalents) consumbed by denitrification (g-O2/m2/d) + """ + + return max(roc * JC - JC_dn, 1.0E-10) + + +def MatrixSolution(x1, x2, a11, a12, b1, a21, a22, b2): + x1 = x1 + x2 = x2 + a11 = a11 + a12 = a12 + b1 = b1 + a21 = a21 + a22 = a22 + b2 = b2 + + if (a11 * a22 - a12 * a21 == 0.0): + print('Twod is singular: A11,A12,A21,A22') + print('a11, a12, a21, a22') + + x1 = (a22 * b1 - a12 * b2) / (a11 * a22 - a12 * a21) + x2 = (a11 * b2 - a21 * b1) / (a11 * a22 - a12 * a21) + return x1, x2 + +""" + # NO31 and NO32 + + # SO41, SO42 and TH2S1, TH2S2 + #coefficients for SO41, SO42, H2S1 and H2S2 equations + + bx=[0]*4 + ad=[(0,0,0,0),(0,0,0,0), (0,0,0,0), (0,0,0,0)] # 4x4 + + #coefficients for SO41 and SO42 equations + g=[0]*2 + h=[(0,0),(0,0)] #2x2 +""" +@numba.njit +def HSO4_new( +POCdiagenesis_part_option: xr.DataArray, +Dd_tc: xr.DataArray, +SO4: xr.DataArray, +h2: xr.DataArray, +JCc: xr.DataArray, +ra1: xr.DataArray, +ra2: xr.DataArray, +ra0: xr.DataArray, + +) -> xr.DataArray: + """Calculate HSO4_new: hydrogen sulfate water concentration (TODO units) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + SO4: sulfate water concentration (mg-O2/L) + h2: h2: active Sediment layer thickness (m) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + ra1: first order quadratic equation coefficent for when POCdiagenesis_part_option==2 + ra2: second order quadratic equation coefficent for when POCdiagenesis_part_option==2 + ra0: quadratic equation coefficent for when POCdiagenesis_part_option==2 + """ + HSO4_new=xr.where(POCdiagenesis_part_option == 1, math.sqrt(2.0 * Dd_tc * SO4 * h2 / JCc), + xr.where(SO4 <= 0.1, 0.0, (- ra1 + math.sqrt(ra1 * ra1 - 4.0 * ra2 * ra0)) / 2.0 / ra2)) + HSO4_new=xr.where(HSO4_new > h2, h2, HSO4_new) + + return HSO4_new + +def KL12SO4( +POCdiagenesis_part_option: xr.DataArray, +Dd_tc: xr.DataArray, +SO4: xr.DataArray, +h2: xr.DataArray, +HSO4_new: xr.DataArray, +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + SO4: sulfate water concentration (mg-O2/L) + h2: active Sediment layer thickness (m) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + HSO4_new: TODO define this + + """ + + return xr.where (POCdiagenesis_part_option==1, + xr.where(HSO4_new ==0.0, 1, Dd_tc / (0.5 * HSO4_new)), + xr.where(SO4 <= 0.1,1, + xr.where(HSO4_new==h2, KL12, Dd_tc / (0.5 * HSO4_new)))) +""" +four equations, only solved when POCdiagenesis_part_option==1 +0 = bx_1 + ad_1_1 * SO41 + ad_1_2 * SO42 + ad_1_3 * TH2S1 +0 = bx_2 + ad_2_1 * SO41 + ad_2_2 * SO42 - JCc * SO42 / (SO42 + KsSO4) +0 = bx_3 + ad_3_3 * TH2S1 + ad_3_4 * TH2S2 +0 = bx_4 + ad_4_3 * TH2S1 + ad_4_4 * TH2S2 + JCc * SO42 / (SO42 + KsSO4) + +""" + +@numba.njit +def bx_1( +KL01: xr.DataArray, +SO4: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, + +) -> xr.DataArray: + """Calculate bx_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO4: sulfate water concentration (mg-O2/L) + """ + + return xr.where(POCdiagenesis_part_option==1,KL01 * SO4,"NaN") + +@numba.njit +def bx_3( +KL01: xr.DataArray, +H2S: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, + +) -> xr.DataArray: + """Calculate bx_3: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + H2S: sulfide water concentration (mg-O2/L) + """ + + return xr.where(POCdiagenesis_part_option==1,KL01 * H2S,"NaN") + +@numba.njit +def ad_1_1( +KL01: xr.DataArray, +KL12SO4: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_1_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + """ + + return xr.where(POCdiagenesis_part_option==1,KL01 - KL12SO4,"NaN") + +@numba.njit +def ad_1_2( +KL12SO4: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_1_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + """ + + return xr.where(POCdiagenesis_part_option==1,KL12SO4,"NaN") + +@numba.njit +def ad_1_3( +con_sox: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, +KL01: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_1_3: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + con_sox: #TODO define that this is () + """ + + return xr.where(POCdiagenesis_part_option==1,con_sox / KL01,"NaN") + +@numba.njit +def ad_3_3( +con_sox: xr.DataArray, +POCdiagenesis_part_option: xr.DataArray, +KL01: xr.DataArray, +vb: xr.DataArray, +fps1: xr.DataArray, +w12: xr.DataArray, +fds1: xr.DataArray, +KL12SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_3_3: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + con_sox: #TODO define that this is () + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + fps1: particulate fraction for H2S1 and H2S2 in layer 1 (unitless) + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + """ + + return xr.where(POCdiagenesis_part_option==1,- vb - fps1 * w12 - fds1 * KL01 - fds1 * KL12SO4 - con_sox / KL01,"NaN") + +@numba.njit +def ad_3_4( +POCdiagenesis_part_option: xr.DataArray, +fps2: xr.DataArray, +w12: xr.DataArray, +fds2: xr.DataArray, +KL12SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_3_4: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + fps2: particulate fraction for H2S1 and H2S2 in layer 2 (unitless) + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + """ + + return xr.where(POCdiagenesis_part_option==1,w12 * fps2 + KL12SO4 * fds2,"NaN") + +@numba.njit +def ad_2_1( +POCdiagenesis_part_option: xr.DataArray, +KL12SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_2_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + + """ + + return xr.where(POCdiagenesis_part_option==1, KL12SO4,"NaN") + +@numba.njit +def ad_4_3( +POCdiagenesis_part_option: xr.DataArray, +vb: xr.DataArray, +fps1: xr.DataArray, +w12: xr.DataArray, +fds1: xr.DataArray, +KL12SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_4_3: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + fps1: particulate fraction for H2S1 and H2S2 in layer 1 (unitless) + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + + """ + + return xr.where(POCdiagenesis_part_option==1, vb + fps1 * w12 + fds1 * KL12SO4,"NaN") + +@numba.njit +def ad_2_2( +POCdiagenesis_part_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +KL12SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_2_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + h2: active Sediment layer thickness (m) + dt: time (d) + + """ + + return xr.where(POCdiagenesis_part_option==1, + xr.where(SedFlux_solution_option==1, - KL12SO4, - KL12SO4 - h2 / dt),"NaN") + +@numba.njit +def bx_2( +POCdiagenesis_part_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +SO42: xr.DataArray, + +) -> xr.DataArray: + """Calculate bx_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + SO42: SO4 in sediment in layers 2 (mg-O/L) + h2: active Sediment layer thickness (m) + dt: time (d) + + """ + + return xr.where(POCdiagenesis_part_option==1, + xr.where(SedFlux_solution_option==1, 0.0, h2 * SO42 / dt),"NaN") + +@numba.njit +def ad_4_4( +POCdiagenesis_part_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +fps2: xr.DataArray, +w12: xr.DataArray, +fds2: xr.DataArray, +KL12SO4: xr.DataArray, +vb: xr.DataArray, + +) -> xr.DataArray: + """Calculate ad_4_4: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + fps2: particulate fraction for H2S1 and H2S2 in layer 2 (unitless) + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + h2: active Sediment layer thickness (m) + dt: time (d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + + """ + + return xr.where(POCdiagenesis_part_option==1, + xr.where(SedFlux_solution_option==1, - vb - KL12SO4 * fds2 - w12 * fps2, - vb - KL12SO4 * fds2 - w12 * fps2 - h2 / dt),"NaN") + +@numba.njit +def bx_4( +POCdiagenesis_part_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +TH2S2: xr.DataArray, + +) -> xr.DataArray: + """Calculate bx_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + TH2S2: TH2S sediment layer 2 (mg-O/L) + h2: active Sediment layer thickness (m) + dt: time (d) + + """ + + return xr.where(POCdiagenesis_part_option==1, + xr.where(SedFlux_solution_option==1, 0.0, h2 * TH2S2 / dt),"NaN") + +""" +eliminate H2ST1 and H2ST2 from above equation sets, get two equations +0 = g_1 + h_1_1 * SO41 + h_1_2_ * SO42 +0 = g_2 + h_2_1 * SO41 + h_2_2 * SO42 + JCc * SO42 / (SO42 + KsSO4) +""" + +@numba.njit +def g_2( +POCdiagenesis_part_option: xr.DataArray, +bx_1: xr.DataArray, +ad_3_3: xr.DataArray, +ad_1_3: xr.DataArray, +bx_3: xr.DataArray, +ad_4_4: xr.DataArray, +ad_3_4: xr.DataArray, +ad_4_3: xr.DataArray, +bx_4: xr.DataArray, + +) -> xr.DataArray: + """Calculate g_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + bx_1, ad_3_3, ad_1_3, bx_3,ad_4_4, ad_3_4, ad_4_3, bx_4: coefficents for system of equation + + """ + + return xr.where(POCdiagenesis_part_option==1, ((bx_1 * ad_3_3 - ad_1_3 * bx_3) * ad_4_4 - bx_1 * ad_3_4 * ad_4_3) / (ad_1_3 * ad_3_4) + bx_4 ,"NaN") + +@numba.njit +def g_1( +POCdiagenesis_part_option: xr.DataArray, +g_2: xr.DataArray, +bx_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate g_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + bx_2, g_2: coefficents for system of equation + + """ + + return xr.where(POCdiagenesis_part_option==1, g_2+bx_2 ,"NaN") + +@numba.njit +def h_2_1( +POCdiagenesis_part_option: xr.DataArray, +ad_1_1: xr.DataArray, +ad_3_3: xr.DataArray, +ad_4_4: xr.DataArray, +ad_3_4: xr.DataArray, +ad_4_3: xr.DataArray, +ad_1_3: xr.DataArray, + +) -> xr.DataArray: + """Calculate h_2_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ad_1_1, ad_3_3, ad_4_4, ad_3_4, ad_4_3, ad_1_3: coefficents for system of equation + + """ + return xr.where(POCdiagenesis_part_option==1, ad_1_1 * (ad_3_3 * ad_4_4 - ad_3_4 * ad_4_3) / (ad_1_3 * ad_3_4) ,"NaN") + +@numba.njit +def h_2_2( +POCdiagenesis_part_option: xr.DataArray, +ad_3_3: xr.DataArray, +ad_4_4: xr.DataArray, +ad_3_4: xr.DataArray, +ad_4_3: xr.DataArray, +ad_1_3: xr.DataArray, +ad_1_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate h_2_2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ad_1_2, ad_3_3, ad_4_4, ad_3_4, ad_4_3, ad_1_3: coefficents for system of equation + + """ + return xr.where(POCdiagenesis_part_option==1, ad_1_2 * (ad_3_3 * ad_4_4 - ad_3_4 * ad_4_3) / (ad_1_3 * ad_3_4) ,"NaN") + +@numba.njit +def h_1_1( +POCdiagenesis_part_option: xr.DataArray, +h_2_1: xr.DataArray, +ad_2_1: xr.DataArray, + +) -> xr.DataArray: + """Calculate h_1_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_2_1, ad_2_1: coefficents for system of equation + + """ + return xr.where(POCdiagenesis_part_option==1, h_2_1 + ad_2_1 ,"NaN") + +@numba.njit +def h_1_2( +POCdiagenesis_part_option: xr.DataArray, +h_2_2: xr.DataArray, +ad_2_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate h_1_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_2_2, ad_2_2: coefficents for system of equation + + """ + return xr.where(POCdiagenesis_part_option==1, h_2_2 + ad_2_2 ,"NaN") + +""" +eliminate SO41 and get a quadratic equation of SO42 +ra2 * SO42 * SO42 + ra1 * SO42 + ra0 = 0.0 +""" +@numba.njit +def ra0_POC_1( +POCdiagenesis_part_option: xr.DataArray, +h_1_1: xr.DataArray, +g_2: xr.DataArray, +h_2_1: xr.DataArray, +g_1: xr.DataArray, +KsSO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra0_POC_1: quadratic equation coefficent (constant) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_1_1, g_2, h_2_1, g_1: coefficents for system of equation + KsSO4: half-saturation constant for sulfate in sulfate reduction (mg-O2/L) + + """ + return xr.where(POCdiagenesis_part_option==1, (h_1_1 * g_2 - h_2_1 * g_1) * KsSO4 ,"NaN") + +@numba.njit +def ra1_POC_1( +POCdiagenesis_part_option: xr.DataArray, +h_1_1: xr.DataArray, +g_2: xr.DataArray, +h_2_1: xr.DataArray, +g_1: xr.DataArray, +KsSO4: xr.DataArray, +JCc: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra1_POC_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_1_1, g_2, h_2_1, g_1: coefficents for system of equation + KsSO4: half-saturation constant for sulfate in sulfate reduction (mg-O2/L) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + """ + return xr.where(POCdiagenesis_part_option==1, h_1_1 * g_2 - h_2_1 * g_1 + (h_1_1 * h_2_2 - h_1_2 * h_2_1) * KsSO4 + h_1_1 * JCc,"NaN") + +@numba.njit +def ra2_POC_1( +POCdiagenesis_part_option: xr.DataArray, +h_1_1: xr.DataArray, +h_2_1: xr.DataArray, +h_2_2: xr.DataArray, +h_1_2: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra2_POC_1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_1_1, h_2_1, h_1_2, h_2_2: coefficents for system of equation + """ + return xr.where(POCdiagenesis_part_option==1, h_1_1 * h_2_2 - h_1_2 * h_2_1,"NaN") + +@numba.njit +def sn1( +POCdiagenesis_part_option: xr.DataArray, +ra1_POC_1: xr.DataArray, + +) -> xr.DataArray: + """Calculate sn1: roots to quadratic equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ra1_POC_1: equation coefficent + """ + return xr.where(POCdiagenesis_part_option==1, + xr.where(ra1_POC_1 <= 0.00, -1,1)) + +@numba.njit +def disc( +POCdiagenesis_part_option: xr.DataArray, +ra0_POC_1: xr.DataArray, +ra1_POC_1: xr.DataArray, +ra2_POC_1: xr.DataArray, + +) -> xr.DataArray: + """Calculate disc: roots to quadratic equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ra0_POC_1, ra1_POC_1, ra2_POC_1 : equation coefficent + """ + return xr.where(POCdiagenesis_part_option==1, (- ra1_POC_1 - sn1 * math.sqrt(ra1_POC_1 * ra1_POC_1 - 4.0 * ra2_POC_1 * ra0_POC_1)) / 2.0, "NaN") + +@numba.njit +def r1( +POCdiagenesis_part_option: xr.DataArray, +ra0_POC_1: xr.DataArray, +ra1_POC_1: xr.DataArray, +ra2_POC_1: xr.DataArray, +disc: xr.DataArray, + +) -> xr.DataArray: + """Calculate r1: roots to quadratic equation + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ra0_POC_1, ra1_POC_1, ra2_POC_1 : equation coefficent + disc: roots to quadratic equation + """ + return xr.where(POCdiagenesis_part_option==1, + xr.where(disc != 0.0, disc/ra2_POC_1, + xr.where(ra2_POC_1==0.0, -ra0_POC_1/ra1_POC_1, -ra1_POC_1/ra2_POC_1)), "NaN") + +@numba.njit +def r2( +POCdiagenesis_part_option: xr.DataArray, +ra0_POC_1: xr.DataArray, +r1: xr.DataArray, +ra2_POC_1: xr.DataArray, +disc: xr.DataArray, + +) -> xr.DataArray: + """Calculate r2: roots to quadratic equation + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + ra0_POC_1, ra1_POC_1, ra2_POC_1 : equation coefficent + disc,r1: roots to quadratic equation + """ + return xr.where(POCdiagenesis_part_option==1, + xr.where(disc != 0.0, ra0_POC_1/disc, + xr.where(ra2_POC_1==0.0, -r1, 0.0)), "NaN") + +@numba.njit +def SO42_new( +POCdiagenesis_part_option: xr.DataArray, +r1: xr.DataArray, +r2: xr.DataArray, +h2: xr.DataArray, +KL01: xr.DataArray, +KL12: xr.DataArray, +SO4: xr.DataArray, +CSOD_H2S: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc: xr.DataArray, +SO41: xr.DataArray, +SO42: xr.DataArray, +HSO4: xr.DataArray, +dt: xr.DataArray, +a12_SO4: xr.DataArray, +a21_SO4: xr.DataArray, +a22_SO4: xr.DataArray, +HSO4_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + disc,r1,r2: roots to quadratic equation + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + h2: active Sediment layer thickness (m) + dt: time (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO4: sulfate water concentration (mg-O2/L) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + HSO4_new: hydrogen sulfate water concentration (TODO units) + CSOD_H2S: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SO41: SO4 concentration in sediment in layers 1 (mg-O/L) + SO42: SO4 concentration in sediment in layers (mg-O/L) + HSO4: hydrogen sulfate water concentration (TODO units) + a12_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + a21_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + """ + a11=KL01 + KL12 + b1 = KL01 * SO4 + CSOD_H2S + b2 = xr.where(SedFlux_solution_option == 1,JCc, JCc - SO42* HSO4 / dt) + hold, SO42_new = MatrixSolution(SO41, SO42, a11, a12_SO4, b1, a21_SO4, a22_SO4, b2) + SO42_new=xr.where(HSO4_new==h2, max(SO42_new,0.0), SO41 / 2.0) + + return xr.where(POCdiagenesis_part_option==1, + xr.where(r1<0.0, r2,r1), + xr.where(SO4<=0.1, SO4, SO42_new)) + +@numba.njit +def SO41_new( +POCdiagenesis_part_option: xr.DataArray, +g_1: xr.DataArray, +h_1_2: xr.DataArray, +SO42_new: xr.DataArray, +h_1_1: xr.DataArray, +h2: xr.DataArray, +KL01: xr.DataArray, +KL12: xr.DataArray, +SO4: xr.DataArray, +CSOD_H2S: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc: xr.DataArray, +SO41: xr.DataArray, +SO42: xr.DataArray, +HSO4: xr.DataArray, +dt: xr.DataArray, +a12_SO4: xr.DataArray, +a21_SO4: xr.DataArray, +a22_SO4: xr.DataArray, +KL12SO4: xr.DataArray, +HSO4_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate SO41_new: new SO4 concentration in sediment in layers 1 (mg-O/L) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + h_1_1, h_1_2, g_1: coefficents for system of equation + SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + TH2S2: TH2S sediment layer 2 (mg-O/L) + h2: active Sediment layer thickness (m) + dt: time (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + SO4: sulfate water concentration (mg-O2/L) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + HSO4_new: hydrogen sulfate water concentration (TODO units) + CSOD_H2S: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SO41: SO4 concentration in sediment in layers 1 (mg-O/L) + SO42: SO4 concentration in sediment in layers (mg-O/L) + HSO4: hydrogen sulfate water concentration (TODO units) + a12_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + a21_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_SO4: coefficents for implicit finite difference form for SO4 (a11, a12, a21, a22, b1, b2) (m/d) + + """ + a11=KL01 + KL12 + b1 = KL01 * SO4 + CSOD_H2S + b2 = xr.where(SedFlux_solution_option == 1,JCc, JCc - SO42* HSO4 / dt) + SO41_new, hold = MatrixSolution(SO41, SO42, a11, a12_SO4, b1, a21_SO4, a22_SO4, b2) + SO41_new=xr.where(HSO4_new==h2, max(SO41_new,0.0),(KL01 * SO4 + CSOD_H2S) / (KL01 + KL12SO4 * 0.5)) + + + return xr.where(POCdiagenesis_part_option==1, - (g_1 + h_1_2 * SO42_new) / h_1_1, + xr.where(SO4<=0.1, SO4, SO41_new)) + +@numba.njit +def TH2S1_new( +POCdiagenesis_part_option: xr.DataArray, +bx_1: xr.DataArray, +ad_1_1: xr.DataArray, +SO41_new: xr.DataArray, +ad_1_2: xr.DataArray, +SO42_new: xr.DataArray, +ad_1_3: xr.DataArray, +a21_TH2S: xr.DataArray, +con_sox: xr.DataArray, +KL01: xr.DataArray, +fds1: xr.DataArray, +H2S: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc: xr.DataArray, +HSO4_new: xr.DataArray, +h2: xr.DataArray, +TH2S2: xr.DataArray, +dt: xr.DataArray, +TH2S1: xr.DataArray, +a12_TH2S: xr.DataArray, +a22_TH2S: xr.DataArray, + +) -> xr.DataArray: + """Calculate TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + bx_1, ad_1_1, ad_1_2, ad_1_3,: coefficents for system of equation + SO41_new: new SO4 concentration in sediment in layers 1 (mg-O/L) + SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + a21_TH2S: a21_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + con_sox: #TODO define that this is () + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + H2S: sulfide water concentration (mg-O2/L) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + HSO4_new: hydrogen sulfate water concentration (TODO units) + h2: active sediment layer (m) + TH2S2: TH2S sediment layer 2 (mg-O/L) + dt: timestep (d) + TH2S1: TH2S sediment layer 1 (mg-O/L) + a12_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + a22_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + """ + a11=-a21_TH2S + con_sox / KL01 + KL01 * fds1 + b1 = KL01 * H2S + b2=xr.where(SedFlux_solution_option == 1, JCc * HSO4_new / h2, JCc * HSO4_new / h2 + TH2S2 * h2 / dt) + TH2S1_new, hold = MatrixSolution(TH2S1, TH2S2, a11, a12_TH2S, b1, a21_TH2S, a22_TH2S, b2) + TH2S1_new=max(TH2S1_new,0.0) + return xr.where(POCdiagenesis_part_option==1, - (bx_1 + ad_1_1 * SO41_new + ad_1_2 * SO42_new) / ad_1_3, TH2S1_new) + +@numba.njit +def TH2S2_new( +POCdiagenesis_part_option: xr.DataArray, +bx_3: xr.DataArray, +ad_3_3: xr.DataArray, +TH2S1_new: xr.DataArray, +ad_3_4: xr.DataArray, +a21_TH2S: xr.DataArray, +con_sox: xr.DataArray, +KL01: xr.DataArray, +fds1: xr.DataArray, +H2S: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc: xr.DataArray, +HSO4_new: xr.DataArray, +h2: xr.DataArray, +TH2S2: xr.DataArray, +dt: xr.DataArray, +TH2S1: xr.DataArray, +a12_TH2S: xr.DataArray, +a22_TH2S: xr.DataArray, + +) -> xr.DataArray: + """Calculate TH2S2_new: new TH2S concentration in sediment in layers 2 (mg-O/L) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + bx_3, ad_3_3, ad_3_4: coefficents for system of equation + TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + a21_TH2S: a21_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + con_sox: #TODO define that this is () + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + H2S: sulfide water concentration (mg-O2/L) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + HSO4_new: hydrogen sulfate water concentration (TODO units) + h2: active sediment layer (m) + TH2S2: TH2S sediment layer 2 (mg-O/L) + dt: timestep (d) + TH2S1: TH2S sediment layer 1 (mg-O/L) + a12_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + a22_TH2S: coefficents for implicit finite difference form for TH2S (a11, a12, a21, a22, b1, b2) (m/d) + """ + a11=-a21_TH2S + con_sox / KL01 + KL01 * fds1 + b1 = KL01 * H2S + b2=xr.where(SedFlux_solution_option == 1, JCc * HSO4_new / h2, JCc * HSO4_new / h2 + TH2S2 * h2 / dt) + hold,TH2S2_new = MatrixSolution(TH2S1, TH2S2, a11, a12_TH2S, b1, a21_TH2S, a22_TH2S, b2) + TH2S2_new=max(TH2S2_new,0.0) + + return xr.where(POCdiagenesis_part_option==1, - (bx_3 + ad_3_3 * TH2S1_new) / ad_3_4, TH2S2_new) + +@numba.njit +def CSOD_H2S( +POCdiagenesis_part_option: xr.DataArray, +con_sox: xr.DataArray, +KL01: xr.DataArray, +TH2S1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate CSOD_H2S: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + con_sox: #TODO define that this is () + TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + """ + + return xr.where(POCdiagenesis_part_option==1, con_sox / KL01 * TH2S1_new, con_sox / KL01 * TH2S1_new) + +@numba.njit +def JCc_CH4( +POCdiagenesis_part_option: xr.DataArray, +JCc: xr.DataArray, +KsSO4: xr.DataArray, +SO42_new: xr.DataArray, +h2: xr.DataArray, +HSO4_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + KsSO4: half-saturation constant for sulfate in sulfate reduction (mg-O2/L) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + HSO4_new: hydrogen sulfate water concentration (TODO units) + h2: active sediment layer (m) + """ + + return xr.where(POCdiagenesis_part_option==1, JCc * KsSO4 / (SO42_new + KsSO4), JCc * (h2 - HSO4_new) / h2) #TODO find this formula. See page 170 is SO42 supposed to be on top as well? + +@numba.njit +def ra2( +POCdiagenesis_part_option: xr.DataArray, +JCc: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +KL01: xr.DataArray, +h2: xr.DataArray, +SO4: xr.DataArray, +con_sox: xr.DataArray, +TH2S1: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra2: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + h2: active Sediment layer thickness (m) + dt: time (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO4: sulfate water concentration (mg-O2/L) + con_sox: #TODO define that this is () + TH2S1: TH2S sediment layer 1 (mg-O/L) + """ + + return xr.where(POCdiagenesis_part_option==2, + xr.where(SO4>0.1, + xr.where(SedFlux_solution_option == 1, 2.0 * KL01 * JCc / h2, 2.0 * KL01 * JCc / h2 + (KL01 * SO4 + con_sox / KL01 * TH2S1) / dt), "NaN"), "NaN") + + +@numba.njit +def ra1( +POCdiagenesis_part_option: xr.DataArray, +JCc: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +KL01: xr.DataArray, +h2: xr.DataArray, +SO4: xr.DataArray, +dt: xr.DataArray, +HSO4: xr.DataArray, +SO42: xr.DataArray, +Dd_tc: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra1: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + h2: active Sediment layer thickness (m) + dt: time (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO4: sulfate water concentration (mg-O2/L) + HSO4: hydrogen sulfate water concentration (TODO units) + SO42: SO4 concentration in sediment in layers (mg-O/L) + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + """ + + return xr.where(POCdiagenesis_part_option==2, + xr.where(SO4>0.1, + xr.where(SedFlux_solution_option == 1, 2.0 * Dd_tc * JCc / h2, 2.0 * Dd_tc * JCc / h2 - 2.0 * KL01 * HSO4 * SO42 / dt), "NaN"), "NaN") + + +@numba.njit +def ra0( +POCdiagenesis_part_option: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +KL01: xr.DataArray, +SO4: xr.DataArray, +con_sox: xr.DataArray, +TH2S1: xr.DataArray, +Dd_tc: xr.DataArray, + +) -> xr.DataArray: + """Calculate ra0: equation coefficent + + Args: + POCdiagenesis_part_option: method for partitioin carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO4: sulfate water concentration (mg-O2/L) + Dd_tc: pore-water diffusion coefficient between layer 1 and 2 temperature corrected (m2/d) + con_sox: #TODO define that this is () + TH2S1: TH2S sediment layer 1 (mg-O/L) + """ + + return xr.where(POCdiagenesis_part_option==2, xr.where(SO4>0.1, xr.where(SedFlux_solution_option == 1, - 2.0 * Dd_tc * (KL01 * SO4 + con_sox / KL01 * TH2S1), - 2.0 * Dd_tc * (KL01 * SO4 + con_sox / KL01 * TH2S1)), "NaN"), "NaN") + + +@numba.njit +def CSODmax( +Methane_solution_option: xr.DataArray, +KL12: xr.DataArray, +CH4sat: xr.DataArray, +JCc_CH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate CSODmax: used for analytical soluton of methane (g-O2/m2/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + KL12: mass transfer velocity between the two sediment layers (m/d) + CH4sat: saturated concentration of methane in oxygen equivalents (mg-O2/L) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + """ + + return xr.where(Methane_solution_option == 1, min(math.sqrt(2.0 * KL12 * CH4sat * JCc_CH4), JCc_CH4), "NaN") + +@numba.njit +def CSOD_CH4( +Methane_solution_option: xr.DataArray, +vch41_tc: xr.DataArray, +KL01: xr.DataArray, +CSODmax: xr.DataArray, +CH41_new: xr.DataArray, +con_cox: xr.DataArray, + +) -> xr.DataArray: + """Calculate CSOD_CH4: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + vch41_tc: methane oxidation reaction velocity in sediment layer 1 temperature corrected (m/d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + CSODmax: used for analytical soluton of methane (g-O2/m2/d) + CH41_new: CH4 sediment layer 1 (mg-O/L) + con_cox: #TODO define that this is () + + """ + + return xr.where(Methane_solution_option == 1, + xr.where(vch41_tc/KL01 <100.0, CSODmax * (1.0 - 2.0 / (math.exp(vch41_tc / KL01) + math.exp(-vch41_tc / KL01))), CSODmax), con_cox / KL01 * CH41_new) + +@numba.njit +def CH41_new( +Methane_solution_option: xr.DataArray, +vch41_tc: xr.DataArray, +KL01: xr.DataArray, +con_cox: xr.DataArray, +KL12: xr.DataArray, +CH4: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc_CH4: xr.DataArray, +CH41: xr.DataArray, +CH42: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +a12_CH4: xr.DataArray, +a21_CH4: xr.DataArray, +a22_CH4: xr.DataArray, +CH42_new: xr.DataArray, +CH4sat: xr.DataArray, +CSOD_CH4: xr.DataArray + +) -> xr.DataArray: + """Calculate CH41_new: new CH4 sediment layer 1 (mg-O/L) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + vch41_tc: methane oxidation reaction velocity in sediment layer 1 temperature corrected (m/d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + + con_cox: #TODO define that this is () + KL12: mass transfer velocity between the two sediment layers (m/d) + CH4: methane concentration (mg-o)/L + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + CH41: CH4 sediment layer 1 (mg-O/L) + CH42: CH4 sediment layer 2 (mg-O/L) + h2: active Sediment layer thickness (m) + dt: time (d) + a12_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + a21_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + CH42_new: new CH4 sediment layer 2 (mg-O/L) + CH4sat: saturated concentration of methane in oxygen equivalents (mg-O2/L) + + """ + a11 = KL12 + con_cox / KL01 + KL01 + b1 = KL01 * CH4 + b2 = xr.where(SedFlux_solution_option == 1, KL01 * CH4, JCc_CH4 + CH42 * h2 / dt) + CH41_new, hold = MatrixSolution(CH41, CH42, a11, a12_CH4, b1, a21_CH4, a22_CH4, b2) + CH41_new=xr.where(CH42_new > CH4sat, max((b1 - a12_CH4 * CH42) / a11,0.0), max(CH41_new,0.0)) + + return xr.where(Methane_solution_option == 2, CH41_new, + xr.where( vch41_tc <= 0, 0.0, CSOD_CH4 / (vch41_tc * vch41_tc / KL01))) + +@numba.njit +def CH42_new( +Methane_solution_option: xr.DataArray, +KL01: xr.DataArray, +con_cox: xr.DataArray, +KL12: xr.DataArray, +CH4: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc_CH4: xr.DataArray, +CH41: xr.DataArray, +CH42: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, +a12_CH4: xr.DataArray, +a21_CH4: xr.DataArray, +a22_CH4: xr.DataArray, +CH42_new: xr.DataArray, +CH4sat: xr.DataArray + +) -> xr.DataArray: + """Calculate CH42_new: new CH4 sediment layer 2 (mg-O/L) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + + con_cox: #TODO define that this is () + KL12: mass transfer velocity between the two sediment layers (m/d) + CH4: methane concentration (mg-o)/L + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + CH41: CH4 sediment layer 1 (mg-O/L) + CH42: CH4 sediment layer 2 (mg-O/L) + h2: active Sediment layer thickness (m) + dt: time (d) + a12_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + a21_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + a22_CH4: coefficents for implicit finite difference form for CH4 (a11, a12, a21, a22, b1, b2) (m/d) + CH42_new: new CH4 sediment layer 2 (mg-O/L) + CH4sat: saturated concentration of methane in oxygen equivalents (mg-O2/L) + + """ + a11 = KL12 + con_cox / KL01 + KL01 + b1 = KL01 * CH4 + b2 = xr.where(SedFlux_solution_option == 1, KL01 * CH4, JCc_CH4 + CH42 * h2 / dt) + hold, CH42_new = MatrixSolution(CH41, CH42, a11, a12_CH4, b1, a21_CH4, a22_CH4, b2) + CH42_new=xr.where(CH42_new > CH4sat, max(CH4sat,0.0), max(CH42_new,0.0)) + + return xr.where(Methane_solution_option == 2, CH42_new, 0.0) + +@numba.njit +def NSOD( +KL01: xr.DataArray, +ron: xr.DataArray, +con_nit: xr.DataArray, +FNH4: xr.DataArray, +TNH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NSOD: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + ron: oxygen stoichiometric coeff for nitrification (g-O2/g-N) + con_nit: #TODO define that this is () + FNH4: modification of nitrification reaction in layer 1 (unitless) + THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + + + """ + + return ron * con_nit * FNH4 / KL01 * TNH41_new + +@numba.njit +def KL01( +SOD_Bed: xr.DataArray, +DOX: xr.DataArray, + +) -> xr.DataArray: + """Calculate KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + + Args: + SOD_Bed: SedFlux sediment oxygen demand (g-O2/m2/d) + DOX: dissolved oxygen (mg-O/L) + + """ + + return xr.where(math.isnan(SOD_Bed / DOX) or (SOD_Bed / DOX) ==0, 1.0E-8, SOD_Bed / DOX) + +@numba.njit +def SOD_Bed( +CSOD_CH4: xr.DataArray, +res: xr.DataArray, +DOX: xr.DataArray, +CSOD_H2S: xr.DataArray, +NSOD: xr.DataArray, +maxit: xr.DataArray, +JC: xr.DataArray, +roc: xr.DataArray, +JN: xr.DataArray, + +) -> xr.DataArray: + """Calculate SOD_Bed: SedFlux sediment oxygen demand (g-O2/m2/d) + + Args: + NSOD: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + CSOD_CH4: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + CSOD_H2S: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + NSOD: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + JC: total sediment diagenesis flux of POC (g-C/m2/d) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + JN: total sediment diagenesis flux of PON (g-N/m2/d) + """ + + + for i in range(1, maxit) : + if i == 1: + SOD_Bed= JC * roc + 1.714 * JN + + KL01 = KL01(SOD_Bed,DOX) #TODO need this to update for each loop + + if(math.nan(KL01) or KL01==0.0): + KL01 = 0.00000001 + + SOD_Bed_old = SOD_Bed + SOD_Bed = (CSOD_CH4 + CSOD_H2S + NSOD + SOD_Bed_old) / 2.0 + if (abs(SOD_Bed - SOD_Bed_old) / SOD_Bed * 100.0 < res): + exit + + return SOD_Bed + return SOD_Bed + +""" +Output pathways +""" + +@numba.njit +def NH41_new( +fd1: xr.DataArray, +TNH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH41: NH4 sediment layer 1 (mg-N/L) + + Args: + fd1: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 1 (unitless) + THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + + """ + + return fd1 * TNH41_new + +@numba.njit +def NH42_new( +fd2: xr.DataArray, +TNH42_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH42: NH4 sediment layer 2 (mg-N/L) + + Args: + fd2: fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer 2 (unitless) + THN42_new: newtotal concentration NH4 dissolved layer 2 (mg-N/L) + + """ + + return fd2 * TNH42_new + +@numba.njit +def JNH4( +KL01: xr.DataArray, +NH41_new: xr.DataArray, +NH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH42: NH4 sediment layer 2 (mg-N/L) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + NH41: NH4 sediment layer 1 (mg-N/L) + NH4: Ammonia water concentration (mg-N/L) + + """ + + return KL01 * (NH41_new - NH4) + +@numba.njit +def TNH41_Burial( +vb: xr.DataArray, +TNH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TNH41_Burial: burial of TNH41 in sediment layer 1 (g-N/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + + """ + + return vb * TNH41_new + +@numba.njit +def NH41_Nitrification( +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +TNH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH41_Nitrification: nitrification of TNH41 in sediment layer 1 (g-N/m2/d) + + Args: + con_nit: #TODO define that this is () + FNH4: modification of nitrification reaction in layer 1 (unitless) + THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + + """ + + return con_nit * FNH4 / KL01 * TNH41_new + +@numba.njit +def NH41_NH42( +con_nit: xr.DataArray, +FNH4: xr.DataArray, +KL01: xr.DataArray, +TNH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NH41_NH42: mass transfer between TNH41 and TNH42 in dissolved form (g-N/m2/d) + + Args: + con_nit: #TODO define that this is () + FNH4: modification of nitrification reaction in layer 1 (unitless) + THN41_new: newtotal concentration NH4 dissolved layer 1 (mg-N/L) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + + """ + + return con_nit * FNH4 / KL01 * TNH41_new + +@numba.njit +def TNH42_Burial( +vb: xr.DataArray, +TNH42_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TNH42_Burial: burial of TNH41 in sediment layer 2 (g-N/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + THN42_new: newtotal concentration NH4 dissolved layer 2 (mg-N/L) + + """ + + return vb * TNH42_new + +@numba.njit +def JNO3( +KL01: xr.DataArray, +NO31_new: xr.DataArray, +NO3: xr.DataArray, + +) -> xr.DataArray: + """Calculate JNO3: sediment-water flux of nitrate (g-N/m2/d) + + Args: + NO31_new: new NO3 sediment layer 1 (mg-N/L) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + NO3: nitrate concentation water (mg-N/L) + """ + + return KL01 * (NO31_new - NO3) + +@numba.njit +def NO31_Denit( +KL01: xr.DataArray, +vno31_tc: xr.DataArray, +NO31_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO31_Denit: denitrification of NO31 in sediment layer 1 (g-N/m2/d) + + Args: + NO31_new: new NO3 sediment layer 1 (mg-N/L) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + vno31_tc: denitrification reaction velocity in sediment layer 1 temperature corrected (m/d) + + """ + + return vno31_tc * vno31_tc / KL01 * NO31_new + +@numba.njit +def NO31_NO32( +KL12: xr.DataArray, +NO32_new: xr.DataArray, +NO31_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO31_NO32: mass transfer between NO31 and NO32 (g-N/m2/d) + + Args: + NO31_new: new NO3 sediment layer 1 (mg-N/L) + NO32_new: new NO3 sediment layer 2 (mg-N/L) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + + return KL12 * (NO32_new - NO31_new) + +@numba.njit +def NO32_Denit( +vno32_tc: xr.DataArray, +NO32_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate NO32_Denit: denitrification of NO31 in sediment layer 2 (g-N/m2/d) + + Args: + NO32_new: new NO3 sediment layer 2 (mg-N/L) + vno32_tc: denitrification reaction velocity in sediment layer 2 temperature corrected (m/d) + + """ + + return vno32_tc * NO32_new + +@numba.njit +def JCc_SO4( +POCdiagenesis_part_option: xr.DataArray, +JCc: xr.DataArray, +SO42_new: xr.DataArray, +KsSO4: xr.DataArray, +HSO4_new: xr.DataArray, +h2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JCc_SO4: carbon diagenesis flux consumed for sulfate reduction (g-O2/m2/d) + + Args: + POCdiagenesis_part_option: method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) (unitless) + JCc: carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + KsSO4: half-saturation constant for sulfate in sulfate reduction (mg-O2/L) + HSO4_new: hydrogen sulfate water concentration (TODO units) + h2: active sediment layer (m) + + """ + + return xr.where(POCdiagenesis_part_option==1, JCc * SO42_new / (SO42_new + KsSO4), JCc * HSO4_new / h2) + +@numba.njit +def JSO4( +KL01: xr.DataArray, +SO41_new: xr.DataArray, +SO4: xr.DataArray, + +) -> xr.DataArray: + """Calculate JSO4: sediment-water flux of sulfate (g-O2/m2/d) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + SO41_new: new SO4 concentration in sediment in layers 1 (mg-O/L) + SO4: SO4 concentration in water (mg-O/L) + """ + + return KL01 * (SO41_new - SO4) + +@numba.njit +def SO41_SO42( +SO41_new: xr.DataArray, +KL12SO4: xr.DataArray, +SO42_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate SO41_SO42: mass transfer between SO41 and SO42 (g-O2/m2/d) + ! + + Args: + KL12SO4: dissolved mass transfer velocity of sulfate between two layers (m/d) + SO41_new: new SO4 concentration in sediment in layers 1 (mg-O/L) + SO42_new: new SO4 concentration in sediment in layers 2 (mg-O/L) + """ + + return KL12SO4 * (SO42_new - SO41_new) + +@numba.njit +def H2S1_new( +fds1: xr.DataArray, +TH2S1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate H2S1_new: new H2S1 concentration in sediment layer 1 (mg-O/L) + ! + + Args: + fds1: dissolved fraction for H2S1 and H2S2 in layer 1 (unitless) + TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + + """ + + return fds1 * TH2S1_new + +@numba.njit +def H2S2_new( +fds2: xr.DataArray, +TH2S2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate H2S2_new: new H2S2 concentration in sediment layer 2 (mg-O/L) + ! + + Args: + fds2: dissolved fraction for H2S1 and H2S2 in layer 2 (unitless) + TH2S2_new: new TH2S concentration in sediment in layers 2 (mg-O/L) + + """ + + return fds2 * TH2S2_new + +@numba.njit +def JH2S( +KL01: xr.DataArray, +H2S1_new: xr.DataArray, +H2S: xr.DataArray, + +) -> xr.DataArray: + """Calculate JH2S: sediment-water flux of sulfide (g-O2/m2/d) + ! + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + H2S1_new: new H2S1 concentration in sediment layer 1 (mg-O/L) + H2S: H2S water concentration (mg-O/L) + + """ + + return KL01 * (H2S1_new - H2S) + +@numba.njit +def H2S1_Oxidation( +KL01: xr.DataArray, +TH2S1_new: xr.DataArray, +con_sox: xr.DataArray, + +) -> xr.DataArray: + """Calculate H2S1_Oxidation: sulfide oxidation in sediment layer 1 (g-O2/m2/d) + ! + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + con_sox: #TODO define that this is () + + """ + + return con_sox / KL01 * TH2S1_new + +@numba.njit +def TH2S1_Burial ( +vb: xr.DataArray, +TH2S1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TH2S1_Burial: burial of H2S1 in sediment layer 1 (g-O2/m2/d) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + TH2S1_new: new TH2S concentration in sediment in layers 1 (mg-O/L) + """ + + return vb * TH2S1_new + +@numba.njit +def H2S1_H2S2( +KL12: xr.DataArray, +H2S2_new: xr.DataArray, +H2S1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate H2S1_H2S2: mass transfer between H2S1 and H2S2 in dissolved form (g-O2/m2/d) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + H2S2_new: new H2S2 concentration in sediment layer 2 (mg-O/L) + H2S1_new: new H2S1 concentration in sediment layer 1 (mg-O/L) + """ + + return KL12 * (H2S2_new - H2S1_new) + +@numba.njit +def TH2S2_Burial( +vb: xr.DataArray, +TH2S2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate H2S1_H2S2: mass transfer between H2S1 and H2S2 in dissolved form (g-O2/m2/d) + + Args: + vb: burial velocity of POM2 in bed sediment (m/d) #TODO double check units + TH2S2_new: new TH2S concentration in sediment in layers 2 (mg-O/L) + + """ + + return vb * TH2S2_new + +@numba.njit +def CH41_Oxidation( +Methane_solution_option: xr.DataArray, +CSOD_CH4: xr.DataArray, +con_cox: xr.DataArray, +KL01: xr.DataArray, +CH41_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate CH41_Oxidation: methane oxidation in sediment layer 1 (g-O2/m2/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + CSOD_CH4: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + con_cox: #TODO define that this is () + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + CH41_new: new CH4 sediment layer 1 (mg-O/L) + + """ + + return xr.where(Methane_solution_option==1, CSOD_CH4, con_cox / KL01 * CH41_new) + +@numba.njit +def JCH4( +Methane_solution_option: xr.DataArray, +CSOD_CH4: xr.DataArray, +KL01: xr.DataArray, +CH41_new: xr.DataArray, +CSODmax: xr.DataArray, +CH4: xr.DataArray, + +) -> xr.DataArray: + """Calculate JCH4: sediment-water flux of methane (g-O2/m2/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + CSOD_CH4: carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + CH41_new: new CH4 sediment layer 1 (mg-O/L) + CSODmax: used for analytical soluton of methane (g-O2/m2/d) + CH4: CH4 concentration water (mg-O/L) + + """ + + return xr.where(Methane_solution_option==1, CSODmax - CSOD_CH4, KL01 * (CH41_new - CH4)) + +@numba.njit +def JCH4g( +Methane_solution_option: xr.DataArray, +CSODmax: xr.DataArray, +CH42_new: xr.DataArray, +CH4sat: xr.DataArray, +JCc_CH4: xr.DataArray, +JCH4: xr.DataArray, +CH41_Oxidation: xr.DataArray, +CH42: xr.DataArray, +dt: xr.DataArray, +h2: xr.DataArray, + +) -> xr.DataArray: + """Calculate JCH4g: methane loss as bubbles from sediment (g-O2/m2/d) + + Args: + Methane_solution_option: method for solving methane concentration (1 analytical and 2 numerical) + CSODmax: used for analytical soluton of methane (g-O2/m2/d) + CH42_new: new CH4 sediment layer 2 (mg-O/L) + CH4sat: saturated concentration of methane in oxygen equivalents (mg-O2/L) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + JCH4: sediment-water flux of methane (g-O2/m2/d) + CH41_Oxidation: methane oxidation in sediment layer 1 (g-O2/m2/d) + CH42_new: old CH4 sediment layer 2 (mg-O/L), + h2: active Sediment layer thickness (m) + dt: time (d) + + """ + + return xr.where(Methane_solution_option==1, JCc_CH4 - CSODmax, + xr.where(CH42_new == CH4sat, JCc_CH4 - JCH4 - CH41_Oxidation - (CH42_new - CH42) / dt * h2, 0.0)) + +@numba.njit +def DIC1_new( +KL01: xr.DataArray, +DIC: xr.DataArray, +CH41_Oxidation: xr.DataArray, +roc: xr.DataArray, +rcdn: xr.DataArray, +NO31_Denit: xr.DataArray, +KL12: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc_CH4: xr.DataArray, +JCc_SO4: xr.DataArray, +NO32_Denit: xr.DataArray, +DIC1: xr.DataArray, +DIC2: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC1_new: new DIC sediment layer 1 (mg-C/L) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + DIC: DIC water concentration (mg-C/L) + CH41_Oxidation: methane oxidation in sediment layer 1 (g-O2/m2/d) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + rcdn: carbon stoichiometric coeff for denitrification (g-C/g-N) + NO31_Denit: NO31_Denit: denitrification of NO31 in sediment layer 1 (g-N/m2/d) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + JCc_SO4: carbon diagenesis flux consumed for sulfate reduction (g-O2/m2/d) + NO32_Denit:denitrification of NO31 in sediment layer 2 (g-N/m2/d) + DIC1: DIC sediment layer 1 (mg-C/L) + DIC2: DIC sediment layer 1 (mg-C/L) + h2: active sediment layer (m) + dt: time (d) + + """ + a11= KL01 + KL12 + a12= -KL12 + b1= KL01 * DIC * 12000.0 + CH41_Oxidation / 2.0 / roc + rcdn * NO31_Denit + a21= -KL12 + + b2=xr.where(SedFlux_solution_option == 1, (JCc_CH4 / 2.0 + JCc_SO4) / roc + rcdn * NO32_Denit, (JCc_CH4 / 2.0 + JCc_SO4) / roc + rcdn * NO32_Denit + DIC2 * h2 / dt) + a22=xr.where(SedFlux_solution_option == 1, KL12, KL12 + h2 / dt) + DIC1_new, hold = MatrixSolution(DIC1, DIC2, a11, a12, b1, a21, a22, b2) + + return max(DIC1_new,0.0) + +@numba.njit +def DIC2_new( +KL01: xr.DataArray, +DIC: xr.DataArray, +CH41_Oxidation: xr.DataArray, +roc: xr.DataArray, +rcdn: xr.DataArray, +NO31_Denit: xr.DataArray, +KL12: xr.DataArray, +SedFlux_solution_option: xr.DataArray, +JCc_CH4: xr.DataArray, +JCc_SO4: xr.DataArray, +NO32_Denit: xr.DataArray, +DIC1: xr.DataArray, +DIC2: xr.DataArray, +h2: xr.DataArray, +dt: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC2_new: new DIC sediment layer 2 (mg-C/L) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + DIC: DIC water concentration (mg-C/L) + CH41_Oxidation: methane oxidation in sediment layer 1 (g-O2/m2/d) + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + rcdn: carbon stoichiometric coeff for denitrification (g-C/g-N) + NO31_Denit: NO31_Denit: denitrification of NO31 in sediment layer 1 (g-N/m2/d) + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + JCc_SO4: carbon diagenesis flux consumed for sulfate reduction (g-O2/m2/d) + NO32_Denit:denitrification of NO31 in sediment layer 2 (g-N/m2/d) + DIC1: DIC sediment layer 1 (mg-C/L) + DIC2: DIC sediment layer 1 (mg-C/L) + h2: active sediment layer (m) + dt: time (d) + + """ + a11= KL01 + KL12 + a12= -KL12 + b1= KL01 * DIC * 12000.0 + CH41_Oxidation / 2.0 / roc + rcdn * NO31_Denit + a21= -KL12 + + b2=xr.where(SedFlux_solution_option == 1, (JCc_CH4 / 2.0 + JCc_SO4) / roc + rcdn * NO32_Denit, (JCc_CH4 / 2.0 + JCc_SO4) / roc + rcdn * NO32_Denit + DIC2 * h2 / dt) + a22=xr.where(SedFlux_solution_option == 1, KL12, KL12 + h2 / dt) + hold, DIC2_new = MatrixSolution(DIC1, DIC2, a11, a12, b1, a21, a22, b2) + + return max(DIC2_new,0.0) + +@numba.njit +def JDIC( +KL01: xr.DataArray, +DIC: xr.DataArray, +DIC1_new: xr.DataArray, + + +) -> xr.DataArray: + """Calculate JDIC: sediment-water flux of dissolved inorganic carbon (g-C/m2/d) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + DIC: DIC water concentration (mg-C/L) + DIC1_new: new DIC sediment layer 1 (mg-C/L) + """ + + return KL01 * (DIC1_new - DIC * 12000.0) + +@numba.njit +def DIC1_CH41_Oxidation( +CH41_Oxidation: xr.DataArray, +roc: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC1_CH41_Oxidation: DIC1 produced by CH41 oxidation in sediment layer 1 (g-C/m2/d) + + Args: + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + CH41_Oxidation: methane oxidation in sediment layer 1 (g-O2/m2/d) + """ + + return CH41_Oxidation / 2.0 / roc + +@numba.njit +def DIC1_NO31_Denit( +rcdn: xr.DataArray, +NO31_Denit: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC1_NO31_Denit: DIC1 produced by NO31 denitrification in sediment layer 1 (g-C/m2/d) + + Args: + rcdn: carbon stoichiometric coeff for denitrification (g-C/g-N) + NO31_Denit: denitrification of NO31 in sediment layer 1 (g-N/m2/d) + + """ + + return rcdn * NO31_Denit + +@numba.njit +def DIC1_DIC2( +KL12: xr.DataArray, +DIC2_new: xr.DataArray, +DIC1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC1_DIC2: mass transfer between DIC1 and DIC2 in dissolved form (g-C/m2/d) + + Args: + KL12: dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + DIC1_new: new DIC sediment layer 1 (mg-C/L) + DIC2_new: new DIC sediment layer 2 (mg-C/L) + + """ + + return KL12 * (DIC2_new - DIC1_new) + +@numba.njit +def DIC2_POC2_SO42( +JCc_SO4: xr.DataArray, +roc: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC2_POC2_SO42: DIC2 produced by sulfate reduction in sediment layer 2 (g-C/m2/d) + + Args: + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + JCc_SO4: carbon diagenesis flux consumed for sulfate reduction (g-O2/m2/d) + + """ + + return JCc_SO4 / roc + +@numba.njit +def DIC2_CH42( +JCc_CH4: xr.DataArray, +roc: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC2_CH42: DIC2 produced by mathene formation in sediment layer 2 (g-C/m2/d) + + Args: + roc: oxygen stoichiometric coefficent for organic carbon decay (g-O2/g-C) + JCc_CH4: carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + + """ + + return JCc_CH4 / 2.0 / roc + +@numba.njit +def DIC2_NO32_Denit( +rcdn: xr.DataArray, +NO32_Denit: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIC2_NO32_Denit: DIC2 produced by mathene formation in sediment layer 2 (g-C/m2/d) + + Args: + rcdn: carbon stoichiometric coeff for denitrification (g-C/g-N) + NO32_Denit : denitrification of NO31 in sediment layer 2 (g-N/m2/d) + + """ + + return rcdn * NO32_Denit + +@numba.njit +def kdpo41( +DOX: xr.DataArray, +DOcr: xr.DataArray, +kdpo42: xr.DataArray, +d_kpo41: xr.DataArray, + +) -> xr.DataArray: + """Calculate kdpo41: partition coefficient for inorganic P in sediment layer 1 (L/kg) + + Args: + DOX: dissolved oxygen concentration (mg-O/L) + DOcr: critical oxygen concentration for incremental phosphate sorption (mg-O2/L) [avoid to repeat with DOC] + kdpo42: partition coefficient for inorganic P in sediment layer 2 (L/kg) + d_kpo41: factor that increases the aerobic layer phosphate partition coefficient (unitless) + + """ + + return xr.where(DOX >= DOcr, kdpo42 * d_kpo41, kdpo42 * d_kpo41**(DOX / DOcr)) + +@numba.njit +def TIP1_new( +SedFlux_solution_option: xr.DataArray, +JP: xr.DataArray, +TIP: xr.DataArray, +fdp: xr.DataArray, +vs: xr.DataArray, +vb: xr.DataArray, +h2: xr.DataArray, +TIP1: xr.DataArray, +TIP2: xr.DataArray, +dt: xr.DataArray, +KL01: xr.DataArray, +Css2: xr.DataArray, +kdpo42: xr.DataArray, +Css1: xr.DataArray, +kdpo41: xr.DataArray, +w12: xr.DataArray, +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate TIP1_new: new TIP sediment layer 1 (mg-P/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JP: total sediment diagenesis flux of POP (g-P/m2/d) + TIP: TIP water concentration (mg-P/L) + fdp: fraction of dissolved phosphrous (unitless) + vs: sediment settling velocity (m/d) + vb: burial velocity of POM2 in bed sediment (m/d) + h2: active sediment layer (m) + TIP1: TIP sediment layer 1 (mg-P/L) + TIP2: TIP sediment layer 2 (mg-P/L) + dt: time step (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + Css2: solids concentration in sediment layer 2 (kg/L) + kdpo42: partition coefficient for inorganic P in sediment layer 2 (L/kg) + Css1: solids concentration in sediment layer 1 (kg/L) + kdpo41: kdpo41: partition coefficient for inorganic P in sediment layer 1 (L/kg) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + KL12: Dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + fd1 = 1.0 / (1.0 + Css1 * kdpo41) + fd2 = 1.0 / (1.0 + Css2 * kdpo42) + fp2 = 1.0 - fd2 + fp1 = 1.0 - fd1 + + a21 = -w12 * fp1 - KL12 * fd1 - vb + a11 = -a21 + KL01 * fd1 + a12 = -w12 * fp2 - KL12 * fd2 + b1 = KL01 * fdp * TIP + + a22 = xr.where (SedFlux_solution_option == 1,-a12 + vb,-a12 + vb + h2 / dt) + b2= xr.where (SedFlux_solution_option == 1,JP + TIP * (1.0 - fdp) * vs,JP + TIP * (1.0 - fdp) * vs + h2 * TIP2 / dt) + TIP1_new, hold = MatrixSolution(TIP1, TIP2, a11, a12, b1, a21, a22, b2) + + return max(TIP1_new,0.0) + +@numba.njit +def TIP2_new( +SedFlux_solution_option: xr.DataArray, +JP: xr.DataArray, +TIP: xr.DataArray, +fdp: xr.DataArray, +vs: xr.DataArray, +vb: xr.DataArray, +h2: xr.DataArray, +TIP1: xr.DataArray, +TIP2: xr.DataArray, +dt: xr.DataArray, +KL01: xr.DataArray, +Css2: xr.DataArray, +kdpo42: xr.DataArray, +Css1: xr.DataArray, +kdpo41: xr.DataArray, +w12: xr.DataArray, +KL12: xr.DataArray, + +) -> xr.DataArray: + """Calculate TIP2_new: new TIP sediment layer 2 (mg-P/L) + + Args: + SedFlux_solution_option: numerical method (1 steady, 2 unsteady) + JP: total sediment diagenesis flux of POP (g-P/m2/d) + TIP: TIP water concentration (mg-P/L) + fdp: fraction of dissolved phosphrous (unitless) + vs: sediment settling velocity (m/d) + vb: burial velocity of POM2 in bed sediment (m/d) + h2: active sediment layer (m) + TIP1: TIP sediment layer 1 (mg-P/L) + TIP2: TIP sediment layer 2 (mg-P/L) + dt: time step (d) + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + Css2: solids concentration in sediment layer 2 (kg/L) + kdpo42: partition coefficient for inorganic P in sediment layer 2 (L/kg) + Css1: solids concentration in sediment layer 1 (kg/L) + kdpo41: partition coefficient for inorganic P in sediment layer 1 (L/kg) + w12: Partical mixing transfer velocity: transfer for NH4, H2S, and PIP between layer 1 and 2 (m/d) + KL12: Dissolved and particulate phase mixing coefficient between layer 1 and layer 2 (m/d) + + """ + fd1 = 1.0 / (1.0 + Css1 * kdpo41) + fd2 = 1.0 / (1.0 + Css2 * kdpo42) + fp2 = 1.0 - fd2 + fp1 = 1.0 - fd1 + + a21 = -w12 * fp1 - KL12 * fd1 - vb + a11 = -a21 + KL01 * fd1 + a12 = -w12 * fp2 - KL12 * fd2 + b1 = KL01 * fdp * TIP + + a22 = xr.where (SedFlux_solution_option == 1,-a12 + vb,-a12 + vb + h2 / dt) + b2= xr.where (SedFlux_solution_option == 1,JP + TIP * (1.0 - fdp) * vs,JP + TIP * (1.0 - fdp) * vs + h2 * TIP2 / dt) + hold, TIP2_new = MatrixSolution(TIP1, TIP2, a11, a12, b1, a21, a22, b2) + + return max(TIP2_new,0.0) + +@numba.njit +def DIP1_new( +TIP1_new: xr.DataArray, +Css1: xr.DataArray, +kdpo41: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIP1_new: new DIP sediment layer 1 (mg-P/L) + + Args: + TIP1_new: new TIP sediment layer 1 (mg-P/L) + Css1: solids concentration in sediment layer 1 (kg/L) + kdpo41: partition coefficient for inorganic P in sediment layer 1 (L/kg) + + """ + + return TIP1_new * (1.0 / (1.0 + Css1 * kdpo41)) + +@numba.njit +def DIP2_new( +TIP2_new: xr.DataArray, +Css2: xr.DataArray, +kdpo42: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIP2_new: new DIP sediment layer 2 (mg-P/L) + + Args: + TIP2_new: new TIP sediment layer 2 (mg-P/L) + Css2: solids concentration in sediment layer 2 (kg/L) + kdpo42: partition coefficient for inorganic P in sediment layer 2 (L/kg) + + """ + + return TIP2_new * (1.0 / (1.0 + Css2 * kdpo42)) + +@numba.njit +def JDIP( +KL01: xr.DataArray, +DIP1_new: xr.DataArray, +fdp: xr.DataArray, +TIP: xr.DataArray, + +) -> xr.DataArray: + """Calculate JDIP: sediment-water flux of phosphate (g-P/m2/d) + + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + DIP1_new: new DIP sediment layer 1 (mg-P/L) + fdp: fraction of dissolved phosphrous (unitless) + TIP: TIP water concentration (mg-P/L) + + """ + + return KL01 * (DIP1_new - fdp * TIP) + +@numba.njit +def TIP_TIP2( +vs: xr.DataArray, +fdp: xr.DataArray, +TIP: xr.DataArray, + +) -> xr.DataArray: + """Calculate TIP_TIP2: settling of PIP of water column into PIP2 in layer 2 (g-P/m2/d) + + Args: + vs: sediment settling velocity (m/d) + fdp: fraction of dissolved phosphrous (unitless) + TIP: TIP water concentration (mg-P/L) + + """ + + return TIP * (1.0 - fdp) * vs + +@numba.njit +def TIP1_Burial( +vb: xr.DataArray, +TIP1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TIP1_Burial: burial of TIP1 in sediment layer 1 (g-P/m2/d) + Args: + vb: burial velocity of POM2 in bed sediment (m/d) + TIP1_new: new TIP sediment layer 1 (mg-P/L) + """ + + return vb * TIP1_new + +@numba.njit +def DIP1_DIP2( +KL12: xr.DataArray, +DIP2_new: xr.DataArray, +DIP1_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate DIP1_DIP2: mass transfer between TIP1 and TPO42 in dissolved form (g-P/m2/d) + Args: + KL01: mass transfer velocity between overlying water and the aerobic layer (m/d) + DIP1_new: new DIP sediment layer 1 (mg-P/L) + DIP2_new: new DIP sediment layer 2 (mg-P/L) + + """ + + return KL12 * (DIP2_new - DIP1_new) + +@numba.njit +def TIP2_Burial( +vb: xr.DataArray, +TIP2_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TIP2_Burial: burial of TIP2 in sediment layer 2 (g-P/m2/d) + Args: + vb: burial velocity of POM2 in bed sediment (m/d) + TIP2_new: new TIP sediment layer 2 (mg-P/L) + """ + + return vb * TIP2_new + +@numba.njit +def TPOC2( +POC2_1_new: xr.DataArray, +POC2_2_new: xr.DataArray, +POC2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TPOC2: total sediment POC (mg-C/L) + + Args: + POC2_1_new: POC G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + POC2_2_new: POC G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + POC2_3_new: POC G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-C/L) + """ + + return POC2_1_new + POC2_2_new + POC2_3_new + +@numba.njit +def TPON2( +PON2_1_new: xr.DataArray, +PON2_2_new: xr.DataArray, +PON2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TPON2: total sediment PON (mg-N/L) + + Args: + PON2_1_new: PON G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + PON2_2_new: PON G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + PON2_3_new: PON G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-N/L) + """ + + return PON2_1_new + PON2_2_new + PON2_3_new + +@numba.njit +def TPOP2( +POP2_1_new: xr.DataArray, +POP2_2_new: xr.DataArray, +POP2_3_new: xr.DataArray, + +) -> xr.DataArray: + """Calculate TPOP2: total sediment POP (mg-P/L) + + Args: + POP2_1_new: POP G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + POP2_2_new: POP G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + POP2_3_new: POP G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + """ + + return POP2_1_new + POP2_2_new + POP2_3_new + +@numba.njit +def POM2( +TPOC2_new: xr.DataArray, +focm2: xr.DataArray, + +) -> xr.DataArray: + """Calculate POM2: particulate organic matter (mg/L) + + Args: + POP2_1_new: POP G1 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + POP2_2_new: POP G2 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + POP2_3_new: POP G3 in the second layer. Able for diagenesis and depends on depositional flux above (mg-P/L) + """ + + return TPOC2_new / focm2 +""" + + # TIP1 and TIP2 + + fd1 = 1.0 / (1.0 + Css1 * kdpo41) + fd2 = 1.0 / (1.0 + Css2 * kdpo42) + fp1 = 1.0 - fd1 + fp2 = 1.0 - fd2 + + + # TH2S1 and TH2S2 + H2S1 = TH2S1 / (1.0 + Css1 * kdh2s2) + H2S2 = TH2S2 / (1.0 + Css2 * kdh2s2) + + # TIP1 and TIP2 + if DOX >= DOcr : + kdpo41 = kdpo42 * d_kpo41 + else : + kdpo41 = kdpo42 * d_kpo41**(DOX / DOcr) + + DIP1 = TIP1 / (1.0 + Css1 * kdpo41) + DIP2 = TIP2 / (1.0 + Css2 * kdpo42) + + +def MatrixSolution(x1, x2, a11, a12, b1, a21, a22, b2): + x1 = x1 + x2 = x2 + a11 = a11 + a12 = a12 + b1 = b1 + a21 = a21 + a22 = a22 + b2 = b2 + + if (a11 * a22 - a12 * a21 == 0.0): + print('Twod is singular: A11,A12,A21,A22') + print('a11, a12, a21, a22') + + x1 = (a22 * b1 - a12 * b2) / (a11 * a22 - a12 * a21) + x2 = (a11 * b2 - a21 * b1) / (a11 * a22 - a12 * a21) + return x1, x2 +""" \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/old/sedflux/static_variable.py b/src/clearwater_modules/nsm1/old/sedflux/static_variable.py new file mode 100644 index 0000000..5dc4dd4 --- /dev/null +++ b/src/clearwater_modules/nsm1/old/sedflux/static_variable.py @@ -0,0 +1,259 @@ +""" +File contains static variables related to the SedFlux module +""" + +import clearwater_modules.base as base +from clearwater_modules.nsm1.model import NutrientBudget + + +@base.register_variable(models=NutrientBudget) +class Variable(base.Variable): + ... + + + + +Variable( + name='Awd', + long_name='Algal Dry Weight', + units='mg', + description='Algal Dry Weight', + use='static', +) + +""" + self.sedFlux_constants = OrderedDict() + self.sedFlux_constants = { + 'Dd': 0.0025, + 'Dp': 0.00006, + 'vnh41': 0.1313, + 'vno31': 0.1, + 'vch41': 0.7, + 'vh2sd': 0.2, + 'vh2sp': 0.4, + 'KPONG1': 0.035, + 'KPONG2': 0.0018, + 'KPOPG1': 0.035, + 'KPOPG2': 0.0018, + 'KPOCG1': 0.035, + 'KPOCG2': 0.0018, + 'vno32': 0.25, + + 'KsDp' : 4.0, + 'POCr' : 0.1, + 'res' : 0.001, + 'maxit' : 500, + 'kst' : 0.03, + 'So4_fresh' : 2, + 'focm2' : 0.4, + 'd_kpo41' : 20.0, + 'DOcr' : 2, + 'KsOxch' : 0.1, + 'KSh2s' : 4.0, + 'KsOxna1' : 0.37, + 'KsNh4' : 0.728, + 'Css1' : 0.5, + 'FPON1' : 0.15, + 'FPON2' : 0.35, + 'FPOP1' : 0.15, + 'FPOP2' : 0.35, + 'FPOC1' : 0.15, + 'FPOC2' : 0.35, + 'FAP1' : 0.6, + 'FAP2' : 0.2, + 'FAB1' : 0.6, + 'FAB2' : 0.2, + 'FCBOD1' : 0.6, + 'FCBOD2' : 0.2, + 'kdnh42' : 1.0, + 'kdh2s2' : 100.0, + 'kdpo42' :20.0, + 'KsSO4' : 1.08, + 'Css2' : 0.5, + 'SedFlux_solution_option' : 1, + 'Methane_solution_option' : 1, + 'POCdiagenesis_part_option' : 1, + 'BFORmax' : 0.0, + } + + #correction coefficients (14) + Dd = 0 #pore-water diffusion coefficient between layer 1 and 2 (m2/d) + Dd_tc = 0 + Dp = 0 # particle mixing diffusion coefficient between layer 1 and 2 (m2/d) + Dp_tc = 0 + vnh41 = 0 #nitrification reaction velocity in sediment layer 1 (m/d) + vnh41_tc = 0 + vno31 = 0 # denitrification reaction velocity in sediment layer 1 (m/d) + vno31_tc= 0 + vch41 = 0 # methane oxidation reaction velocity in sediment layer 1 (m/d) + vch41_tc= 0 + vh2sd = 0 # dissolved sulfide oxidation reaction velocity in sediment layer 1 (m/d) + vh2sd_tc = 0 + vh2sp = 0 # particulate sulfide oxidation reaction velocity in sediment layer 1 (m/d) + vh2sp_tc = 0 + + KPONG1 = 0 # diagenesis rate of PON G1 in sediment layer 2 (1/d) + KPONG2 = 0 # diagenesis rate of PON G2 in sediment layer 2 (1/d) + KPON_tc = 0 + KPOPG1 = 0 # diagenesis rate of POP G1 in sediment layer 2 (1/d) + KPOPG2 = 0 # diagenesis rate of POP G2 in sediment layer 2 (1/d) + KPOP_tc= 0 + KPOCG1 = 0 # diagenesis rate of POC G1 in sediment layer 2 (1/d) + KPOCG2 = 0 # diagenesis rate of POC G2 in sediment layer 2 (1/d) + KPOC_tc= 0 + vno32 = 0 # denitrification reaction velocity in sediment layer 2 (m/d) + vno32_tc = 0 + + res = 0 # relative error of SOD solution + maxit = 0 # max allowable iteration number for SOD solution + kst= 0 # decay rate of benthic stress (1/d) + SO4_fresh= 0 # SO4 concentration of overlaying water column in freshwater (mg-O2/L) + focm2= 0 # ratio of carbon to organic matter in bed sediment (unitless) + + d_kpo41= 0 # factor that increases the aerobic layer phosphate partition coefficient (unitless) + DOcr= 0 # critical oxygen concentration for incremental phosphate sorption (mg-O2/L) [avoid to repeat with DOC] + KsOxna1= 0 # half-saturation oxygen constant for sediment nitrification (mg-O2/L) + KsNh4= 0 # half-saturation ammonia constant for sediment nitrification (mg-N/L) + KsOxch= 0 # half-saturation coefficient for oxygen in oxidation of methane (mg-O2/L) + KSh2s= 0 # sulfide oxidation normalization constant (mg-O2/L) + KsDp= 0 # half-saturation constant for oxygen in particle mixing (mg-O2/L) + POCr= 0 # reference POC G1 concentration for bioturbation (mg-C/L) + Css1= 0 # solids concentration in sediment layer 1 (kg/L) + + FPON1= 0 # fraction of settled RPON to sediment PON G1 (unitless) + FPON2= 0 # fraction of settled RPON to sediment PON G2 (unitless) + FPOP1= 0 # fraction of settled RPOP to sediment POP G1 (unitless) + FPOP2= 0 # fraction of settled RPOP to sediment POP G2 (unitless) + FPOC1= 0 # fraction of settled RPOC to sediment POC G1 (unitless) + FPOC2= 0 # fraction of settled RPOC to sediment POC G2 (unitless) + FAP1= 0 # fraction of settled algae to G1 (unitless) + FAP2= 0 # fraction of settled algae to G2 (unitless) + FAB1= 0 # fraction of benthic algae death to G1 (unitless) + FAB2= 0 # fraction of benthic algae death to G2 (unitless) + FCBOD1= 0 # fraction of CBOD sedimentation to G1 (unitless) + FCBOD2= 0 # fraction of CBOD sedimentation to G2 (unitless) + kdnh42= 0 # partition coefficient for ammonium in sediment layer 2 (L/kg) + kdh2s2= 0 # partition coefficient for sulfide in sediment layer 2 (L/kg) + kdpo42= 0 # partition coefficient for inorganic P in sediment layer 2 (L/kg) + KsSO4= 0 # half-saturation constant for sulfate in sulfate reduction (mg-O2/L) + Css2= 0 # solids concentration in sediment layer 2 (kg/L) + + # integer parameter (3) + SedFlux_solution_option=1 # numerical method (1 steady and 2 unsteady) + Methane_solution_option=1 # method for solving methane concentration (1 analytical and 2 numerical) + POCdiagenesis_part_option=1 # method for partitioing carbon diagenesis flux into methane and sulfide (1 half-saturation and 2 sulfate reduction depth) + + # pathway (72) + JPOC= 0 # depositional flux of POC G1/G2/G3 from overlying water column to bed sediments (g-C/m2/d) + POC2_Diagenesis[3]= 0 # sediment disgenesis of POC G1/G2/G3 in sediment layer 2 (g-C/m2/d) + POC2_Burial= 0 # burial of POC G1/G2/G3 in sediment layer 2 (g-C/m2/d) + JC= 0 # total sediment diagenesis flux of POC (g-C/m2/d) + JC_dn= 0 # carbon (oxygen equivalents) consumed by denitrification (g-O2/m2/d) + + JPON= 0 # depositional flux of PON G1/G2/G3 from overlying water column to bed sediments (g-N/m2/d) + PON2_Diagenesis= 0 # sediment disgenesis of PON G1/G2/G3 in sediment layer 2 (g-N/m2/d) + PON2_Burial= 0 # burial of PON G1/G2/G3 in sediment layer 2 (g-N/m2/d) + JN = 0 # total sediment diagenesis flux of PON (g-N/m2/d) + + JPOP= 0 # depositional flux of POP G1/G2/G3 from water column to bed sediments (g-P/m2/d) + POP2_Diagenesis= 0 # sediment disgenesis of POP G1/G2/G3 in sediment layer 2 (g-P/m2/d) + POP2_Burial= 0 # burial of POP G1/G2/G3 in sediment layer 2 (g-P/m2/d) + JP # total sediment diagenesis flux of POP (g-P/m2/d) + + w12= 0 # particle mixing mass transfer coefficient (m/d) + KL12= 0 # mass transfer velocity between the two sediment layers (m/d) + KL01= 0 # mass transfer velocity between overlying water and the aerobic layer (m/d) + SOD_Bed= 0 # SedFlux sediment oxygen demand (g-O2/m2/d) + + JNH4= 0 # sediment-water flux of ammonia (g-N/m2/d) + TNH41_Burial= 0 # burial of TNH41 in sediment layer 1 (g-N/m2/d) + NH41_Nitrification= 0 # nitrification of TNH41 in sediment layer 1 (g-N/m2/d) + PNH41_PNH42= 0 # mass transfer between TNH41 and TNH42 in adsorbed form (g-N/m2/d) + NH41_NH42= 0 # mass transfer between TNH41 and TNH42 in dissolved form (g-N/m2/d) + TNH42_Burial= 0 # burial of TNH42 in sediment layer 2 (g-N/m2/d) + + JNO3= 0 # sediment-water flux of nitrate (g-N/m2/d) + NO31_Denit= 0 # denitrification of NO31 in sediment layer 1 (g-N/m2/d) + NO31_NO32= 0 # mass transfer between NO31 and NO32 (g-N/m2/d) + NO32_Denit= 0 # denitrification of NO32 in sediment layer 2 (g-N/m2/d) + + JCH4= 0 # sediment-water flux of methane (g-O2/m2/d) + JCH4g= 0 # methane loss as bubbles from sediment (g-O2/m2/d) + CH4sat= 0 # saturated concentration of methane in oxygen equivalents (mg-O2/L) + JCc_CH4= 0 # carbon diagenesis flux consumed for methane formation (g-O2/m2/d) + CH41_Oxidation= 0 # methane oxidation in sediment layer 1 (g-O2/m2/d) + + JSO4= 0 # sediment-water flux of sulfate (g-O2/m2/d) + JCc_SO4= 0 # carbon diagenesis flux consumed for sulfate reduction (g-O2/m2/d) + SO41_SO42= 0 # mass transfer between SO41 and SO42 (g-O2/m2/d) + + JH2S= 0 # sediment-water flux of sulfide (g-O2/m2/d) + H2S1_Oxidation= 0 # sulfide oxidation in sediment layer 1 (g-O2/m2/d) + TH2S1_Burial= 0 # burial of H2S1 in sediment layer 1 (g-O2/m2/d) + H2S1_H2S2= 0 # mass transfer between H2S1 and H2S2 in dissolved form (g-O2/m2/d) + PH2S1_PH2S2= 0 # mass transfer between H2S1 and H2S2 in adsorbed form (g-O2/m2/d) + TH2S2_Burial= 0 # burial of H2S2 in sediment layer 2 (g-O2/m2/d) + + JDIC= 0 # sediment-water flux of dissolved inorganic carbon (g-C/m2/d) + DIC1_CH41_Oxidation= 0 # DIC1 produced by CH41 oxidation in sediment layer 1 (g-C/m2/d) + DIC1_NO31_Denit= 0 # DIC1 produced by NO31 denitrification in sediment layer 1(g-C/m2/d) + DIC1_DIC2= 0 # mass transfer between DIC1 and DIC2 in dissolved form (g-C/m2/d) + DIC2_POC2_SO42= 0 # DIC2 produced by sulfate reduction in sediment layer 2 (g-C/m2/d) + DIC2_CH42= 0 # DIC2 produced by mathene formation in sediment layer 2 (g-C/m2/d) + DIC2_NO32_Denit= 0 # DIC2 produced by NO32 denitrification in sediment layer 2(g-C/m2/d) + + JDIP= 0 # sediment-water flux of phosphate (g-P/m2/d) + TIP_TIP2= 0 # settling of PIP of water column into PIP2 in layer 2 (g-P/m2/d) + TIP1_Burial= 0 # burial of TIP1 in sediment layer 1 (g-P/m2/d) + PIP1_PIP2= 0 # mass transfer between TIP1 and TPO42 in adsorbed form (g-P/m2/d) + DIP1_DIP2= 0 # mass transfer between TIP1 and TPO42 in dissolved form (g-P/m2/d) + TIP2_Burial= 0 # burial of TIP2 in sediment layer 2 (g-P/m2/d) + + + # local variables + TNH41, TNH42 = 0 # total ammonia concentration in sediment layer (mg-N/L) + Si1, Si2 = 0 # total silica concentration in sediment layer (mg-Si/L) + CSOD_CH4, CSOD_H2S, NSOD = 0 # carbonaceous oxygen demand, nitrogenous oxygen demand (mg-O2/L) + fd1, fd2= 0 # fraction of inorganic matter (ammonia, phosphate) in dissolved form in sediment layer + fp1, fp2= 0 # fraction of inorganic matter (ammonia, phosphate) in particulate form in sediment layer + FNH4= 0 # modification of nitrification reaction in layer 1 + FOxna= 0 # nitrification attenuation due to low oxygen in layer 1 + FOxch= 0 # methane oxidation attenuation due to low oxygen in layer 1 + rondn = 32.0 / 12.0 * 10.0 / 8.0 * 12.0 / 14.0 # oxygen stoichiometric coeff for denitrification (g-O2/g-N) + rcdn = 5.0 * 12.0 / (4.0 * 14.0) # carbon stoichiometric coeff for denitrification (g-C/g-N) + roc = 32.0 / 12.0 # oxygen stoichiometric coeff for organic carbon decay (g-O2/g-C) + ron = 2.0 * 32.0 / 14.0 # oxygen stoichiometric coeff for nitrification (g-O2/g-N) + roso4 = 2.0 * 32.0 / 98.0 # oxygen stoichiometric coeff for sulfate SO4 (g-O2/g-SO4) + a12_TNH4, a21_TNH4, a22_TNH4, b2_TNH4= 0 # matrix coefficient for TNH41, TNH42 + a12_NO3, a21_NO3, a22_NO3, b2_NO3= 0 # matrix coefficient for NO31, NO32 + a12_CH4, a21_CH4, a22_CH4= 0 # matrix coefficient for CH41, CH42 + a12_SO4, a21_SO4, a22_SO4= 0 # matrix coefficient for SO41, SO42 + a12_TH2S, a21_TH2S, a22_TH2S= 0 # matrix coefficient for TH2S1, TH2S2 + a11, a12, b1, a21, a22, b2= 0 + con_nit, con_cox, con_sox= 0 + fds1, fps1, fds2, fps2= 0 # dissolved and particulate fraction for H2S1 and H2S2 in layer 1 and 2 + CH42_prev, TH2S2_prev= 0 + + JCc= 0 # carbon diagenesis flux corrected for denitrification (g-O2/m2/d) + CSODmax= 0 # used for analytical soluton of methane (g-O2/m2/d) + TempBen = 10.0 # critical temperature for benthic stress (oC) + ISWBEN= 0 # check if water temperature of last time step < TempBen + FORmax= 0 # maximum benthic stress oxygen correction coefficient + BFORmax= 0 + + CH4 = 0.0 # methane concentration in overlying water column (mg-O2/L) + H2S = 0.0 # H2S concentration in overlying water column (mg-O2/L) + + SO4= 0 # sulfate concentration in overlying water column (mg-O2/L) + KL12SO4= 0 # dissolved mass transfer velocity of sulfate between two layers (m/day) + SO42_prev, HSO4_prev, TH2S1_prev= 0 + + roc = 32.0 / 12.0 + TempBen = 10 + roso4 = 2.0 * 32.0 / 98.0 + rondn = 32.0 / 12.0 * 10.0 / 8.0 * 12.0 / 14.0 + H2S = 0.0 + CH4 = 0.0 + ron = 2.0 * 32.0 / 14.0 + rcdn = 5.0 * 12.0 / (4.0 * 14.0) +""" \ No newline at end of file diff --git a/src/clearwater_modules/nsm1/processes.py b/src/clearwater_modules/nsm1/processes.py index c22d4a2..a30a2b8 100644 --- a/src/clearwater_modules/nsm1/processes.py +++ b/src/clearwater_modules/nsm1/processes.py @@ -315,7 +315,7 @@ def rna( AWn: xr.DataArray, AWa: xr.DataArray ) -> xr.DataArray: - """Calculate rna (mg-N/ug-Chla). + """Calculate rna (mg-N/ug-Chla) using Redfield ratios. Args: AWn: Nitrogen Weight (mg) @@ -329,7 +329,7 @@ def rpa( AWp: xr.DataArray, AWa: xr.DataArray ) -> xr.DataArray: - """Calculate rpa (mg-P/ug-Chla). + """Calculate rpa (mg-P/ug-Chla) using Redfield ratios. Args: AWp: Phosphorus Weight (mg) @@ -344,7 +344,7 @@ def rca( AWc: xr.DataArray, AWa: xr.DataArray ) -> xr.DataArray: - """Calculate rca (mg-C/ug-Chla). + """Calculate rca (mg-C/ug-Chla) using Redfield ratios. Args: AWc: Carbon Weight (mg) @@ -358,7 +358,7 @@ def rda( AWd: xr.DataArray, AWa: xr.DataArray ) -> xr.DataArray: - """Calculate rda (mg-D/ug-Chla). + """Calculate rda (mg-D/ug-Chla) using Redfield ratios. Args: AWd: Dry Algal Weight (mg) @@ -705,7 +705,7 @@ def mub_max_tc( """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) + mub_max_20: Maximum benthic algal growth rate at 20C (1/d) TwaterC: Water temperature (C) """ return arrhenius_correction(TwaterC, mub_max_20, 1.047) @@ -744,7 +744,7 @@ def rnb( BWn: xr.DataArray, BWd: xr.DataArray ) -> xr.DataArray: - """Calculate rnb (mg-N/mg-D). + """Calculate rnb (mg-N/mg-D) using Redfield ratios. Args: BWn: Benthic algae nitrogen (unitless) @@ -758,7 +758,7 @@ def rpb( BWp: xr.DataArray, BWd: xr.DataArray ) -> xr.DataArray: - """Calculate rpd: Benthic algae phosphorus to dry weight ratio (mg-P/mg-D). + """Calculate rpd: Benthic algae phosphorus to dry weight ratio (mg-P/mg-D) using Redfield ratios. Args: BWp: Benthic algae phosphorus (mg-P) @@ -772,7 +772,7 @@ def rcb( BWc: xr.DataArray, BWd: xr.DataArray ) -> xr.DataArray: - """Calculate rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D). + """Calculate rcb: Benthic algae carbon to dry weight ratio (mg-C/mg-D) using Redfield ratios. Args: BWc: Benthic algae carbon (mg-C) @@ -786,7 +786,7 @@ 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). + """Calculate rab: Benthic algae chlorophyll-a to dry weight ratio (ug-Chla-a/mg-D) using Redfield ratios. Args: BWa: Benthic algae chlorophyll-a (ug-Chla-a) @@ -907,7 +907,8 @@ def FNb( default = FNb_orig ) - + + return FNb @@ -1013,7 +1014,7 @@ def mub( default = 0 ) - + return mub @@ -1101,7 +1102,7 @@ def Chlb( Ab: xr.DataArray, ) -> xr.DataArray: - """Calculate chlorophyll-a concentration (mg-Chla/m^2) + """Calculate chlorophyll-a concentration (mg-Chla/m^2) using Redfield ratios Args: rab: Balgae Chla to Dry ratio (mg-D/ug-Chla) @@ -1170,7 +1171,7 @@ def kon_tc( kon_20: Decay rate of OrgN to NH4 (1/d) """ - return arrhenius_correction(TwaterC, kon_20, 1.074) + return arrhenius_correction(TwaterC, kon_20, 1.047) @@ -1439,6 +1440,7 @@ def NH4_Nitrification( return xr.where(use_NH4, NitrificationInhibition * knit_tc * NH4, 0) + def NH4fromBed( depth: xr.DataArray, rnh4_tc: xr.DataArray, @@ -1485,12 +1487,13 @@ def NH4_ApGrowth( 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) def NH4_AbRespiration( use_Balgae: bool, rnb: xr.DataArray, + Fb: xr.DataArray, + depth: xr.DataArray, AbRespiration: xr.DataArray, ) -> xr.DataArray: @@ -1500,10 +1503,12 @@ def NH4_AbRespiration( use_Balgae: true/false to use benthic algae module (unitless), rnb: xr.DataArray, AbRespiration: Benthic algal respiration rate (g/m^2/d), + depth: water depth (m), + Fb: Fraction of bottom area for benthic algae (unitless), """ # 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 ) + return xr.where(use_Balgae, (rnb * AbRespiration*Fb)/depth, 0.0 ) def NH4_AbGrowth( use_Balgae: bool, @@ -1706,7 +1711,6 @@ def dNO3dt( """ - return xr.where(use_NO3, NH4_Nitrification - NO3_Denit - NO3_BedDenit - NO3_ApGrowth - NO3_AbGrowth ,0) @@ -1945,8 +1949,6 @@ def DIPfromBed( """ return rpo4_tc / depth -#TODO calcuate fdp? - def TIP_Settling( vs: xr.DataArray, depth: xr.DataArray, diff --git a/tests/test_8_nsm_balgae_calculations.py b/tests/test_8_nsm_balgae_calculations.py new file mode 100644 index 0000000..beb0fd4 --- /dev/null +++ b/tests/test_8_nsm_balgae_calculations.py @@ -0,0 +1,1985 @@ +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': 36.77, + 'Ab': 24, + 'NH4': 0.063, + 'NO3': 5.54, + 'OrgN': 1.7, + 'N2': 1, + 'TIP': 0.071, + 'OrgP': 0.25, + 'POC': 4.356, + '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 + ) + +@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 + 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= 5000, + 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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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, + ) + +@pytest.fixture(scope='function') +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( + + ) + +@pytest.fixture(scope='function') +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 + ) + +@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 + 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 + ) + +@pytest.fixture(scope='function') +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, + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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 = 1, #TODO Dynamic or static? + depth = 1.5, #TODO Dynamic or static? + TwaterC = 25, + 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 = .174, + 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, + +) -> 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, + time_dim='nsm1_time_step', + ) + +@pytest.fixture(scope='module') +def tolerance() -> float: + """Controls the precision of the pytest.approx() function.""" + return 0.000001 + +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() + Ab = nsm1.dataset.isel(nsm1_time_step=-1).Ab.values.item() + + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.82632 + +def test_changed_KLb( + 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_balgae_params['KLb'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.74222 + +def test_changed_KsNb( + 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_balgae_params['KsNb'] = 0.4 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.81861 + +def test_changed_KsPb( + 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_balgae_params['KsPb'] = 0.05 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.01754 + +def test_changed_Ksb( + 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_balgae_params['Ksb'] = 20 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.99459 + +def test_changed_mub_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_balgae_params['mub_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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.67469 + +def test_changed_krb( + 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_balgae_params['krb_20'] = 0.01 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 14.92863 + +def test_changed_kdb( + 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_balgae_params['kdb_20'] = 0.8 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == -6.27152 + +def test_changed_Ab( + 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_nsm1_state['Ab'] = 40 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 14.54599 + +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_nsm1_state['NH4'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.83262 + +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_nsm1_state['NO3'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.80525 + +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_nsm1_state['TIP'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.33539 + +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'] = 30 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 4.39484 + +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'] = 0.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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.56564 + +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_nsm1_state['Ap'] = 20 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.96109 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.51805 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.63363 + +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'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.51782 + +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.008 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.54539 + +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_nsm1_state['POC'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.52808 + +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.25 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.58832 + +def test_changed_use_algae( + 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_Algae'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.22085 + +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'] = 100 + + # 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.59497 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.36945 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.56670 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.82617 + +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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.58268 + +def test_changed_use_NO3_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_NO3'] = False + 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.84008 + +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_balgae_params['b_growth_rate_option'] = 2 + default_balgae_params['b_light_limitation_option'] = 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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.84008 + +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_balgae_params['b_growth_rate_option'] = 1 + default_balgae_params['b_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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.90818 + +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_balgae_params['b_growth_rate_option'] = 2 + default_balgae_params['b_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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 8.92559 + +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_balgae_params['b_growth_rate_option'] = 1 + default_balgae_params['b_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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.31883 + +def test_changed_g2_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_balgae_params['b_growth_rate_option'] = 2 + default_balgae_params['b_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() + Ab = nsm1.dataset.isel( + nsm1_time_step=-1).Ab.values.item() + assert isinstance(Ab, float) + assert pytest.approx(Ab, tolerance) == 9.35457 \ No newline at end of file diff --git a/tests/test_9_nsm_nitrogen_calculations.py b/tests/test_9_nsm_nitrogen_calculations.py new file mode 100644 index 0000000..37147c2 --- /dev/null +++ b/tests/test_9_nsm_nitrogen_calculations.py @@ -0,0 +1,1959 @@ +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': 36.77, + 'Ab': 24, + 'NH4': 0.063, + 'NO3': 5.54, + 'OrgN': 1.726, + 'N2': 1, + 'TIP': 0.071, + 'OrgP': 0.25, + 'POC': 4.356, + '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 + ) + +@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 + 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= 5000, + 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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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 + ) + +@pytest.fixture(scope='function') +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, + ) + +@pytest.fixture(scope='function') +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( + + ) + +@pytest.fixture(scope='function') +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 + ) + +@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 + 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 + ) + +@pytest.fixture(scope='function') +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, + ) + +@pytest.fixture(scope='function') +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= False, + use_SedFlux= False, + use_POC = False, + 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 + ) + +@pytest.fixture(scope='function') +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 = 1, #TODO Dynamic or static? + depth = 1.5, #TODO Dynamic or static? + TwaterC = 25, + theta = 1.047, + velocity = 1, + flow = 150, + topwidth = 100, + slope = 0.0002, + shear_velocity = 0.05334, + pressure_atm = 1, + wind_speed = 3, + q_solar = 500, + Solid = 1, + lambda0 = .02, + lambda1 = .0088, + lambda2 = .054, + lambdas = .052, + lambdam = .174, + 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, + +) -> 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, + time_dim='nsm1_time_step', + ) + +@pytest.fixture(scope='module') +def tolerance() -> float: + """Controls the precision of the pytest.approx() function.""" + return 0.000001 + +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() + NH4 = nsm1.dataset.isel(nsm1_time_step=-1).NH4.values.item() + + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.6101494 + + NO3 = nsm1.dataset.isel(nsm1_time_step=-1).NO3.values.item() + + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.1260636 + + OrgN = nsm1.dataset.isel(nsm1_time_step=-1).OrgN.values.item() + + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.899502 + +def test_changed_knit( + 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_nitrogen_params['knit_20'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == -0.3114223 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 6.0476352 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.8995017 + +def test_changed_kon( + 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_nitrogen_params['kon_20'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 2.564564 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.1260636 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == -0.05491296 + +def test_changed_kdnit( + 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_nitrogen_params['kdnit_20'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.610149 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 4.955769 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.8995017 + +def test_changed_rnh4( + 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_nitrogen_params['rnh4_20'] = -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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == -0.3424935 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.12606356 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +def test_changed_rnh4_KsOxdn( + 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_nitrogen_params['rnh4_20'] = 1 + default_nitrogen_params['KsOxdn'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 1.5627923 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.11856308 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +def test_changed_vno3( + 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_nitrogen_params['vno3_20'] = 0.9 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.610149379 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 0.242017033 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +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'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.472669296 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.23749182 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.729153886 + +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'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.31604458 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.330296324 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.8073881 + +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_nsm1_state['NH4'] = 0.01 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.569020898 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.114263537 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +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_nsm1_state['NO3'] = 20 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.61359955 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 19.57664053 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +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_nsm1_state['Ap'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.5553608647 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.3696889 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.85633245 + +def test_changed_DOX( + 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_nsm1_state['DOX'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.6152233076 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.1199048523 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.899501691 + +def test_changed_OrgN( + 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_nsm1_state['OrgN'] = 7 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 1.2736991965 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.12606356 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 6.47479187 + +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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.063 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.1120288 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.40213002 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.54 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +def test_changed_use_OrgN( + 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_OrgN'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.392992196 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.126063560 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.726 + +def test_changed_use_DOX( + 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_DOX'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.61007213 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.12631127 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +def test_changed_use_Algae( + 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_Algae'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.54676037 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.409982005 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.849538428 + +def test_changed_use_Balgae( + 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_Balgae'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.33406138337 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.24974272 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.547299413 + +def test_changed_PN( + 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_nitrogen_params['PN'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.6120854746 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.124127465 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.899501691 + +def test_changed_PNb( + 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_nitrogen_params['PNb'] = 0.7 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.60832257266 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.127890367 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.89950169 + +def test_changed_Fw( + 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_balgae_params['Fw'] = 0.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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.610149379 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.12606356028 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.7429673455 + +def test_changed_Fb( + 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_balgae_params['Fb'] = 0.4 + + # 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.456767159 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.194774206 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.703833759 + +def test_changed_use_Algae_use_Balgae( + 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_Algae'] = False + default_gp_params['use_Balgae'] = 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.2708483787 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.549138339 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.49733615 + +def test_changed_use_Algae_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_Algae'] = False + 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.063 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.39915906 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.849538428 + +def test_changed_use_Algae_use_NH4_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_Algae'] = False + default_gp_params['use_NH4'] = False + 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() + NH4 = nsm1.dataset.isel( + nsm1_time_step=-1).NH4.values.item() + assert isinstance(NH4, float) + assert pytest.approx(NH4, tolerance) == 0.063 + + NO3 = nsm1.dataset.isel( + nsm1_time_step=-1).NO3.values.item() + assert isinstance(NO3, float) + assert pytest.approx(NO3, tolerance) == 5.54 + + OrgN = nsm1.dataset.isel( + nsm1_time_step=-1).OrgN.values.item() + assert isinstance(OrgN, float) + assert pytest.approx(OrgN, tolerance) == 1.849538428 \ No newline at end of file