class Growth_Monod_Eppley_Steele: resource = phydra.variable(foreign=True, flux='growth', negative=True) consumer = phydra.variable(foreign=True, flux='growth', negative=False) Temp = phydra.forcing(foreign=True, description='Temperature forcing') Light = phydra.forcing(foreign=True, description='Light forcing') MLD = phydra.forcing(foreign=True, description='Mixed Layer Depth forcing') halfsat = phydra.parameter(description='monod half-saturation constant') eppley = phydra.parameter(description='eppley exponent') i_opt = phydra.parameter(description='Optimal irradiance of consumer') µ_max = phydra.parameter(description='maximum growth rate') kw = phydra.parameter(description='light attenuation coef for water') kc = phydra.parameter(description='light attenuation coef for consumer') @phydra.flux def growth(self, resource, consumer, Temp, Light, MLD, i_opt, kw, kc, eppley, halfsat, µ_max): temp_lim = self.m.exp(eppley * Temp) monod_lim = resource / (resource + halfsat) kPAR = kw + kc * consumer light_lim = 1. / (kPAR * MLD) * ( -self.m.exp(1. - Light / i_opt) - ( -self.m.exp((1. - (Light * self.m.exp(-kPAR * MLD)) / i_opt)))) return µ_max * temp_lim * monod_lim * light_lim * consumer
class GrossGrowthEfficiency: """ to N: beta*(1-epsilon) to D: 1-beta to Z: beta*epsilon """ assimilated_consumer = phydra.variable(foreign=True, flux='assimilation') egested_detritus = phydra.variable(foreign=True, flux='egestion') excreted_nutrient = phydra.variable(foreign=True, flux='excretion') beta = phydra.parameter(description='absorption efficiency') epsilon = phydra.parameter(description='net production efficiency') @phydra.flux(group_to_arg='graze_out') def assimilation(self, assimilated_consumer, egested_detritus, excreted_nutrient, graze_out, beta, epsilon): return self.m.sum(graze_out) * beta * epsilon @phydra.flux(group_to_arg='graze_out') def egestion(self, assimilated_consumer, egested_detritus, excreted_nutrient, graze_out, beta, epsilon): return self.m.sum(graze_out) * (1 - beta) @phydra.flux(group_to_arg='graze_out') def excretion(self, assimilated_consumer, egested_detritus, excreted_nutrient, graze_out, beta, epsilon): return self.m.sum(graze_out) * beta * (1 - epsilon)
class HollingTypeIII: resource = phydra.variable(foreign=True, flux='grazing', negative=True) consumer = phydra.variable(foreign=True, flux='grazing', negative=False) feed_pref = phydra.parameter(description='feeding preferences') Imax = phydra.parameter(description='maximum ingestion rate') kZ = phydra.parameter(description='feeding preferences') @phydra.flux def grazing(self, resource, consumer, feed_pref, Imax, kZ): return Imax * resource ** 2 \ * feed_pref / (kZ ** 2 + self.m.sum([resource ** 2 * feed_pref])) * consumer
class MonodGrowth: resource = phydra.variable(foreign=True, flux='uptake', negative=True) consumer = phydra.variable(foreign=True, flux='uptake', negative=False) # dims='var', halfsat = phydra.parameter( description='half-saturation constant') # dims='var' @phydra.flux def uptake(self, resource, consumer, halfsat): return resource / (resource + halfsat) * consumer
class LinearExchange_SourceDim: """ """ source = phydra.variable(foreign=True, dims='var', flux='decay', negative=True) sink = phydra.variable(foreign=True, flux='decay', negative=False) rate = phydra.parameter(description='decay/mortality rate') @phydra.flux(dims='var') def decay(self, source, sink, rate): return source * rate
class EMPOWER_Growth_ML: """ XXX """ resource = phydra.variable(foreign=True, flux='growth', negative=True) consumer = phydra.variable(foreign=True, flux='growth', negative=False) mu_max = phydra.parameter(description='maximum growth rate') @phydra.flux(group_to_arg='growth_lims') def growth(self, resource, consumer, mu_max, growth_lims): # print("in growth flux func now", resource, consumer, mu_max, growth_lims) return mu_max * self.m.product(growth_lims) * consumer
class QuadraticExchange_SourceDim: """ """ source = phydra.variable(foreign=True, dims='var', flux='decay', negative=True) sink = phydra.variable(foreign=True, flux='decay', negative=False) rate = phydra.parameter(description='quadratic rate of change') @phydra.flux(dims='var') def decay(self, source, sink, rate): """ """ return source**2 * rate
class MonodGrowth_mu_ConsumerDim: resource = phydra.variable(foreign=True, flux='uptake', negative=True) consumer = phydra.variable(foreign=True, dims='var', flux='uptake', negative=False) # dims='var', halfsat = phydra.parameter( dims='var', description='half-saturation constant') # dims='var' mu_max = phydra.parameter(dims='var', description='maximum growth rate') @phydra.flux(dims='var') def uptake(self, resource, consumer, halfsat, mu_max): return mu_max * resource / (resource + halfsat) * consumer
class ListInputFlux: """ get variable input of multiple labels as list and do the routing etc. """ resources = phydra.variable(foreign=True, negative=True, flux='growth', list_input=True, dims='resources') consumer = phydra.variable(foreign=True, flux='growth') halfsats = phydra.parameter(dims='resources') @phydra.flux(dims='resources') def growth(self, resources, consumer, halfsats): print(resources, consumer, halfsats) print(sum(resources + halfsats)) out = resources / sum(resources + halfsats) * consumer print("out:", out, np.shape(out)) return out
class SizebasedGrazingKernel_Dims: """ ASTroCAT Grazing Kernel """ resource = phydra.variable(foreign=True, dims='resource') consumer = phydra.variable(foreign=True, dims='consumer') phiP = phydra.parameter(dims=('resource', 'consumer'), description='feeding preferences') Imax = phydra.parameter(dims='consumer', description='maximum ingestion rate') KsZ = phydra.parameter(description='half sat of grazing') @phydra.flux(group='graze_matrix', dims=('resource', 'consumer')) def grazing(self, resource, consumer, phiP, Imax, KsZ): """ """ PscaledAsFood = phiP / KsZ * resource[:, None] FgrazP = Imax * consumer * PscaledAsFood / ( 1 + self.m.sum(PscaledAsFood, axis=0)) return FgrazP
class EMPOWER_Monod_ML: """ """ resource = phydra.variable(foreign=True) halfsat = phydra.parameter(description='monod half-saturation constant') @phydra.flux(group='growth_lims') def monod_lim(self, resource, halfsat): return resource / (resource + halfsat)
class SlabSinking: """ """ var = phydra.variable(foreign=True, flux='sinking', negative=True) mld = phydra.forcing(foreign=True) rate = phydra.parameter(description='sinking rate, units: m d^-1') @phydra.flux def sinking(self, var, rate, mld): return var * rate / mld
class GroupedFlux: """ XXX """ var = phydra.variable(foreign=True, flux='growth') @phydra.flux(group_to_arg='X_growth', description='HELLO') def growth(self, var, X_growth): # print(X_growth) return sum(X_growth)
class HollingTypeIII_ResourcesListInput_Consumption2Group: """ """ resources = phydra.variable(foreign=True, negative=True, flux='grazing', list_input=True, dims='resources') consumer = phydra.variable(foreign=True) feed_prefs = phydra.parameter( dims='resources', description='feeding preference for resources') Imax = phydra.parameter(description='maximum ingestion rate') kZ = phydra.parameter(description='feeding preferences') @phydra.flux(group='graze_out', dims='resources') def grazing(self, resources, consumer, feed_prefs, Imax, kZ): scaled_resources = resources**2 * feed_prefs return scaled_resources * Imax / ( kZ**2 + self.m.sum(scaled_resources)) * consumer
class Monod_ML_ConsumerDim: """ """ resource = phydra.variable(foreign=True) halfsat = phydra.parameter(dims='vars', description='monod half-saturation constant') @phydra.flux(dims='vars', group='growth_lims') def monod_lim(self, resource, halfsat): #print("in monod lim", resource, halfsat) #print(resource.value.ndim) return resource / (resource + halfsat)
class SubFlux: var = phydra.variable(foreign=True) rate = phydra.parameter() @phydra.flux(group='X_growth') def one_growth(self, var, rate): # print(var) return var * rate @phydra.flux(group='X_growth') def two_growth(self, var, rate): return - var * rate
class ExponentialGrowth_Dim: """ """ var = phydra.variable(foreign=True, dims='var', flux='growth', negative=False, description='variable affected by flux') rate = phydra.parameter(description='linear rate of change') @phydra.flux(dims='var') def growth(self, var, rate): """ """ return var * rate
class LinearDecay_VarDim: """ """ var = phydra.variable(dims='var', foreign=True, flux='decay', negative=True, description='variable affected by flux') rate = phydra.parameter(description='linear rate of decay/mortality') @phydra.flux(dims='var') def decay(self, var, rate): """ """ return var * rate
class LinearInput_Dim: """ """ var = phydra.variable(foreign=True, dims='var', flux='input', negative=False, description='variable affected by flux') rate = phydra.parameter(dims='var', description='linear rate of change') @phydra.flux(dims='var') def input(self, var, rate): """ """ return rate
class QuadraticDecay_Dim: """ """ var = phydra.variable(foreign=True, dims='var', flux='decay', negative=True, description='variable affected by flux') rate = phydra.parameter(description='quadratic rate of change') @phydra.flux(dims='var') def decay(self, var, rate): """ """ return var**2 * rate
class LinearForcingInput: var = phydra.variable(foreign=True, flux='input', negative=False, description='variable affected by flux') forcing = phydra.forcing(foreign=True, description='forcing affecting flux') rate = phydra.parameter(description='linear rate of change') @phydra.flux def input(self, var, forcing, rate): """ """ return forcing * rate
class GrossGrowthEfficiency_MatrixGrazing: """ to N: beta*(1-epsilon) to D: 1-beta to Z: beta*epsilon """ grazed_resource = phydra.variable(dims='resource', foreign=True, flux='grazing', negative=True) assimilated_consumer = phydra.variable(dims='consumer', foreign=True, flux='assimilation') egested_detritus = phydra.variable(foreign=True, flux='egestion') f_eg = phydra.parameter(description='fraction egested') epsilon = phydra.parameter(description='net production efficiency') @phydra.flux(dims='resource', group_to_arg='graze_matrix') def grazing(self, assimilated_consumer, egested_detritus, grazed_resource, graze_matrix, f_eg, epsilon): """ """ out = self.m.sum(graze_matrix, axis=1) return out @phydra.flux(dims='consumer', group_to_arg='graze_matrix') def assimilation(self, assimilated_consumer, egested_detritus, grazed_resource, graze_matrix, f_eg, epsilon): """ """ out = self.m.sum(graze_matrix, axis=0) * epsilon return out @phydra.flux(group_to_arg='graze_matrix') def egestion(self, assimilated_consumer, egested_detritus, grazed_resource, graze_matrix, f_eg, epsilon): """ """ out = self.m.sum(graze_matrix, axis=None) * (1 - f_eg - epsilon) return out
class SlabUpwelling_KfromGroup: """ """ n = phydra.variable(foreign=True, flux='mixing', description='nutrient mixed into system') n_0 = phydra.forcing( foreign=True, description='nutrient concentration below mixed layer depth') @phydra.flux(group_to_arg='mixing_K') def mixing(self, n, n_0, mixing_K): """ compute function of on_demand xarray variable specific flux needs to be implemented in BaseFlux """ return (n_0 - n) * mixing_K
class SlabMixing_KfromGroup: """ """ vars_sink = phydra.variable(foreign=True, negative=True, flux='mixing', list_input=True, dims='sinking_vars', description='list of variables affected') @phydra.flux(dims='sinking_vars_full', group_to_arg='mixing_K') def mixing(self, vars_sink, mixing_K): """ compute function of on_demand xarray variable specific flux needs to be implemented in BaseFlux """ return vars_sink * mixing_K
class SlabUpwelling: """ """ n = phydra.variable(foreign=True, flux='mixing', description='nutrient mixed into system') n_0 = phydra.forcing( foreign=True, description='nutrient concentration below mixed layer depth') mld = phydra.forcing(foreign=True) mld_deriv = phydra.forcing(foreign=True) kappa = phydra.parameter(description='constant mixing coefficient') @phydra.flux def mixing(self, n, n_0, mld, mld_deriv, kappa): """ compute function of on_demand xarray variable specific flux needs to be implemented in BaseFlux """ return (n_0 - n) * (self.m.max(mld_deriv, 0) + kappa) / mld
class SlabMixing: """ """ vars_sink = phydra.variable(foreign=True, negative=True, flux='mixing', list_input=True, dims='sinking_vars', description='list of variables affected') mld = phydra.forcing(foreign=True) mld_deriv = phydra.forcing(foreign=True) kappa = phydra.parameter(description='constant mixing coefficient') @phydra.flux(dims='sinking_vars_full') def mixing(self, vars_sink, mld, mld_deriv, kappa): """ compute function of on_demand xarray variable specific flux needs to be implemented in BaseFlux """ return vars_sink * (self.m.max(mld_deriv, 0) + kappa) / mld
class Steele_ML: """ """ pigment_biomass = phydra.variable(foreign=True) i_0 = phydra.forcing(foreign=True, description='Light forcing') mld = phydra.forcing(foreign=True, description='Mixed Layer Depth forcing') i_opt = phydra.parameter(description='Optimal irradiance of consumer') kw = phydra.parameter(description='light attenuation coef for water') kc = phydra.parameter( description='light attenuation coef for pigment biomass') @phydra.flux(group='growth_lims') def steele_light_lim(self, i_0, mld, pigment_biomass, i_opt, kw, kc): kPAR = kw + kc * pigment_biomass light_lim = 1. / (kPAR * mld) * (-self.m.exp(1. - i_0 / i_opt) - (-self.m.exp( (1. - (i_0 * self.m.exp(-kPAR * mld)) / i_opt)))) return light_lim
class EMPOWER_Smith_ML: """ """ pigment_biomass = phydra.variable(foreign=True) i_0 = phydra.forcing(foreign=True, description='Light forcing') mld = phydra.forcing(foreign=True, description='Mixed Layer Depth forcing') alpha = phydra.parameter(description='initial slop of PI curve') CtoChl = phydra.parameter(description='chlorophyll to carbon ratio') kw = phydra.parameter(description='light attenuation coef for water') kc = phydra.parameter( description='light attenuation coef for pigment biomass') @phydra.flux(group_to_arg='VpT', group='growth_lims') def smith_light_lim(self, i_0, mld, pigment_biomass, alpha, VpT, kw, kc, CtoChl): kPAR = kw + kc * pigment_biomass i_0 = i_0 / 24 # from per day to per h x_0 = alpha * i_0 # * self.m.exp(- kPAR * 0) # (== 1) x_H = alpha * i_0 * self.m.exp(-kPAR * mld) VpH = VpT / kPAR / mld * (self.m.log(x_0 + (VpT**2 + x_0**2)**0.5) - self.m.log(x_H + (VpT**2 + x_H**2)**0.5)) return VpH * 24 / CtoChl
class Smith_ML: """ """ pigment_biomass = phydra.variable(foreign=True) i_0 = phydra.forcing(foreign=True, description='Light forcing') mld = phydra.forcing(foreign=True, description='Mixed Layer Depth forcing') alpha = phydra.parameter(description='initial slop of PI curve') VpMax = phydra.parameter(description='Maximum photosynthetic rate') kw = phydra.parameter(description='light attenuation coef for water') kc = phydra.parameter( description='light attenuation coef for pigment biomass') @phydra.flux(group='growth_lims') def smith_light_lim(self, i_0, mld, pigment_biomass, alpha, VpMax, kw, kc): kPAR = kw + kc * pigment_biomass x_0 = alpha * i_0 # * self.m.exp(- kPAR * 0) # (== 1) x_H = alpha * i_0 * self.m.exp(-kPAR * mld) VpH = (VpMax / (kPAR * mld)) * \ self.m.log( (x_0 + self.m.sqrt(VpMax ** 2 + x_0 ** 2)) / (x_H + self.m.sqrt(VpMax ** 2 + x_H ** 2)) ) return VpH
class SV: """represents a state variable in the model""" var = phydra.variable(description='basic state variable')