Open sarahcleary opened 3 years ago
I appreicate all your efforts, specially Peter's. I have a general question. What is the difference between using a Rotation Manager and play with dates in a manager script (usually a Manager2) to plant/harvest crops in a spceific order? What benefits are there in using a Rotation Manager compared with the other approach?
Hey Brian - "Less is More". If you can build a simulation with fewer components, then that's a good thing. The benefit from describing a rotation comes when somebody wants to extend your cropping system into a (eg flexible, opportunistic) more complicated one.
Hello Peter Greeting Nice lecture...and good initiative from Team APSIM. Can you suggest to me how to simulate No-tillage with residue retention in APSIM...
Hi Nishant, glad to hear of your interest.
By default apsim does nothing unless you tell it to, so if you don't specify a tillage management, it won't happen - thus no-till is the default behaviour, and your job is done.. :)
Seriously, there are many aspects to consider here. One of the reasons we use the "Reset XYZ on sowing" component is to avoid dealing with SOM pools, which can accumulate to obscene levels if left unattended - I once encountered an embarassing simulation with 60t of accumulated surface residues after only a few years. If you are simulating a continuous SOM pool, you must manage it by tilling (eg at sowing) to incorporate the residues - there are manager components in the toolbox that do this.
If your concern is the economics of weed management, you need to describe when the model should spray - here's a simple hydro-thermal time model attached that I've used in the past that simply models weed germination, and counts the number of consequent weeding events.
If the system you're working with doesnt immediately kill weeds, you can sow a weed module that consumes resources - the sample "Continuous maize and weeds" demonstrates the detail needed to implement the weed and crop components as intercrops.
In the same space, there is also a facility to model surface residues as two pools - one standing, the other lying on the surface - the standing pool doesnt contribute to the surface cover and thus doesnt affect runoff / infiltration calculation. There's a sample in the test dataset.
HTH
Thank you Peter
With Regards
Dr Nishant K. Sinha
Scientist (Agricultural Physics)
ICAR-Indian Institute of Soil Science
*Email: @. @.>*
On Fri, May 21, 2021 at 5:47 AM Peter de Voil @.***> wrote:
Hi Nishant, glad to hear of your interest.
By default apsim does nothing unless you tell it to, so if you don't specify a tillage management, it won't happen - thus no-till is the default behaviour, and your job is done.. :)
Seriously, there are many aspects to consider here. One of the reasons we use the "Reset XYZ on sowing" component is to avoid dealing with SOM pools, which can accumulate to obscene levels if left unattended - I once encountered an embarassing simulation with 60t of accumulated surface residues after only a few years. If you are simulating a continuous SOM pool, you must manage it by tilling (eg at sowing) to incorporate the residues - there are manager components in the toolbox that do this.
If your concern is the economics of weed management, you need to describe when the model should spray - here's https://github.com/APSIMInitiative/APSIMClassic/files/6519273/weeds.zip a simple hydro-thermal time model attached that I've used in the past that simply models weed germination, and counts the number of consequent weeding events.
If the system you're working with doesnt immediately kill weeds, you can sow a weed module that consumes resources - the sample "Continuous maize and weeds" demonstrates the detail needed to implement the weed and crop components as intercrops.
In the same space, there is also a facility to model surface residues as two pools - one standing, the other lying on the surface - the standing pool doesnt contribute to the surface cover and thus doesnt affect runoff / infiltration calculation. There's a sample in the test dataset https://github.com/APSIMInitiative/APSIMClassic/blob/master/Tests/SurfaceOM/SOM_Test.apsim .
HTH
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/APSIMInitiative/APSIMClassic/issues/2039#issuecomment-845564817, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABQUTR5WA27FMOJEAECCSZ3TOWRCDANCNFSM43JKZVZQ .
I appreicate all your efforts, specially Peter's. I have a general question. What is the difference between using a Rotation Manager and play with dates in a manager script (usually a Manager2) to plant/harvest crops in a spceific order? What benefits are there in using a Rotation Manager compared with the other approach?
Hi @BrianCollinss could you please share an example of rotations using a Manager2 instead of the RotationManager? Thanks
@peter-devoil can we add fixed date N fertilisation for specific years as a part of the Rotation Management?
Of course.
You can use fixed dates, hook into crop sowing events, or even an operations schedule.
@peter-devoil I have an issue when I want to create the rotation maize-wheat as double crop, i.e. both crops in the same year, wheat as cover crop and maize in summer. I am running a simulation for 6 years (1998-2003) which should have 3 wheat harvests and 3 maize harvests, instead I am getting 2 harvest for each crop (maize in 1998 and 2001 and wheat in 2000 and 2003). The issue is that the rotation manager is considering the fallow too. I need to sow the wheat right after the maize with no fallow (or reduced fallow). Here is the rotation manager:
You need to check your exit logic out of your fallows. It isn't exiting from there until the following year.
I cannot figure out the issue yet. here is the sim (second sim MWMWMW) in the tree: v3.zip
This is working now, however I also found an issue related with the parameter Enter the end date of the pause
, what is the exact meaning of this, it is the last day that the fallow can be?
For a 3-year rotation, could I setup a harvest rule based on maturity for the first two years and fixed date for the last year?
@peter-devoil. For a 3-year rotation, could I setup a harvest rule based on maturity for the first two years and fixed date for the last year?
Of course. For the 1st two, use the "CanLeave" rule in the crop manager. For the last, a bit of logic that returns 1 on the date you want to harvest, 0 otherwise.
@peter-devoil. I created the following updated code and a new property (harvest date = date4 in the code) for maize management but it provides an error in L61. Could you please have a look?
using System;
using ModelFramework;
using CSGeneral;
// Basic crop management: sowing & harvesting.
// Multi-paddock aware.
// This component DOES NOT require a trigger from the sequencer.
// It will assume it is the only crop in the system if it doesnt find a sequencer.
// If it does find a sequencer, it will do nothing until told to (via Enter/Leave).
public class Script
{
[Link()] public Simulation MySimulation;
[Param()] private string crop; // The module name of this crop
[Param()] private string date1; //Start of sowing window
[Param()] private string date2; //End of sowing window
[Param()] private string date3; //date to change to different cultivar
[Param()] private string date4; //date to harvest the 3rd summer crop
[Param()] int esw_amount;
[Param()] private string must_sow;
[Input()] private DateTime today;
// Rainfall accumulator
[Param()] int rain_days; //check for rain over this period
[Param()] int rain_amount; //this much rain over that period
// Daily rainfall from the system
[Input] private double rain;
private ManagerUtility.Tracker<double> rainTracker;
private bool inWindow = false;
private bool endOfWindow = false;
private bool ChangeCultivar = false;
//initialise tracker, telling it how many days to track
[EventHandler] public void OnInitialised()
{
rainTracker = new ManagerUtility.Tracker<double>(rain_days);
}
// Daily tests common to all paddocks
[EventHandler] public void OnPrepare()
{
bool startOfWindow = DateUtility.DatesEqual(date1, today);
inWindow = DateUtility.WithinDates(date1, today, date2);
ChangeCultivar = false;
if(date3 != "na")
ChangeCultivar = DateUtility.WithinDates(date3, today, date2);
endOfWindow = DateUtility.DatesEqual(date2, today);
rainTracker.Add(rain);
string currentPaddock = "";
if (MySimulation.Get("currentPaddock", out currentPaddock) == false)
{
// If there is no sequencer plugged in then we are it..
if (canEnter > 0) {
OnEnter();
}
if (canLeave > 0) or (today == date4) {
OnLeave();
}
}
}
// Test whether we can sow a crop today
// +ve number - yes
// 0 - no
// -ve number - no, out of scope (planting window)
[Output, Description("Test whether we can sow a crop today")] public int canEnter {
get {
bool isPossibleToday = false;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
//Console.WriteLine("1. '" + currentPaddock + "'");
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = (Component) MySimulation.ChildPaddocks[0];
//Console.WriteLine("2. " + paddockModule.Name);
Component cropModule = (Component) paddockModule.LinkByName( crop );
//Console.WriteLine("3. " + cropModule.Name);
string plantStatus = "";
cropModule.Get("plant_status", out plantStatus);
double esw = 0.0;
Component soilModule = (Component) paddockModule.LinkByType("SoilWat");
soilModule.Get("esw", out esw);
if (plantStatus == "out" &&
inWindow &&
rainTracker.Sum() >= rain_amount &&
esw > esw_amount)
{
isPossibleToday = true;
}
if (isPossibleToday)
return 1;
if (plantStatus == "out" && endOfWindow && must_sow == "yes")
return 1;
if (plantStatus == "out" && !inWindow)
return -1;
return 0;
}
}
[Output, Description("Test whether we have passed the end of the window")] public int pastWindow {
get {
return( (DateUtility.CompareDates(date2, today) < 0) ? 1 : 0);
}
}
// Sow a crop
[Param()] private string cultivar1;
[Param()] private string cultivar2;
[Param()] private double density1;
[Param()] private double depth1;
[Param()] private double row_spacing1;
[Param()] private string ftn1;
[Param()] private string skiprow1;
[Param()] private string tillageImplement;
[EventHandler, Description("Sow the crop")] public void OnEnter()
{
Console.WriteLine(today + " Sowing Crop");
SowType data = new SowType();
data.Cultivar = cultivar1;
if(ChangeCultivar)
data.Cultivar = cultivar2;
data.plants = density1;
data.sowing_depth = depth1;
data.row_spacing = row_spacing1;
data.tiller_no_fertile = (ftn1 == "na") ? "" : ftn1;
data.SkipRow = 0 ;
if (skiprow1 == "single")
data.SkipRow = 1;
else if (skiprow1 == "double")
data.SkipRow = 2;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("Sow", data);
if (tillageImplement.ToLower() != "na")
{
TillageType t = new TillageType();
t.type = tillageImplement;
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = MySimulation.ChildPaddocks[0];
paddockModule.Publish("tillage", t);
}
}
// Test whether we can harvest a crop today
// +ve number - yes
// 0 - no
// -ve - out of scope
[Output] public int canLeave
{
get
{
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
string plantStatus = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".plant_status", out plantStatus);
if (plantStatus == "out")
return -1;
string StageName = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".StageName", out StageName);
if (StageName == "harvest_ripe" || plantStatus == "dead")
return 1;
return 0;
}
}
[EventHandler] public void OnLeave()
{
Console.WriteLine(today + " Harvesting Crop");
HarvestType hdata = new HarvestType();
hdata.Remove = 0.0;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("harvest", hdata);
KillCropType kdata = new KillCropType();
kdata.KillFraction = 0.0F;
cropModule.Publish("killcrop", kdata);
cropModule.Publish("end_crop");
}
}
here the error:
Of course. For the 1st two, use the "CanLeave" rule in the crop manager. For the last, a bit of logic that returns 1 on the date you want to harvest, 0 otherwise.
@peter-devoil. Were are the harvest rules specified in the crop manager? I could not see this code in my example provided below?...
It's not python :) Try:
if (canLeave > 0 || today == date4) {
The harvest rules come in 2 parts: a test (canLeave) and an action (Leave). The rotation manager gets the test, and if satisfied, calls the action. The code you want for fixed sowing date is very similar to the pastWindow function you have there. The test would be "pastWindow" (or whatever you call it), the action would be "Leave".
Using this
if (canLeave > 0 || today == date4) {
I got this error. I think we need to change the way to call date4. date4 is ddmmyyyy format
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
APSIM Fatal Error
-------------------
Operator '==' cannot be applied to operands of type 'System.DateTime' and 'string'. Line number: 61
Component name: Maize Management
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Try if (canLeave > 0 || DateUtility.CompareDates(date4, today))
if (canLeave > 0 || DateUtility.CompareDates(date4, today))
------- Maize Management Initialisation ---------------------------------------
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
APSIM Fatal Error
-------------------
Operator '||' cannot be applied to operands of type 'bool' and 'int'. Line number: 61
Component name: Maize Management
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Argh. Try 2: if (canLeave > 0 || (DateUtility.CompareDates(date4, today) == 0)
it works now but still the crop is not harvested at the indicated date (15/09/2002). Maybe we need to add an extra code in the "// Test whether we can harvest a crop today" section?
this code works!
using System;
using ModelFramework;
using CSGeneral;
// Basic crop management: sowing & harvesting.
// Multi-paddock aware.
// This component DOES NOT require a trigger from the sequencer.
// It will assume it is the only crop in the system if it doesnt find a sequencer.
// If it does find a sequencer, it will do nothing until told to (via Enter/Leave).
public class Script
{
[Link()] public Simulation MySimulation;
[Param()] private string crop; // The module name of this crop
[Param()] private string date1; //Start of sowing window
[Param()] private string date2; //End of sowing window
[Param()] private string date3; //date to change to different cultivar
[Param] private DateTime date4; //date to harvest the 3rd summer crop
[Param()] int esw_amount;
[Param()] private string must_sow;
[Input()] private DateTime today;
// Rainfall accumulator
[Param()] int rain_days; //check for rain over this period
[Param()] int rain_amount; //this much rain over that period
// Daily rainfall from the system
[Input] private double rain;
private ManagerUtility.Tracker<double> rainTracker;
private bool inWindow = false;
private bool endOfWindow = false;
private bool ChangeCultivar = false;
//initialise tracker, telling it how many days to track
[EventHandler] public void OnInitialised()
{
rainTracker = new ManagerUtility.Tracker<double>(rain_days);
}
// Daily tests common to all paddocks
[EventHandler] public void OnPrepare()
{
bool startOfWindow = DateUtility.DatesEqual(date1, today);
inWindow = DateUtility.WithinDates(date1, today, date2);
ChangeCultivar = false;
if(date3 != "na")
ChangeCultivar = DateUtility.WithinDates(date3, today, date2);
endOfWindow = DateUtility.DatesEqual(date2, today);
rainTracker.Add(rain);
string currentPaddock = "";
if (MySimulation.Get("currentPaddock", out currentPaddock) == false)
{
// If there is no sequencer plugged in then we are it..
if (canEnter > 0) {
OnEnter();
}
if (canLeave > 0) {
OnLeave();
}
}
}
// Test whether we can sow a crop today
// +ve number - yes
// 0 - no
// -ve number - no, out of scope (planting window)
[Output, Description("Test whether we can sow a crop today")] public int canEnter {
get {
bool isPossibleToday = false;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
//Console.WriteLine("1. '" + currentPaddock + "'");
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = (Component) MySimulation.ChildPaddocks[0];
//Console.WriteLine("2. " + paddockModule.Name);
Component cropModule = (Component) paddockModule.LinkByName( crop );
//Console.WriteLine("3. " + cropModule.Name);
string plantStatus = "";
cropModule.Get("plant_status", out plantStatus);
double esw = 0.0;
Component soilModule = (Component) paddockModule.LinkByType("SoilWat");
soilModule.Get("esw", out esw);
if (plantStatus == "out" &&
inWindow &&
rainTracker.Sum() >= rain_amount &&
esw > esw_amount)
{
isPossibleToday = true;
}
if (isPossibleToday)
return 1;
if (plantStatus == "out" && endOfWindow && must_sow == "yes")
return 1;
if (plantStatus == "out" && !inWindow)
return -1;
return 0;
}
}
[Output, Description("Test whether we have passed the end of the window")] public int pastWindow {
get {
return( (DateUtility.CompareDates(date2, today) < 0) ? 1 : 0);
}
}
// Sow a crop
[Param()] private string cultivar1;
[Param()] private string cultivar2;
[Param()] private double density1;
[Param()] private double depth1;
[Param()] private double row_spacing1;
[Param()] private string ftn1;
[Param()] private string skiprow1;
[Param()] private string tillageImplement;
[EventHandler, Description("Sow the crop")] public void OnEnter()
{
Console.WriteLine(today + " Sowing Crop");
SowType data = new SowType();
data.Cultivar = cultivar1;
if(ChangeCultivar)
data.Cultivar = cultivar2;
data.plants = density1;
data.sowing_depth = depth1;
data.row_spacing = row_spacing1;
data.tiller_no_fertile = (ftn1 == "na") ? "" : ftn1;
data.SkipRow = 0 ;
if (skiprow1 == "single")
data.SkipRow = 1;
else if (skiprow1 == "double")
data.SkipRow = 2;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("Sow", data);
if (tillageImplement.ToLower() != "na")
{
TillageType t = new TillageType();
t.type = tillageImplement;
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = MySimulation.ChildPaddocks[0];
paddockModule.Publish("tillage", t);
}
}
// Test whether we can harvest a crop today
// +ve number - yes
// 0 - no
// -ve - out of scope
[Output] public int canLeave
{
get
{
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
string plantStatus = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".plant_status", out plantStatus);
if (plantStatus == "out")
return -1;
string StageName = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".StageName", out StageName);
if (StageName == "harvest_ripe" || plantStatus == "dead" || today == date4)
return 1;
return 0;
}
}
[EventHandler] public void OnLeave()
{
Console.WriteLine(today + " Harvesting Crop");
HarvestType hdata = new HarvestType();
hdata.Remove = 0.0;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("harvest", hdata);
KillCropType kdata = new KillCropType();
kdata.KillFraction = 0.0F;
cropModule.Publish("killcrop", kdata);
cropModule.Publish("end_crop");
}
}
@peter-devoil I got the following error for a rotation simulation. Do you know which could be the source of it?
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
APSIM Fatal Error
-------------------
paddock.Soybean Management The property canEnter is not a gettable property. (Exception has been thrown by the target of an invocation.)
Error in readFromPropertyList(). Property: 9
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
APSIM Fatal Error
-------------------
std::exception
Component name: paddock
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
There was an exception whenthe "canEnter" code was called. Bad date? incorrect crop module? It will be somewhere in the parameters for the soybean manager
@peter-devoil I have an issue with date formatting in a rotation simulation. I setup a date (date4
) to fix the wheat harvest as fixed date following this code:
using System;
using ModelFramework;
using CSGeneral;
// Basic crop management: sowing & harvesting.
// Multi-paddock aware.
// This component DOES NOT require a trigger from the sequencer.
// It will assume it is the only crop in the system if it doesnt find a sequencer.
// If it does find a sequencer, it will do nothing until told to (via Enter/Leave).
public class Script
{
[Link()] public Simulation MySimulation;
[Param()] private string crop; // The module name of this crop
[Param()] private string date1; //Start of sowing window
[Param()] private string date2; //End of sowing window
[Param()] private string date3; //date to change to different cultivar
[Param] private DateTime date4; //date to harvest the last crop of the rotation
[Param()] int esw_amount;
[Param()] private string must_sow;
[Input()] private DateTime today;
// Rainfall accumulator
[Param()] int rain_days; //check for rain over this period
[Param()] int rain_amount; //this much rain over that period
// Daily rainfall from the system
[Input] private double rain;
private ManagerUtility.Tracker<double> rainTracker;
private bool inWindow = false;
private bool endOfWindow = false;
private bool ChangeCultivar = false;
//initialise tracker, telling it how many days to track
[EventHandler] public void OnInitialised()
{
rainTracker = new ManagerUtility.Tracker<double>(rain_days);
}
// Daily tests common to all paddocks
[EventHandler] public void OnPrepare()
{
bool startOfWindow = DateUtility.DatesEqual(date1, today);
inWindow = DateUtility.WithinDates(date1, today, date2);
ChangeCultivar = false;
if(date3 != "na")
ChangeCultivar = DateUtility.WithinDates(date3, today, date2);
endOfWindow = DateUtility.DatesEqual(date2, today);
rainTracker.Add(rain);
string currentPaddock = "";
if (MySimulation.Get("currentPaddock", out currentPaddock) == false)
{
// If there is no sequencer plugged in then we are it..
if (canEnter > 0) {
OnEnter();
}
if (canLeave > 0) {
OnLeave();
}
}
}
// Test whether we can sow a crop today
// +ve number - yes
// 0 - no
// -ve number - no, out of scope (planting window)
[Output, Description("Test whether we can sow a crop today")] public int canEnter {
get {
bool isPossibleToday = false;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
//Console.WriteLine("1. '" + currentPaddock + "'");
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = (Component) MySimulation.ChildPaddocks[0];
//Console.WriteLine("2. " + paddockModule.Name);
Component cropModule = (Component) paddockModule.LinkByName( crop );
//Console.WriteLine("3. " + cropModule.Name);
string plantStatus = "";
cropModule.Get("plant_status", out plantStatus);
double esw = 0.0;
Component soilModule = (Component) paddockModule.LinkByType("SoilWat");
soilModule.Get("esw", out esw);
if (plantStatus == "out" &&
inWindow &&
rainTracker.Sum() >= rain_amount &&
esw > esw_amount)
{
isPossibleToday = true;
}
if (isPossibleToday)
return 1;
if (plantStatus == "out" && endOfWindow && must_sow == "yes")
return 1;
if (plantStatus == "out" && !inWindow)
return -1;
return 0;
}
}
[Output, Description("Test whether we have passed the end of the window")] public int pastWindow {
get {
return( (DateUtility.CompareDates(date2, today) < 0) ? 1 : 0);
}
}
// Sow a crop
[Param()] private string cultivar;
[Param()] private double density;
[Param()] private double depth;
[Param()] private double row_spacing;
[Param()] private string ftn;
[Param()] private string skiprow;
[Param()] private string tillageImplement;
[EventHandler, Description("Sow the crop")] public void OnEnter()
{
Console.WriteLine(today + " Sowing Crop");
SowType data = new SowType();
data.Cultivar = cultivar;
if(ChangeCultivar)
data.Cultivar = cultivar;
data.plants = density;
data.sowing_depth = depth;
data.row_spacing = row_spacing;
data.tiller_no_fertile = (ftn == "na") ? "" : ftn;
data.SkipRow = 0 ;
if (skiprow == "single")
data.SkipRow = 1;
else if (skiprow == "double")
data.SkipRow = 2;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("Sow", data);
if (tillageImplement.ToLower() != "na")
{
TillageType t = new TillageType();
t.type = tillageImplement;
Component paddockModule;
if (currentPaddock != "")
paddockModule = (Component) MySimulation.LinkByName(currentPaddock);
else
paddockModule = MySimulation.ChildPaddocks[0];
paddockModule.Publish("tillage", t);
}
}
// Test whether we can harvest a crop today
// +ve number - yes
// 0 - no
// -ve - out of scope
[Output] public int canLeave
{
get
{
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
string plantStatus = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".plant_status", out plantStatus);
if (plantStatus == "out")
return -1;
string StageName = "";
MySimulation.Get((currentPaddock != "" ? currentPaddock + "." : "") + crop + ".StageName", out StageName);
if (StageName == "harvest_ripe" || plantStatus == "dead" || today == date4)
return 1;
return 0;
}
}
[EventHandler] public void OnLeave()
{
Console.WriteLine(today + " Harvesting Crop");
HarvestType hdata = new HarvestType();
hdata.Remove = 0.0;
string currentPaddock;
MySimulation.Get("currentPaddock", out currentPaddock);
Component cropModule;
if (currentPaddock != "")
cropModule = (Component) MySimulation.LinkByName(currentPaddock + "." + crop);
else
cropModule = (Component) MySimulation.ChildPaddocks[0].LinkByName(crop);
cropModule.Publish("harvest", hdata);
KillCropType kdata = new KillCropType();
kdata.KillFraction = 0.0F;
cropModule.Publish("killcrop", kdata);
cropModule.Publish("end_crop");
}
}
The date of harvest is retrieved automaticly from our FluroSense platform and should be 1-May-2020 (which is in the format yyyy-mm-dd), however it is harvesting the crop on 5-Jan-2020 (see below). Although in the UI it seems to be the right date:
it is harvesting the crop in the wrong one (5-Jan-2020).
Then I checked the clock format in the same sum file and it considers the rigth date format (dd-mm-yyyy). Could you help me with this?
Try:
... || today == DateTime.ParseExact(date4, "dd/MM/yyyy", CultureInfo.InvariantCulture))
By default, the .net runtime thinks you're in the center of the universe - en-US.
@peter-devoil I changed date4
to string ([Param()] private string date4; //date to harvest the last crop of the rotation
) and added
today == DateTime.ParseExact(date4, "dd/MM/yyyy", CultureInfo.InvariantCulture))
in the harvest rule but I got this error:
@peter-devoil I solved it adding using System.Globalization;
at the top of the script
Excellent.
Please use this issue to comment and/or ask questions in relation to the following videos: https://www.youtube.com/watch?v=W7IqQMQi8GQ https://www.youtube.com/watch?v=DX0xFo1SW4Q More information can be found here: https://www.apsim.info/support/apsim-training-manuals/crop-rotations-in-apsim/
If you're interested in receiving updates on new videos developed by the APSIM team, please email apsim@csiro.au