Class TargetDescription
apply()
method. See the section on
fine-grained control of target activation
for a description of the optional
activate(java.lang.Object)
, deactivate(java.lang.Object)
and update(int, int)
methods.
TargetDecription objects are used to define management targets
to the ScenarioDescription
class.
This class is abstract so you must provide the apply()
method.
Here is an example that could be used from within a BeanShell script
to instantiate a TargetDescription and assign it to a variable:
setHarvestLow = new TargetDescription("Set harvest low", "setHarvest") { public void apply() { setMinimum("product.Yield.conifer", 100000); setMinWeight("product.Yield.conifer", 1); setActive("product.Yield.conifer", true, true, false); } };
The first argument to the class constructor is a description of the the target action. This description can be a simple label (as above) or as an HTML string containing advanced formatting such as text formatting and table layouts.
The second argument is a category name. The ScenarioSet class can use the category name information to check for duplicate categories within a single scenario (for example, setting and then inadvertently resetting the harvest levels).
The apply()
method contains arbitrary code to adjust the
simulation parameters. Most often these commands will manipulate
targets, but they can also act on timing constraints, load schedules
or take any other action.
This TargetDescription can be used by name in the declaration of a ScenarioDescription:
s.addScenario("scenarios/Scenario_2", "Harvest only scenario", new TargetDescription[] { setHarvestLow });
Scripted TargetDescriptions
The example above is a simple declaration of an instance of a TargetDescription. This simple declaration works well, but the entire subclass would have to be duplicated if the harvest target or weight needs to be altered. Even for a few combinations of targets and weights the repetition would be cumbersome.An alternative to having many near identical subclass declarations is to use a scripted function to create TargetDescriptions as required. Functions can receive parameters, and these parameters can be used to specify the TargetDescription values that are needed to vary. When the function is called a custom TargetDescription is created and returned. For example:
setHarvest(double level, double weight) { return new TargetDescription("Set harvest to "+level+" with weight="+weight, "setHarvest") { public void apply() { setMinimum("product.Yield.conifer", level); setMinWeight("product.Yield.conifer", weight); setActive("product.Yield.conifer", true, true, false); } }; }The parameters 'level' and 'weight' are used to set the appropriate values, and also included in the description string. When the scenario is run the description string will be included in the scenario meta-data to help document the settings that were used.
Compared to the previous example this function can be used with parameters in the declaration of a ScenarioDescription:
s.addScenario("scenarios/Scenario_2", "Harvest only scenario with low harvest levels", new TargetDescription[] { setHarvest(100000, 1) });The setHarvest function may be efficiently reused in multiple ScenarioDescription definitions with a range of parameter values.
Using the objective definition helper function
The Patchworks script library contains an objective defintion helper function that can substantially simplify the creation of multi-target TargetDescription objects. This helper function accepts a few parameters (description, category) and an array of objective specifications, such as in this simple example:objs = new Object[] { annualObjective("SPF", 120000, 1, null, null).linear(true), annualObjective("Birch", 100000, 1, null, null).linear(true), annualObjective("Aspen", 30000, 1, null, null).linear(true) }; primaryHarvest = objective("Harvest by species groups", objs, "product.Spg.", "Harvest_Level");See the UserGuide documentation for more details about parameters and options.
The objective definition helper function can be combined with a scripted function to allow for better flexibility and reuse:
setPrimaryHarvest(double factor, double weight) { objs = new Object[] { annualObjective("SPF", 120000*factor, weight, null, null).linear(true), annualObjective("Birch", 100000*factor, weight, null, null).linear(true), annualObjective("Aspen", 30000*factor, weight, null, null).linear(true) }; return objective("Harvest by species groups", objs, "product.Spg.", "Harvest_Level"); }
Asserting pre-conditions
TargetDescriptions are most often used to set target values, but they can also be used to assert that model conditions are appropriate for the scenario to be run. For example, consider a model setup where the Patchworks Input File (PIN file) contains an option to select the tracks dataset (input matrix), perhaps to facilitate a sensitivity analysis. The track dataset selection is saved in to a global variable, such as in this code snip from the PIN file:volTypes = new String[] {"Orig", "Adjust50", "Adjust70", "Raw"}; volType = select("Choose the volume type:", "Choose volume", volTypes, 1); String tracks_path_prefix = "../tracks_"+volType+"/";When a selection is chosen the global variable volType is set, and it is then used to help define the location of the tracks folder.
Some scenarios might be dependent on one of the choices, and the scenario would be incorrect if executed with the wrong choice. To help guard against the accidental mis-match of the wrong input data set for a scenario the following TargetDescription could be used:
/** * Check that the input matrix being used is the one that is required * for this scenario. Throw an exception if it is incorrect. */ usingInput(String selection) { title = "Using input matrix for "+selection; return new TargetDescription(title, "UsingInput") { public void apply() { if (!selection.equals(volType)) throw new IllegalStateException("Input matrix in use does not match the matrix required for this scenario. Wanted '"+selection+"' but loaded '"+volType+"'"); } }; }The ScenarioSet would then make use of this TargetDescription to assert that the precondition was met. If the condition is not met an error will be raised and the scenario will not run.
s.addScenario("scenarios/Scenario_5", "Test LRSY with Adjust70 inputs", new TargetDescription[] { usingInput("Adjust70"), maxLRSY(1), noLargeCC(1000), millAllocation(0.01) });
Fine-grained control of target activation
Theactivate(java.lang.Object)
and deactivate(java.lang.Object)
methods are optional,
and can be used with the update(int, int)
method for fine-grained
control of target activation. When a ScenarioDescription
is
run under the control of the scenario manager
(via ScenarioDescription.runScenario()
) the scenario life cycle
methods will be called as the scenario makes progress. In particular,
-
Each
TargetDescription
object will have it'sapply()
andactivate(java.lang.Object)
methods called prior to the start of scenario execution. -
Each
TargetDescription
object will have it'supdate(int, int)
method called for each interval of iterations of the simulation.
activate(java.lang.Object)
and deactivate(java.lang.Object)
methods may be called by
user code, from within a ScenarioChangeListener
, or
by the Objective Explorer tool. Deactivation typically turns off the
active status of targets. Activation can be as simple as turning on the
activation of targets, or by setting instance varaibles that can be
monitored by the update(int, int)
method to determine the timing
to activate individual target components relative to progress
achieved or other simulation state.
Here is an example of fine-grained control of target activation. In this case the patching objectives work much better if the individual targets are activated in a sequence with a brief pause between each to allow for stabilization. The activate method sets the variables for activation to occur, but it is the update method that actually turns on the targets one by one. Note that this target uses an objective object to to simplify setting the initial target values.
dchsPatch(double minWeight, double maxWeight, double shapeWeight, double attrWeight) { dchsPatchSpecs = new Object[] { periodicObjective("0_1000.area", null, null, 0, maxWeight), periodicObjective("1000_5000.area", null, null, 0, maxWeight), periodicObjective("5000_10000.area", null, null, 0, maxWeight), periodicObjective("30000_plus.area", null, null, 0, maxWeight), }; td = objective("DCHS patch size target", dchsPatchSpecs, "patch.North.", "PatchNorth"); return new TargetDescription(td.getDescription(), td.getCategory()) { int count = 0; boolean active; void apply() { td.apply(); deactivate(null); activate(null); } /** * When activating set the count to 0 and set the active flag */ void activate(Object userVal) { count = 0; active = true; } /** * When deactivating set a flag and turn all the targets off */ void deactivate(Object userVal) { active = false; td.deactivate(null); } /** * During an update event check if the activate flag is * set, and if so, determine when the time is right to * activate each sub-target. */ void update(int accepted, int attempted) { if (active && count < 400000) { if (count < 100000 && total > 100000) { Diagnostic.status("activate dchs 0_1000"); td.activate("0_1000.area"); } else if (count < 200000 && total > 200000) { Diagnostic.status("activate dchs 1000_5000"); td.activate("1000_5000.area"); } else if (count < 300000 && total > 300000) { Diagnostic.status("activate dchs 30000_plus"); td.activate("30000_plus.area"); } else if (count < 400000 && total > 400000) { Diagnostic.status("activate dchs 5000_10000"); td.activate("5000_10000.area"); } count += attempted; } } }; }For more information on scenario life cycle management see the
ScenarioChangeListener
documentation.- See Also:
ScenarioSet
,ScenarioDescription
,ScenarioChangeListener
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid
The activate method is an optional method that can be implemented to activate the targets that are controlled by thisTargetDescription
object.abstract void
apply()
This method must be overriden to specify the actions that will set the target correctly.void
deactivate(Object userVal)
The deactivate method is an optional method that can be implemented to deactivate the targets that are controlled by thisTargetDescription
object.Get the category that this target belongs to.Get the text that describes the purpose of the target.void
update(int accepted, int attempted)
This method is called by the scenario manager for each set of iterations that are processed.
-
Constructor Details
-
TargetDescription
- Parameters:
description
- An HTML string that describes the target being set.category
- A string that identifies the category of this target. Category names are arbitrary, and are used to group targets into sets where only on target from a set should be applied within a scenario. For example, if you have three TargetDescription objects that set low, medium and high harvest levels, you should give them all the same category name (for example, "Harvest level").
-
-
Method Details
-
getDescription
Get the text that describes the purpose of the target. -
getCategory
Get the category that this target belongs to. -
deactivate
The deactivate method is an optional method that can be implemented to deactivate the targets that are controlled by thisTargetDescription
object. This method may be populated with any code, but the general contract is to deactivate the targets that were activated by theapply()
method.Typical scripting code could look like:
public void deactivate() { setActive("ratio.Harvest.F_Block.CAR", false, true, false); }
The default implementation does nothing.- Parameters:
userVal
- A value containing information to customize and guide the deactivation process. Any value (including null) may be used as appropriate to the situation.
-
activate
The activate method is an optional method that can be implemented to activate the targets that are controlled by thisTargetDescription
object. This method may be populated with any code, but the general contract is to activate the targets that were activated by theapply()
method.Typical scripting code could look like:
public void activate() { setActive("ratio.Harvest.F_Block.CAR", true, true, false); }
although additional code could be included to change the value of instance variables. This could be used with theupdate(int, int)
method to provide a finer grained control on the incremental activation of targets.The default implementation does nothing.
- Parameters:
userVal
- A value containing information to customize and guide the activation process. Any value (including null) may be used as appropriate to the situation.
-
apply
public abstract void apply()This method must be overriden to specify the actions that will set the target correctly. For example,setHarvestLow = new TargetDescription("Set harvest low", "setHarvest") { public void apply() { setMinimum("product.Yield.conifer", 100000); setActive("product.Yield.conifer", true, true, false); } };
-
update
public void update(int accepted, int attempted)This method is called by the scenario manager for each set of iterations that are processed. Typically this will be every 5,000 or 10,000 iterations, but this depends on the complexity of the targets that have been set. This is more frequently than theScenarioSet
iteration count, which is typically set to several hundred thousand iterations.The purpose of this method is to provide an alternate fine-granied control on adjustment to target values as scenarios are run.
- Parameters:
accepted
- The number of permutations that were accepted in this interval.attempted
- The number of permutations that were attempted in this interval.
-