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 Mixing_K: """ pre-computes K to be used in all mixing processes """ mld = phydra.forcing(foreign=True) mld_deriv = phydra.forcing(foreign=True) kappa = phydra.parameter(description='constant mixing coefficient') @phydra.flux(group='mixing_K') def mixing(self, mld, mld_deriv, kappa): return (self.m.max(mld_deriv, 0) + kappa) / mld
class GlobalSlabClimatologyForcing: forcing = phydra.forcing(foreign=False, setup_func='forcing_setup') dataset = phydra.parameter(description="Options: 'n0x', 'mld', 'tmld', 'par'") lat = phydra.parameter(description='constant value of forcing') lon = phydra.parameter(description='constant value of forcing') rbb = phydra.parameter(description='constant value of forcing') smooth = phydra.parameter(description='smoothing conditions, larger values = stronger smoothing') k = phydra.parameter(description='The degree of the spline fit') deriv = phydra.parameter(description='order of derivative to store, for basic forcing pass 0') def forcing_setup(self, dataset, lat, lon, rbb, smooth, k, deriv): data = ClimatologyForcing(lat, lon, rbb, dataset).outForcing dayspermonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] dpm = dayspermonth dpm_cumsum = np.cumsum(dpm) - np.array(dpm) / 2 time = np.concatenate([[0], dpm_cumsum, [365]], axis=None) boundary_int = [(data[0] + data[-1]) / 2] dat = np.concatenate([boundary_int, data, boundary_int], axis=None) spl = intrp.splrep(time, dat, per=True, k=k, s=smooth) def forcing(time): return intrp.splev(np.mod(time, 365), spl, der=deriv) return forcing
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 Eppley_ML: """ """ temp = phydra.forcing(foreign=True, description='Temperature forcing') eppley_exp = phydra.parameter(description='eppley exponent') @phydra.flux(group='growth_lims') def eppley_growth(self, temp, eppley_exp): return self.m.exp(eppley_exp * temp)
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 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 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 EMPOWER_Eppley_ML: """ """ temp = phydra.forcing(foreign=True, description='Temperature forcing') VpMax = phydra.parameter( description='Maximum photosynthetic rate at 0 degrees celcius') @phydra.flux(group='VpT') def temp_dependence(self, temp, VpMax): return VpMax * 1.066**temp
class IrradianceFromNoonPAR: """ Calculate I0 at surface from noon PAR TODO: DOESNT WORK WITH FOREIGN FORCING YET! NEED TO FIX IN XARRAY SIMLAB ODE """ NoonPAR = phydra.forcing(foreign=True) I0 = phydra.forcing(setup_func='calculate_I0', description='calculated irradiance for latitude', attrs={'unit': 'W m^-2'}) station = phydra.parameter(description="name of station, options: 'india', 'biotrans', 'kerfix', 'papa'") def calculate_I0(self, station, NoonPAR): def day_length_calc(jday, latradians): """ Function to calculate day length for location """ declin = 23.45 * np.sin(2 * np.pi * (284 + jday) * 0.00274) * np.pi / 180 # solar declination angle daylnow = 2 * np.arccos(-1 * np.tan(latradians) * np.tan(declin)) * 12 / np.pi # day length return daylnow if station == 'india': latitude = 60.0 # latitude, degrees elif station == 'biotrans': latitude = 47.0 elif station == 'kerfix': latitude = -50.67 elif station == 'papa': latitude = 50.0 else: raise ValueError("station label not found, options: 'india', 'biotrans', 'kerfix', 'papa'") latradians = latitude * np.pi / 180. def return_PAR_forcing(time): day_length = day_length_calc(time, latradians) print("day_len", day_length) noonpar = NoonPAR print("NOON PAR", noonpar) return noonpar * day_length * np.sin(2 / np.pi) # sinusoidal integration # return noonpar * day_length / 2 # trapezoidal integration return return_PAR_forcing
class SinusoidalForcing: forcing = phydra.forcing(foreign=False, setup_func='forcing_setup') period = phydra.parameter(description='period of sinusoidal forcing') def forcing_setup(self, period): cwd = os.getcwd() print("forcing function is in directory:", cwd) @np.vectorize def forcing(time): return np.cos(time / period * 2 * np.pi) + 1 return forcing
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 NoonPARfromLat: """ Component that calculates Photosynthetically Active Radiation (PAR) from Latitude""" NoonPAR = phydra.forcing(setup_func='calcNoonPAR', description='calculated PAR from Irradiance', attrs={'unit': 'W m^-2'}) station = phydra.parameter(description="name of station, options: 'india', 'biotrans', 'kerfix', 'papa'") def calcNoonPAR(self, station): """ Function adapted from EMPOWER model (Anderson et al. 2015)""" def noon_PAR_calc(jday, latradians, clouds, e0): albedo = 0.04 # albedo solarconst = 1368.0 # solar constant, w m-2 parrac = 0.43 # PAR fraction declin = 23.45 * np.sin(2 * np.pi * (284 + jday) * 0.00274) * np.pi / 180 # solar declination angle coszen = np.sin(latradians) * np.sin(declin) + np.cos(latradians) * np.cos(declin) # cosine of zenith angle zen = np.arccos(coszen) * 180 / np.pi # zenith angle, degrees Rvector = 1 / np.sqrt(1 + 0.033 * np.cos(2 * np.pi * jday * 0.00274)) # Earth's radius vector Iclear = solarconst * coszen ** 2 / (Rvector ** 2) / ( 1.2 * coszen + e0 * (1.0 + coszen) * 0.001 + 0.0455) # irradiance at ocean surface, clear sky cfac = (1 - 0.62 * clouds * 0.125 + 0.0019 * (90 - zen)) # cloud factor (atmospheric transmission) Inoon = Iclear * cfac * (1 - albedo) # noon irradiance: total solar noonparnow = parrac * Inoon return noonparnow if station == 'india': latitude = 60.0 # latitude, degrees clouds = 6.0 # cloud fraction, oktas e0 = 12.0 # atmospheric vapour pressure elif station == 'biotrans': latitude = 47.0 clouds = 6.0 e0 = 12.0 elif station == 'kerfix': latitude = -50.67 clouds = 6.0 e0 = 12.0 elif station == 'papa': latitude = 50.0 clouds = 6.0 e0 = 12.0 else: raise ValueError("station label not found, options: 'india', 'biotrans', 'kerfix', 'papa'") latradians = latitude * np.pi / 180. def return_noonPAR(time): return noon_PAR_calc(time, latradians, clouds, e0) return return_noonPAR
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 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 ConstantForcing: forcing = phydra.forcing(foreign=False, setup_func='forcing_setup') value = phydra.parameter(description='constant value of forcing') def forcing_setup(self, value): cwd = os.getcwd() print("forcing function is in directory:", cwd) print("forcing_val:", value) @np.vectorize def forcing(time): return value return forcing
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 EMPOWER_Anderson_Light_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 irradiance_out(self, i_0, mld, pigment_biomass, alpha, VpT, kw, kc, CtoChl): """ """ i_0 = i_0 / 24 chl = pigment_biomass * 6.625 * 12.0 / CtoChl # chlorophyll, mg m-3 (Redfield ratio of 6.625 mol C mol N-1 assumed for C:N of phytoplankton) ss = chl**0.5 # square root of chlorophyll kPAR_1 = 0.13096 + 0.030969 * ss + 0.042644 * ss**2 - 0.013738 * ss**3 + 0.0024617 * ss**4 - 0.00018059 * ss**5 kPAR_2 = 0.041025 + 0.036211 * ss + 0.062297 * ss**2 - 0.030098 * ss**3 + 0.0062597 * ss**4 - 0.00051944 * ss**5 kPAR_3 = 0.021517 + 0.050150 * ss + 0.058900 * ss**2 - 0.040539 * ss**3 + 0.0087586 * ss**4 - 0.00049476 * ss**5 kPAR = [kPAR_1, kPAR_2, kPAR_3] if mld <= 5.0: jnlay = 1 zbase = [0., mld] zdep = [0., mld] I_1 = i_0 * np.exp(-kPAR_1 * mld) Ibase = [i_0, I_1] elif mld > 5.0 and mld <= 23.0: jnlay = 2 zbase = [0., 5.0, mld] zdep = [0., 5.0, mld - 5.0] mld_rest = mld - 5.0 I_1 = i_0 * np.exp(-kPAR_1 * 5.0) I_2 = I_1 * np.exp(-kPAR_2 * mld - 5.0) Ibase = [i_0, I_1, I_2] elif mld > 23.0: jnlay = 3 zbase = [0., 5.0, 23.0, mld] zdep = [0., 5.0, 23.0 - 5.0, mld - 23.0] I_1 = i_0 * np.exp(-kPAR_1 * 5.0) I_2 = I_1 * np.exp(-kPAR_2 * 23.0 - 5.0) I_3 = I_2 * np.exp(-kPAR_3 * mld - 23.0) Ibase = [i_0, I_1, I_2, I_3] aphybase = [0, 0, 0, 0] aphybase[ 0] = 0.36796 + 0.17537 * ss - 0.065276 * ss**2 + 0.013528 * ss**3 - 0.0011108 * ss**4 # a (chl absorption) at ocean surface as function chl L_Isum = 0 for ilay in range(1, jnlay + 1): L_I = self.SmithFunc(zdep[ilay], Ibase[ilay - 1], Ibase[ilay], kPAR[ilay - 1], alpha, VpT) L_I = L_I * 24 / CtoChl # / VpT L_Isum = L_Isum + L_I * zdep[ilay] # for ilay in range(1, jnlay+1): # ahash = self.FNaphy(ss,zbase[ilay-1],zbase[ilay],aphybase[ilay-1]) # change in a with depth # aphybase[ilay] = aphybase[ilay-1]+ahash # a at base of layer # aphyav = aphybase[ilay-1]+ahash*0.5 # average a in layer (from which alpha is calculated: alpha = a*alphamax # L_I = self.FNLIcalcA93(zdep[ilay],Ibase[ilay-1],Ibase[ilay],kPAR[ilay-1],alpha,VpT,aphyav) # L_Isum = L_Isum + L_I*zdep[ilay] # multiply by layer depth in order to set up weighted average for total mixed layer L_I = L_Isum / mld return L_I def SmithFunc(self, zdepth, Iin, Iout, kPARlay, alpha, Vp): x0 = alpha * Iin xH = alpha * Iout # *np.exp(-kPARlay*zdepth) VpH = Vp / kPARlay / zdepth * (np.log(x0 + (Vp**2 + x0**2)**0.5) - np.log(xH + (Vp**2 + xH**2)**0.5)) return VpH def FNaphy(self, ss, ztop, zbottom, aphylast): """ FNaphy calculates values of a (chlorophyll abosorption) for each layer; alpha[layer] is then calculated as a[layer]*alphamax """ g = [ 0.048014, 0.00023779, -0.023074, 0.0031095, -0.0090545, 0.0027974, 0.00085217, -3.9804E-06, 0.0012398, -0.00061991 ] # coeffs. for calculating a# x = zbottom + 1.0 xlg = np.log(x) termf1a = x * xlg - x termf2a = x * xlg**2 - 2 * x * xlg + 2 * x termf3a = x * xlg**3 - 3 * x * xlg**2 + 6 * x * xlg - 6 * x x = ztop + 1.0 xlg = np.log(x) termf1b = x * xlg - x termf2b = x * xlg**2 - 2 * x * xlg + 2 * x termf3b = x * xlg**3 - 3 * x * xlg**2 + 6 * x * xlg - 6 * x terma = g[0] + g[1] * ss + g[4] * ss**2 + g[6] * ss**3 termb = g[2] + g[3] * ss + g[8] * ss**2 termc = g[5] + g[9] * ss acalc = (zbottom + 1.0) * terma + termf1a * termb + \ termf2a * termc + termf3a * g[7] - ((ztop + 1.0) * terma + \ termf1b * termb + termf2b * termc + termf3b * g[7]) return acalc def FNLIcalcA93(self, zdepth, Iin, Iout, kPARlay, alpha, Vp, ahashnow): """ # Photosynthesis calculated using polynomial approximation (Anderson, 1993) """ omeg = [ 1.9004, -2.8333E-01, 2.8050E-02, -1.4729E-03, 3.0841E-05 ] # polynomial coefficients for calculating photosynthesis (Platt et al., 1990) # Calculate alphamax alphamax = alpha * 2.602 # alphamax is alpha at wavelength of maximum absorption cross section # Calculate daily photosynthesis in each layer, mg C m-2 d-1 V0 = Vp / (np.pi * kPARlay) V1 = alphamax * ahashnow * Iin / Vp V2 = alphamax * ahashnow * Iout / Vp Qpsnow = V0 * (omeg[0] * (V1 - V2) + omeg[1] * (V1**2 - V2**2) + omeg[2] * (V1**3 - V2**3) + omeg[3] * (V1**4 - V2**4) + omeg[4] * (V1**5 - V2**5)) # convert to dimensionless units to get 0 <= J <= 1 Lim_I = Qpsnow / zdepth / Vp # /24. return Lim_I
class EMPOWER_IrradianceFromLat: """ Component that calculates daily irradiance from latitude of station """ I0 = phydra.forcing(setup_func='calculate_I0', description='calculated irradiance for latitude', attrs={'unit': 'W m^-2'}) station = phydra.parameter(description="name of station, options: 'india', 'biotrans', 'kerfix', 'papa'") def calculate_I0(self, station): """ Function adapted from EMPOWER model (Anderson et al. 2015)""" def day_length_calc(jday, latradians): """ Function to calculate day length for location """ declin = 23.45 * np.sin(2 * np.pi * (284 + jday) * 0.00274) * np.pi / 180 # solar declination angle daylnow = 2 * np.arccos(-1 * np.tan(latradians) * np.tan(declin)) * 12 / np.pi # day length return daylnow def noon_PAR_calc(jday, latradians, clouds, e0): albedo = 0.04 # albedo solarconst = 1368.0 # solar constant, w m-2 parrac = 0.43 # PAR fraction declin = 23.45 * np.sin(2 * np.pi * (284 + jday) * 0.00274) * np.pi / 180 # solar declination angle coszen = np.sin(latradians) * np.sin(declin) + np.cos(latradians) * np.cos(declin) # cosine of zenith angle zen = np.arccos(coszen) * 180 / np.pi # zenith angle, degrees Rvector = 1 / np.sqrt(1 + 0.033 * np.cos(2 * np.pi * jday * 0.00274)) # Earth's radius vector Iclear = solarconst * coszen ** 2 / (Rvector ** 2) / ( 1.2 * coszen + e0 * (1.0 + coszen) * 0.001 + 0.0455) # irradiance at ocean surface, clear sky cfac = (1 - 0.62 * clouds * 0.125 + 0.0019 * (90 - zen)) # cloud factor (atmospheric transmission) Inoon = Iclear * cfac * (1 - albedo) # noon irradiance: total solar noonparnow = parrac * Inoon return noonparnow if station == 'india': latitude = 60.0 # latitude, degrees clouds = 6.0 # cloud fraction, oktas e0 = 12.0 # atmospheric vapour pressure elif station == 'biotrans': latitude = 47.0 clouds = 6.0 e0 = 12.0 elif station == 'kerfix': latitude = -50.67 clouds = 6.0 e0 = 12.0 elif station == 'papa': latitude = 50.0 clouds = 6.0 e0 = 12.0 else: raise ValueError("station label not found, options: 'india', 'biotrans', 'kerfix', 'papa'") latradians = latitude * np.pi / 180. def return_PAR_forcing(time): day_length = day_length_calc(time, latradians) # print("day_len", day_length) noonpar = noon_PAR_calc(time, latradians, clouds, e0) return noonpar * day_length * np.sin(2 / np.pi) # sinusoidal integration # return noonpar * day_length / 2 # trapezoidal integration return return_PAR_forcing
class EMPOWER_ForcingFromFile: """ """ MLD = phydra.forcing(setup_func='create_MLD_forcing', description='Empower MLD Forcing') MLDderiv = phydra.forcing(setup_func='create_MLD_deriv_forcing', description='Empower MLDderiv Forcing') SST = phydra.forcing(setup_func='create_SST_forcing', description='Empower SST Forcing') N0 = phydra.forcing(setup_func='create_N0_forcing', description='Empower N0 Forcing') station = phydra.parameter(description="name of station, options: 'india', 'biotrans', 'kerfix', 'papa'") def read_intrp_forcing(self, station, data, k, smooth, deriv): """ """ stations_dict = {'india': {'MLD': 'MLD_India', 'SST': 'SST_India'}, 'biotrans': {'MLD': 'MLD_Biotrans', 'SST': 'SST_Biotrans'}, 'kerfix': {'MLD': 'MLD_Kerfix', 'SST': 'SST_Kerfix'}, 'papa': {'MLD': 'MLD_Papa', 'SST': 'SST_Papa'}} all_forcings = pandas.read_csv("stations_forcing.txt", sep=r'\s*,\s*', header=0, encoding='ascii', engine='python') station_data = all_forcings[stations_dict[station][data]].values[:-1] dayspermonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] dpm = dayspermonth dpm_cumsum = np.cumsum(dpm) - np.array(dpm) / 2 time = np.concatenate([[0], dpm_cumsum, [365]], axis=None) boundary_int = [(station_data[0] + station_data[-1]) / 2] dat = np.concatenate([boundary_int, station_data, boundary_int], axis=None) spl = intrp.splrep(time, dat, per=True, k=k, s=smooth) def forcing(time): return intrp.splev(np.mod(time, 365), spl, der=deriv) return forcing def create_MLD_forcing(self, station): return self.read_intrp_forcing(station, 'MLD', deriv=0, k=1, smooth=1) def create_MLD_deriv_forcing(self, station): return self.read_intrp_forcing(station, 'MLD', deriv=1, k=1, smooth=1) def create_SST_forcing(self, station): return self.read_intrp_forcing(station, 'SST', deriv=0, k=1, smooth=1) def create_N0_forcing(self, station): MLD_func = self.read_intrp_forcing(station, 'MLD', deriv=0, k=1, smooth=1) if station == 'india': aN = 0.0074 # coeff. for N0 as fn depth bN = 10.85 # coeff. for N0 as fn depth elif station == 'biotrans': aN = 0.0174 bN = 4.0 elif station == 'kerfix': aN = 0 bN = 26.1 elif station == 'papa': aN = 0.0 bN = 14.6 else: raise ValueError("station label not found, options: 'india', 'biotrans', 'kerfix', 'papa'") def N0_forcing(time): return aN * MLD_func(time) + bN return N0_forcing