V5_0.java [src/java/m/prms/model] Revision: default Date:
package m.prms.model;
import csip.api.server.Executable;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import java.io.File;
import java.io.FileWriter;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.ws.rs.Path;
import m.prms.model.Utils.*;
import org.apache.commons.io.FileUtils;
import static m.prms.model.V5_0.PRMS5_EXE;
import ngmf.util.cosu.luca.of.NS;
import ngmf.util.cosu.luca.of.NS2LOG;
import ngmf.util.cosu.luca.of.RMSE;
import ngmf.util.cosu.luca.of.TRMSE;
import oms3.Conversions;
import oms3.ObjectiveFunction;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
/**
* PRMS Service. Execution of the original PRMS model.
*
* @author od
*/
@Name("PRMS")
@Description("Precipitation Runoff Modeling System.")
@State(State.UNSTABLE)
@Author(org = "USGS")
@Author(org = "CSU")
@Category("Hydrology")
@Path("m/prms/5.0")
@Polling(first = 5000, next = 2000)
@Resource(type = EXECUTABLE, file = "/bin/lin-amd64/prms-5.0", id = PRMS5_EXE)
@Resource(type = OUTPUT, file = "*-stdout.txt *-stderr.txt recharge.* output/*.statvar")
public class V5_0 extends ModelDataService {
static final String PRMS5_EXE = "prms";
// static final String CONTROL_FILE_VM = "m/prms/model/control_1.vm";
static final String CONTROL_FILE_VM = "m/prms/model/animas-PRMS.control";
static final String PARAM_FILE_VM = "m/prms/model/animas5test.params";
private static VelocityEngine velocity;
Calendar st;
Calendar en;
static final Map<String, ObjectiveFunction> OF = new HashMap<>();
double missing;
// parameter to calibrate
double den_max;
double cecn_coef;
double jh_coef;
double rain_cbh_adj;
double snow_cbh_adj;
double tmax_allsnow;
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());
}
@Override
protected void doProcess() throws Exception {
missing = parameter().getDouble("missing", -9999d);
// Parameter
den_max = parameter().getDouble("den_max", 0.6); // range 0.4-0.7
cecn_coef = parameter().getDouble("cecn_coef", 0.782); // range 0.6 - 1.0
jh_coef = parameter().getDouble("jh_coef", 0.007); // range 0.004 - 0.014
rain_cbh_adj = parameter().getDouble("rain_cbh_adj", 1.0); // range 0.8 - 1.5
snow_cbh_adj = parameter().getDouble("snow_cbh_adj", 1.3); // range 0.8 - 1.5
tmax_allsnow = parameter().getDouble("tmax_allsnow", 36.0); // range 28.0 - 37.0
createControlFile(workspace().getFile("run.control"));
createParamFile(workspace().getFile("run.params"));
workspace().getFile("output").mkdirs();
Executable e = resources().getExe(PRMS5_EXE);
e.setArguments("run.control");
int ret = e.exec();
if (ret != 0)
throw new ServiceException("Error executing prms: "
+ FileUtils.readFileToString(e.stderr(), "UTF-8"));
for (String pname : parameter().getNames()) {
for (String ofNameM : OF.keySet()) {
if (pname.toLowerCase().startsWith(ofNameM)) {
String[] data = parameter().getStringArray(pname);
double v = calc_of(OF.get(ofNameM), data[0], data[1], st, en);
results().put(pname, v);
if (LOG.isLoggable(Level.INFO))
LOG.info("of: " + pname + " " + v);
}
}
}
// cleanup files even before the workspace get's wiped.
Arrays.stream(workspace().getFiles("*.cbh")).forEach(f -> f.delete());
}
private double calc_of(ObjectiveFunction of, String obs,
String sim, Calendar start, Calendar end) throws Exception {
// get observed data
// e.g. obs_data02_14.csv/obs/orun[1]
String o[] = obs.split("\\s+");
double[] obsData = o[0].endsWith("csv")
? Utils.extractCSVColumn(workspace().getFile(o[0]), o[1], 1)
: Utils.extractStatvarColumn(workspace().getFile(o[0]), o[1]);
// e.g. output/csip_run/out/Outlet.csv/output/catchmentSimRunoff
String s[] = sim.split("\\s+");
double[] simData = s[0].endsWith("csv")
? Utils.extractCSVColumn(workspace().getFile(s[0]), s[1], 1)
: Utils.extractStatvarColumn(workspace().getFile(s[0]), s[1]);
double result = of.calculate(obsData, simData, missing);
return checkForNaN(result);
}
double checkForNaN(double result) {
double checkedResult = missing;
if (!Double.isNaN(result))
checkedResult = result;
return checkedResult;
}
void createControlFile(File controlfile) throws Exception {
st = Conversions.convert(parameter().getString("start_time"), Calendar.class);
en = Conversions.convert(parameter().getString("end_time"), Calendar.class);
VelocityContext context = new VelocityContext();
context.put("service", this);
FileWriter w = new FileWriter(controlfile);
_velocity().getTemplate(CONTROL_FILE_VM, "UTF-8").merge(context, w);
w.close();
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Created: " + context);
LOG.fine("\n" + FileUtils.readFileToString(controlfile, "UTF-8"));
}
}
void createParamFile(File paramfile) throws Exception {
VelocityContext context = new VelocityContext();
context.put("param", this);
FileWriter w = new FileWriter(paramfile);
_velocity().getTemplate(PARAM_FILE_VM, "UTF-8").merge(context, w);
w.close();
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Created: " + context);
LOG.fine("\n" + FileUtils.readFileToString(paramfile, "UTF-8"));
}
}
static synchronized VelocityEngine _velocity() {
if (velocity == null) {
velocity = new VelocityEngine();
velocity.setProperty("file.resource.loader.class",
ClasspathResourceLoader.class.getName());
velocity.setProperty("runtime.log", "/tmp/velocity.log");
velocity.init();
}
return velocity;
}
//parameter
public double getDen_max() {
return den_max;
}
public double getCecn_coef() {
return cecn_coef;
}
public double getJh_coef() {
return jh_coef;
}
public double getRain_cbh_adj() {
return rain_cbh_adj;
}
public double getSnow_cbh_adj() {
return snow_cbh_adj;
}
public double getTmax_allsnow() {
return tmax_allsnow;
}
///////// for velocity
public int getStartYear() {
return st.get(Calendar.YEAR);
}
public int getStartMonth() {
return st.get(Calendar.MONTH) + 1;
}
public int getStartDay() {
return st.get(Calendar.DAY_OF_MONTH);
}
public int getEndYear() {
return en.get(Calendar.YEAR);
}
public int getEndMonth() {
return en.get(Calendar.MONTH) + 1;
}
public int getEndDay() {
return en.get(Calendar.DAY_OF_MONTH);
}
}