Displaying differences for changeset
 
display as  

src/java/m/oms/ages/V1_0.java

@@ -18,7 +18,6 @@
 import java.util.Set;
 import javax.ws.rs.Path;
 import static m.oms.ages.V1_0.KEY_SCRIPT;
-import ngmf.util.cosu.luca.of.KGE;
 import ngmf.util.cosu.luca.of.NS;
 import ngmf.util.cosu.luca.of.RMSE;
 import ngmf.util.cosu.luca.of.TRMSE;
@@ -27,6 +26,7 @@
 import oms.utils.Utils.PBIAS;
 import oms.utils.Utils.NSLOG1P;
 import oms.utils.Utils.NSLOG2;
+import oms.utils.Utils.KGE;
 import oms3.ObjectiveFunction;
 
 /**
@@ -45,218 +45,214 @@
 @Resource(file = "${csip.dir}/bin/ages/simulation/ages.sim", type = REFERENCE, id = KEY_SCRIPT)
 public class V1_0 extends ModelDataService {
 
-  public static final String KEY_SCRIPT = "ages.sim";
-  public static final String RUN_INC = "run.inc";
+    public static final String KEY_SCRIPT = "ages.sim";
+    public static final String RUN_INC = "run.inc";
 
-  public static final String PAR_STARTTIME = "startTime";
-  public static final String PAR_ENDTIME = "endTime";
+    public static final String PAR_STARTTIME = "startTime";
+    public static final String PAR_ENDTIME = "endTime";
 
-  public static final String CAL_STARTTIME = "cal_startTime";
-  public static final String CAL_ENDTIME = "cal_endTime";
+    public static final String CAL_STARTTIME = "cal_startTime";
+    public static final String CAL_ENDTIME = "cal_endTime";
 
-  static final Map<String, ObjectiveFunction> OF = new HashMap<>();
+    static final Map<String, ObjectiveFunction> OF = new HashMap<>();
 
+    static {
+        OF.put("kge", new KGE());
+        OF.put("ns", new NS());
+        OF.put("nslog", new NS2LOG());
+        OF.put("nslog1p", new NSLOG1P());
+        OF.put("nslog2", new NSLOG2());
+        OF.put("rmse", new RMSE());
+        OF.put("trmse", new TRMSE());
+        OF.put("pbias", new PBIAS());
+    }
 
-  static {
-    OF.put("kge", new KGE());
-    OF.put("ns", new NS());
-    OF.put("nslog", new NS2LOG());
-    OF.put("nslog1p", new NSLOG1P());
-    OF.put("nslog2", new NSLOG2());
-    OF.put("rmse", new RMSE());
-    OF.put("trmse", new TRMSE());
-    OF.put("pbias", new PBIAS());
-  }
-
-  // required parameter
-  String[] reqParams = {
-    PAR_STARTTIME,
-    PAR_ENDTIME
-  };
-
-  // optional parameter
-  String[] optParams = {
-    "ACAdaptation",
-    "BetaW",
-    "Beta_min",
-    "Beta_rsd",
-    "FCAdaptation",
-    "Ksink",
-    "LExCoef",
-    "N_delay_RG1",
-    "N_delay_RG2",
-    "a_rain",
-    "a_snow",
-    "angstrom_a",
-    "angstrom_b",
-    "baseTemp",
-    "calib_clat_fact",
-    "ccf_factor",
-    "defaultCO2",
-    "denitfac",
-    "delayNitrification",
-    "denitrificationRateCoefficient",
-    "denitrificationSoilSaturationThreshold",
-    "depdr",
-    "deposition_factor",
-    "drrad",
-    "drspac",
-    "f1",
-    "f12",
-    "f13",
-    "f14",
-    "f15",
-    "f16",
-    "f17",
-    "f18",
-    "f19",
-    "f2",
-    "f3",
-    "f4",
-    "f5",
-    "f6",
-    "f7",
-    "f8",
-    "flowRouteTA",
-    "fmt_date",
-    "fmt_double",
-    "g_factor",
-    "geoMaxPerc",
-    "gwCapRise",
-    "gwRG1Fact",
-    "gwRG1RG2dist",
-    "gwRG2Fact",
-    "halflife_RG1",
-    "halflife_RG2",
-    "infil_conc_factor",
-    "initLPS",
-    "initMPS",
-    "initN_concRG1",
-    "initN_concRG2",
-    "initRG1",
-    "initRG2",
-    "kdiff_layer",
-    "kf_calib",
-    "lagSurfaceRunoff",
-    "lagInterflow",
-    "locGrw",
-    "longTZ",
-    "nitri_delay",
-    "nitrificationSoilTemperatureThreshold",
-    "nitrificationSurfaceTemperatureThreshold",
-    "opti",
-    "piadin",
-    "r_factor",
-    "rootfactor",
-    "sceno",
-    "skipRegression",
-    "snowCritDens",
-    "snowDensConst",
-    "snowFactorA",
-    "snowFactorB",
-    "snowFactorC",
-    "snow_trans",
-    "snow_trs",
-    "soilDiffMPSLPS",
-    "soilDistMPSLPS",
-    "soilImpGT80",
-    "soilImpLT80",
-    "soilLatVertLPS",
-    "soilLinRed",
-    "soilMaxDPS",
-    "soilMaxInfSnow",
-    "soilMaxInfSummer",
-    "soilMaxInfWinter",
-    "soilMaxPerc",
-    "soilOutLPS",
-    "soilPolRed",
-    "t_factor",
-    "tempRes",
-    "temp_lag"
-  };
-
-  // simulation flags
-  String[] flags = {
-    "flagParallel",
-    "flagRegionalization",
-    "flagHRURouting",
-    "flagReachRouting",
-    "flagSort",
-    "flagSplit",
-    "flagInfiltration",
-    "flagTillage",
-    "flagTileDrain",
-    "flagUPGM",
-    "parallelismFactor",
-    "parallelismThreads",
-    "flagSaveState",
-    "flagLoadState",
-    "flagWB"
-  };
-
-
-  @Override
-  public void doProcess() throws Exception {
-    String dsl = parameter().getString(KEY_SCRIPT,
-        resources().getFile(KEY_SCRIPT).toString());
-
-    // pass request param to model runtime parameter -> run.inc
-    Map<String, String> agesParam = new LinkedHashMap<>();
-    Utils.passReqQuotedParam(agesParam, parameter(), reqParams);
-
-    // scalar parameter
-    Utils.passOptParam(agesParam, parameter(), optParams);
-
-    // optional flags
-    Utils.passOptQuotedParam(agesParam, parameter(), flags);
-
-    // create parameter include file
-    Utils.createParamInclude(agesParam, getWorkspaceFile(RUN_INC));
-
-    String start = parameter().getString(PAR_STARTTIME);
-    String end = parameter().getString(PAR_ENDTIME);
+    // required parameter
+    String[] reqParams = {
+        PAR_STARTTIME,
+        PAR_ENDTIME
+    };
 
     // optional parameter
-    String cal_start = parameter().getString(CAL_STARTTIME, start);
-    String cal_end = parameter().getString(CAL_ENDTIME, end);
+    String[] optParams = {
+        "ACAdaptation",
+        "BetaW",
+        "Beta_min",
+        "Beta_rsd",
+        "FCAdaptation",
+        "Ksink",
+        "LExCoef",
+        "N_delay_RG1",
+        "N_delay_RG2",
+        "a_rain",
+        "a_snow",
+        "angstrom_a",
+        "angstrom_b",
+        "baseTemp",
+        "calib_clat_fact",
+        "ccf_factor",
+        "defaultCO2",
+        "denitfac",
+        "delayNitrification",
+        "denitrificationRateCoefficient",
+        "denitrificationSoilSaturationThreshold",
+        "depdr",
+        "deposition_factor",
+        "drrad",
+        "drspac",
+        "f1",
+        "f12",
+        "f13",
+        "f14",
+        "f15",
+        "f16",
+        "f17",
+        "f18",
+        "f19",
+        "f2",
+        "f3",
+        "f4",
+        "f5",
+        "f6",
+        "f7",
+        "f8",
+        "flowRouteTA",
+        "fmt_date",
+        "fmt_double",
+        "g_factor",
+        "geoMaxPerc",
+        "gwCapRise",
+        "gwRG1Fact",
+        "gwRG1RG2dist",
+        "gwRG2Fact",
+        "halflife_RG1",
+        "halflife_RG2",
+        "infil_conc_factor",
+        "initLPS",
+        "initMPS",
+        "initN_concRG1",
+        "initN_concRG2",
+        "initRG1",
+        "initRG2",
+        "kdiff_layer",
+        "kf_calib",
+        "lagSurfaceRunoff",
+        "lagInterflow",
+        "locGrw",
+        "longTZ",
+        "nitri_delay",
+        "nitrificationSoilTemperatureThreshold",
+        "nitrificationSurfaceTemperatureThreshold",
+        "opti",
+        "piadin",
+        "r_factor",
+        "rootfactor",
+        "sceno",
+        "skipRegression",
+        "snowCritDens",
+        "snowDensConst",
+        "snowFactorA",
+        "snowFactorB",
+        "snowFactorC",
+        "snow_trans",
+        "snow_trs",
+        "soilDiffMPSLPS",
+        "soilDistMPSLPS",
+        "soilImpGT80",
+        "soilImpLT80",
+        "soilLatVertLPS",
+        "soilLinRed",
+        "soilMaxDPS",
+        "soilMaxInfSnow",
+        "soilMaxInfSummer",
+        "soilMaxInfWinter",
+        "soilMaxPerc",
+        "soilOutLPS",
+        "soilPolRed",
+        "t_factor",
+        "tempRes",
+        "temp_lag"
+    };
 
-    File d = new File(dsl);
-    if (!(d.isAbsolute() && d.exists())) {
-      d = getWorkspaceFile(dsl);
+    // simulation flags
+    String[] flags = {
+        "flagParallel",
+        "flagRegionalization",
+        "flagHRURouting",
+        "flagReachRouting",
+        "flagSort",
+        "flagSplit",
+        "flagInfiltration",
+        "flagTillage",
+        "flagTileDrain",
+        "flagUPGM",
+        "parallelismFactor",
+        "parallelismThreads",
+        "flagSaveState",
+        "flagLoadState",
+        "flagWB"
+    };
+
+    @Override
+    public void doProcess() throws Exception {
+        String dsl = parameter().getString(KEY_SCRIPT,
+                resources().getFile(KEY_SCRIPT).toString());
+
+        // pass request param to model runtime parameter -> run.inc
+        Map<String, String> agesParam = new LinkedHashMap<>();
+        Utils.passReqQuotedParam(agesParam, parameter(), reqParams);
+
+        // scalar parameter
+        Utils.passOptParam(agesParam, parameter(), optParams);
+
+        // optional flags
+        Utils.passOptQuotedParam(agesParam, parameter(), flags);
+
+        // create parameter include file
+        Utils.createParamInclude(agesParam, getWorkspaceFile(RUN_INC));
+
+        String start = parameter().getString(PAR_STARTTIME);
+        String end = parameter().getString(PAR_ENDTIME);
+
+        // optional parameter
+        String cal_start = parameter().getString(CAL_STARTTIME, start);
+        String cal_end = parameter().getString(CAL_ENDTIME, end);
+
+        File d = new File(dsl);
+        if (!(d.isAbsolute() && d.exists())) {
+            d = getWorkspaceFile(dsl);
+        }
+
+        getWorkspaceFile("output").mkdirs();
+        getWorkspaceFile("logs").mkdirs();
+
+        Utils.runAges(d, getWorkspaceDir(), parameter(), resources(), LOG);
+
+        for (String ofName : getRequestedObjfunc(OF.keySet())) {
+            String[] data = parameter().getStringArray(ofName);
+            double v = calc_of(OF.get(ofName), data[0], data[1], cal_start, cal_end);
+            results().put(ofName, v);
+        }
+//  results().put(getWorkspaceFile("output"));
     }
 
-    getWorkspaceFile("output").mkdirs();
-    getWorkspaceFile("logs").mkdirs();
+    private List<String> getRequestedObjfunc(Set<String> names) {
+        List<String> l = new ArrayList<>();
+        for (String ofName : names) {
+            if (parameter().has(ofName)) {
+                l.add(ofName);
+            }
+        }
+        return l;
+    }
 
-    Utils.runAges(d, getWorkspaceDir(), parameter(), resources(), LOG);
-
-    for (String ofName : getRequestedObjfunc(OF.keySet())) {
-      String[] data = parameter().getStringArray(ofName);
-      double v = calc_of(OF.get(ofName), data[0], data[1], cal_start, cal_end);
-      results().put(ofName, v);
+    private double calc_of(ObjectiveFunction of, String obs,
+            String sim, String start, String end) throws IOException, ServiceException {
+        // e.g. obs_data02_14.csv/obs/orun[1]
+        double[] obsData = Utils.getData(obs, getWorkspaceDir(), start, end);
+        // e.g. output/csip_run/out/Outlet.csv/output/catchmentSimRunoff
+        double[] simData = Utils.getData(sim, getWorkspaceDir(), start, end);
+        return of.calculate(obsData, simData, parameter().getDouble("missing", -9999d));
     }
-//  results().put(getWorkspaceFile("output"));
-  }
-
-
-  private List<String> getRequestedObjfunc(Set<String> names) {
-    List<String> l = new ArrayList<>();
-    for (String ofName : names) {
-      if (parameter().has(ofName)) {
-        l.add(ofName);
-      }
-    }
-    return l;
-  }
-
-
-  private double calc_of(ObjectiveFunction of, String obs,
-      String sim, String start, String end) throws IOException, ServiceException {
-    // e.g. obs_data02_14.csv/obs/orun[1]
-    double[] obsData = Utils.getData(obs, getWorkspaceDir(), start, end);
-    // e.g. output/csip_run/out/Outlet.csv/output/catchmentSimRunoff
-    double[] simData = Utils.getData(sim, getWorkspaceDir(), start, end);
-    return of.calculate(obsData, simData, parameter().getDouble("missing", -9999d));
-  }
 
 }

src/java/oms/utils/Utils.java

@@ -33,274 +33,319 @@
  */
 public class Utils {
 
-  // parameter keys
-  public static final String KEY_LOGLEVEL = "loglevel";
-  public static final String KEY_OPTIONS = "java.options";
+    // parameter keys
+    public static final String KEY_LOGLEVEL = "loglevel";
+    public static final String KEY_OPTIONS = "java.options";
 
-  public static final String ID_AGES_JAR = "ages.jar";
+    public static final String ID_AGES_JAR = "ages.jar";
 
-  /**
-   *
-   */
-  public static class PBIAS implements ObjectiveFunction {
+    /**
+     *
+     */
+    public static class PBIAS implements ObjectiveFunction {
 
-    @Override
-    public double calculate(double[] obs, double[] sim, double missing) {
-      if (sim.length != obs.length) {
-        throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
-      }
-      double diffsum = 0;
-      double obssum = 0;
-      for (int i = 0; i < sim.length; i++) {
-        if (obs[i] > missing) {
-          diffsum += sim[i] - obs[i];
-          obssum += obs[i];
+        @Override
+        public double calculate(double[] obs, double[] sim, double missing) {
+            if (sim.length != obs.length) {
+                throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
+            }
+            double diffsum = 0;
+            double obssum = 0;
+            for (int i = 0; i < sim.length; i++) {
+                if (obs[i] > missing) {
+                    diffsum += sim[i] - obs[i];
+                    obssum += obs[i];
+                }
+            }
+            return (diffsum / obssum) * 100.0;
         }
-      }
-      return (diffsum / obssum) * 100.0;
+
+        @Override
+        public boolean positiveDirection() {
+            return false;
+        }
     }
 
+    /**
+     *
+     */
+    public static class NSLOG1P implements ObjectiveFunction {
 
-    @Override
-    public boolean positiveDirection() {
-      return false;
-    }
-  }
+        @Override
+        public double calculate(double[] obs, double[] sim, double missing) {
+            if (sim.length != obs.length) {
+                throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
+            }
 
-  /**
-   *
-   */
-  public static class NSLOG1P implements ObjectiveFunction {
+            /**
+             * calculating logarithmic values of both data sets. Sets 0 if data
+             * is 0
+             */
+            int valid = 0;
+            double avg = 0.0;
+            for (int i = 0; i < sim.length; i++) {
+                if (sim[i] >= 0.0 && obs[i] >= 0.0) {
+                    // summing up 
+                    avg += Math.log1p(obs[i]);
+                    valid++;
+                }
+            }
 
-    @Override
-    public double calculate(double[] obs, double[] sim, double missing) {
-      if (sim.length != obs.length) {
-        throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
-      }
+            if (valid < 2) {
+                return Double.NEGATIVE_INFINITY;
+            }
 
-      /**
-       * calculating logarithmic values of both data sets. Sets 0 if data is 0
-       */
-      int valid = 0;
-      double avg = 0.0;
-      for (int i = 0; i < sim.length; i++) {
-        if (sim[i] >= 0.0 && obs[i] >= 0.0) {
-          // summing up 
-          avg += Math.log1p(obs[i]);
-          valid++;
+            // calculating mean 
+            avg /= valid;
+
+            // calculating mean pow deviations
+            double rmse = 0.0;
+            double e = 0.0;
+            for (int i = 0; i < sim.length; i++) {
+                if (sim[i] >= 0 && obs[i] >= 0) {
+                    double l1po = Math.log1p(obs[i]);
+                    rmse += Math.pow(Math.abs(l1po - Math.log1p(sim[i])), 2);
+                    e += Math.pow(Math.abs(l1po - avg), 2);
+                }
+            }
+            double r = 1 - (rmse / e);
+            return Double.isNaN(r) ? 0.0 : r;
         }
-      }
 
-      if (valid < 2) {
-        return Double.NEGATIVE_INFINITY;
-      }
-
-      // calculating mean 
-      avg /= valid;
-
-      // calculating mean pow deviations
-      double rmse = 0.0;
-      double e = 0.0;
-      for (int i = 0; i < sim.length; i++) {
-        if (sim[i] >= 0 && obs[i] >= 0) {
-          double l1po = Math.log1p(obs[i]);
-          rmse += Math.pow(Math.abs(l1po - Math.log1p(sim[i])), 2);
-          e += Math.pow(Math.abs(l1po - avg), 2);
+        @Override
+        public boolean positiveDirection() {
+            return true;
         }
-      }
-      double r = 1 - (rmse / e);
-      return Double.isNaN(r) ? 0.0 : r;
     }
 
+    /**
+     *
+     */
+    public static class NSLOG2 implements ObjectiveFunction {
 
-    @Override
-    public boolean positiveDirection() {
-      return true;
-    }
-  }
+        @Override
+        public double calculate(double obs[], double sim[], double missing) {
+            if (obs.length != sim.length) {
+                throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
+            }
+            double pow = 2;
+            double rsme = 0;
+            double var = 0;
+            double avg = 0;
+            double count = 0;
+            for (int i = 0; i < obs.length; i++) {
+                if (obs[i] > 0 && obs[i] != missing) {
+                    avg += Math.log(obs[i]);
+                    count += 1;
+                }
+            }
+            avg /= count;
 
-  /**
-   *
-   */
-  public static class NSLOG2 implements ObjectiveFunction {
+            for (int i = 0; i < obs.length; i++) {
+                if (obs[i] > 0 && sim[i] > 0 && obs[i] != missing) {
+                    rsme += Math.pow(Math.abs(Math.log(obs[i]) - Math.log(sim[i])), pow);
+                    var += Math.pow(Math.abs(Math.log(obs[i]) - avg), pow);
+                }
+            }
+            double result = 1.0 - (rsme / var);
+            if (Double.isNaN(result)) {
+                result = 0;
+            }
+            return result;
+        }
 
-    @Override
-    public double calculate(double obs[], double sim[], double missing) {
-      if (obs.length != sim.length) {
-        throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
-      }
-      double pow = 2;
-      double rsme = 0;
-      double var = 0;
-      double avg = 0;
-      double count = 0;
-      for (int i = 0; i < obs.length; i++) {
-        if (obs[i] > 0 && obs[i] != missing) {
-          avg += Math.log(obs[i]);
-          count += 1;
+        @Override
+        public boolean positiveDirection() {
+            return true;
         }
-      }
-      avg /= count;
-
-      for (int i = 0; i < obs.length; i++) {
-        if (obs[i] > 0 && sim[i] > 0 && obs[i] != missing) {
-          rsme += Math.pow(Math.abs(Math.log(obs[i]) - Math.log(sim[i])), pow);
-          var += Math.pow(Math.abs(Math.log(obs[i]) - avg), pow);
-        }
-      }
-      double result = 1.0 - (rsme / var);
-      if (Double.isNaN(result)) {
-        result = 0;
-      }
-      return result;
     }
 
+    /**
+     * KGE 2012
+     */
+    public static class KGE implements ObjectiveFunction {
 
-    @Override
-    public boolean positiveDirection() {
-      return true;
-    }
-  }
+        @Override
+        public double calculate(double obs[], double sim[], double missing) {
+            if (obs.length != sim.length) {
+                throw new IllegalArgumentException("obs/sim length differ: " + obs.length + "!=" + sim.length);
+            }
+            int contamedia = 0;
+            double sommamediaoss = 0;
+            double sommamediasim = 0;
+            for (int i = 0; i < obs.length; i++) {
+                if (obs[i] > missing) {
+                    contamedia++;
+                    sommamediaoss += obs[i];
+                    sommamediasim += sim[i];
+                }
+            }
+            double mediaoss = sommamediaoss / contamedia;
+            double mediasim = sommamediasim / contamedia;
+            int count = 0;
+            double numvaprev = 0;
+            double coef1_den = 0;
+            double numR = 0;
+            double den1R = 0;
+            double den2R = 0;
+            for (int i = 0; i < obs.length; i++) {
+                if (obs[i] > missing) {
+                    count++;
+                    coef1_den += (obs[i] - mediaoss) * (obs[i] - mediaoss);
+                    numR += (obs[i] - mediaoss) * (sim[i] - mediasim);
+                    den1R += (obs[i] - mediaoss) * (obs[i] - mediaoss);
+                    den2R += (sim[i] - mediasim) * (sim[i] - mediasim);
+                    numvaprev += (sim[i] - mediasim) * (sim[i] - mediasim);
+                }
+            }
+            double sdosservati = Math.sqrt(coef1_den / (count - 1));
+            double sdsimulati = Math.sqrt(numvaprev / (count - 1));
+            double R = numR / (Math.sqrt(den1R) * Math.sqrt(den2R));
+            //double alpha = sdsimulati / sdosservati; 2009
+            double beta = mediasim / mediaoss;
+            double gamma = (mediaoss * sdsimulati) / (sdosservati * mediasim);
+            //return 1 - Math.sqrt((R - 1) * (R - 1) + (alpha - 1) * (alpha - 1) + (beta - 1) * (beta - 1)); 2009
+            return 1 - Math.sqrt((R - 1) * (R - 1) + (gamma - 1) * (gamma - 1) + (beta - 1) * (beta - 1));
+        }
 
-
-  /**
-   * create a 'sim' include file for the run part.
-   */
-  public static void createParamInclude(Map<String, String> p,
-      File file) throws IOException {
-    StringBuilder b = new StringBuilder();
-    b.append("parameter {\n");
-    p.keySet().forEach((name) -> {
-      b.append("  ").append(name).append(" ").append(p.get(name)).append("\n");
-    });
-    b.append("}\n");
-    FileUtils.writeStringToFile(file, b.toString());
-  }
-
-
-  /**
-   * pass a required parameter, quoted (string).
-   */
-  public static void passReqQuotedParam(Map<String, String> p,
-      PayloadParameter param, String... names) throws ServiceException {
-    for (String name : names) {
-      p.put(name, "\"" + param.getString(name) + "\"");
-    }
-  }
-
-
-  /**
-   * pass optional parameter, no quotes.
-   */
-  public static void passOptParam(Map<String, String> p,
-      PayloadParameter param, String... names) throws ServiceException {
-    for (String name : names) {
-      if (param.has(name)) {
-        p.put(name, param.getString(name));
-      }
-    }
-  }
-
-
-  public static void passOptQuotedParam(Map<String, String> p,
-      PayloadParameter param, String... names) throws ServiceException {
-    for (String name : names) {
-      if (param.has(name)) {
-        p.put(name, "\"" + param.getString(name) + "\"");
-      }
-    }
-  }
-
-
-  /**
-   * Run Ages
-   *
-   * @param dsl
-   * @param options
-   * @throws Exception
-   */
-  public static void runAges(File dsl, File ws, PayloadParameter param,
-      ServiceResources res, SessionLogger LOG) throws Exception {
-
-    // Create/execute a Ages.
-    Executable p = createProcess(dsl, ws, param, res, LOG);
-    int result = p.exec();
-    if (result != 0) {
-      FilenameFilter ff = new WildcardFileFilter("java*stderr.txt", IOCase.INSENSITIVE);
-      File[] f = ws.listFiles(ff);
-      if (f != null && f.length > 0) {
-        String err = FileUtils.readFileToString(f[0]);
-        LOG.info("Ages execution error. " + f[0] + ":\n" + err);
-        throw new ServiceException("Ages execution error. " + f[0] + ":\n" + err);
-      }
-      throw new ServiceException("Ages execution error." + result);
-    }
-  }
-
-
-  /**
-   * Create the external Ages process.
-   */
-  public static Executable createProcess(File dsl, File ws,
-      PayloadParameter param, ServiceResources res, SessionLogger LOG) throws Exception {
-
-    Map<String, String> sysprops = new HashMap();
-    sysprops.put("oms_prj", ws.toString());
-    sysprops.put("csip_ages", res.getFile(ID_AGES_JAR).getParent());
-
-    String[] jvmOptions = Binaries.asSysProps(sysprops);
-    String options = param.getString(KEY_OPTIONS, "");
-    if (options != null && !options.isEmpty()) {
-      jvmOptions = (String[]) ArrayUtils.addAll(jvmOptions, options.split("\\s+"));
+        @Override
+        public boolean positiveDirection() {
+            return true;
+        }
     }
 
-    // java -Doms_prj=. -cp "dist/AgES.jar" oms3.CLI -l OFF -r "projects/sfir30/simulation/sfir30.sim"
-    return Binaries.getResourceOMSDSL(
-        dsl, // the dsl file to run
-        jvmOptions, // jvm options
-        ws, // workspace dir
-        Arrays.asList(res.getFile(ID_AGES_JAR)), // the ages jar file 
-        param.getString(KEY_LOGLEVEL, "INFO"), // The log level
-        LOG); // This session logger
-  }
-
-  private static final int FILE = 0;
-  private static final int TABLE = 1;
-  private static final int COLUMN = 2;
-
-
-  /**
-   *
-   * @param d
-   * @param workspace
-   * @param start
-   * @param end
-   * @return
-   * @throws IOException
-   */
-  public static double[] getData(String d, File workspace,
-      String start, String end) throws IOException {
-    if (d == null) {
-      throw new IllegalArgumentException("Missing data property: " + d);
-    }
-    String[] parts = DataIO.parseCsvFilename(d);
-    if (parts.length != 3) {
-      throw new IllegalArgumentException("invalid: " + d + " expected:: <file>/<table>/<column>");
+    /**
+     * create a 'sim' include file for the run part.
+     */
+    public static void createParamInclude(Map<String, String> p,
+            File file) throws IOException {
+        StringBuilder b = new StringBuilder();
+        b.append("parameter {\n");
+        p.keySet().forEach((name) -> {
+            b.append("  ").append(name).append(" ").append(p.get(name)).append("\n");
+        });
+        b.append("}\n");
+        FileUtils.writeStringToFile(file, b.toString());
     }
 
+    /**
+     * pass a required parameter, quoted (string).
+     */
+    public static void passReqQuotedParam(Map<String, String> p,
+            PayloadParameter param, String... names) throws ServiceException {
+        for (String name : names) {
+            p.put(name, "\"" + param.getString(name) + "\"");
+        }
+    }
+
+    /**
+     * pass optional parameter, no quotes.
+     */
+    public static void passOptParam(Map<String, String> p,
+            PayloadParameter param, String... names) throws ServiceException {
+        for (String name : names) {
+            if (param.has(name)) {
+                p.put(name, param.getString(name));
+            }
+        }
+    }
+
+    public static void passOptQuotedParam(Map<String, String> p,
+            PayloadParameter param, String... names) throws ServiceException {
+        for (String name : names) {
+            if (param.has(name)) {
+                p.put(name, "\"" + param.getString(name) + "\"");
+            }
+        }
+    }
+
+    /**
+     * Run Ages
+     *
+     * @param dsl
+     * @param options
+     * @throws Exception
+     */
+    public static void runAges(File dsl, File ws, PayloadParameter param,
+            ServiceResources res, SessionLogger LOG) throws Exception {
+
+        // Create/execute a Ages.
+        Executable p = createProcess(dsl, ws, param, res, LOG);
+        int result = p.exec();
+        if (result != 0) {
+            FilenameFilter ff = new WildcardFileFilter("java*stderr.txt", IOCase.INSENSITIVE);
+            File[] f = ws.listFiles(ff);
+            if (f != null && f.length > 0) {
+                String err = FileUtils.readFileToString(f[0]);
+                LOG.info("Ages execution error. " + f[0] + ":\n" + err);
+                throw new ServiceException("Ages execution error. " + f[0] + ":\n" + err);
+            }
+            throw new ServiceException("Ages execution error." + result);
+        }
+    }
+
+    /**
+     * Create the external Ages process.
+     */
+    public static Executable createProcess(File dsl, File ws,
+            PayloadParameter param, ServiceResources res, SessionLogger LOG) throws Exception {
+
+        Map<String, String> sysprops = new HashMap();
+        sysprops.put("oms_prj", ws.toString());
+        sysprops.put("csip_ages", res.getFile(ID_AGES_JAR).getParent());
+
+        String[] jvmOptions = Binaries.asSysProps(sysprops);
+        String options = param.getString(KEY_OPTIONS, "");
+        if (options != null && !options.isEmpty()) {
+            jvmOptions = (String[]) ArrayUtils.addAll(jvmOptions, options.split("\\s+"));
+        }
+
+        // java -Doms_prj=. -cp "dist/AgES.jar" oms3.CLI -l OFF -r "projects/sfir30/simulation/sfir30.sim"
+        return Binaries.getResourceOMSDSL(
+                dsl, // the dsl file to run
+                jvmOptions, // jvm options
+                ws, // workspace dir
+                Arrays.asList(res.getFile(ID_AGES_JAR)), // the ages jar file 
+                param.getString(KEY_LOGLEVEL, "INFO"), // The log level
+                LOG); // This session logger
+    }
+
+    private static final int FILE = 0;
+    private static final int TABLE = 1;
+    private static final int COLUMN = 2;
+
+    /**
+     *
+     * @param d
+     * @param workspace
+     * @param start
+     * @param end
+     * @return
+     * @throws IOException
+     */
+    public static double[] getData(String d, File workspace,
+            String start, String end) throws IOException {
+        if (d == null) {
+            throw new IllegalArgumentException("Missing data property: " + d);
+        }
+        String[] parts = DataIO.parseCsvFilename(d);
+        if (parts.length != 3) {
+            throw new IllegalArgumentException("invalid: " + d + " expected:: <file>/<table>/<column>");
+        }
+
 //    System.out.println(Arrays.toString(parts));
-    CSTable t = DataIO.table(new File(workspace, parts[FILE]), parts[TABLE]);
+        CSTable t = DataIO.table(new File(workspace, parts[FILE]), parts[TABLE]);
 
-    Date startDate = Conversions.convert(start, Date.class);
-    Date endDate = Conversions.convert(end, Date.class);
+        Date startDate = Conversions.convert(start, Date.class);
+        Date endDate = Conversions.convert(end, Date.class);
 
 //    System.out.println(startDate);
 //    System.out.println(endDate);
-    double[] vals = DataIO.getColumnDoubleValuesInterval(startDate, endDate, t,
-        parts[COLUMN], DataIO.DAILY);
+        double[] vals = DataIO.getColumnDoubleValuesInterval(startDate, endDate, t,
+                parts[COLUMN], DataIO.DAILY);
 
-    return vals;
-  }
+        return vals;
+    }
 
 //  static void d() throws IOException {
 //    CSProperties pr = DataIO.properties(new File("/od/projects/csip-all/csip-oms/tmp/data/main_params.csv"), "Parameter");
@@ -310,12 +355,11 @@
 //      System.out.println("\"" + string + "\",");
 //    }
 //  }
-
-  public static void main(String[] args) throws IOException {
-    // small test
-    double[] d = getData("obs_data02_14.csv/obs/orun[1]", new File("/tmp"), "2002-01-18", "2002-02-18");
-    System.out.println(Arrays.toString(d));
+    public static void main(String[] args) throws IOException {
+        // small test
+        double[] d = getData("obs_data02_14.csv/obs/orun[1]", new File("/tmp"), "2002-01-18", "2002-02-18");
+        System.out.println(Arrays.toString(d));
 //    d();
-  }
+    }
 
 }