Exemple #1
0
 class StateVariables(StatesTemplate):
     TAGP = Float(-99.)
     GASST = Float(-99.)
     MREST = Float(-99.)
     CTRAT = Float(-99.)
     CEVST = Float(-99.)
     HI = Float(-99.)
     DOF = Instance(datetime.date)
     FINISH_TYPE = Unicode(allow_none=True)
Exemple #2
0
 class StateVariables(StatesTemplate):
     PTa = Float(-99.)
     #Soil water balance
     TPE = Float(-99.)
     TPT = Float(-99.)
     TPREC = Float(-99.)
     TINTERC = Float(-99.)
     TRUNOFF = Float(-99.)
     PERC = Float(-99.)
     TE = Float(-99.)
     Ta = Float(-99.)
     WC = Instance(np.ndarray)
     WCv = Instance(np.ndarray)
     #To chech WB closed
     TT = Float(-99.)
     WB_close = Float(-99.)
     Diff_WC = Float(-99.)
     TWC = Float(-99.)
     W_Stress = Float(-99.)
Exemple #3
0
 class StateVariables(StatesTemplate):
     DVS = Float(-99.)  # Development stage
     TSUM = Float(-99.)  # Temperature sum state
     TSUME = Float(-99.)  # Temperature sum for emergence state
     # States which register phenological events
     DOS = Instance(date)  # Day of sowing
     DOE = Instance(date)  # Day of emergence
     DOR1 = Instance(date)  # Day of start of flowering
     DOR3 = Instance(date)  # Day of pod development
     DOR5 = Instance(date)  # Day of seed filling
     DOR8 = Instance(date)  # Day of full ripeness
     DOH = Instance(date)  # Day of harvest
     STAGE = Enum(
         [None, "emerging", "vegetative", "reproductive", "mature"])
Exemple #4
0
class TestSimulationObject(SimulationObject):
    """This wraps the SimulationObject for testing to ensure that the computations are not
    carried out before crop emergence (e.g. DVS >= 0). The latter does not apply for the
    phenology simobject itself which simulates emergence. The phenology simobject is recognized
    because the variable DVS is not an external variable.

    """

    test_class = None
    subsimobject = Instance(SimulationObject)

    def initialize(self, day, kiosk, parvalues):
        self.subsimobject = self.test_class(day, kiosk, parvalues)

    def calc_rates(self, day, drv):
        # some simobject do not provide a `calc_rates()` function but are directly callable
        # here we check for those cases.
        func = self.subsimobject if callable(
            self.subsimobject) else self.subsimobject.calc_rates
        if not self.kiosk.is_external_state("DVS"):
            func(day, drv)
        else:
            if self.kiosk.DVS >= 0:
                func(day, drv)
            else:
                self.subsimobject.zerofy()

    def integrate(self, day, delt=1.0):
        # If the simobject is callable, we do not need integration so we use the `nothing()` function.
        func = nothing if callable(
            self.subsimobject) else self.subsimobject.integrate
        if not self.kiosk.is_external_state("DVS"):
            func(day, delt)
        else:
            if self.kiosk.DVS >= 0:
                func(day, delt)
            else:
                self.subsimobject.touch()
Exemple #5
0
class Wofost(SimulationObject):
    """Top level object organizing the different components of the WOFOST crop
    simulation.
            
    The CropSimulation object organizes the different processes of the crop
    simulation. Moreover, it contains the parameters, rate and state variables
    which are relevant at the level of the entire crop. The processes that are
    implemented as embedded simulation objects consist of:
    
        1. Phenology (self.pheno)
        2. Partitioning (self.part)
        3. Assimilation (self.assim)
        4. Maintenance respiration (self.mres)
        5. Evapotranspiration (self.evtra)
        6. Leaf dynamics (self.lv_dynamics)
        7. Stem dynamics (self.st_dynamics)
        8. Root dynamics (self.ro_dynamics)
        9. Storage organ dynamics (self.so_dynamics)

    **Simulation parameters:**
    
    ======== =============================================== =======  ==========
     Name     Description                                     Type     Unit
    ======== =============================================== =======  ==========
    CVL      Conversion factor for assimilates to leaves       SCr     -
    CVO      Conversion factor for assimilates to storage      SCr     -
             organs.
    CVR      Conversion factor for assimilates to roots        SCr     -
    CVS      Conversion factor for assimilates to stems        SCr     -
    ======== =============================================== =======  ==========
    
    
    **State variables:**

    =========== ================================================= ==== ===============
     Name        Description                                      Pbl      Unit
    =========== ================================================= ==== ===============
    TAGP        Total above-ground Production                      N    |kg ha-1|
    GASST       Total gross assimilation                           N    |kg CH2O ha-1|
    MREST       Total gross maintenance respiration                N    |kg CH2O ha-1|
    CTRAT       Total crop transpiration accumulated over the
                crop cycle                                         N    cm
    CEVST       Total soil evaporation accumulated over the
                crop cycle                                         N    cm
    HI          Harvest Index (only calculated during              N    -
                `finalize()`)
    DOF         Date representing the day of finish of the crop    N    -
                simulation. 
    FINISH_TYPE String representing the reason for finishing the   N    -
                simulation: maturity, harvest, leave death, etc.
    =========== ================================================= ==== ===============

 
     **Rate variables:**

    =======  ================================================ ==== =============
     Name     Description                                      Pbl      Unit
    =======  ================================================ ==== =============
    GASS     Assimilation rate corrected for water stress       N  |kg CH2O ha-1 d-1|
    MRES     Actual maintenance respiration rate, taking into
             account that MRES <= GASS.                         N  |kg CH2O ha-1 d-1|
    ASRC     Net available assimilates (GASS - MRES)            N  |kg CH2O ha-1 d-1|
    DMI      Total dry matter increase, calculated as ASRC
             times a weighted conversion efficiency.            Y  |kg ha-1 d-1|
    ADMI     Aboveground dry matter increase                    Y  |kg ha-1 d-1|
    =======  ================================================ ==== =============

    """

    # sub-model components for crop simulation
    pheno = Instance(SimulationObject)
    part = Instance(SimulationObject)
    assim = Instance(SimulationObject)
    mres = Instance(SimulationObject)
    evtra = Instance(SimulationObject)
    lv_dynamics = Instance(SimulationObject)
    st_dynamics = Instance(SimulationObject)
    ro_dynamics = Instance(SimulationObject)
    so_dynamics = Instance(SimulationObject)

    # Parameters, rates and states which are relevant at the main crop
    # simulation level
    class Parameters(ParamTemplate):
        CVL = Float(-99.)
        CVO = Float(-99.)
        CVR = Float(-99.)
        CVS = Float(-99.)

    class StateVariables(StatesTemplate):
        TAGP = Float(-99.)
        GASST = Float(-99.)
        MREST = Float(-99.)
        CTRAT = Float(-99.)
        CEVST = Float(-99.)
        HI = Float(-99.)
        DOF = Instance(datetime.date)
        FINISH_TYPE = Unicode(allow_none=True)

    class RateVariables(RatesTemplate):
        GASS = Float(-99.)
        MRES = Float(-99.)
        ASRC = Float(-99.)
        DMI = Float(-99.)
        ADMI = Float(-99.)

    def initialize(self, day, kiosk, parvalues):
        """
        :param day: start date of the simulation
        :param kiosk: variable kiosk of this PCSE  instance
        :param parvalues: `ParameterProvider` object providing parameters as
                key/value pairs
        """

        self.params = self.Parameters(parvalues)
        self.rates = self.RateVariables(kiosk, publish=["DMI", "ADMI"])
        self.kiosk = kiosk

        # Initialize components of the crop
        self.pheno = Phenology(day, kiosk, parvalues)
        self.part = Partitioning(day, kiosk, parvalues)
        self.assim = Assimilation(day, kiosk, parvalues)
        self.mres = MaintenanceRespiration(day, kiosk, parvalues)
        self.evtra = Evapotranspiration(day, kiosk, parvalues)
        self.ro_dynamics = Root_Dynamics(day, kiosk, parvalues)
        self.st_dynamics = Stem_Dynamics(day, kiosk, parvalues)
        self.so_dynamics = Storage_Organ_Dynamics(day, kiosk, parvalues)
        self.lv_dynamics = Leaf_Dynamics(day, kiosk, parvalues)

        # Initial total (living+dead) above-ground biomass of the crop
        TAGP = self.kiosk.TWLV + self.kiosk.TWST + self.kiosk.TWSO
        self.states = self.StateVariables(
            kiosk,
            publish=["TAGP", "GASST", "MREST", "HI"],
            TAGP=TAGP,
            GASST=0.0,
            MREST=0.0,
            CTRAT=0.0,
            CEVST=0.0,
            HI=0.0,
            DOF=None,
            FINISH_TYPE=None)

        # Check partitioning of TDWI over plant organs
        checksum = parvalues["TDWI"] - self.states.TAGP - self.kiosk["TWRT"]
        if abs(checksum) > 0.0001:
            msg = "Error in partitioning of initial biomass (TDWI)!"
            raise exc.PartitioningError(msg)

        # assign handler for CROP_FINISH signal
        self._connect_signal(self._on_CROP_FINISH, signal=signals.crop_finish)

    @staticmethod
    def _check_carbon_balance(day, DMI, GASS, MRES, CVF, pf):
        (FR, FL, FS, FO) = pf
        checksum = (GASS - MRES -
                    (FR + (FL + FS + FO) *
                     (1. - FR)) * DMI / CVF) * 1. / (max(0.0001, GASS))
        if abs(checksum) >= 0.0001:
            msg = "Carbon flows not balanced on day %s\n" % day
            msg += "Checksum: %f, GASS: %f, MRES: %f\n" % (checksum, GASS,
                                                           MRES)
            msg += "FR,L,S,O: %5.3f,%5.3f,%5.3f,%5.3f, DMI: %f, CVF: %f\n" % \
                   (FR, FL, FS, FO, DMI, CVF)
            raise exc.CarbonBalanceError(msg)

    @prepare_rates
    def calc_rates(self, day, drv):
        p = self.params
        r = self.rates
        k = self.kiosk

        # Phenology
        self.pheno.calc_rates(day, drv)
        crop_stage = self.pheno.get_variable("STAGE")

        # if before emergence there is no need to continue
        # because only the phenology is running.
        if crop_stage == "emerging":
            return

        # Potential assimilation
        PGASS = self.assim(day, drv)

        # (evapo)transpiration rates
        self.evtra(day, drv)

        # water stress reduction
        r.GASS = PGASS * k.RFTRA

        # Respiration
        PMRES = self.mres(day, drv)
        r.MRES = min(r.GASS, PMRES)

        # Net available assimilates
        r.ASRC = r.GASS - r.MRES

        # DM partitioning factors (pf), conversion factor (CVF),
        # dry matter increase (DMI) and check on carbon balance
        pf = self.part.calc_rates(day, drv)
        CVF = 1. / ((pf.FL / p.CVL + pf.FS / p.CVS + pf.FO / p.CVO) *
                    (1. - pf.FR) + pf.FR / p.CVR)
        r.DMI = CVF * r.ASRC
        self._check_carbon_balance(day, r.DMI, r.GASS, r.MRES, CVF, pf)

        # distribution over plant organ

        # Below-ground dry matter increase and root dynamics
        self.ro_dynamics.calc_rates(day, drv)
        # Aboveground dry matter increase and distribution over stems,
        # leaves, organs
        r.ADMI = (1. - pf.FR) * r.DMI
        self.st_dynamics.calc_rates(day, drv)
        self.so_dynamics.calc_rates(day, drv)
        self.lv_dynamics.calc_rates(day, drv)

    @prepare_states
    def integrate(self, day, delt=1.0):
        rates = self.rates
        states = self.states

        # crop stage before integration
        crop_stage = self.pheno.get_variable("STAGE")

        # Phenology
        self.pheno.integrate(day, delt)

        # if before emergence there is no need to continue
        # because only the phenology is running.
        # Just run a touch() to to ensure that all state variables are available
        # in the kiosk
        if crop_stage == "emerging":
            self.touch()
            return

        # Partitioning
        self.part.integrate(day, delt)

        # Integrate states on leaves, storage organs, stems and roots
        self.ro_dynamics.integrate(day, delt)
        self.so_dynamics.integrate(day, delt)
        self.st_dynamics.integrate(day, delt)
        self.lv_dynamics.integrate(day, delt)

        # Integrate total (living+dead) above-ground biomass of the crop
        states.TAGP = self.kiosk.TWLV + self.kiosk.TWST + self.kiosk.TWSO

        # total gross assimilation and maintenance respiration
        states.GASST += rates.GASS
        states.MREST += rates.MRES

        # total crop transpiration and soil evaporation
        states.CTRAT += self.kiosk.TRA
        states.CEVST += self.kiosk.EVS

    @prepare_states
    def finalize(self, day):

        # Calculate Harvest Index
        if self.states.TAGP > 0:
            self.states.HI = self.kiosk.TWSO / self.states.TAGP
        else:
            msg = "Cannot calculate Harvest Index because TAGP=0"
            self.logger.warning(msg)
            self.states.HI = -1.

        SimulationObject.finalize(self, day)

    def _on_CROP_FINISH(self, day, finish_type=None):
        """Handler for setting day of finish (DOF) and reason for
        crop finishing (FINISH).
        """
        self._for_finalize["DOF"] = day
        self._for_finalize["FINISH_TYPE"] = finish_type
Exemple #6
0
class Water_balance(SimulationObject):
    '''Parameters**

    ============ ================================================= ==== ========
     Name        Description                                             Unit
    ============ ================================================= ==== ========
    FCP          Field capacity                                     mH2O m Soil
    PWPP         Permanent wilting point                            mH2O m Soi   
    ADWCP         Air dry water content                              mH2O m Soi   
    TCK          Thickness of soil layer                                    m
    RUNOFF1      Parameter 1 for runoff function   
    RUNOFF2      Parameter 2 for runoff function          
    RMIN         Root resistance                                         J kg-1 
    PSIPWP       Permanent wilting water potential                       J kg-1 
    PSIFC        Field capacity water potential                          J kg-1 
    S            Surface storage condition                                  m
    RDMAX        Maximun root depth                                         m
                                           m               
    ============ ================================================= ==== ========
    Rates**

    ============ ================================================= ==== ========
     Name        Description                                             Unit
    ============ ================================================= ==== ========
    FC           Parameter FCP in m of H2O per layer                       m
    PWP          Parameter PWPP in m of H2O per layer                      m
    INTERC       Precipitation intercepted by the canopy                    m
    RUNOFF       Rate of runoff                                             m
    INFIL        Water available for infiltration                           m
    RW           Rate of recharging water in each layer                     m
    NWC          Rate of water in the 1st layer                             m
    EVS          Rate of soil evaporation                                   m
    RDr          Rate of root growth                                        m
    B            Value for power equation of soil potential
    A            Value for power equation of soil potential
    SPSI         Soil potential per layer                            J kg-1 m-1
    FROOT        Root fraction per layer
    AVESPSI      Soil potential weighten by rooting fraction         J kg-1 m-1
    RBAR         Root resistance                                     J kg-1 m-1
    PSIX         Xilem Potential                                     J kg-1 m-1
    LOSS         Rate of water loss per layer                            mH2O m
    TL           Transpiration per layer                                    m
    AT           Actual Evapotranspiration per layer                        m
    T            Total Evapotranspiration                                   m
   
    ============ ================================================= ==== ========
    State variables**
 
    Name         Description                                             Unit
    ============ ================================================= ==== ========
    TINTERC      Total interception by the canopy                           m
    GPREC        Ground precipitation                                       m
    TRUNOFF      Total runoff                                               m
    PERC         Total deep percolation                                     m
    TWC          Water content                                          m-3 m-3
    TEVS         Total soil evaporation                                     m
    TRD          Root depth                                                 m
    TFR          Root fraction in each layer 
                                    
    ============ ================================================= ==== ========
    **External dependencies:**
    
    =======  =================================== =================  ============
     Name     Description                         Provided by         Unit
    =======  =================================== =================  ============
     FR        Fraction partitioned to roots.                     Y    -
     FS        Fraction partitioned to stems.                     Y    -
     FL        Fraction partitioned to leaves.                    Y    -
     FO        Fraction partitioned to storage orgains            Y    -
     DVS       Development stage
    =======  =================================== =================  ============    
    '''
    pheno = Instance(SimulationObject)

    class Parameters(ParamTemplate):
        #Soil water balance
        FCP = Float(-99.)
        PWPP = Float(-99.)
        ADWCP = Float(-99.)
        TCK = Float(-99.)
        RUNOFF1 = Float(-99.)
        RUNOFF2 = Float(-99.)
        RMIN = Float(-99.)
        PSIPWP = Float(-99.)
        PSIFC = Float(-99.)
        S = Float(-99.)

        RDMAX = Float(-99.)

    class RateVariables(RatesTemplate):
        PE = Float(-99.)
        PT = Float(-99.)
        EPT = Float(-99.)
        PREC = Float(-99.)
        nl = Int
        FC = Float(-99.)
        PWP = Float(-99.)
        ADWC = Float(-99.)

        B = Float(-99.)
        A = Float(-99.)
        INTERC = Float(-99.)
        GPREC = Float(-99.)
        RUNOFF = Float(-99.)
        INFIL = Float(-99.)
        RW = Float(-99.)
        values_RW = []
        RWATER = Instance(np.ndarray)
        NWC = Float(-99.)
        EVS = Float(-99.)
        SPSI = Float(-99.)
        values_SPSI = []
        SP = Instance(np.ndarray)
        #root
        FcR = Instance(np.ndarray)
        values_FR = []
        FROOT = Float(-99.)
        AVEPSI = Float(-99.)
        RBAR = Float(-99.)
        PSIX = Float(-99.)
        z = Float(-99.)

        LOSS = Instance(np.ndarray)
        W = Instance(np.ndarray)
        arr_bool = Instance(np.ndarray)
        arr_TRUE = Instance(np.ndarray)
        TL = Instance(np.ndarray)
        net_RW = Instance(np.ndarray)
        T = Float(-99.)
        arr_subt = Instance(np.ndarray)
        arr_mult = Instance(np.ndarray)
        AT = Instance(np.ndarray)
        check = Float(-99.)

    class StateVariables(StatesTemplate):
        PTa = Float(-99.)
        #Soil water balance
        TPE = Float(-99.)
        TPT = Float(-99.)
        TPREC = Float(-99.)
        TINTERC = Float(-99.)
        TRUNOFF = Float(-99.)
        PERC = Float(-99.)
        TE = Float(-99.)
        Ta = Float(-99.)
        WC = Instance(np.ndarray)
        WCv = Instance(np.ndarray)
        #To chech WB closed
        TT = Float(-99.)
        WB_close = Float(-99.)
        Diff_WC = Float(-99.)
        TWC = Float(-99.)
        W_Stress = Float(-99.)

    def initialize(self, day, kiosk, parametervalues):
        self.params = self.Parameters(parametervalues)
        self.rates = self.RateVariables(kiosk, publish=None)
        self.kiosk = kiosk
        layers = math.floor(self.params.RDMAX / self.params.TCK)
        self.states = self.StateVariables(
            kiosk,
            publish=["Ta", "W_Stress", "PTa"],
            PTa=0,
            TPE=0.0,
            TPT=0.0,
            WC=np.full(layers, self.params.FCP * self.params.TCK),
            WCv=np.full(layers, self.params.FCP * self.params.TCK),
            TT=0.0,
            Diff_WC=0.,
            W_Stress=0,
            TINTERC=0,
            TRUNOFF=0,
            PERC=0,
            TE=0,
            Ta=0,
            WB_close=0,
            TPREC=0.0,
            TWC=0.)

    @prepare_rates
    def calc_rates(self, day, drv):
        p = self.params
        r = self.rates
        s = self.states
        k = self.kiosk

        if "FI" not in self.kiosk:
            k.FI = 0.0
        else:
            k.FI = self.kiosk["FI"]

        if "TRD" not in self.kiosk:
            k.TRD = 0.0
        else:
            k.TRD = self.kiosk["TRD"]

        r.PE = convert_cm_to_m(drv.ET0 * (1 - k.FI))
        r.PT = convert_cm_to_m(drv.ET0 * k.FI)
        r.ETP = convert_cm_to_m(drv.ET0) * 100 * 10

        # Convert fc and pwp to m of H2O
        r.nl = math.floor(p.RDMAX / p.TCK)
        r.FC = p.FCP * p.TCK
        r.PWP = p.PWPP * p.TCK
        r.ADWC = p.ADWCP * p.TCK

        # Parameters for eq os SPSI
        r.B = math.log(p.PSIPWP / p.PSIFC) / math.log(p.FCP / p.PWPP)
        r.A = math.exp((math.log(-p.PSIFC)) +
                       r.B * math.log(max(p.FCP, sys.float_info.min)))

        # Interception
        r.PREC = drv.RAIN / 100

        if drv.RAIN != 0.:
            r.INTERC = min(drv.RAIN / 100, 0.001 * k.FI)
        r.GPREC = ((drv.RAIN / 100) - r.INTERC)

        # Runoff calculation
        if r.GPREC <= 0.2 * p.S:
            r.RUNOFF = 0
        else:
            r.RUNOFF = (
                (r.GPREC - p.RUNOFF1 * p.S)**2) / (r.GPREC + p.RUNOFF2 * p.S)
        r.INFIL = ((drv.RAIN / 100) - r.INTERC - r.RUNOFF)

        # Recharge water per layer
        r.values_RW = []
        r.values_FR = []
        r.values_SPSI = []
        for j in range(s.WC.shape[0]):
            if r.INFIL > 0:
                if r.INFIL <= (r.FC - s.WC[j]):
                    r.RW = r.INFIL
                    r.INFIL = 0.
                else:
                    r.RW = r.FC - s.WC[j]
                    r.INFIL = r.INFIL - (r.FC - s.WC[j])
            else:
                r.RW = 0

            r.values_RW.append(r.RW)
            r.RWATER = np.array(r.values_RW)

            # Evaporation calculation
            if j < 1:
                # if s.WC[0]>r.PWP:
                #      r.EVS=r.PE
                if s.WC[0] < r.PWP:
                    r.PE = r.PE * (((s.WC[0] / p.TCK) - p.ADWCP) /
                                   (p.PWPP - p.ADWCP))**2.
                r.NWC = s.WC[0] - r.PE
                r.EVS = r.PE
                if r.NWC < r.ADWC:
                    r.NWC = r.ADWC
                    r.EVS = r.EVS - r.NWC

            # Fraction root per layer
            if j >= 1:
                r.z += p.TCK
                if r.z <= k.TRD:
                    r.FROOT = p.TCK * (2. *
                                       (k.TRD - r.z) + p.TCK) / (k.TRD * k.TRD)
                elif r.z > k.TRD and (r.z - p.TCK) < k.TRD:
                    r.FROOT = ((k.TRD - r.z + p.TCK) / k.TRD)**2.
                else:
                    r.FROOT = 0.

                r.SPSI = -r.A * mp.exp(
                    -r.B * math.log(max(
                        (s.WC[j] / p.TCK), sys.float_info.min)))
                r.AVEPSI += (r.FROOT * r.SPSI)
                r.values_FR.append(r.FROOT)
                r.FcR = np.array(r.values_FR)
                r.values_SPSI.append(r.SPSI)
                r.SP = np.array(r.values_SPSI)

        r.RBAR = p.RMIN / max(k.FI, 1e-70)
        r.PSIX = r.AVEPSI - (r.RBAR * r.PT)

        if r.PSIX < p.PSIPWP: r.PSIX = p.PSIPWP

        # Transpiration calculation
        r.arr_subt = np.subtract(r.SP, r.PSIX)
        r.arr_mult = np.multiply(r.FcR, r.arr_subt)
        r.LOSS = np.true_divide(r.arr_mult, (r.RBAR * p.TCK))

        # check loss under water deficit
        r.W = np.true_divide(s.WC[1::], p.TCK)
        r.arr_bool = (np.subtract(r.W, r.LOSS)) < p.PWPP
        r.arr_TRUE = np.subtract(r.W, p.PWPP)

        # Actual evapotranspiration
        r.TL = np.multiply(np.where(r.arr_bool, r.arr_TRUE, r.LOSS), p.TCK)
        r.AT = np.append(r.EVS, r.TL)
        r.T = np.sum(r.TL)
        r.net_RW = np.subtract(r.RWATER, r.AT)

    @prepare_states
    def integrate(self, day, delt):
        p = self.params
        r = self.rates
        s = self.states
        k = self.kiosk

        s.PTa = r.PT
        # Soil water balance
        s.TPE += r.PE
        s.TPT = r.PT
        s.TPREC = r.PREC
        s.TINTERC += r.GPREC
        s.TRUNOFF += r.RUNOFF
        s.PERC += r.INFIL
        s.TE += r.EVS
        s.Ta = r.T
        s.WC = np.add(s.WC, r.net_RW)
        s.WCv = (s.WC / p.TCK)

        # check WB closed
        s.TT += r.T
        s.Diff_WC = np.sum(np.subtract(np.full(r.nl, r.FC), s.WC))
        s.WB_close = s.TINTERC - s.TRUNOFF - s.PERC - s.TT - s.TE + s.Diff_WC
        s.TWC = (np.sum(np.subtract(s.WC, r.PWP))) * 1000

        s.W_Stress = r.T / max(r.PT, 1e-70)
Exemple #7
0
    class RateVariables(RatesTemplate):
        PE = Float(-99.)
        PT = Float(-99.)
        EPT = Float(-99.)
        PREC = Float(-99.)
        nl = Int
        FC = Float(-99.)
        PWP = Float(-99.)
        ADWC = Float(-99.)

        B = Float(-99.)
        A = Float(-99.)
        INTERC = Float(-99.)
        GPREC = Float(-99.)
        RUNOFF = Float(-99.)
        INFIL = Float(-99.)
        RW = Float(-99.)
        values_RW = []
        RWATER = Instance(np.ndarray)
        NWC = Float(-99.)
        EVS = Float(-99.)
        SPSI = Float(-99.)
        values_SPSI = []
        SP = Instance(np.ndarray)
        #root
        FcR = Instance(np.ndarray)
        values_FR = []
        FROOT = Float(-99.)
        AVEPSI = Float(-99.)
        RBAR = Float(-99.)
        PSIX = Float(-99.)
        z = Float(-99.)

        LOSS = Instance(np.ndarray)
        W = Instance(np.ndarray)
        arr_bool = Instance(np.ndarray)
        arr_TRUE = Instance(np.ndarray)
        TL = Instance(np.ndarray)
        net_RW = Instance(np.ndarray)
        T = Float(-99.)
        arr_subt = Instance(np.ndarray)
        arr_mult = Instance(np.ndarray)
        AT = Instance(np.ndarray)
        check = Float(-99.)
Exemple #8
0
class Campbell(SimulationObject):
    """Parameters**

    ============ ================================================= ==== ========
     Name        Description                                             Unit
    ============ ================================================= ==== ========
    DVV1         Paramter 1 for vapor deficit equation
    DVV2         Paramter 2 for vapor deficit equation
    DVV3         Paramter 3 for vapor deficit equation
    NTR          Nitrogen content in grain                                g.g-1
    LNTR         Nitrogen content in leaves                               g.g-1
    FNTR         Fraction of N translocated from leaves to seeds
    HD           Factor to standardize humidity content at 13% 
    K            Light extinction coefficient (Kukal and Irmak, 2020)
    Ppar         Proportion of PAR in the total radiation
    WUE          Dry matter water ratio                                     Pa
    DSLA         Specific leaf area for dead leaves                    m-2 kg-1
    RUE          Radiation use efficiency (Kukal and Irmak, 2020)       g Mj m2
    GCC          Conversion coefficient (CHO to soyeban seed)
    LAIC         Critic leaf area index                                 m-2 m-2
    FTRANSL      Fraction of TDM to be translocated
    RDRSHM       Maximum relative death rate of leaves due to shading (LINTUL2)  d-1
    ============ ================================================= ==== ========
    Rates**

    ============ ================================================= ==== ========
     Name        Description                                             Unit
    ============ ================================================= ==== ========
    FI           Fractional interception
    PE           Potential evaporation                                      m
    PT           Potential transpiration                                    m
    VDD          Correction by vapor deficit water                         KPa
    PARi         Intercepted PAR                                         Mj m-2
    DM           Rate of growth                                          kg m-2
    ROOT         Growth rate root                                        kg m-2
    STEMS        Growth rate stems                                       kg m-2
    LEAF         Growth rate leaf                                        kg m-2
    SEED         Growth rate storage organs                              kg m-2
    TN           Translocated nitrogen from leaves to grains             kg m-2
    DLEAF        Senescence rate of leaf                                 kg m-2
    RDRSH        Relative death rate of leaves due to shading (LINTUL2)   d-1
    RDRT         Table of RDR as a function of temperature
    ============ ================================================= ==== ========
    State variables**

    Name         Description                                             Unit
    ============ ================================================= ==== ========
    TPE          Total potential evaporation                                m
    TPT          Total potential transpiration                              m
    TDM          Total above-ground biomass                              kg m-2
    TROOT        Total weight of roots                                   kg m-2
    TSTEMS       Total weight of stems                                   kg m-2
    TLEAF        Total weight of leaves                                 m-2 m-2
    TSEED        Total weight of storage organs                          kg m-2
    LAI          Leaf area index                                        m-2 m-2
    TDLEAF       Total of dead leaves                                   m-2 m-2
    GLEAF        Total of green leaves                                  m-2 m-2
    SLA          Specific leaf area                                    m-2 kg-1

    ============ ================================================= ==== ========
    **External dependencies:**

    =======  =================================== =================  ============
     Name     Description                         Provided by         Unit
    =======  =================================== =================  ============
     FR        Fraction partitioned to roots.                     Y    -
     FS        Fraction partitioned to stems.                     Y    -
     FL        Fraction partitioned to leaves.                    Y    -
     FO        Fraction partitioned to storage orgains            Y    -
     DVS       Development stage
    =======  =================================== =================  ============
    """
    # sub-model components for crop simulation
    pheno = Instance(SimulationObject)
    part = Instance(SimulationObject)
    soil = Instance(SimulationObject)

    class Parameters(ParamTemplate):
        RDRT = AfgenTrait()
        RDRSHM = Float(-99.)
        LAIC = Float(-99.)

        DVV1 = Float(-99.)
        DVV2 = Float(-99.)
        DVV3 = Float(-99.)

        initLAI = Float(-99.)

        K = Float(-99.)
        Ppar = Float(-99.)
        WUE = Float(-99.)

        DSLA = Float(-99.)
        NTR = Float(-99.)
        LNTR = Float(-99.)
        FNTR = Float(-99.)
        HD = Float(-99.)

        GCC = Float(-99.)
        FTRANSL = Float(-99.)

        SLATB = AfgenTrait()
        RUE = Float(-99.)

        RDMAX = Float(-99.)

    class RateVariables(RatesTemplate):
        RDRDV = Float(-99.)
        RDRSH = Float(-99.)
        RDR = Float(-99.)
        DLAI = Float(-99.)

        DM_W = Float(-99.)
        DM_R = Float(-99.)
        DM = Float(-99.)
        PDM = Float(-99.)
        VDD = Float(-99.)

        FI = Float(-99.)
        ROOT = Float(-99.)
        STEMS = Float(-99.)
        LEAF = Float(-99.)
        WLEAF = Float(-99.)
        SEED = Float(-99.)
        PSEED = Float(-99.)
        TN = Float(-99.)
        WDLEAF = Float(-99.)
        DLEAF = Float(-99.)
        GLEAF = Float(-99.)
        TRANSL = Float(-99.)

        #root
        RD = Float(-99.)
        WD = Float(-99.)

    class StateVariables(StatesTemplate):
        TDM = Float(-99.)
        TDMv = Float(-99.)

        TSTEM = Float(-99.)
        TLEAF = Float(-99.)
        TSEED = Float(-99.)
        YIELD = Float(-99.)
        LAI = Float(-99.)
        LAIFlowering = Float(-99.)
        TDLEAF = Float(-99.)
        SLA = Float(-99.)

        TDMFlowering = Float(-99.)
        TDMTRANSL = Float(-99.)
        POOLTRSL = Float(-99.)
        #root
        TRD = Float(-99.)
        da = Int
        CWDv = Float(-99.)
        CWDr = Float(-99.)

    def initialize(self, day, kiosk, parametervalues):
        self.params = self.Parameters(parametervalues)
        self.rates = self.RateVariables(kiosk, publish=["FI"])
        self.kiosk = kiosk
        # Initialize components of the crop
        self.pheno = Phenology(day, kiosk, parametervalues)
        self.part = Partitioning(day, kiosk, parametervalues)

        DVS = self.kiosk["DVS"]
        SLA = self.params.SLATB(DVS)

        # =============================================================================
        #         # Initial total (living+dead) above-ground biomass of the crop
        #         FR = self.kiosk["FR"]
        #         FS = self.kiosk["FS"]
        #         FL = self.kiosk["FL"]
        #         FO = self.kiosk["FO"]
        # =============================================================================
        self.states = self.StateVariables(kiosk,
                                          publish=["TRD"],
                                          TDM=0.00,
                                          TDMv=0,
                                          GLEAF=0.0,
                                          TSTEM=0.0,
                                          TLEAF=0.0,
                                          TSEED=0.0,
                                          YIELD=0.0,
                                          LAI=self.params.initLAI,
                                          TDLEAF=0,
                                          SLA=SLA,
                                          TRD=0.0,
                                          da=0,
                                          TDMFlowering=None,
                                          LAIFlowering=None,
                                          TDMTRANSL=0,
                                          POOLTRSL=0,
                                          CWDv=0.,
                                          CWDr=0.)

    @prepare_rates
    def calc_rates(self, day, drv):
        p = self.params
        r = self.rates
        s = self.states
        k = self.kiosk

        self.pheno.calc_rates(day, drv)
        crop_stage = self.pheno.get_variable("STAGE")

        # if before emergence there is no need to continue
        # because only the phenology is running.
        if crop_stage == "emerging":
            return

        self.part.calc_rates(day, drv)

        r.VDD = convert_hPa_to_KPa(drv.TMAX - drv.TMIN) * (
            (p.DVV1 * drv.TEMP + p.DVV2) * drv.TEMP + p.DVV3)

        print("VDD=", r.VDD)
        r.FI = 1. - mp.exp(-p.K * s.LAI)
        r.PARi = convert_j_Mj(drv.IRRAD) * p.Ppar * r.FI

        if k.DVS < 2:
            if "Ta" not in self.kiosk:
                k.Ta = 0.001
            else:
                k.Ta = self.kiosk["Ta"]

            if "W_Stress" not in self.kiosk:
                k.W_Stress = 0.0
            else:
                k.W_Stress = self.kiosk["W_Stress"]

            if "PTa" not in self.kiosk:
                k.PTa = 0.0
            else:
                k.PTa = self.kiosk["PTa"]

            r.DM_W = k.Ta * (p.WUE / r.VDD)
            print("Ta=", k.Ta)
            print("DM=", r.DM_W)
            r.DM_R = convert_g_kg(r.PARi * p.RUE)
            r.DM = min(r.DM_W, r.DM_R)
            r.PDM = k.PTa * (p.WUE / r.VDD)
            r.STEMS = r.DM * k.FS
            r.WLEAF = r.DM * k.FL
            r.LEAF = r.DM * k.FL * convert_ha_m2(s.SLA)
            r.PSEED = r.PDM * k.FO

            # Biomass reallocated from vegetative to seed
            if s.TDMTRANSL > 0:
                r.TRANSL = r.PSEED - (r.DM * k.FO)
                r.SEED = (r.DM * k.FO) + r.TRANSL
            else:
                r.SEED = r.DM * k.FO

            # Senescence from N translocation
            r.TN = ((r.SEED * p.NTR) / p.FNTR)

            #senescence rate from LINTUL
            if k.DVS > 1.5:
                r.RDRDV = p.RDRT(drv.TEMP)
                r.RDRSH = p.RDRSHM * ((s.LAI - p.LAIC) / p.LAIC)
                if r.RDRSH > 0 or r.RDRSH < 0.03:
                    r.RDRSH = r.RDRSH
                if r.RDRSH < 0:
                    r.RDRSH = 0
                if r.RDRSH > 0.03:
                    r.RDRSH = 0.03
            else:
                r.RDRDV = 0

            r.RDR = max(r.RDRDV, r.RDRSH)
            r.DLAI = s.LAI * r.RDR
            r.WDLEAF = r.TN / p.LNTR
            r.DLEAF = r.WDLEAF * p.DSLA
            r.GLEAF = r.LEAF - max(r.DLAI, r.DLEAF)

        #Rooting growth
        r.RD = p.RDMAX * (1. / (1 + 44.2 * math.exp(-15 * (s.da) / (140))))
        r.WD = k.PTa - k.Ta

    @prepare_states
    def integrate(self, day, delt):
        p = self.params
        r = self.rates
        s = self.states
        k = self.kiosk

        # crop stage before integration
        crop_stage = self.pheno.get_variable("STAGE")
        self.pheno.integrate(day, delt=1.0)
        # if before emergence there is no need to continue
        # because only the phenology is running.
        # Just run a touch() to to ensure that all state variables are available
        # in the kiosk
        if crop_stage == "emerging":
            self.touch()
            return

        self.part.integrate(day, delt=1.0)

        DVS = self.kiosk["DVS"]
        s.SLA = p.SLATB(DVS)

        s.TDM += r.DM
        print("TDM", s.TDM)
        s.TDMv += r.STEMS + r.WLEAF
        if s.TDMFlowering is None and k.DVS >= 1.:
            s.TDMFlowering = s.TDMv
            s.TDMTRANSL = s.TDMFlowering * p.FTRANSL

        s.TDMTRANSL -= r.TRANSL
        s.TSEED += r.SEED
        s.YIELD = s.TSEED * p.GCC * p.HD
        s.TSTEM += r.STEMS
        s.TLEAF += r.DM * k.FL
        s.LAI += r.GLEAF

        if s.LAIFlowering is None and k.DVS >= 1.3:
            s.LAIFlowering = s.LAI

        s.da += 1

        s.TRD = r.RD
        if k.DVS < 1:
            s.CWDv += r.WD

        else:
            s.CWDr += r.WD
Exemple #9
0
class SoybeanPhenology(SimulationObject):
    """Implements the algorithms for phenologic development in WOFOST specifically for soybean.

    Phenologic development in WOFOST is expresses using a unitless scale which
    takes the values 0 at emergence, 1 at Anthesis (flowering) and 2 at
    maturity. This type of phenological development is mainly representative
    for cereal crops. All other crops that are simulated with WOFOST are
    forced into this scheme as well, although this may not be appropriate for
    all crops. For example, for potatoes development stage 1 represents the
    start of tuber formation rather than flowering.


    **Simulation parameters**

    =======  =============================================   =======  ============
     Name     Description                                     Type     Unit
    =======  =============================================   =======  ============
    TSUMEM   Temperature sum from sowing to emergence         SCr        |C| day
    TBASEM   Base temperature for emergence                   SCr        |C|
    TEFFMX   Maximum effective temperature for emergence      SCr        |C|
    DVRMAX1  Maximum development rate emergence to anthesis   SCr        |C| day
    DVRMAX2  Maximum develpment rate anthesis to maturity     SCr        |C| day
    DVSI     Initial development stage at emergence.          SCr        -
             Usually this is zero, but it can be higher
             for crops that are transplanted (e.g. paddy
             rice)
    DVSEND   Final development stage                          SCr        -
    MG       Maturity group rating for daylength sensivity    SCr        -
    Topt     Optimum temperature for phenological dev.        SCr        |C|
    Tmin     Temperature below which development is zero.     SCr        |C|
    Tmax     Temperature above which development is zero.     SCr        |C|
    =======  =============================================   =======  ============

    **State variables**

    =======  ================================================= ==== ============
     Name     Description                                      Pbl      Unit
    =======  ================================================= ==== ============
    DVS      Development stage                                  Y    -
    TSUM     Temperature sum                                    N    |C| day
    TSUME    Temperature sum for emergence                      N    |C| day
    DOS      Day of sowing                                      N    -
    DOE      Day of emergence                                   N    -
    DOR1     Day of R1 stage (beginning of flowering)           N    -
    DOR3     Day of R3 stage (pod development)                  N    -
    DOR5     Day of R5 stage (seed development)                 N    -
    DOR8     Day of R8 stage (fully ripe                        N    -
    STAGE    Current phenological stage, can take the           N    -
             folowing values:
             `emerging|vegetative|reproductive|mature`
    =======  ================================================= ==== ============

    **Rate variables**

    =======  ================================================= ==== ============
     Name     Description                                      Pbl      Unit
    =======  ================================================= ==== ============
    DTSUME   Increase in temperature sum for emergence          N    |C|
    DTSUM    Increase in temperature sum for anthesis or        N    |C|
             maturity
    DVR      Development rate                                   Y    |day-1|
    =======  ================================================= ==== ============

    **External dependencies:**

    None

    **Signals sent or handled**

    `SoybeanPhenology` sends the `crop_finish` signal when maturity is
    reached and the `end_type` is 'maturity' or 'earliest'.

    """

    photoperiod_reduction_factor = Instance(PhotoperiodReductionFactor)
    temperature_reduction_factor = Instance(TemperatureReductionFactor)

    class Parameters(ParamTemplate):
        TSUMEM = Float(-99.)  # Temp. sum for emergence
        TBASEM = Float(-99.)  # Base temp. for emergence
        TEFFMX = Float(-99.)  # Max eff temperature for emergence
        DVRMAX1 = Float(-99.)  # Max development rate towards anthesis
        DVRMAX2 = Float(-99.)  # Max development rate towards maturity
        DVSI = Float(-99.)  # Initial development stage
        DVSEND = Float(-99.)  # Final development stage
        CROP_START_TYPE = Enum(["sowing", "emergence"])
        CROP_END_TYPE = Enum(["maturity", "harvest", "earliest"])

    #-------------------------------------------------------------------------------
    class RateVariables(RatesTemplate):
        DTSUME = Float(-99.)  # increase in temperature sum for emergence
        DVR = Float(-99.)  # development rate
        DAYL = Float(-99)
        PHOTORF = Float(-99)
        TEMPRF = Float(-99)

    #-------------------------------------------------------------------------------
    class StateVariables(StatesTemplate):
        DVS = Float(-99.)  # Development stage
        TSUM = Float(-99.)  # Temperature sum state
        TSUME = Float(-99.)  # Temperature sum for emergence state
        # States which register phenological events
        DOS = Instance(date)  # Day of sowing
        DOE = Instance(date)  # Day of emergence
        DOR1 = Instance(date)  # Day of start of flowering
        DOR3 = Instance(date)  # Day of pod development
        DOR5 = Instance(date)  # Day of seed filling
        DOR8 = Instance(date)  # Day of full ripeness
        DOH = Instance(date)  # Day of harvest
        STAGE = Enum(
            [None, "emerging", "vegetative", "reproductive", "mature"])

    #---------------------------------------------------------------------------
    def initialize(self, day, kiosk, parvalues):
        """
        :param day: start date of the simulation
        :param kiosk: variable kiosk of this PCSE  instance
        :param parvalues: `ParameterProvider` object providing parameters as
                key/value pairs
        """
        self.photoperiod_reduction_factor = PhotoperiodReductionFactor(
            day, kiosk, parvalues)
        self.temperature_reduction_factor = TemperatureReductionFactor(
            day, kiosk, parvalues)
        self.params = self.Parameters(parvalues)
        self.rates = self.RateVariables(kiosk)
        self.kiosk = kiosk

        self._connect_signal(self._on_CROP_FINISH, signal=signals.crop_finish)

        # Define initial states
        DVS = self.params.DVSI
        DOS, DOE, STAGE = self._get_initial_stage(day)
        self.states = self.StateVariables(kiosk,
                                          publish="DVS",
                                          TSUM=0.,
                                          TSUME=0.,
                                          DVS=DVS,
                                          DOS=DOS,
                                          DOE=DOE,
                                          DOR1=None,
                                          DOR3=None,
                                          DOR5=None,
                                          DOR8=None,
                                          DOH=None,
                                          STAGE=STAGE)

    def _get_initial_stage(self, day):
        """"""
        p = self.params

        # Define initial stage type (emergence/sowing) and fill the
        # respective day of sowing/emergence (DOS/DOE)
        if p.CROP_START_TYPE == "emergence":
            STAGE = "vegetative"
            DOE = day
            DOS = None

            # send signal to indicate crop emergence
            self._send_signal(signals.crop_emerged)

        elif p.CROP_START_TYPE == "sowing":
            STAGE = "emerging"
            DOS = day
            DOE = None

        else:
            msg = "Unknown start type: %s" % p.CROP_START_TYPE
            raise exc.PCSEError(msg)

        return DOS, DOE, STAGE

    @prepare_rates
    def calc_rates(self, day, drv):
        """Calculates the rates for phenological development
        """
        p = self.params
        r = self.rates
        s = self.states

        # Day length
        r.DAYL = daylength(day, drv.LAT, angle=-0.83)

        # temperature reduction factor
        r.TEMPRF = self.temperature_reduction_factor(drv.TEMP)

        # photoperiod
        r.PHOTORF = 1.0

        if s.STAGE == "emerging":
            r.DTSUME = limit(0., (p.TEFFMX - p.TBASEM), (drv.TEMP - p.TBASEM))
        elif s.STAGE == 'vegetative':
            r.DVR = p.DVRMAX1 * r.TEMPRF
        elif s.STAGE in ['reproductive', 'mature']:
            # photoperiod reduction factor
            r.PHOTORF = self.photoperiod_reduction_factor(r.DAYL)
            r.DVR = p.DVRMAX2 * r.PHOTORF * r.TEMPRF
        else:  # Problem: no stage defined
            msg = "No STAGE defined in phenology submodule"
            raise exc.PCSEError(msg)

        msg = "Finished rate calculation for %s"
        self.logger.debug(msg % day)

    #---------------------------------------------------------------------------
    @prepare_states
    def integrate(self, day, delt):
        """Updates the state variable and checks for phenologic stages
        """

        p = self.params
        r = self.rates
        s = self.states

        if s.STAGE == "emerging":
            s.TSUME += r.DTSUME
            if s.TSUME >= p.TSUMEM:
                self._next_stage(day)

        elif s.STAGE == 'vegetative':
            s.DVS += r.DVR
            if s.DVS >= 1.0:
                self._next_stage(day)
                s.DVS = 1.0

        elif s.STAGE == 'reproductive':
            s.DVS += r.DVR
            # Check of R5 stage is reached at DVS=1.15.
            if s.DVS >= 1.15 and s.DOR5 is None:
                s.DOR5 = day

            # Check if maturity is reached
            if s.DVS >= p.DVSEND:
                self._next_stage(day)

        elif s.STAGE == 'mature':
            s.DVS += r.DVR

        else:  # Problem no stage defined
            msg = "No STAGE defined in phenology submodule"
            raise exc.PCSEError(msg)

        msg = "Finished state integration for %s"
        self.logger.debug(msg % day)

    #---------------------------------------------------------------------------
    def _next_stage(self, day):
        """Moves states.STAGE to the next phenological stage"""
        s = self.states
        p = self.params

        current_STAGE = s.STAGE
        if s.STAGE == "emerging":
            s.STAGE = "vegetative"
            s.DOE = day
            # send signal to indicate crop emergence
            self._send_signal(signals.crop_emerged)

        elif s.STAGE == "vegetative":
            s.STAGE = "reproductive"
            s.DOR1 = day

        elif s.STAGE == "reproductive":
            s.STAGE = "mature"
            s.DOR8 = day
            if p.CROP_END_TYPE in ["maturity", "earliest"]:
                self._send_signal(signal=signals.crop_finish,
                                  day=day,
                                  finish_type="maturity")
        elif s.STAGE == "mature":
            msg = "Cannot move to next phenology stage: maturity already reached!"
            raise exc.PCSEError(msg)

        else:  # Problem no stage defined
            msg = "No STAGE defined in phenology submodule."
            raise exc.PCSEError(msg)

        msg = "Changed phenological stage '%s' to '%s' on %s"
        self.logger.info(msg % (current_STAGE, s.STAGE, day))

    #---------------------------------------------------------------------------
    def _on_CROP_FINISH(self, day, finish_type=None):
        """Handler for setting day of harvest (DOH). Although DOH is not
        strictly related to phenology (but to management) this is the most
        logical place to put it.
        """
        if finish_type == 'harvest':
            self._for_finalize["DOH"] = day
Exemple #10
0
 class StateVariables(StatesTemplate):
     FR = Float(-99.)
     FL = Float(-99.)
     FS = Float(-99.)
     FO = Float(-99.)
     PF = Instance(PartioningFactors)