Skip to content

entities

aquacrop.entities.clockStruct

Contains model information regarding dates and step times etc.

ClockStruct

Contains model information regarding dates and step times etc.

Attributes:

time_step_counter (int): Keeps track of current timestep

model_is_finished (Bool): False unless model has finished

simulation_start_date (np.Datetime64): Date of simulation start

simulation_end_date (np.Datetime64): Date of simulation end

time_step (int): time step (evaluation needed

n_steps (int): total number of days of simulation

time_span (np.array): all dates that lie within the start and end dates of simulation

step_start_time (np.Datetime64): Date at start of timestep

step_end_time (np.Datetime64): Date at end of timestep

evap_time_steps (int): Number of time-steps (per day) for soil evaporation calculation

sim_off_season (str): 'Y' if you want to simulate the off season,'N' otherwise

planting_dates (list-like): list of planting dates in datetime format

harvest_dates (list-like): list of harvest dates in datetime format

n_seasons (int): Total number of seasons to be simulated

season_counter (int): counter to keep track of which season we are currenlty simulating
Source code in aquacrop/entities/clockStruct.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class ClockStruct:
    """
    Contains model information regarding dates and step times etc.

    Attributes:

        time_step_counter (int): Keeps track of current timestep

        model_is_finished (Bool): False unless model has finished

        simulation_start_date (np.Datetime64): Date of simulation start

        simulation_end_date (np.Datetime64): Date of simulation end

        time_step (int): time step (evaluation needed

        n_steps (int): total number of days of simulation

        time_span (np.array): all dates that lie within the start and end dates of simulation

        step_start_time (np.Datetime64): Date at start of timestep

        step_end_time (np.Datetime64): Date at end of timestep

        evap_time_steps (int): Number of time-steps (per day) for soil evaporation calculation

        sim_off_season (str): 'Y' if you want to simulate the off season,'N' otherwise

        planting_dates (list-like): list of planting dates in datetime format

        harvest_dates (list-like): list of harvest dates in datetime format

        n_seasons (int): Total number of seasons to be simulated

        season_counter (int): counter to keep track of which season we are currenlty simulating


    """

    def __init__(self):

        self.time_step_counter = 0  # Keeps track of current timestep
        self.model_is_finished = False  # False unless model has finished
        self.simulation_start_date = 0  # Date of simulation start
        self.simulation_end_date = 0  # Date of simulation end
        self.time_step = 0  # time step (evaluaiton needed)
        self.n_steps = 0  # total number of days of simulation
        self.time_span = (
            0  # all dates that lie within the start and end dates of simulation
        )
        self.step_start_time = 0  # Date at start of timestep
        self.step_end_time = 0  # Date at start of timestep
        # Number of time-steps (per day) for soil evaporation calculation
        self.evap_time_steps = 20
        self.sim_off_season = (
            "N"  # 'Yes' if you want to simulate the off season, 'N' otherwise
        )
        self.planting_dates = (
            []
        )  # list of crop planting dates during simulation
        self.harvest_dates = []  # list of crop planting dates during simulation
        self.n_seasons = 0  # total number of seasons (plant and harvest)
        self.season_counter = -1  # running counter of seasons

aquacrop.entities.co2

CO2

Bases: object

Attributes:

ref_concentration (float): reference CO2 concentration

current_concentration (float): current CO2 concentration (initialize if constant_conc=True)

constant_conc (bool): use constant conc every season

co2_data (DataFrame): CO2 timeseries (2 columns: 'year' and 'ppm')
Source code in aquacrop/entities/co2.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class CO2(object):

    """

    Attributes:

        ref_concentration (float): reference CO2 concentration

        current_concentration (float): current CO2 concentration (initialize if constant_conc=True)

        constant_conc (bool): use constant conc every season

        co2_data (DataFrame): CO2 timeseries (2 columns: 'year' and 'ppm')

    """

    def __init__(
        self,
        ref_concentration=369.41,
        current_concentration=0.,
        constant_conc=False,
        co2_data=None,
    ):
        self.ref_concentration = ref_concentration
        self.current_concentration = current_concentration
        self.constant_conc = constant_conc
        if co2_data is not None:
            self.co2_data = co2_data
        else:
            self.co2_data = pd.read_csv(
                    f"{acfp}/data/MaunaLoaCO2.txt",
                    header=1,
                    delim_whitespace=True,
                    names=["year", "ppm"],
    )
        self.co2_data_processed = None

aquacrop.entities.crop

Crop class module

Crop

The Crop Class contains paramaters and variables of the crop used in the simulation

Most Crop attributes can be found in the crops.crop_params.py file

A number of default program properties of type float are also specified during initialisation

Initialization example:

crop = Crop('Maize', planting_date='05/01')

Attributes:

c_name (str): crop name ('custom' or one of built in defaults e.g. 'Maize')

planting_date (str): Planting Date (mm/dd)

harvest_date (str): Latest Harvest Date (mm/dd)
Source code in aquacrop/entities/crop.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
class Crop:
    """
    The Crop Class contains paramaters and variables of the crop used in the simulation

    Most Crop attributes can be found in the `crops.crop_params.py` file

    A number of default program properties of type float are also specified during initialisation

    ```
    Initialization example:

    crop = Crop('Maize', planting_date='05/01')
    ```

    Attributes:

        c_name (str): crop name ('custom' or one of built in defaults e.g. 'Maize')

        planting_date (str): Planting Date (mm/dd)

        harvest_date (str): Latest Harvest Date (mm/dd)


    """

    def __init__(self, c_name, planting_date, harvest_date=None, **kwargs):

        self.Name = c_name

        # Assign default program properties (should not be changed without expert knowledge)

        self.fshape_b = 13.8135  # Shape factor describing the reduction in biomass production for insufficient growing degree days
        self.PctZmin = (
            70  # Initial percentage of minimum effective rooting depth
        )
        self.fshape_ex = (
            -6
        )  # Shape factor describing the effects of water stress on root expansion
        self.ETadj = 1  # Adjustment to water stress thresholds depending on daily ET0 (0 = No, 1 = Yes)
        self.ET0dorm = 0 # Duration of dormant crop period (during early senescence) in terms of cumulative reference ET (mm)
        self.Aer = 5  # Vol (%) below saturation at which stress begins to occur due to deficient aeration
        self.LagAer = (
            3  # Number of days lag before aeration stress affects crop growth
        )
        self.beta = 12  # Reduction (%) to p_lo3 when early canopy senescence is triggered
        self.a_Tr = 1  # Exponent parameter for adjustment of Kcx once senescence is triggered
        self.GermThr = 0.2  # Proportion of total water storage needed for crop to germinate
        self.CCmin = 0.05  # Minimum canopy size below which yield_ formation cannot occur
        self.MaxFlowPct = (
            100 / 3
        )  # Proportion of total flowering time (%) at which peak flowering occurs
        self.HIini = 0.01  # Initial harvest index
        self.bsted = 0.000138  # WP co2 adjustment parameter given by Steduto et al. 2007
        self.bface = (
            0.001165  # WP co2 adjustment parameter given by FACE experiments
        )

        if c_name == "custom":

            self.Name = "custom"
            self.planting_date = planting_date  # Planting Date (mm/dd)
            self.harvest_date = harvest_date  # Latest Harvest Date (mm/dd)

        elif c_name in crop_params.keys():
            self.__dict__.update(
                (k, v) for k, v in crop_params[c_name].items()
            )
            self.planting_date = planting_date  # Planting Date (mm/dd)
            self.harvest_date = harvest_date  # Latest Harvest Date (mm/dd)

        else:
            assert (
                c_name in crop_params.keys()
            ), f"Crop name not defined in crop_params dictionary, \
        if defining a custom crop please use crop name 'custom'. Otherwise use one of the \
        pre-defined crops: {crop_params.keys()}"

        # overide any pre-defined paramater with any passed by the user
        allowed_keys = {
            "fshape_b",
            "PctZmin",
            "fshape_ex",
            "ETadj",
            "ET0dorm",
            "Aer",
            "LagAer",
            "beta",
            "a_Tr",
            "GermThr",
            "CCmin",
            "MaxFlowPct",
            "HIini",
            "bsted",
            "bface",
            "Name",
            "CropType",
            "PlantMethod",
            "CalendarType",
            "SwitchGDD",
            "planting_date",
            "harvest_date",
            "Emergence",
            "MaxRooting",
            "Senescence",
            "Maturity",
            "HIstart",
            "Flowering",
            "YldForm",
            "YldWC",
            "GDDmethod",
            "Tbase",
            "Tupp",
            "PolHeatStress",
            "Tmax_up",
            "Tmax_lo",
            "PolColdStress",
            "Tmin_up",
            "Tmin_lo",
            "TrColdStress",
            "GDD_up",
            "GDD_lo",
            "Zmin",
            "Zmax",
            "fshape_r",
            "SxTopQ",
            "SxBotQ",
            "SeedSize",
            "PlantPop",
            "CCx",
            "CDC",
            "CGC",
            "Kcb",
            "fage",
            "WP",
            "WPy",
            "fsink",
            "HI0",
            "dHI_pre",
            "a_HI",
            "b_HI",
            "dHI0",
            "Determinant",
            "exc",
            "p_up1",
            "p_up2",
            "p_up3",
            "p_up4",
            "p_lo1",
            "p_lo2",
            "p_lo3",
            "p_lo4",
            "fshape_w1",
            "fshape_w2",
            "fshape_w3",
            "fshape_w4",
            "CGC_CD",
            "CDC_CD",
            "EmergenceCD",
            "MaxRootingCD",
            "SenescenceCD",
            "MaturityCD",
            "HIstartCD",
            "FloweringCD",
            "YldFormCD",
        }

        self.__dict__.update(
            (k, v) for k, v in kwargs.items() if k in allowed_keys
        )

        self.calculate_additional_params()

    def calculate_additional_params(
        self,
    ):
        '''
        Calculate additional parameters for all self types in mix
        '''

        # Fractional canopy cover size at emergence
        self.CC0 = self.PlantPop * self.SeedSize * 1e-8
        # Root extraction terms
        SxTopQ = self.SxTopQ
        SxBotQ = self.SxBotQ
        S1 = self.SxTopQ
        S2 = self.SxBotQ
        if S1 == S2:
            SxTop = S1
            SxBot = S2
        else:
            if SxTopQ < SxBotQ:
                S1 = SxBotQ
                S2 = SxTopQ

            xx = 3 * (S2 / (S1 - S2))
            if xx < 0.5:
                SS1 = (4 / 3.5) * S1
                SS2 = 0
            else:
                SS1 = (xx + 3.5) * (S1 / (xx + 3))
                SS2 = (xx - 0.5) * (S2 / xx)

            if SxTopQ > SxBotQ:
                SxTop = SS1
                SxBot = SS2
            else:
                SxTop = SS2
                SxBot = SS1

        self.SxTop = SxTop
        self.SxBot = SxBot

        # Water stress thresholds
        self.p_up = np.array([self.p_up1, self.p_up2, self.p_up3, self.p_up4])

        self.p_lo = np.array([self.p_lo1, self.p_lo2, self.p_lo3, self.p_lo4])

        self.fshape_w = np.array(
            [self.fshape_w1, self.fshape_w2, self.fshape_w3, self.fshape_w4]
        )

calculate_additional_params()

Calculate additional parameters for all self types in mix

Source code in aquacrop/entities/crop.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def calculate_additional_params(
    self,
):
    '''
    Calculate additional parameters for all self types in mix
    '''

    # Fractional canopy cover size at emergence
    self.CC0 = self.PlantPop * self.SeedSize * 1e-8
    # Root extraction terms
    SxTopQ = self.SxTopQ
    SxBotQ = self.SxBotQ
    S1 = self.SxTopQ
    S2 = self.SxBotQ
    if S1 == S2:
        SxTop = S1
        SxBot = S2
    else:
        if SxTopQ < SxBotQ:
            S1 = SxBotQ
            S2 = SxTopQ

        xx = 3 * (S2 / (S1 - S2))
        if xx < 0.5:
            SS1 = (4 / 3.5) * S1
            SS2 = 0
        else:
            SS1 = (xx + 3.5) * (S1 / (xx + 3))
            SS2 = (xx - 0.5) * (S2 / xx)

        if SxTopQ > SxBotQ:
            SxTop = SS1
            SxBot = SS2
        else:
            SxTop = SS2
            SxBot = SS1

    self.SxTop = SxTop
    self.SxBot = SxBot

    # Water stress thresholds
    self.p_up = np.array([self.p_up1, self.p_up2, self.p_up3, self.p_up4])

    self.p_lo = np.array([self.p_lo1, self.p_lo2, self.p_lo3, self.p_lo4])

    self.fshape_w = np.array(
        [self.fshape_w1, self.fshape_w2, self.fshape_w3, self.fshape_w4]
    )

CropStruct

Bases: object

Duplicate crop object for Jit compilation

Source code in aquacrop/entities/crop.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
class CropStruct(object):
    """
    Duplicate crop object for Jit compilation


    """

    def __init__(
        self,
    ):

        # Assign default program properties (should not be changed without expert knowledge)

        self.fshape_b = 13.8135  # Shape factor describing the reduction in biomass production for insufficient growing degree days
        self.PctZmin = (
            70  # Initial percentage of minimum effective rooting depth
        )
        self.fshape_ex = (
            -6
        )  # Shape factor describing the effects of water stress on root expansion
        self.ETadj = 1  # Adjustment to water stress thresholds depending on daily ET0 (0 = No, 1 = Yes)
        self.ET0dorm = 0 # Duration of dormant crop period (during early senescence) in terms of cumulative reference ET (mm)
        self.Aer = 5  # Vol (%) below saturation at which stress begins to occur due to deficient aeration
        self.LagAer = (
            3  # Number of days lag before aeration stress affects crop growth
        )
        self.beta = 12  # Reduction (%) to p_lo3 when early canopy senescence is triggered
        self.a_Tr = 1  # Exponent parameter for adjustment of Kcx once senescence is triggered
        self.GermThr = 0.2  # Proportion of total water storage needed for crop to germinate
        self.CCmin = 0.05  # Minimum canopy size below which yield_ formation cannot occur
        self.MaxFlowPct = (
            100 / 3
        )  # Proportion of total flowering time (%) at which peak flowering occurs
        self.HIini = 0.01  # Initial harvest index
        self.bsted = 0.000138  # WP co2 adjustment parameter given by Steduto et al. 2007
        self.bface = (
            0.001165  # WP co2 adjustment parameter given by FACE experiments
        )

        # added in Read_Model_Paramaters
        self.CropType = 3  # Crop Type (1 = Leafy vegetable, 2 = Root/tuber, 3 = Fruit/grain)
        self.PlantMethod = 1  # Planting method (0 = Transplanted, 1 =  Sown)
        self.CalendarType = (
            2  # Calendar Type (1 = Calendar days, 2 = Growing degree days)
        )
        self.SwitchGDD = 0  # Convert calendar to gdd mode if inputs are given in calendar days (0 = No; 1 = Yes)

        self.EmergenceCD = 0
        self.Canopy10PctCD = 0
        self.MaxRootingCD = 0
        self.SenescenceCD = 0
        self.MaturityCD = 0
        self.MaxCanopyCD = 0
        self.CanopyDevEndCD = 0
        self.HIstartCD = 0
        self.HIendCD = 0
        self.YldFormCD = 0

        self.Emergence = 80  # Growing degree/Calendar days from sowing to emergence/transplant recovery
        self.MaxRooting = (
            1420  # Growing degree/Calendar days from sowing to maximum rooting
        )
        self.Senescence = (
            1420  # Growing degree/Calendar days from sowing to senescence
        )
        self.Maturity = (
            1670  # Growing degree/Calendar days from sowing to maturity
        )
        self.HIstart = 850  # Growing degree/Calendar days from sowing to start of yield_ formation
        self.Flowering = 190  # Duration of flowering in growing degree/calendar days (-999 for non-fruit/grain crops)
        self.YldForm = (
            775  # Duration of yield_ formation in growing degree/calendar days
        )
        self.HIend = 0
        self.MaxCanopy = 0
        self.CanopyDevEnd = 0
        self.Canopy10Pct = 0
        self.YldWC = 0
        self.GDDmethod = 2  # Growing degree day calculation method
        self.Tbase = (
            8  # Base temperature (degC) below which growth does not progress
        )
        self.Tupp = 30  # Upper temperature (degC) above which crop development no longer increases
        self.PolHeatStress = (
            1  # Pollination affected by heat stress (0 = No, 1 = Yes)
        )
        self.Tmax_up = 40  # Maximum air temperature (degC) above which pollination begins to fail
        self.Tmax_lo = 45  # Maximum air temperature (degC) at which pollination completely fails
        self.PolColdStress = (
            1  # Pollination affected by cold stress (0 = No, 1 = Yes)
        )
        self.Tmin_up = 10  # Minimum air temperature (degC) below which pollination begins to fail
        self.Tmin_lo = 5  # Minimum air temperature (degC) at which pollination completely fails
        self.TrColdStress = 1  # Transpiration affected by cold temperature stress (0 = No, 1 = Yes)
        self.GDD_up = 12  # Minimum growing degree days (degC/day) required for full crop transpiration potential
        self.GDD_lo = 0  # Growing degree days (degC/day) at which no crop transpiration occurs
        self.Zmin = 0.3  # Minimum effective rooting depth (m)
        self.Zmax = 1.7  # Maximum rooting depth (m)
        self.fshape_r = 1.3  # Shape factor describing root expansion
        self.SxTopQ = 0.0480  # Maximum root water extraction at top of the root zone (m3/m3/day)
        self.SxBotQ = 0.0117  # Maximum root water extraction at the bottom of the root zone (m3/m3/day)

        self.SxTop = 0.0
        self.SxBot = 0.0

        self.SeedSize = 6.5  # Soil surface area (cm2) covered by an individual seedling at 90% emergence
        self.PlantPop = 75_000  # Number of plants per hectare
        self.CCx = 0.96  # Maximum canopy cover (fraction of soil cover)
        self.CDC = (
            0.01  # Canopy decline coefficient (fraction per gdd/calendar day)
        )
        self.CGC = 0.0125  # Canopy growth coefficient (fraction per gdd)
        self.CDC_CD = (
            0.01  # Canopy decline coefficient (fraction per gdd/calendar day)
        )
        self.CGC_CD = 0.0125  # Canopy growth coefficient (fraction per gdd)
        self.Kcb = 1.05  # Crop coefficient when canopy growth is complete but prior to senescence
        self.fage = 0.3  #  Decline of crop coefficient due to ageing (%/day)
        self.WP = 33.7  # Water productivity normalized for ET0 and C02 (g/m2)
        self.WPy = 100  # Adjustment of water productivity in yield_ formation stage (% of WP)
        self.fsink = 0.5  # Crop performance under elevated atmospheric CO2 concentration (%/100)
        self.HI0 = 0.48  # Reference harvest index
        self.dHI_pre = 0  # Possible increase of harvest index due to water stress before flowering (%)
        self.a_HI = 7  # Coefficient describing positive impact on harvest index of restricted vegetative growth during yield_ formation
        self.b_HI = 3  # Coefficient describing negative impact on harvest index of stomatal closure during yield_ formation
        self.dHI0 = 15  # Maximum allowable increase of harvest index above reference value
        self.Determinant = (
            1  # Crop Determinancy (0 = Indeterminant, 1 = Determinant)
        )
        self.exc = 50  # Excess of potential fruits
        self.p_up = np.zeros(
            4
        )  # Upper soil water depletion threshold for water stress effects on affect canopy expansion
        self.p_lo = np.zeros(
            4
        )  # Lower soil water depletion threshold for water stress effects on canopy expansion
        self.fshape_w = np.ones(
            4
        )  # Shape factor describing water stress effects on canopy expansion

        self.CC0 = 0.0

        self.HIGC = 0.0
        self.tLinSwitch = 0
        self.dHILinear = 0.0

        self.fCO2 = 0.0

        self.FloweringCD = 0
        self.FloweringEnd = 0.0

aquacrop.entities.fieldManagement

FieldMngt

Field Management Class containing mulches and bunds parameters

Attributes:

mulches (bool):  Soil surface covered by mulches (yield_ or N)

bunds (bool):  Surface bunds present (yield_ or N)

curve_number_adj (bool): Field conditions affect curve number (yield_ or N)

sr_inhb (bool): Management practices fully inhibit surface runoff (yield_ or N)

mulch_pct (float):  Area of soil surface covered by mulches (%)

f_mulch (float): Soil evaporation adjustment factor due to effect of mulches

z_bund (float): Bund height (m)

bund_water (float): Initial water height in surface bunds (mm)

curve_number_adj_pct (float): Percentage change in curve number (positive or negative)
Source code in aquacrop/entities/fieldManagement.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class FieldMngt:
    """
    Field Management Class containing mulches and bunds parameters

    Attributes:

        mulches (bool):  Soil surface covered by mulches (yield_ or N)

        bunds (bool):  Surface bunds present (yield_ or N)

        curve_number_adj (bool): Field conditions affect curve number (yield_ or N)

        sr_inhb (bool): Management practices fully inhibit surface runoff (yield_ or N)

        mulch_pct (float):  Area of soil surface covered by mulches (%)

        f_mulch (float): Soil evaporation adjustment factor due to effect of mulches

        z_bund (float): Bund height (m)

        bund_water (float): Initial water height in surface bunds (mm)

        curve_number_adj_pct (float): Percentage change in curve number (positive or negative)

    """

    def __init__(
        self,
        mulches=False,
        bunds=False,
        curve_number_adj=False,
        sr_inhb=False,
        mulch_pct=50,
        f_mulch=0.5,
        z_bund=0,
        bund_water=0,
        curve_number_adj_pct=0,
    ):

        self.mulches = mulches  #  Soil surface covered by mulches (yield_ or N)
        self.bunds = bunds  #  Surface bunds present (yield_ or N)
        self.curve_number_adj = curve_number_adj  # Field conditions affect curve number (yield_ or N)
        self.sr_inhb = sr_inhb  # Management practices fully inhibit surface runoff (yield_ or N)

        self.mulch_pct = mulch_pct  #  Area of soil surface covered by mulches (%)
        self.f_mulch = f_mulch  # Soil evaporation adjustment factor due to effect of mulches
        self.z_bund = z_bund  # Bund height (m)
        self.bund_water = bund_water  # Initial water height in surface bunds (mm)
        self.curve_number_adj_pct = curve_number_adj_pct  # Percentage change in curve number (positive or negative)

FieldMngtStruct

Source code in aquacrop/entities/fieldManagement.py
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class FieldMngtStruct:

    """


    """

    def __init__(self):
        self.mulches = False
        self.bunds = False
        self.curve_number_adj = False
        self.sr_inhb = False

        self.mulch_pct = 0.0
        self.f_mulch = 0.0
        self.z_bund = 0.0
        self.bund_water = 0.0
        self.curve_number_adj_pct = 0.0

aquacrop.entities.groundWater

GroundWater

Ground Water Class stores information on water table params

Attributes:

water_table (str):  Water table considered (Y or N)

method (str):  Water table input data ('Constant' or 'Variable')

dates (list): water table observation dates

values (list): water table observation depths
Source code in aquacrop/entities/groundWater.py
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class GroundWater:
    """
    Ground Water Class stores information on water table params

    Attributes:

        water_table (str):  Water table considered (Y or N)

        method (str):  Water table input data ('Constant' or 'Variable')

        dates (list): water table observation dates

        values (list): water table observation depths

    """

    def __init__(self, water_table="N", method="Constant", dates=[], values=[]):

        self.water_table = water_table
        self.method = method
        self.dates = dates
        self.values = values

aquacrop.entities.inititalWaterContent

InitialWaterContent

Initial water content Class defines water content at start of sim

Attributes:

wc_type (str):  Type of value ('Prop' = 'WP'/'FC'/'SAT'; 'Num' = XXX m3/m3; 'Pct' = % taw))

method (str):  method ('Depth' = Interpolate depth points; 'Layer' = Constant value for each soil layer)

depth_layer (list): location in soil profile (soil layer or depth)

value (list): value at each location given in depth_layer
Source code in aquacrop/entities/inititalWaterContent.py
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class InitialWaterContent:
    """
    Initial water content Class defines water content at start of sim

    Attributes:

        wc_type (str):  Type of value ('Prop' = 'WP'/'FC'/'SAT'; 'Num' = XXX m3/m3; 'Pct' = % taw))

        method (str):  method ('Depth' = Interpolate depth points; 'Layer' = Constant value for each soil layer)

        depth_layer (list): location in soil profile (soil layer or depth)

        value (list): value at each location given in depth_layer

    """

    def __init__(self, wc_type="Prop", method="Layer", depth_layer=[1], value=["FC"]):

        self.wc_type = wc_type
        self.method = method
        self.depth_layer = depth_layer
        self.value = value

aquacrop.entities.initParamVariables

InitialCondition

The InitCond Class contains all Paramaters and variables used in the simulation

updated each timestep with the name NewCond

Source code in aquacrop/entities/initParamVariables.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
class InitialCondition:
    """
    The InitCond Class contains all Paramaters and variables used in the simulation

    updated each timestep with the name NewCond


    """

    def __init__(self, num_comp):
        # counters
        self.age_days = 0
        self.age_days_ns = 0
        self.aer_days = 0
        self.aer_days_comp = np.zeros(num_comp)
        self.irr_cum = 0
        self.delayed_gdds = 0
        self.delayed_cds = 0
        self.pct_lag_phase = 0
        self.t_early_sen = 0
        self.gdd_cum = 0
        self.day_submerged = 0
        self.irr_net_cum = 0
        self.dap = 0
        self.e_pot = 0
        self.t_pot = 0

        # States
        self.pre_adj = False
        self.crop_mature = False
        self.crop_dead = False
        self.germination = False
        self.premat_senes = False
        self.harvest_flag = False
        self.growing_season = False
        self.yield_form = False
        self.stage2 = False

        self.wt_in_soil = False

        # harvest_index
        self.stage = 1
        self.f_pre = 1
        self.f_post = 1
        self.fpost_dwn = 1
        self.fpost_upp = 1

        self.h1_cor_asum = 0
        self.h1_cor_bsum = 0
        self.f_pol = 0
        self.s_cor1 = 0
        self.s_cor2 = 0
        self.hi_ref = 0.0
        self.HIfinal = 0.0

        # GS
        self.growth_stage = 0

        # Transpiration
        self.tr_ratio = 1

        # crop growth
        self.r_cor = 1

        self.canopy_cover = 0
        self.canopy_cover_adj = 0
        self.canopy_cover_ns = 0
        self.canopy_cover_adj_ns = 0
        self.biomass = 0
        self.biomass_ns = 0
        self.YieldPot = 0
        self.harvest_index = 0
        self.harvest_index_adj = 0
        self.ccx_act = 0
        self.ccx_act_ns = 0
        self.ccx_w = 0
        self.ccx_w_ns = 0
        self.ccx_early_sen = 0
        self.cc_prev = 0
        self.protected_seed = 0
        self.DryYield = 0
        self.FreshYield = 0

        self.z_root = 0.0
        self.cc0_adj = 0
        self.surface_storage = 0
        self.z_gw = ModelConstants.NO_VALUE

        self.th_fc_Adj = np.zeros(num_comp)
        self.th = np.zeros(num_comp)
        self.thini = np.zeros(num_comp)

        self.time_step_counter = 0

        self.precipitation = 0
        self.temp_max = 0
        self.temp_min = 0
        self.et0 = 0
        self.sumET0EarlySen = 0
        self.gdd = 0

        self.w_surf = 0
        self.evap_z = 0
        self.w_stage_2 = 0

        self.depletion = 0
        self.taw = 0

aquacrop.entities.irrigationManagement

IrrMngtStruct

Source code in aquacrop/entities/irrigationManagement.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
class IrrMngtStruct:

    """


    """

    def __init__(self, sim_len):
        self.irrigation_method = 0

        self.WetSurf = 100.0
        self.AppEff = 100.0
        self.MaxIrr = 25.0
        self.MaxIrrSeason = 10_000
        self.SMT = np.zeros(4)
        self.IrrInterval = 0
        self.Schedule = np.zeros(sim_len)
        self.NetIrrSMT = 80.0
        self.depth = 0.0

IrrigationManagement

IrrigationManagement Class defines irrigation strategy

Attributes:

irrigation_method (int):  Irrigation method {0: rainfed, 1: soil moisture targets, 2: set time interval,
                                        3: predifined schedule, 4: net irrigation, 5: constant depth }

WetSurf (int): Soil surface wetted by irrigation (%)

AppEff (int): Irrigation application efficiency (%)

MaxIrr (float): Maximum depth (mm) that can be applied each day

SMT (list):  Soil moisture targets (%taw) to maintain in each growth stage (only used if irrigation method is equal to 1)

IrrInterval (int): Irrigation interval in days (only used if irrigation method is equal to 2)

Schedule (pandas.DataFrame): DataFrame containing dates and depths

NetIrrSMT (float): Net irrigation threshold moisture level (% of taw that will be maintained, for irrigation_method=4)

Depth (float): constant depth to apply on each day (mm)
Source code in aquacrop/entities/irrigationManagement.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class IrrigationManagement:

    """
    IrrigationManagement Class defines irrigation strategy

    Attributes:


        irrigation_method (int):  Irrigation method {0: rainfed, 1: soil moisture targets, 2: set time interval,
                                                3: predifined schedule, 4: net irrigation, 5: constant depth }

        WetSurf (int): Soil surface wetted by irrigation (%)

        AppEff (int): Irrigation application efficiency (%)

        MaxIrr (float): Maximum depth (mm) that can be applied each day

        SMT (list):  Soil moisture targets (%taw) to maintain in each growth stage (only used if irrigation method is equal to 1)

        IrrInterval (int): Irrigation interval in days (only used if irrigation method is equal to 2)

        Schedule (pandas.DataFrame): DataFrame containing dates and depths

        NetIrrSMT (float): Net irrigation threshold moisture level (% of taw that will be maintained, for irrigation_method=4)

        Depth (float): constant depth to apply on each day (mm)

    """

    def __init__(self, irrigation_method, **kwargs):
        self.irrigation_method = irrigation_method

        self.WetSurf = 100.0
        self.AppEff = 100.0
        self.MaxIrr = 25.0
        self.MaxIrrSeason = 10_000.0
        self.SMT = np.zeros(4)
        self.IrrInterval = 0
        self.Schedule = []
        self.NetIrrSMT = 80.0
        self.depth = 0.0

        if irrigation_method == 1:
            self.SMT = [100] * 4

        if irrigation_method == 2:
            self.IrrInterval = 3

        if irrigation_method == 3:
            # wants a pandas dataframe with Date and Depth, pd.Datetime and float
            """
            dates = pd.DatetimeIndex(['20/10/1979','20/11/1979','20/12/1979'])
            depths = [25,25,25]
            irr=pd.DataFrame([dates,depths]).T
            irr.columns=['Date','Depth']
            """
            self.Schedule = pd.DataFrame(columns=["Date", "Depth"])

        if irrigation_method == 4:
            self.NetIrrSMT = 80

        if irrigation_method == 5:
            self.depth = 0

        allowed_keys = {
            "name",
            "WetSurf",
            "AppEff",
            "MaxIrr",
            "MaxIrrSeason",
            "SMT",
            "IrrInterval",
            "NetIrrSMT",
            "Schedule",
            "depth",
        }

        self.__dict__.update((k, v) for k, v in kwargs.items() if k in allowed_keys)

aquacrop.entities.moistureDepletion

Dr

Depletion class to hold the rootzone and topsoil depletion

Attributes:

Rz (float): Root zone soil-water depletion

Zt (float): Top soil depletion

Source code in aquacrop/entities/moistureDepletion.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Dr:
    """
    Depletion class to hold the rootzone and topsoil depletion

    Attributes:

    Rz (float): Root zone soil-water depletion

    Zt (float): Top soil depletion


    """

    def __init__(self):
        self.Rz = 0.0
        self.Zt = 0.0

aquacrop.entities.output

Output

Class to hold output data

During Simulation these are numpy arrays and are converted to pandas dataframes at the end of the simulation

Atributes:

water_flux (pandas.DataFrame, numpy.array): Daily water flux changes

water_storage (pandas.DataFrame, numpy array): daily water content of each soil compartment

crop_growth (pandas.DataFrame, numpy array): daily crop growth variables

final_stats (pandas.DataFrame, numpy array): final stats at end of each season
Source code in aquacrop/entities/output.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Output:
    """
    Class to hold output data

    During Simulation these are numpy arrays and are converted to pandas dataframes
    at the end of the simulation

    Atributes:

        water_flux (pandas.DataFrame, numpy.array): Daily water flux changes

        water_storage (pandas.DataFrame, numpy array): daily water content of each soil compartment

        crop_growth (pandas.DataFrame, numpy array): daily crop growth variables

        final_stats (pandas.DataFrame, numpy array): final stats at end of each season

    """

    def __init__(self, time_span, initial_th):

        self.water_storage = np.zeros((len(time_span), 3 + len(initial_th)))
        self.water_flux = np.zeros((len(time_span), 16))
        self.crop_growth = np.zeros((len(time_span), 15))
        self.final_stats = pd.DataFrame(
            columns=[
                "Season",
                "crop Type",
                "Harvest Date (YYYY/MM/DD)",
                "Harvest Date (Step)",
                "Dry yield (tonne/ha)",
                "Fresh yield (tonne/ha)",
                "Yield potential (tonne/ha)",
                "Seasonal irrigation (mm)",
            ]
        )

aquacrop.entities.paramStruct

ParamStruct

The ParamStruct class contains the bulk of model Paramaters. In general these will not change over the course of the simulation

Attributes:

Soil (Soil): Soil object contains data and paramaters related to the soil

FallowFieldMngt (FieldMngt): Object containing field management variables for the off season (fallow periods)

NCrops (int): Number of crop types to be simulated

SpecifiedPlantCalander (str):  Specified crop rotation calendar (yield_ or N)

CropChoices (list): List of crop type names in each simulated season

CO2data (pd.Series): CO2 data indexed by year

CO2 (CO2): object containing reference and current co2 concentration

water_table (int): Water table present (1=yes, 0=no)

z_gw (np.array): water_table depth (mm) for each day of simulation

zGW_dates (np.array): Corresponding dates to the z_gw values

WTMethod (str): 'Constant' or 'Variable'

CropList (list): List of Crop Objects which contain paramaters for all the differnet crops used in simulations

python_crop_list (list): List of Crop Objects, one for each season

python_fallow_crop (Crop): Crop object for off season

Seasonal_Crop_List (list): List of CropStructs, one for each season (jit class objects)

crop_name_list (list): List of crop names, one for each season

Fallow_Crop (CropStruct): CropStruct object (jit class) for off season

Fallow_Crop_Name (str): name of fallow crop
Source code in aquacrop/entities/paramStruct.py
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class ParamStruct:
    """
    The ParamStruct class contains the bulk of model Paramaters. 
    In general these will not change over the course of the simulation


    Attributes:

        Soil (Soil): Soil object contains data and paramaters related to the soil

        FallowFieldMngt (FieldMngt): Object containing field management variables for the off season (fallow periods)

        NCrops (int): Number of crop types to be simulated

        SpecifiedPlantCalander (str):  Specified crop rotation calendar (yield_ or N)

        CropChoices (list): List of crop type names in each simulated season

        CO2data (pd.Series): CO2 data indexed by year

        CO2 (CO2): object containing reference and current co2 concentration

        water_table (int): Water table present (1=yes, 0=no)

        z_gw (np.array): water_table depth (mm) for each day of simulation

        zGW_dates (np.array): Corresponding dates to the z_gw values

        WTMethod (str): 'Constant' or 'Variable'

        CropList (list): List of Crop Objects which contain paramaters for all the differnet crops used in simulations

        python_crop_list (list): List of Crop Objects, one for each season

        python_fallow_crop (Crop): Crop object for off season

        Seasonal_Crop_List (list): List of CropStructs, one for each season (jit class objects)

        crop_name_list (list): List of crop names, one for each season

        Fallow_Crop (CropStruct): CropStruct object (jit class) for off season

        Fallow_Crop_Name (str): name of fallow crop

        """

    def __init__(self):

        # soil
        self.Soil = 0

        # field management
        self.FallowFieldMngt = 0

        # variables extracted from cropmix.txt
        self.NCrops = 0
        self.SpecifiedPlantCalander = ""
        self.RotationFilename = ""

        # calculated Co2 variables
        self.CO2data = []
        self.CO2 = 0
        self.co2_concentration_adj = None

        # water table
        self.water_table = 0
        self.z_gw = []
        self.zGW_dates = []
        self.WTMethod = ""

        # crops
        self.CropList = []
        self.python_crop_list = []
        self.python_fallow_crop = 0
        self.Seasonal_Crop_List = []
        self.crop_name_list = []
        self.Fallow_Crop = 0
        self.Fallow_Crop_Name = ""

aquacrop.entities.rootZoneWaterContent

RootZoneWater

Bases: object

TODO: This class is not used

root zone water content

Attributes:

Act : float : .

S : float : .

FC : float : .

WP : float : .

Dry : float : .

Aer : float : .

Source code in aquacrop/entities/rootZoneWaterContent.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class RootZoneWater(object):
    """
    TODO: This class is not used

    root zone water content

    **Attributes:**\n



    `Act` : `float` : .

    `S` : `float` : .

    `FC` : `float` : .

    `WP` : `float` : .

    `Dry` : `float` : .

    `Aer` : `float` : .



    """

    def __init__(self):
        self.Act = 0.0
        self.S = 0.0
        self.FC = 0.0
        self.WP = 0.0
        self.Dry = 0.0
        self.Aer = 0.0

aquacrop.entities.soil

Soil

The Soil Class contains Paramaters and variables of the soil used in the simulation

More float attributes are specified in the initialisation of the class

Attributes:

profile (pandas.DataFrame): holds soil profile information

Profile (SoilProfile): jit class object holdsing soil profile information

Hydrology (pandas.DataFrame): holds soil layer hydrology informaiton

Comp (pandas.DataFrame): holds soil compartment information
Source code in aquacrop/entities/soil.py
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
class Soil:
    """
    The Soil Class contains Paramaters and variables of the soil used in the simulation

    More float attributes are specified in the initialisation of the class

    Attributes:

        profile (pandas.DataFrame): holds soil profile information

        Profile (SoilProfile): jit class object holdsing soil profile information

        Hydrology (pandas.DataFrame): holds soil layer hydrology informaiton

        Comp (pandas.DataFrame): holds soil compartment information


    """

    def __init__(
        self,
        soil_type,
        dz=[0.1] * 12,
        adj_rew=1,
        rew=9.0,
        calc_cn=0,
        cn=61.0,
        z_res=ModelConstants.NO_VALUE,
        evap_z_surf=0.04,
        evap_z_min=0.15,
        evap_z_max=0.30,
        kex=1.1,
        f_evap=4,
        f_wrel_exp=0.4,
        fwcc=50,
        z_cn=0.3,
        z_germ=0.3,
        adj_cn=1,
        fshape_cr=16,
        z_top=0.1,
    ):

        self.Name = soil_type

        self.zSoil = sum(dz)  # Total thickness of soil profile (m)
        self.nComp = len(dz)  # Total number of soil compartments
        self.nLayer = 0  # Total number of soil layers
        self.adj_rew = adj_rew  # Adjust default value for readily evaporable water (0 = No, 1 = Yes)
        self.rew = rew  # Readily evaporable water (mm) (only used if adjusting from default value)
        self.calc_cn = calc_cn  # adjust Curve number based on Ksat
        self.cn = cn  # Curve number  (0 = No, 1 = Yes)
        self.z_res = z_res  # Depth of restrictive soil layer (set to negative value if not present)

        # Assign default program properties (should not be changed without expert knowledge)
        self.evap_z_surf = (
            evap_z_surf  # Thickness of soil surface skin evaporation layer (m)
        )
        self.evap_z_min = (
            evap_z_min  # Minimum thickness of full soil surface evaporation layer (m)
        )
        self.evap_z_max = (
            evap_z_max  # Maximum thickness of full soil surface evaporation layer (m)
        )
        self.kex = kex  # Maximum soil evaporation coefficient
        self.f_evap = (
            f_evap  # Shape factor describing reduction in soil evaporation in stage 2.
        )
        self.f_wrel_exp = f_wrel_exp  # Proportional value of Wrel at which soil evaporation layer expands
        self.fwcc = fwcc  # Maximum coefficient for soil evaporation reduction due to sheltering effect of withered canopy
        self.z_cn = z_cn  # Thickness of soil surface (m) used to calculate water content to adjust curve number
        self.z_germ = z_germ  # Thickness of soil surface (m) used to calculate water content for germination
        self.adj_cn = (
            adj_cn  # Adjust curve number for antecedent moisture content (0: No, 1: Yes)
        )
        self.fshape_cr = fshape_cr  # Capillary rise shape factor
        self.z_top = max(
            z_top, dz[0]
        )  # Thickness of soil surface layer for water stress comparisons (m)

        if soil_type == "custom":
            self.create_df(dz)

        elif soil_type == "Clay":
            self.cn = 77
            self.calc_cn = 0
            self.rew = 14
            self.create_df(dz)
            self.add_layer(sum(dz), 0.39, 0.54, 0.55, 35, 100)

        elif soil_type == "ClayLoam":
            self.cn = 72
            self.calc_cn = 0
            self.rew = 11
            self.create_df(dz)
            self.add_layer(sum(dz), 0.23, 0.39, 0.5, 125, 100)

        elif soil_type == 'Default':
            self.cn = 61
            self.calc_cn = 0
            self.rew = 9
            self.create_df(dz)
            self.add_layer(sum(dz), 0.1, 0.3, 0.5, 500, 100)

        elif soil_type == "Loam":
            self.cn = 61
            self.calc_cn = 0
            self.rew = 9
            self.create_df(dz)
            self.add_layer(sum(dz), 0.15, 0.31, 0.46, 500, 100)

        elif soil_type == "LoamySand":
            self.cn = 46
            self.calc_cn = 0
            self.rew = 5
            self.create_df(dz)
            self.add_layer(sum(dz), 0.08, 0.16, 0.38, 2200, 100)

        elif soil_type == "Sand":
            self.cn = 46
            self.calc_cn = 0
            self.rew = 4
            self.create_df(dz)
            self.add_layer(sum(dz), 0.06, 0.13, 0.36, 3000, 100)

        elif soil_type == "SandyClay":
            self.cn = 77
            self.calc_cn = 0
            self.rew = 10
            self.create_df(dz)
            self.add_layer(sum(dz), 0.27, 0.39, 0.5, 35, 100)

        elif soil_type == "SandyClayLoam":
            self.cn = 72
            self.calc_cn = 0
            self.rew = 9
            self.create_df(dz)
            self.add_layer(sum(dz), 0.20, 0.32, 0.47, 225, 100)

        elif soil_type == "SandyLoam":
            self.cn = 46
            self.calc_cn = 0
            self.rew = 7
            self.create_df(dz)
            self.add_layer(sum(dz), 0.10, 0.22, 0.41, 1200, 100)

        elif soil_type == "Silt":
            self.cn = 61
            self.calc_cn = 0
            self.rew = 11
            self.create_df(dz)
            self.add_layer(sum(dz), 0.09, 0.33, 0.43, 500, 100)

        elif soil_type == "SiltClayLoam":
            self.cn = 72
            self.calc_cn = 0
            self.rew = 13
            self.create_df(dz)
            self.add_layer(sum(dz), 0.23, 0.44, 0.52, 150, 100)

        elif soil_type == "SiltLoam":
            self.cn = 61
            self.calc_cn = 0
            self.rew = 11
            self.create_df(dz)
            self.add_layer(sum(dz), 0.13, 0.33, 0.46, 575, 100)

        elif soil_type == "SiltClay":
            self.cn = 72
            self.calc_cn = 0
            self.rew = 14
            self.create_df(dz)
            self.add_layer(sum(dz), 0.32, 0.50, 0.54, 100, 100)

        elif soil_type == "Paddy":
            self.cn = 77
            self.calc_cn = 0
            self.rew = 10
            self.create_df(dz)
            self.add_layer(0.5, 0.32, 0.50, 0.54, 15, 100)
            self.add_layer(1.5, 0.39, 0.54, 0.55, 2, 100)

        elif soil_type == "ac_TunisLocal":
            self.cn = 72
            self.calc_cn = 0
            self.rew = 11
            dz = [0.1] * 6 + [0.15] * 5 + [0.2]
            self.create_df(dz)
            self.add_layer(0.3, 0.24, 0.40, 0.50, 155, 100)
            self.add_layer(1.7, 0.11, 0.33, 0.46, 500, 100)

        else:
            print("wrong soil type")
            assert 1 == 2

    def __repr__(self):
        for key in self.__dict__:
            if key != "profile":
                print(f"{key}: {getattr(self,key)}")

        return " "

    def create_df(self, dz):

        self.profile = pd.DataFrame(
            np.empty((len(dz), 4)), columns=["Comp", "Layer", "dz", "dzsum"]
        )
        self.profile.dz = dz
        self.profile.dzsum = np.cumsum(self.profile.dz).round(2)
        self.profile.Comp = np.arange(len(dz))
        self.profile.Layer = np.nan

        self.profile["zBot"] = self.profile.dzsum
        self.profile["z_top"] = self.profile["zBot"] - self.profile.dz
        self.profile["zMid"] = (self.profile["z_top"] + self.profile["zBot"]) / 2

    def calculate_soil_hydraulic_properties(self, Sand, Clay, OrgMat, DF=1):

        """
        Function to calculate soil hydraulic properties, given textural inputs.
        Calculations use pedotransfer function equations described in Saxton and Rawls (2006)


        """

        # do calculations

        # Water content at permanent wilting point
        Pred_thWP = (
            -(0.024 * Sand)
            + (0.487 * Clay)
            + (0.006 * OrgMat)
            + (0.005 * Sand * OrgMat)
            - (0.013 * Clay * OrgMat)
            + (0.068 * Sand * Clay)
            + 0.031
        )

        th_wp = Pred_thWP + (0.14 * Pred_thWP) - 0.02

        # Water content at field capacity and saturation
        Pred_thFC = (
            -(0.251 * Sand)
            + (0.195 * Clay)
            + (0.011 * OrgMat)
            + (0.006 * Sand * OrgMat)
            - (0.027 * Clay * OrgMat)
            + (0.452 * Sand * Clay)
            + 0.299
        )

        PredAdj_thFC = Pred_thFC + (
            (1.283 * (np.power(Pred_thFC, 2))) - (0.374 * Pred_thFC) - 0.015
        )

        Pred_thS33 = (
            (0.278 * Sand)
            + (0.034 * Clay)
            + (0.022 * OrgMat)
            - (0.018 * Sand * OrgMat)
            - (0.027 * Clay * OrgMat)
            - (0.584 * Sand * Clay)
            + 0.078
        )

        PredAdj_thS33 = Pred_thS33 + ((0.636 * Pred_thS33) - 0.107)
        Pred_thS = (PredAdj_thFC + PredAdj_thS33) + ((-0.097 * Sand) + 0.043)

        pN = (1 - Pred_thS) * 2.65
        pDF = pN * DF
        PorosComp = (1 - (pDF / 2.65)) - (1 - (pN / 2.65))
        PorosCompOM = 1 - (pDF / 2.65)

        DensAdj_thFC = PredAdj_thFC + (0.2 * PorosComp)
        DensAdj_thS = PorosCompOM

        th_fc = DensAdj_thFC
        th_s = DensAdj_thS

        # Saturated hydraulic conductivity (mm/day)
        lmbda = 1 / ((np.log(1500) - np.log(33)) / (np.log(th_fc) - np.log(th_wp)))
        Ksat = (1930 * (th_s - th_fc) ** (3 - lmbda)) * 24

        # Water content at air dry
        th_dry = th_wp / 2

        # round values
        th_dry = round(10_000 * th_dry) / 10_000
        th_wp = round(1000 * th_wp) / 1000
        th_fc = round(1000 * th_fc) / 1000
        th_s = round(1000 * th_s) / 1000
        Ksat = round(10 * Ksat) / 10

        return th_wp, th_fc, th_s, Ksat

    def add_layer_from_texture(self, thickness, Sand, Clay, OrgMat, penetrability):

        th_wp, th_fc, th_s, Ksat = self.calculate_soil_hydraulic_properties(
            Sand / 100, Clay / 100, OrgMat
        )

        self.add_layer(thickness, th_wp, th_fc, th_s, Ksat, penetrability)

    def add_layer(self, thickness, thWP, thFC, thS, Ksat, penetrability):

        self.nLayer += 1

        num_layers = len(self.profile.dropna().Layer.unique())

        new_layer = num_layers + 1

        if new_layer == 1:
            self.profile.loc[
                (round(thickness, 2) >= round(self.profile.dzsum, 2)), "Layer"
            ] = new_layer
        else:
            last = self.profile[self.profile.Layer == new_layer - 1].dzsum.values[-1]
            self.profile.loc[
                (thickness + last >= self.profile.dzsum) & (self.profile.Layer.isna()),
                "Layer",
            ] = new_layer

        self.profile.loc[
            self.profile.Layer == new_layer, "th_dry"
        ] = self.profile.Layer.map({new_layer: thWP / 2})
        self.profile.loc[
            self.profile.Layer == new_layer, "th_wp"
        ] = self.profile.Layer.map({new_layer: thWP})
        self.profile.loc[
            self.profile.Layer == new_layer, "th_fc"
        ] = self.profile.Layer.map({new_layer: thFC})
        self.profile.loc[
            self.profile.Layer == new_layer, "th_s"
        ] = self.profile.Layer.map({new_layer: thS})
        self.profile.loc[
            self.profile.Layer == new_layer, "Ksat"
        ] = self.profile.Layer.map({new_layer: Ksat})
        self.profile.loc[
            self.profile.Layer == new_layer, "penetrability"
        ] = self.profile.Layer.map({new_layer: penetrability})

        # Calculate drainage characteristic (tau)
        # Calculations use equation given by Raes et al. 2012
        tau = round(0.0866 * (Ksat**0.35), 2)
        if tau > 1:
            tau = 1
        elif tau < 0:
            tau = 0

        self.profile.loc[
            self.profile.Layer == new_layer, "tau"
        ] = self.profile.Layer.map({new_layer: tau})

    def fill_nan(
        self,
    ):

        self.profile = self.profile.fillna(method="ffill")

        self.profile.dz = self.profile.dz.round(2)

        self.profile.dzsum = self.profile.dz.cumsum().round(2)

        self.zSoil = round(self.profile.dz.sum(), 2)

        self.nComp = len(self.profile)

        self.profile.Layer = self.profile.Layer.astype(int)

    def add_capillary_rise_params(
        self,
    ):
        # Calculate capillary rise parameters for all soil layers
        # Only do calculation if water table is present. Calculations use equations
        # described in Raes et al. (2012)
        prof = self.profile

        hydf = prof.groupby("Layer").mean().drop(["dz", "dzsum"], axis=1)

        hydf["aCR"] = 0
        hydf["bCR"] = 0

        for layer in hydf.index.unique():
            layer = int(layer)

            soil = hydf.loc[layer]

            thwp = soil.th_wp
            thfc = soil.th_fc
            ths = soil.th_s
            Ksat = soil.Ksat

            # usually just initialise here (both 0), but temporarily hard-coding for sandy-loam for testing
            aCR =  0
            bCR =  0

            # Define aCR and bCR calculations for each Soil Class 
            aCR_sandy=-0.3112 - Ksat/100000
            bCR_sandy=-1.4936 + 0.2416*np.log(Ksat)

            aCR_loamy=-0.4986 + 9*Ksat/100000
            bCR_loamy=-2.1320 + 0.4778*np.log(Ksat)

            aCR_sandy_clayey=-0.5677 - 4*Ksat/100000
            bCR_sandy_clayey=-3.7189 + 0.5922*np.log(Ksat)

            aCR_silty_clayey=-0.6366 + 8*Ksat/10000
            bCR_silty_clayey=-1.9165 + 0.7063*np.log(Ksat)

            # NEW (V7) aCR bCR calculations logic
            # Assign aCR/bCR based on soil class definition from FAO
            if ths <= 0.55:
                if thwp >= 0.20:
                    if (ths >= 0.49) and (thfc >= 0.40):
                        aCR=aCR_silty_clayey
                        bCR=bCR_silty_clayey
                    else:
                        aCR=aCR_sandy_clayey
                        bCR=bCR_sandy_clayey
                else:
                    if thfc < 0.23:
                        aCR=aCR_sandy
                        bCR=bCR_sandy
                    else:
                        if (thwp > 0.16) and (Ksat < 100):
                            aCR=aCR_sandy_clayey
                            bCR=bCR_sandy_clayey
                        else:
                            if (thwp < 0.06) and (thfc < 0.28) and (Ksat > 750):
                                aCR=aCR_sandy
                                bCR=bCR_sandy
                            else:
                                aCR=aCR_loamy
                                bCR=bCR_loamy
            else:
                aCR=aCR_silty_clayey
                bCR=bCR_silty_clayey






            # OLD (V6) aCR bCR calculation logic
            # if (
            #     (thwp >= 0.04)
            #     and (thwp <= 0.15)
            #     and (thfc >= 0.09)
            #     and (thfc <= 0.28)
            #     and (ths >= 0.32)
            #     and (ths <= 0.51)
            # ):

            #     # Sandy soil class
            #     if (Ksat >= 200) and (Ksat <= 2000):
            #         aCR = -0.3112 - (Ksat * (1e-5))
            #         bCR = -1.4936 + (0.2416 * np.log(Ksat))
            #     elif Ksat < 200:
            #         aCR = -0.3112 - (200 * (1e-5))
            #         bCR = -1.4936 + (0.2416 * np.log(200))
            #     elif Ksat > 2000:
            #         aCR = -0.3112 - (2000 * (1e-5))
            #         bCR = -1.4936 + (0.2416 * np.log(2000))

            # elif (
            #     (thwp >= 0.06)
            #     and (thwp <= 0.20)
            #     and (thfc >= 0.23)
            #     and (thfc <= 0.42)
            #     and (ths >= 0.42)
            #     and (ths <= 0.55)
            # ):

            #     # Loamy soil class
            #     if (Ksat >= 100) and (Ksat <= 750):
            #         aCR = -0.4986 + (9 * (1e-5) * Ksat)
            #         bCR = -2.132 + (0.4778 * np.log(Ksat))
            #     elif Ksat < 100:
            #         aCR = -0.4986 + (9 * (1e-5) * 100)
            #         bCR = -2.132 + (0.4778 * np.log(100))
            #     elif Ksat > 750:
            #         aCR = -0.4986 + (9 * (1e-5) * 750)
            #         bCR = -2.132 + (0.4778 * np.log(750))

            # elif (
            #     (thwp >= 0.16)
            #     and (thwp <= 0.34)
            #     and (thfc >= 0.25)
            #     and (thfc <= 0.45)
            #     and (ths >= 0.40)
            #     and (ths <= 0.53)
            # ):

            #     # Sandy clayey soil class
            #     if (Ksat >= 5) and (Ksat <= 150):
            #         aCR = -0.5677 - (4 * (1e-5) * Ksat)
            #         bCR = -3.7189 + (0.5922 * np.log(Ksat))
            #     elif Ksat < 5:
            #         aCR = -0.5677 - (4 * (1e-5) * 5)
            #         bCR = -3.7189 + (0.5922 * np.log(5))
            #     elif Ksat > 150:
            #         aCR = -0.5677 - (4 * (1e-5) * 150)
            #         bCR = -3.7189 + (0.5922 * np.log(150))

            # elif (
            #     (thwp >= 0.20)
            #     and (thwp <= 0.42)
            #     and (thfc >= 0.40)
            #     and (thfc <= 0.58)
            #     and (ths >= 0.49)
            #     and (ths <= 0.58)
            # ):

            #     # Silty clayey soil class
            #     if (Ksat >= 1) and (Ksat <= 150):
            #         aCR = -0.6366 + (8 * (1e-4) * Ksat)
            #         bCR = -1.9165 + (0.7063 * np.log(Ksat))
            #     elif Ksat < 1:
            #         aCR = -0.6366 + (8 * (1e-4) * 1)
            #         bCR = -1.9165 + (0.7063 * np.log(1))
            #     elif Ksat > 150:
            #         aCR = -0.6366 + (8 * (1e-4) * 150)
            #         bCR = -1.9165 + (0.7063 * np.log(150))

            assert aCR != 0
            assert bCR != 0

            prof.loc[prof.Layer == layer, "aCR"] = prof.Layer.map({layer: aCR})
            prof.loc[prof.Layer == layer, "bCR"] = prof.Layer.map({layer: bCR})

        self.profile = prof

calculate_soil_hydraulic_properties(Sand, Clay, OrgMat, DF=1)

Function to calculate soil hydraulic properties, given textural inputs. Calculations use pedotransfer function equations described in Saxton and Rawls (2006)

Source code in aquacrop/entities/soil.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
def calculate_soil_hydraulic_properties(self, Sand, Clay, OrgMat, DF=1):

    """
    Function to calculate soil hydraulic properties, given textural inputs.
    Calculations use pedotransfer function equations described in Saxton and Rawls (2006)


    """

    # do calculations

    # Water content at permanent wilting point
    Pred_thWP = (
        -(0.024 * Sand)
        + (0.487 * Clay)
        + (0.006 * OrgMat)
        + (0.005 * Sand * OrgMat)
        - (0.013 * Clay * OrgMat)
        + (0.068 * Sand * Clay)
        + 0.031
    )

    th_wp = Pred_thWP + (0.14 * Pred_thWP) - 0.02

    # Water content at field capacity and saturation
    Pred_thFC = (
        -(0.251 * Sand)
        + (0.195 * Clay)
        + (0.011 * OrgMat)
        + (0.006 * Sand * OrgMat)
        - (0.027 * Clay * OrgMat)
        + (0.452 * Sand * Clay)
        + 0.299
    )

    PredAdj_thFC = Pred_thFC + (
        (1.283 * (np.power(Pred_thFC, 2))) - (0.374 * Pred_thFC) - 0.015
    )

    Pred_thS33 = (
        (0.278 * Sand)
        + (0.034 * Clay)
        + (0.022 * OrgMat)
        - (0.018 * Sand * OrgMat)
        - (0.027 * Clay * OrgMat)
        - (0.584 * Sand * Clay)
        + 0.078
    )

    PredAdj_thS33 = Pred_thS33 + ((0.636 * Pred_thS33) - 0.107)
    Pred_thS = (PredAdj_thFC + PredAdj_thS33) + ((-0.097 * Sand) + 0.043)

    pN = (1 - Pred_thS) * 2.65
    pDF = pN * DF
    PorosComp = (1 - (pDF / 2.65)) - (1 - (pN / 2.65))
    PorosCompOM = 1 - (pDF / 2.65)

    DensAdj_thFC = PredAdj_thFC + (0.2 * PorosComp)
    DensAdj_thS = PorosCompOM

    th_fc = DensAdj_thFC
    th_s = DensAdj_thS

    # Saturated hydraulic conductivity (mm/day)
    lmbda = 1 / ((np.log(1500) - np.log(33)) / (np.log(th_fc) - np.log(th_wp)))
    Ksat = (1930 * (th_s - th_fc) ** (3 - lmbda)) * 24

    # Water content at air dry
    th_dry = th_wp / 2

    # round values
    th_dry = round(10_000 * th_dry) / 10_000
    th_wp = round(1000 * th_wp) / 1000
    th_fc = round(1000 * th_fc) / 1000
    th_s = round(1000 * th_s) / 1000
    Ksat = round(10 * Ksat) / 10

    return th_wp, th_fc, th_s, Ksat

aquacrop.entities.soilProfile

SoilProfile

Attributes:

Comp : list :

Layer : list :

dz : list :

dzsum : list :

zBot : list :

z_top : list :

zMid : list :

Source code in aquacrop/entities/soilProfile.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class SoilProfile:
    """

    **Attributes:**\n

    `Comp` : `list` :

    `Layer` : `list` :

    `dz` : `list` :

    `dzsum` : `list` :

    `zBot` : `list` :

    `z_top` : `list` :

    `zMid` : `list` :

    """

    def __init__(self, length):

        self.Comp = np.zeros(length, dtype=np.int64)
        self.dz = np.zeros(length, dtype=np.float64)
        self.Layer = np.zeros(length, dtype=np.int64)
        self.dzsum = np.zeros(length, dtype=np.float64)
        self.th_fc = np.zeros(length, dtype=np.float64)
        self.th_s = np.zeros(length, dtype=np.float64)
        self.th_wp = np.zeros(length, dtype=np.float64)
        self.Ksat = np.zeros(length, dtype=np.float64)
        self.Penetrability = np.zeros(length, dtype=np.float64)
        self.th_dry = np.zeros(length, dtype=np.float64)
        self.tau = np.zeros(length, dtype=np.float64)
        self.zBot = np.zeros(length, dtype=np.float64)
        self.z_top = np.zeros(length, dtype=np.float64)
        self.zMid = np.zeros(length, dtype=np.float64)
        self.th_fc_Adj = np.zeros(length, dtype=np.float64)
        self.aCR = np.zeros(length, dtype=np.float64)
        self.bCR = np.zeros(length, dtype=np.float64)

aquacrop.entities.temperatureStressCoefficients

Kst

Bases: object

TODO: THIS CLASS IS NOT USED

temperature stress coefficients

Attributes:

PolH : float : heat stress

PolC : float : cold stress

Source code in aquacrop/entities/temperatureStressCoefficients.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Kst(object):

    """

    TODO: THIS CLASS IS NOT USED

    temperature stress coefficients

    **Attributes:**\n


    `PolH` : `float` : heat stress

    `PolC` : `float` : cold stress


    """

    def __init__(self):
        self.PolH = 1.0
        self.PolC = 1.0

aquacrop.entities.totalAvailableWater

TAW

TODO: THIS CLASS IS NOT USED - seems to now be in use, CB 14.09.23 Attributes:

Rz : float : .

Zt : float : .

Source code in aquacrop/entities/totalAvailableWater.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class TAW:
    """
    TODO: THIS CLASS IS NOT USED - seems to now be in use, CB 14.09.23
    **Attributes:**\n



    `Rz` : `float` : .

    `Zt` : `float` : .




    """

    def __init__(self):
        self.Rz = 0.0
        self.Zt = 0.0

aquacrop.entities.waterEvaporation

WaterEvaporation

Bases: object

TODO: THIS CLASS IS NOT USED

stores soil water contents in the evaporation layer

Attributes:

Sat : float : Water storage in evaporation layer at saturation (mm)

Fc : float : Water storage in evaporation layer at Field Capacity (mm)

Wp : float: Water storage in evaporation layer at Wilting Point (mm)

Dry : float : Water storage in evaporation layer at air dry (mm)

Act : float : Actual Water storage in evaporation layer (mm)

Source code in aquacrop/entities/waterEvaporation.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class WaterEvaporation(object):
    """
    TODO: THIS CLASS IS NOT USED

    stores soil water contents in the evaporation layer

    **Attributes:**\n


    `Sat` : `float` :  Water storage in evaporation layer at saturation (mm)

    `Fc` : `float` :  Water storage in evaporation layer at Field Capacity (mm)

    `Wp` : `float`:  Water storage in evaporation layer at Wilting Point (mm)

    `Dry` : `float` : Water storage in evaporation layer at air dry (mm)

    `Act` : `float` : Actual Water storage in evaporation layer (mm)

    """

    def __init__(self):
        self.Sat = 0.0
        self.Fc = 0.0
        self.Wp = 0.0
        self.Dry = 0.0
        self.Act = 0.0

aquacrop.entities.waterStressCoefficients

Ksw

Bases: object

water stress coefficients

Attributes:

exp : float : .

sto : float : .

sen : float : .

pol : float : .

sto_lin : float : .

Source code in aquacrop/entities/waterStressCoefficients.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Ksw(object):

    """
    water stress coefficients

    **Attributes:**\n


    `exp` : `float` : .

    `sto` : `float` : .

    `sen` : `float` : .

    `pol` : `float` : .

    `sto_lin` : `float` : .



    """

    def __init__(self):
        self.exp = 1.0
        self.sto = 1.0
        self.sen = 1.0
        self.pol = 1.0
        self.sto_lin = 1.0