ALMaSS Hare ODDox  1.1
The hare model description following ODdox protocol
NLMaize.cpp
Go to the documentation of this file.
1 /*
2 *******************************************************************************************************
3 Copyright (c) 2017, Christopher John Topping, Aarhus University
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without modification, are permitted provided
7 that the following conditions are met:
8 
9 Redistributions of source code must retain the above copyright notice, this list of conditions and the
10 following disclaimer.
11 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12 the following disclaimer in the documentation and/or other materials provided with the distribution.
13 
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
15 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
17 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
19 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 ********************************************************************************************************
23 */
38 //
39 // NLMaize.cpp
40 //
41 
42 
43 #include "../../Landscape/ls.h"
44 #include "../../Landscape/cropprogs/NLMaize.h"
45 
46 // Some things that are defined externally - in this case these variables allow
47 // scaling of the percentage application figures for insecticides, herbicides etc..
48 extern CfgBool cfg_pest_springwheat_on;
49 // check if below are needed
50 extern CfgFloat l_pest_insecticide_amount;
51 extern CfgInt cfg_M_InsecticideDay;
52 extern CfgInt cfg_M_InsecticideMonth;
53 extern CfgFloat cfg_pest_product_1_amount;
54 
55 
64 bool NLMaize::Do(Farm *a_farm, LE *a_field, FarmEvent *a_ev)
65 {
66  bool done = false; // The boolean value done indicates when we are totally finished with this plan (i.e. it is set to true).
67  int d1 = 0;
68  // Depending what event has occured jump to the correct bit of code
69  switch (a_ev->m_todo)
70  {
71  case nl_m_start:
72  {
73  // nl_m_start just sets up all the starting conditions and reference dates that are needed to start a nl_maize
74  NL_M_START_FERTI = false;
75  // Set up the date management stuff
76  // The next bit of code just allows for altering dates after harvest if it is necessary
77  // to allow for a crop which starts its management early.
78 
79  // 5 start and stop dates for all 'movable' events for this crop
80  int noDates = 1;
81  a_field->SetMDates(0, 0, g_date->DayInYear(5, 10)); // last possible day of harvest
82  a_field->SetMDates(1, 0, g_date->DayInYear(10, 10)); // last possible day of straw chopping
83  // then these will be reduced in value to 0
84 
85  a_field->SetMConstants(0, 1);
86 
87  // Check the next crop for early start, unless it is a spring crop
88  // in which case we ASSUME that no checking is necessary!!!!
89  // So DO NOT implement a crop that runs over the year boundary (i.e. from spring to spring!), at least not without fixing this.
90 
91  //new if: do the check only for non-optimising farms and if year>0. (030713 - m_rotation used only in the hidden year, so I modified the condition from >7 to >0)
92  //optimising farms not used for now so most of related code is removed (but not in 'start' case)
93  if (!(a_farm->GetType() == tof_OptimisingFarm && g_date->GetYearNumber() > 0)) {
94 
95  if (a_ev->m_startday > g_date->DayInYear(1, 7)) {
96  if (a_field->GetMDates(0, 0) >= a_ev->m_startday)
97  {
98  g_msg->Warn(WARN_BUG, "NLMaize::Do(): ", "Harvest too late for the next crop to start!!!");
99  int almassnum = g_landscape_p->BackTranslateVegTypes(a_ev->m_next_tov);
100  g_msg->Warn("Next Crop ", (double)almassnum); // this causes exit
101  }
102  // Now fix any late finishing problems
103  for (int i = 0; i < noDates; i++) {
104  if (a_field->GetMDates(0, i) >= a_ev->m_startday) {
105  a_field->SetMDates(0, i, a_ev->m_startday - 1); //move the starting date
106  }
107  if (a_field->GetMDates(1, i) >= a_ev->m_startday) {
108  a_field->SetMConstants(i, 0); //change the default value of the MConst (=1) to 0 (necessary to correctly execute farm events in case the finishing date (MDate) was moved)
109  a_field->SetMDates(1, i, a_ev->m_startday - 1); //move the finishing date
110  }
111  }
112  }
113  // Now no operations can be timed after the start of the next crop.
114 
115  if (!a_ev->m_first_year) {
116  // Are we before July 1st?
117  d1 = g_date->OldDays() + g_date->DayInYear(1, 7);
118  if (g_date->Date() < d1) {
119  // Yes, too early. We assumme this is because the last crop was late
120  printf("Poly: %d\n", a_field->GetPoly());
121  g_msg->Warn(WARN_BUG, "NLMaize::Do(): ", "Crop start attempt between 1st Jan & 1st July");
122  int prev = g_landscape_p->BackTranslateVegTypes(a_field->GetOwner()->GetPreviousCrop(a_field->GetRotIndex()));
123  g_msg->Warn(WARN_BUG, "Previous Crop ", prev);
124  int almassnum = g_landscape_p->BackTranslateVegTypes(a_ev->m_next_tov);
125  g_msg->Warn("Next Crop ", (double)almassnum); // this causes exit
126  exit(1);
127  }
128  else {
129  d1 = g_date->OldDays() + m_first_date; // Add 365 for spring crop
130  if (g_date->Date() > d1) {
131  // Yes too late - should not happen - raise an error
132  g_msg->Warn(WARN_BUG, "NLMaize::Do(): ", "Crop start attempt after last possible start date");
133  int prev = g_landscape_p->BackTranslateVegTypes(a_field->GetOwner()->GetPreviousCrop(a_field->GetRotIndex()));
134  g_msg->Warn(WARN_BUG, "Previous Crop ", prev);
135  int almassnum = g_landscape_p->BackTranslateVegTypes(a_ev->m_next_tov);
136  g_msg->Warn("Next Crop ", (double)almassnum); // this causes exit
137  exit(1);
138  }
139  }
140  }
141  else {
142  // Is the first year
143  // Some special code to cope with that first start-up year in ALMaSS - ignore for all practical purposes
144  // Code for first spring treatment used
145  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(15, 4), nl_m_spring_sow, false, a_farm, a_field);
146  break;
147  }
148  }//if
149 
150  // End single block date checking code. Please see next line comment as well.
151  // Reinit d1 to first possible starting date.
152  d1 = g_date->OldDays() + g_date->DayInYear(1, 9);
153  // OK, let's go.
154  // Here we queue up the first event - this differs depending on whether we have field on snady or clay soils
155  if (a_field->GetSoilType() == 2 || a_field->GetSoilType() == 6) { // on sandy soils (NL ZAND & LOSS)
156  SimpleEvent_(d1, nl_m_stubble_harrow1, false, a_farm, a_field);
157  }
158  else SimpleEvent_(d1, nl_m_stubble_harrow2, false, a_farm, a_field);
159  }
160  break;
161 
162  // This is the first real farm operation
164  if (a_ev->m_lock || a_farm->DoIt_prob(1.00))
165  {
166  if (!a_farm->StubbleHarrowing(a_field, 0.0, g_date->DayInYear(31, 10) - g_date->DayInYear())) {
167  SimpleEvent_(g_date->Date() + 1, nl_m_stubble_harrow1, true, a_farm, a_field);
168  break;
169  }
170  }
171  d1 = g_date->Date() + 10;
172  if (d1 < g_date->OldDays() + g_date->DayInYear(15, 10)) {
173  d1 = g_date->OldDays() + g_date->DayInYear(15, 10);
174  }
175  SimpleEvent_(d1, nl_m_winter_plough1, false, a_farm, a_field);
176  break;
177  case nl_m_winter_plough1:
178  if (a_ev->m_lock || a_farm->DoIt_prob(0))
179  {
180  if (!a_farm->WinterPlough(a_field, 0.0, g_date->DayInYear(1, 12) - g_date->DayInYear())) {
181  SimpleEvent_(g_date->Date() + 1, nl_m_winter_plough1, true, a_farm, a_field);
182  break;
183  }
184  }
185  if (a_farm->IsStockFarmer()) //Stock Farmer
186  {
187  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 4) + 365, nl_m_ferti_s1, false, a_farm, a_field);
188  }
189  else SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 4) + 365, nl_m_ferti_p1, false, a_farm, a_field);
190  break;
192  if (a_ev->m_lock || a_farm->DoIt_prob(0.20))
193  {
194  if (!a_farm->StubbleHarrowing(a_field, 0.0, g_date->DayInYear(31, 10) - g_date->DayInYear())) {
195  SimpleEvent_(g_date->Date() + 1, nl_m_stubble_harrow2, true, a_farm, a_field);
196  break;
197  }
198  }
199  d1 = g_date->Date() + 10;
200  if (d1 < g_date->OldDays() + g_date->DayInYear(15, 11)) {
201  d1 = g_date->OldDays() + g_date->DayInYear(15, 11);
202  }
203  SimpleEvent_(d1, nl_m_winter_plough2, false, a_farm, a_field);
204  break;
205  case nl_m_winter_plough2:
206  if (a_ev->m_lock || a_farm->DoIt_prob(1.00))
207  {
208  if (!a_farm->WinterPlough(a_field, 0.0, g_date->DayInYear(1, 12) - g_date->DayInYear())) {
209  SimpleEvent_(g_date->Date() + 1, nl_m_winter_plough2, true, a_farm, a_field);
210  break;
211  }
212  }
213  if (a_farm->IsStockFarmer()) //Stock Farmer
214  {
215  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 4) + 365, nl_m_ferti_s1, false, a_farm, a_field);
216  }
217  else SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 4) + 365, nl_m_ferti_p1, false, a_farm, a_field);
218  break;
219  case nl_m_ferti_p1:
220  if (!a_farm->FP_Slurry(a_field, 0.0, g_date->DayInYear(25, 4) - g_date->DayInYear())) {
221  SimpleEvent_(g_date->Date() + 1, nl_m_ferti_p1, true, a_farm, a_field);
222  break;
223  }
224  if (a_field->GetSoilType() == 2 || a_field->GetSoilType() == 6) { // on sandy soils (NL ZAND & LOSS)
225  SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough1, false, a_farm, a_field);
226  }
227  else SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough2, false, a_farm, a_field);
228  break;
229  case nl_m_ferti_s1:
230  if (!a_farm->FA_Slurry(a_field, 0.0, g_date->DayInYear(25, 4) - g_date->DayInYear())) {
231  SimpleEvent_(g_date->Date() + 1, nl_m_ferti_s1, true, a_farm, a_field);
232  break;
233  }
234  if (a_field->GetSoilType() == 2 || a_field->GetSoilType() == 6) { // on sandy soils (NL ZAND & LOSS)
235  SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough1, false, a_farm, a_field);
236  }
237  else SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough2, false, a_farm, a_field);
238  break;
239  case nl_m_spring_plough1:
240  if (a_ev->m_lock || a_farm->DoIt_prob(0.20))
241  {
242  if (!a_farm->SpringPlough(a_field, 0.0, g_date->DayInYear(30, 4) - g_date->DayInYear())) {
243  SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough1, true, a_farm, a_field);
244  break;
245  }
246  }
247  SimpleEvent_(g_date->Date() + 10, nl_m_preseeding_cultivator, false, a_farm, a_field);
248  break;
249  case nl_m_spring_plough2:
250  if (a_ev->m_lock || a_farm->DoIt_prob(0))
251  {
252  if (!a_farm->SpringPlough(a_field, 0.0, g_date->DayInYear(30, 4) - g_date->DayInYear())) {
253  SimpleEvent_(g_date->Date() + 1, nl_m_spring_plough2, true, a_farm, a_field);
254  break;
255  }
256  }
257  SimpleEvent_(g_date->Date() + 10, nl_m_preseeding_cultivator, false, a_farm, a_field);
258  break;
260  if (!a_farm->PreseedingCultivator(a_field, 0.0, g_date->DayInYear(4, 5) - g_date->DayInYear())) {
261  SimpleEvent_(g_date->Date() + 1, nl_m_preseeding_cultivator, true, a_farm, a_field);
262  break;
263  }
264  SimpleEvent_(g_date->Date() + 1, nl_m_spring_sow_with_ferti, false, a_farm, a_field);
265  break;
267  // 75% will do sow with firtilizer
268  if (a_ev->m_lock || a_farm->DoIt_prob(0.75))
269  {
270  if (!a_farm->SpringSowWithFerti(a_field, 0.0, g_date->DayInYear(5, 5) - g_date->DayInYear())) {
271  SimpleEvent_(g_date->Date() + 1, nl_m_spring_sow_with_ferti, true, a_farm, a_field);
272  break;
273  }
274  else
275  {
276  // 75% of farmers will do this, but the other 25% won't so we need to remember whether we are in one or the other group
277  NL_M_START_FERTI = true;
278  // Here is a fork leading to parallel events
279  SimpleEvent_(g_date->Date() + 3, nl_m_harrow, false, a_farm, a_field);
280  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 5), nl_m_herbicide1, false, a_farm, a_field); // Herbidide thread
281  if (a_farm->IsStockFarmer()) //Stock Farmer // N thread = MAIN
282  {
283  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(20, 5), nl_m_ferti_s2, false, a_farm, a_field);
284  }
285  else SimpleEvent_(g_date->OldDays() + g_date->DayInYear(20, 5), nl_m_ferti_p2, false, a_farm, a_field);
286  break;
287  }
288  }
289  SimpleEvent_(g_date->Date() + 1, nl_m_spring_sow, false, a_farm, a_field);
290  break;
291  case nl_m_spring_sow:
292  if (!a_farm->SpringSow(a_field, 0.0, g_date->DayInYear(5, 5) - g_date->DayInYear())) {
293  SimpleEvent_(g_date->Date() + 1, nl_m_spring_sow, true, a_farm, a_field);
294  break;
295  }
296  // Here is a fork leading to parallel events
297  SimpleEvent_(g_date->Date() + 3, nl_m_harrow, false, a_farm, a_field);
298  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(1, 5), nl_m_herbicide1, false, a_farm, a_field); // Herbidide thread
299  if (a_farm->IsStockFarmer()) //Stock Farmer // N thread = MAIN
300  {
301  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(20, 5), nl_m_ferti_s2, false, a_farm, a_field);
302  }
303  else SimpleEvent_(g_date->OldDays() + g_date->DayInYear(20, 5), nl_m_ferti_p2, false, a_farm, a_field);
304  break;
305  case nl_m_ferti_p2:
306  // Here comes N thread
307  if (a_ev->m_lock || a_farm->DoIt_prob(0.60) && (NL_M_START_FERTI==0))
308  {
309  if (!a_farm->FP_AmmoniumSulphate(a_field, 0.0, g_date->DayInYear(10, 6) - g_date->DayInYear())) {
310  SimpleEvent_(g_date->Date() + 1, nl_m_ferti_p2, true, a_farm, a_field);
311  break;
312  }
313  }
314  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(10, 9), nl_m_harvest, false, a_farm, a_field);
315  break;
316  case nl_m_ferti_s2:
317  if (a_ev->m_lock || a_farm->DoIt_prob(0.60) && (NL_M_START_FERTI == 0))
318  {
319  if (!a_farm->FA_AmmoniumSulphate(a_field, 0.0, g_date->DayInYear(10, 6) - g_date->DayInYear())) {
320  SimpleEvent_(g_date->Date() + 1, nl_m_ferti_s2, true, a_farm, a_field);
321  break;
322  }
323  }
324  SimpleEvent_(g_date->OldDays() + g_date->DayInYear(10, 9), nl_m_harvest, false, a_farm, a_field);
325  break;
326  case nl_m_herbicide1:
327  // Here comes the herbicide thread
328  if (a_field->GetGreenBiomass() <= 0)
329  {
330  SimpleEvent_(g_date->Date() + 1, nl_m_herbicide1, false, a_farm, a_field);
331  }
332  else
333  {
334  if (a_ev->m_lock || a_farm->DoIt_prob(0.90))
335  {
336  if (!a_farm->HerbicideTreat(a_field, 0.0, g_date->DayInYear(25, 5) - g_date->DayInYear())) {
337  SimpleEvent_(g_date->Date() + 1, nl_m_herbicide1, true, a_farm, a_field);
338  break;
339  }
340  }
341  }
342  // End of thread
343  break;
344  case nl_m_harrow:
345  // Here comes the MAIN thread
346  if (a_ev->m_lock || a_farm->DoIt_prob(0.15))
347  {
348  if (a_field->GetGreenBiomass() <= 0)
349  {
350  if (!a_farm->ShallowHarrow(a_field, 0.0, g_date->DayInYear(15, 5) - g_date->DayInYear())) {
351  SimpleEvent_(g_date->Date() + 1, nl_m_harrow, true, a_farm, a_field);
352  break;
353  }
354  }
355  else { SimpleEvent_(g_date->Date() + 1, nl_m_harrow, true, a_farm, a_field); }
356  }
357  // End of thread
358  break;
359  case nl_m_harvest:
360  // Here the MAIN thread continues
361  // We don't move harvest days
362  if (!a_farm->Harvest(a_field, 0.0, a_field->GetMDates(0, 0) - g_date->DayInYear())) {
363  SimpleEvent_(g_date->Date() + 1, nl_m_harvest, true, a_farm, a_field);
364  break;
365  }
366  SimpleEvent_(g_date->Date() + 1, nl_m_straw_chopping, false, a_farm, a_field);
367  break;
368  case nl_m_straw_chopping:
369  if (a_field->GetMConstants(0) == 0) {
370  if (!a_farm->StrawChopping(a_field, 0.0, -1)) { // raise an error
371  g_msg->Warn(WARN_BUG, "NLMaize::Do(): failure in 'StrawChopping' execution", "");
372  exit(1);
373  }
374  }
375  else {
376  if (!a_farm->StrawChopping(a_field, 0.0, a_field->GetMDates(1, 0) - g_date->DayInYear())) {
377  SimpleEvent_(g_date->Date() + 1, nl_m_straw_chopping, true, a_farm, a_field);
378  break;
379  }
380  }
381  done = true;
382  // So we are done, and somwhere else the farmer will queue up the start event of the next crop
383  // END of MAIN THREAD
384  break;
385  default:
386  g_msg->Warn(WARN_BUG, "NLMaize::Do(): "
387  "Unknown event type! ", "");
388  exit(1);
389  }
390  return done;
391 }
nl_m_ferti_p1
Definition: NLMaize.h:42
nl_m_spring_sow_with_ferti
Definition: NLMaize.h:47
Farm::IsStockFarmer
bool IsStockFarmer(void)
Definition: farm.h:905
nl_m_stubble_harrow2
Definition: NLMaize.h:39
FarmEvent::m_lock
bool m_lock
Definition: farm.h:465
FarmEvent
A struct to hold the information required to trigger a farm event.
Definition: farm.h:463
nl_m_spring_sow
Definition: NLMaize.h:48
FarmEvent::m_first_year
bool m_first_year
Definition: farm.h:467
tof_OptimisingFarm
Definition: farm.h:273
Farm::DoIt_prob
bool DoIt_prob(double a_probability)
Return chance out of 0 to 1.
Definition: farm.cpp:808
nl_m_winter_plough2
Definition: NLMaize.h:41
nl_m_harrow
Definition: NLMaize.h:49
Landscape::BackTranslateVegTypes
int BackTranslateVegTypes(TTypesOfVegetation VegReference)
Definition: Landscape.h:1669
Farm::GetType
TTypesOfFarm GetType(void)
Definition: farm.h:901
cfg_M_InsecticideMonth
CfgInt cfg_M_InsecticideMonth
nl_m_spring_plough2
Definition: NLMaize.h:45
Crop::m_first_date
int m_first_date
Definition: farm.h:540
FarmEvent::m_startday
int m_startday
Definition: farm.h:466
l_pest_insecticide_amount
CfgFloat l_pest_insecticide_amount
NL_M_START_FERTI
#define NL_M_START_FERTI
A flag used to indicate autumn ploughing status.
Definition: NLMaize.h:28
nl_m_spring_plough1
Definition: NLMaize.h:44
nl_m_ferti_p2
Definition: NLMaize.h:50
cfg_pest_product_1_amount
CfgFloat cfg_pest_product_1_amount
nl_m_winter_plough1
Definition: NLMaize.h:40
nl_m_start
Definition: NLMaize.h:36
FarmEvent::m_next_tov
TTypesOfVegetation m_next_tov
Definition: farm.h:471
FarmEvent::m_todo
int m_todo
Definition: farm.h:469
cfg_pest_springwheat_on
CfgBool cfg_pest_springwheat_on
nl_m_harvest
Definition: NLMaize.h:53
NLMaize::Do
virtual bool Do(Farm *a_farm, LE *a_field, FarmEvent *a_ev)
The one and only method for a crop management plan. All farm actions go through here.
Definition: NLMaize.cpp:64
Farm
The base class for all farm types.
Definition: farm.h:767
Farm::WinterPlough
virtual bool WinterPlough(LE *a_field, double a_user, int a_days)
Carry out a ploughing event in the winter on a_field.
Definition: farmfuncs.cpp:392
nl_m_ferti_s1
Definition: NLMaize.h:43
nl_m_straw_chopping
Definition: NLMaize.h:54
nl_m_herbicide1
Definition: NLMaize.h:52
nl_m_stubble_harrow1
Definition: NLMaize.h:38
nl_m_preseeding_cultivator
Definition: NLMaize.h:46
nl_m_ferti_s2
Definition: NLMaize.h:51
cfg_M_InsecticideDay
CfgInt cfg_M_InsecticideDay
g_landscape_p
Landscape * g_landscape_p
Definition: Landscape.cpp:258
Farm::StubbleHarrowing
virtual bool StubbleHarrowing(LE *a_field, double a_user, int a_days)
Carry out stubble harrowing on a_field.
Definition: farmfuncs.cpp:2209
Crop::SimpleEvent_
void SimpleEvent_(long a_date, int a_todo, bool a_lock, Farm *a_farm, LE *a_field)
Adds an event to this crop management without relying on member variables.
Definition: farm.cpp:312