Search code examples
repast-simphony

How can the Repast file sink filename be set programmatically?


Does anybody know if there is a simple way to make the filename element path of an file sink variable according to one field in the model? So instead of using a fix path like :

fixed_path/filename.csv

{variable_path}/filename.csv


Solution

  • The attached ModelInitializer shows how to do this. I also copied the code below in case attachments doesn’t go through. To enable the ModelInitializer, you need to add the following to the scenario.xml file:

     <model.initializer class="PredatorPrey.MyInitializer" />
    

    I tested this in the Predator Prey demo so you should change the class package name. In the ModelInitializer example, you need to specify the root context ID which is the same as the context ID in the context.xml file. And you should specify the variable output folder name. This example requires a file name to be specified in the file sink as you would normally do and it inserts the variable path. On caveat is that the variable folder path will be saved in the scenario if the scenario is saved in the GUI, however this code will check for any existing path and simply replace the path with the outputFolder string. So you should put the entire path in the outputFolder string and not just part of it, or change the code behavior as needed.

    package PredatorPrey;
    
    import java.io.File;
    
    import repast.simphony.data2.engine.FileSinkComponentControllerAction;
    import repast.simphony.data2.engine.FileSinkDescriptor;
    import repast.simphony.engine.controller.NullAbstractControllerAction;
    import repast.simphony.engine.environment.ControllerAction;
    import repast.simphony.engine.environment.RunEnvironmentBuilder;
    import repast.simphony.engine.environment.RunState;
    import repast.simphony.scenario.ModelInitializer;
    import repast.simphony.scenario.Scenario;
    import repast.simphony.util.collections.Tree;
    
    public class MyInitializer implements ModelInitializer {
    
          @Override
          public void initialize(final Scenario scen, RunEnvironmentBuilder builder) {
    
                scen.addMasterControllerAction(new NullAbstractControllerAction() {
    
                String rootContextID = "Predator Prey";
                String outputFolder = "testoutfolder";
    
                      @Override
                      public void batchInitialize(RunState runState, Object contextId) {
    
                            Tree<ControllerAction> scenarioTree = scen.getControllerRegistry().getActionTree(rootContextID);
    
                            findFileSinkTreeChildren(scenarioTree, scenarioTree.getRoot(), outputFolder);
    
                            // Reset the scenario dirty flag so the changes made to the file sink 
                            //  descriptors don't prompt a scenario save in the GUI
                            scen.setDirty(false);
    
                      }
    
                });
          }
    
          public static void findFileSinkTreeChildren(Tree<ControllerAction> tree, 
                      ControllerAction parent, String outputFolder){
    
                // Check each ControllerAction in the scenario and if it is a FileSink,
                //    modify the output path to include the folder
                for (ControllerAction act : tree.getChildren(parent)){
                      if (act instanceof FileSinkComponentControllerAction){
                            FileSinkDescriptor descriptor = ((FileSinkComponentControllerAction)act).getDescriptor();
                            String fileName = descriptor.getFileName();
    
                            //  remove any prefix directories from the file name
                            int lastSeparatorIndex = fileName.lastIndexOf(File.separator);
    
                            // Check for backslash separator
                            if (fileName.lastIndexOf('\\') > lastSeparatorIndex)
                                  lastSeparatorIndex = fileName.lastIndexOf('\\');
    
                            // Check for forward slash operator
                            if (fileName.lastIndexOf('/') > lastSeparatorIndex)
                                  lastSeparatorIndex = fileName.lastIndexOf('/');
    
                            if (lastSeparatorIndex > 0){
                                  fileName = fileName.substring(lastSeparatorIndex+1, fileName.length());
                            }
    
                            descriptor.setFileName(outputFolder + File.separator + fileName);
                      }
                      else findFileSinkTreeChildren(tree, act, outputFolder);
                }
          }
    }