Skip to content

Commit 46285e8

Browse files
committed
Changed the CGMS11 AgroManagementDataProvider to allow for early campaign starts.
1 parent 577aa3b commit 46285e8

File tree

1 file changed

+40
-11
lines changed

1 file changed

+40
-11
lines changed

pcse/db/cgms11/data_providers.py

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import logging
1313

1414
from sqlalchemy import MetaData, select, Table, and_
15-
# from tabulate import tabulate
15+
from tabulate import tabulate
1616
import numpy as np
1717
import yaml
1818

@@ -226,11 +226,16 @@ class AgroManagementDataProvider(list):
226226
:param campaign_year: Integer campaign year, maps to the YEAR column in the table.
227227
The campaign year usually refers to the year of the harvest. Thus for crops
228228
crossing calendar years, the start_date can be in the previous year.
229-
230-
Note that by default the campaign_start_date is set equal to the crop_start_date which
231-
means that the simulation starts when the crop starts. In some cases this is undesirable
232-
and an earlier start date should be used. In that case use the `set_campaign_start_date(date)`
233-
to update the campaign_start_date.
229+
:keyword campaign_start: Optional keyword that can be used to define the start of the
230+
campaign. Note that by default the campaign_start_date is set equal to the
231+
crop_start_date which means that the simulation starts when the crop starts.
232+
This default behaviour can be changed using this keyword. It can have multiple meanings:
233+
- if a date object is passed, the campaign is assumed to start on this date.
234+
- if an int/float is passed, the campaign_start_date is calculated as the
235+
crop_start_date minus the number of days provided by campaign_start.
236+
237+
For adjusting the campaign_start_Date, see also the `set_campaign_start_date(date)` method
238+
to update the campaign_start_date on an existing AgroManagementDataProvider.
234239
"""
235240
agro_management_template = """
236241
- {campaign_start_date}:
@@ -240,13 +245,13 @@ class AgroManagementDataProvider(list):
240245
crop_start_type: {crop_start_type}
241246
crop_end_date: {crop_end_date}
242247
crop_end_type: {crop_end_type}
243-
max_duration: {duration}
248+
max_duration: {max_duration}
244249
TimedEvents: null
245250
StateEvents: null
246251
- {campaign_end_date}: null
247252
"""
248253

249-
def __init__(self, engine, grid_no, crop_no, campaign_year):
254+
def __init__(self, engine, grid_no, crop_no, campaign_year, campaign_start=None):
250255
list.__init__(self)
251256
self.grid_no = int(grid_no)
252257
self.crop_no = int(crop_no)
@@ -269,7 +274,6 @@ def __init__(self, engine, grid_no, crop_no, campaign_year):
269274
# Determine the start date/type. Only sowing|emergence is accepted by PCSE/WOFOST
270275
cgms11_start_type = str(row.start_type).strip()
271276
self.crop_start_date = check_date(row.start_date)
272-
self.campaign_start_date = self.crop_start_date
273277
if cgms11_start_type == "FIXED_SOWING":
274278
self.crop_start_type = "sowing"
275279
elif cgms11_start_type == "FIXED_EMERGENCE":
@@ -278,6 +282,25 @@ def __init__(self, engine, grid_no, crop_no, campaign_year):
278282
msg = "Unsupported START_TYPE in CROP_CALENDAR table: %s" % row.start_type
279283
raise exc.PCSEError(msg)
280284

285+
# determine the campaign_start
286+
if campaign_start is None:
287+
self.campaign_start_date = self.crop_start_date
288+
elif isinstance(campaign_start, (int, float)):
289+
ndays = abs(int(campaign_start))
290+
self.campaign_start_date = self.crop_start_date - datetime.timedelta(days=ndays)
291+
else:
292+
try:
293+
campaign_start = check_date(campaign_start)
294+
if campaign_start <= self.crop_start_date:
295+
self.campaign_start_date = self.crop_start_date
296+
else:
297+
msg = "Date (%s) specified by keyword 'campaign_start' in call to AgroManagementDataProvider " \
298+
"is later then crop_start_date defined in the CGMS database."
299+
raise exc.PCSEError(msg % campaign_start)
300+
except KeyError as e:
301+
msg = "Value (%s) of keyword 'campaign_start' not recognized in call to AgroManagementDataProvider."
302+
raise exc.PCSEError(msg % campaign_start)
303+
281304
# Determine crop end date/type and the end of the campaign
282305
self.crop_end_type = str(row.end_type).strip().lower()
283306
if self.crop_end_type not in ["harvest", "earliest", "maturity"]:
@@ -308,7 +331,7 @@ def _build_yaml_agromanagement(self):
308331
crop_start_type=self.crop_start_type,
309332
crop_end_date=self.crop_end_date,
310333
crop_end_type=self.crop_end_type,
311-
duration=self.max_duration,
334+
max_duration=self.max_duration,
312335
campaign_end_date=self.campaign_end_date
313336
)
314337
return input
@@ -584,7 +607,6 @@ class SoilDataIterator(list):
584607
(9050131, 625000000, 9000282, 50)
585608
(9050131, 625000000, 9000283, 50)
586609
587-
Ignore this line
588610
"""
589611

590612
# name of the table with Elementary Mapping Units
@@ -839,6 +861,10 @@ class SiteDataProvider(dict):
839861
Note that the parameter SSI (Initial surface storage) is
840862
set to zero
841863
864+
Moreover, the start date of the water balance is defined by the
865+
column GIVEN_STARTDATE_WATBAL. This value can be accessed as
866+
an attribute `start_date_waterbalance`.
867+
842868
"""
843869

844870
def __init__(self, engine, grid_no, crop_no, campaign_year, stu_no):
@@ -874,6 +900,9 @@ def __init__(self, engine, grid_no, crop_no, campaign_year, stu_no):
874900
% (self.grid_no, self.crop_no, self.campaign_year, self.stu_no))
875901
raise exc.PCSEError(msg)
876902

903+
# Start date water balance
904+
self.start_date_waterbalance = check_date(row.given_startdate_watbal)
905+
877906
# Derived global parameters from table SITE
878907
table_site = Table('site', metadata, autoload=True)
879908
r = select([table_site]).execute()

0 commit comments

Comments
 (0)