V1_0.java [src/java/m/oms/ages] Revision: 7eb475c4e68725e81a5e9eb85275c845eb000f77  Date: Fri Sep 10 15:12:50 MDT 2021
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.oms.ages;

import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Path;
import static m.oms.ages.V1_0.KEY_SCRIPT;
import static m.oms.ages.V1_0.KEY_SCRIPT_NP;
import static m.oms.ages.V1_0.KEY_SCRIPT_NP3;
import static m.oms.ages.V1_0.KEY_SCRIPT_NP30;
import static m.oms.ages.V1_0.KEY_SCRIPT_NP300;
import static m.oms.ages.V1_0.KEY_SCRIPT_NP3000;
import static m.oms.ages.V1_0.KEY_SCRIPT_NPBDCW;
import static m.oms.ages.V1_0.KEY_SCRIPT_NPEAGLE;
import static m.oms.ages.V1_0.KEY_SCRIPT_NPDRAKE58;
import ngmf.util.cosu.luca.of.NS;
import ngmf.util.cosu.luca.of.RMSE;
import ngmf.util.cosu.luca.of.TRMSE;
import ngmf.util.cosu.luca.of.NS2LOG;
import oms.utils.Utils;
import oms.utils.Utils.PBIAS;
import oms.utils.Utils.NSLOG1P;
import oms.utils.Utils.NSLOG2;
import oms.utils.Utils.KGE;
import oms3.ObjectiveFunction;

/**
 * Ages service.
 *
 * @author od
 */
@Name("AGES model execution")
@Description("OMS based AGES model service")
@VersionInfo("1.0")
@Path("m/ages/0.3.0")
@Polling(first = 5000, next = 4000)
@Resource(file = "/bin/ages/ages.jar", type = JAR, id = Utils.ID_AGES_JAR)
@Resource(file = "/bin/ages/ages-lib.zip", type = ARCHIVE)
@Resource(file = "/bin/ages/ages-static.zip", type = ARCHIVE)
@Resource(file = "java-*-std*.txt output/csip_run/out/*.csv", type = OUTPUT)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages.sim", type = REFERENCE, id = KEY_SCRIPT)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPL.sim", type = REFERENCE, id = KEY_SCRIPT_NP)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLSFIR3.sim", type = REFERENCE, id = KEY_SCRIPT_NP3)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLSFIR30.sim", type = REFERENCE, id = KEY_SCRIPT_NP30)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLSFIR300.sim", type = REFERENCE, id = KEY_SCRIPT_NP300)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLSFIR3000.sim", type = REFERENCE, id = KEY_SCRIPT_NP3000)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLBDCW.sim", type = REFERENCE, id = KEY_SCRIPT_NPBDCW)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLEAGLE.sim", type = REFERENCE, id = KEY_SCRIPT_NPEAGLE)
@Resource(file = "${csip.dir}/bin/ages/simulation/ages_noPLDRAKE58.sim", type = REFERENCE, id = KEY_SCRIPT_NPDRAKE58)
public class V1_0 extends ModelDataService {

    public static final String KEY_SCRIPT = "ages.sim";
    public static final String KEY_SCRIPT_NP = "ages_noPL.sim"; // no payload script
    public static final String KEY_SCRIPT_NP3 = "ages_noPLSFIR3.sim"; // no payload script
    public static final String KEY_SCRIPT_NP30 = "ages_noPLSFIR30.sim"; // no payload script
    public static final String KEY_SCRIPT_NP300 = "ages_noPLSFIR300.sim"; // no payload script
    public static final String KEY_SCRIPT_NP3000 = "ages_noPLSFIR3000.sim"; // no payload script
    public static final String KEY_SCRIPT_NPBDCW = "ages_noPLBDCW.sim"; // no payload script
    public static final String KEY_SCRIPT_NPEAGLE = "ages_noPLEAGLE.sim"; // no payload script
    public static final String KEY_SCRIPT_NPDRAKE58 = "ages_noPLDRAKE58.sim"; // no payload script
    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 CAL_STARTTIME = "cal_startTime";
    public static final String CAL_ENDTIME = "cal_endTime";

    public static final String PAYLOAD = "payload";
    public static final String PROJECT = "project";

    static final Map<String, ObjectiveFunction> OF = new HashMap<>();

    public String data_folder = "";
    boolean payLoad = false;

    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",
        "baseDepth",
        "BetaW",
        "Beta_min",
        "Beta_rsd",
        "DCAdaptation",
        "FCAdaptation",
        "Ksink",
        "LExCoef",
        "N_delay_RG1",
        "N_delay_RG2",
        "a_rain",
        "a_snow",
        "angstrom_a",
        "angstrom_b",
        "baseTemp",
        "calib_clat_fact",
        "ccf_factor",
        "cn_froz",
        "icn",
        "r2adj",
        "fcimp",
        "meanCNFactor",
        "meanKfFactor",
        "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",
        "kf_fact",
        "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",
        "loadStateFilePath",
        "dataStartTime",
        "dataEndTime"
    };

    @Override
    public void doProcess() throws Exception {
        LOG.info("===>  Running AgES ");

        payLoad = parameter().getBoolean(PAYLOAD, false);

        String project = parameter().getString(PROJECT, "SFIR3");
        String dsl = parameter().getString(KEY_SCRIPT,
                resources().getFile(KEY_SCRIPT).toString());

        if (!payLoad) {
            dsl = parameter().getString(KEY_SCRIPT_NP,
                    resources().getFile(KEY_SCRIPT_NP).toString());
            if (!project.isEmpty()) {
                if (project.equals("SFIR3")) {
                    dsl = parameter().getString(KEY_SCRIPT_NP3,
                            resources().getFile(KEY_SCRIPT_NP3).toString());
                }
                if (project.equals("SFIR30")) {
                    dsl = parameter().getString(KEY_SCRIPT_NP30,
                            resources().getFile(KEY_SCRIPT_NP30).toString());
                }
                if (project.equals("SFIR300")) {
                    dsl = parameter().getString(KEY_SCRIPT_NP300,
                            resources().getFile(KEY_SCRIPT_NP300).toString());
                }
                if (project.equals("SFIR3000")) {
                    dsl = parameter().getString(KEY_SCRIPT_NP3000,
                            resources().getFile(KEY_SCRIPT_NP3000).toString());
                }
                if (project.equals("BDCW")) {
                    dsl = parameter().getString(KEY_SCRIPT_NPBDCW,
                            resources().getFile(KEY_SCRIPT_NPBDCW).toString());
                }
                if (project.equals("EAGLE")) {
                    dsl = parameter().getString(KEY_SCRIPT_NPEAGLE,
                            resources().getFile(KEY_SCRIPT_NPEAGLE).toString());
                }
                if (project.equals("DRAKE58")) {
                    dsl = parameter().getString(KEY_SCRIPT_NPDRAKE58,
                            resources().getFile(KEY_SCRIPT_NPDRAKE58).toString());
                }
            }
        }

        data_folder = project;

        // 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 namee : parameter().getNames()) {
            for (String ofNameM : getRequestedObjfunc(OF.keySet())) {
                if (namee.toLowerCase().startsWith(ofNameM) || namee.equals(ofNameM)) {
                    String[] data = parameter().getStringArray(namee);
                    double v = calc_of(OF.get(ofNameM), data[0], data[1], cal_start, cal_end);
                    results().put(namee, v);
                }
            }
        }
    }

    private List<String> getRequestedObjfunc(Set<String> names) {
        List<String> l = new ArrayList<>();
        for (String ofName : names) {
            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 = null;
        if (!payLoad) {
            String new_string = "/tmp/csip/bin/ages/data/" + data_folder;
            obsData = Utils.getData(obs, new File(new_string), start, end);
        } else {
            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);
        double result = of.calculate(obsData, simData, parameter().getDouble("missing", -9999d));
        return checkForNaN(result);
    }

    public static double checkForNaN(double result) {
        double checkedResult = -999.0;
        if (!Double.isNaN(result)) {
            checkedResult = result;
        }
        return checkedResult;
    }

}