Class TargetDescription

java.lang.Object
ca.spatial.patchworks.TargetDescription

public abstract class TargetDescription extends Object
This class implements a container for describing how targets should be set when a scenario is run. The class maintains meta-data descripting the intent of the action, a user provided category that the action belongs to, and an arbitrary set of target setting actions are specified in the required 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

The activate(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, The 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
    Constructor
    Description
    TargetDescription​(String description, String category)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    activate​(Object userVal)
    The activate method is an optional method that can be implemented to activate the targets that are controlled by this TargetDescription object.
    abstract void
    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 this TargetDescription 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.

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • TargetDescription

      public TargetDescription(String description, String category)
      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

      public String getDescription()
      Get the text that describes the purpose of the target.
    • getCategory

      public String getCategory()
      Get the category that this target belongs to.
    • deactivate

      public void deactivate(Object userVal)
      The deactivate method is an optional method that can be implemented to deactivate the targets that are controlled by this TargetDescription object. This method may be populated with any code, but the general contract is to deactivate the targets that were activated by the apply() 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

      public void activate(Object userVal)
      The activate method is an optional method that can be implemented to activate the targets that are controlled by this TargetDescription object. This method may be populated with any code, but the general contract is to activate the targets that were activated by the apply() 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 the update(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 the ScenarioSet 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.