예제 #1
0
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
예제 #2
0
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
예제 #3
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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
예제 #10
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #11
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #12
0
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
예제 #13
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #14
0
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
예제 #15
0
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
예제 #16
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #17
0
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
예제 #18
0
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
예제 #19
0
파일: forcings.py 프로젝트: ben1post/phydra
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
예제 #20
0
파일: forcings.py 프로젝트: ben1post/phydra
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