V1_0.java [src/java/m/swatc] Revision: default Date:
/*
* $Id:$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API, and application suite.
*
* 2012-2023, OMSLab, Colorado State University.
*
* OMSLab licenses this file to you under the MIT license.
* See the LICENSE file in the project root for more information.
*/
package m.swatc;
import csip.Config;
import csip.ModelDataService;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
import csip.annotations.ResourceType;
import static csip.annotations.ResourceType.OUTPUT;
import csip.api.client.ModelDataServiceCall;
import csip.api.server.Executable;
import csip.api.server.ServiceException;
import csip.utils.Parallel;
import csip.utils.PayloadCache;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.Path;
import static m.swatc.V1_0.SWATC_EXE;
import org.apache.commons.io.FileUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
/**
*
* @author sidereus
*/
@Name("SWAT-C model edge of field")
@Description("Model run")
@Path("m/swatc/1.0")
@Resource(type = ResourceType.EXECUTABLE, file = "/bin/swatc_1.0", id = SWATC_EXE)
@Resource(type = OUTPUT, file = "*-std*.* output*.* *.txt *.out")
public class V1_0 extends ModelDataService {
static final int connTimeout
= Config.getInt("swat.conn.timeout", 4000);
static final int readTimeout
= Config.getInt("swat.read.timeout", 4000);
static final boolean serialdataFetch
= Config.getBoolean("swatc.serial.datafetch", false);
static final String swatplus_cligen_URL
= Config.getString("swatplus.cligen", "http://csip.engr.colostate.edu:8088/csip-climate/d/swatplus/1.0");
static final String swatc_soil_URL
= Config.getString("swatc.soil.service", "http://csip.engr.colostate.edu:8088/csip-soils/d/swatc/1.0");
static final String SWATC_EXE = "swatc1.0";
// cache must be static.
static PayloadCache soilsCache = new PayloadCache().withSize(64);
static PayloadCache climateCache = new PayloadCache().withSize(64);
@Override
public void doProcess() throws ServiceException, Exception {
double latitude = parameter().getDouble("latitude");
double longitude = parameter().getDouble("longitude");
String cokey = parameter().getString("cokey");
int startYear = parameter().getInt("start_year");
int simulationYears = parameter().getInt("simulation_years");
Parallel.run(serialdataFetch,
() -> {
fetchClimate(longitude, latitude, startYear, simulationYears);
},
() -> {
fetchSoil(cokey);
}
);
Executable p = resources().getExe(SWATC_EXE);
int ret = p.exec();
if (ret != 0) {
File errf = p.stderr();
String err = "";
if (errf.exists() && errf.length() > 0)
err = FileUtils.readFileToString(errf, "utf-8");
throw new ServiceException("Error running SWATC: " + ret + "\n" + err);
}
}
@Override
protected void postProcess() throws Exception {
// File zip = ZipFiles.zip(new File(workspace().getDir().getAbsolutePath()));
// results().put(zip);
}
private void fetchClimate(double longitude, double latitude, int startYear, int simulationYears) throws Exception {
ModelDataServiceCall res = new ModelDataServiceCall()
.put("longitude", longitude)
.put("latitude", latitude)
.put("startyear", startYear)
.put("duration", simulationYears)
.url(swatplus_cligen_URL)
.withCache(climateCache)
.withDefaultLogger()
.call();
if (res.serviceFinished()) {
List<WeatherData> wd = new ArrayList();
double elevation = writeClimateData(res, wd);
writeAll(wd, simulationYears, latitude, longitude, elevation);
} else {
throw new ServiceException(res.getError());
}
}
private void fetchSoil(String cokey) throws Exception {
ModelDataServiceCall res = new ModelDataServiceCall()
.put("cokey", cokey)
.url(swatc_soil_URL)
.withCache(soilsCache)
.withDefaultLogger()
.call();
if (res.serviceFinished()) {
String fileName = "hru1.sol";
res.download(fileName, workspace().getFile(fileName));
} else {
throw new ServiceException(res.getError());
}
}
private double writeClimateData(ModelDataServiceCall map, List<WeatherData> wd) {
try {
double elevation = map.getDouble("elevation");
// JSONArray data_template = map.getJSONArray("data_template"); to use for weatherdata
JSONArray data_array = map.getJSONArray("data");
for (int i = 0; i < data_array.length(); i++) {
wd.add(new WeatherData(data_array.getJSONArray(i)));
}
return elevation;
} catch (JSONException ex) {
throw new RuntimeException(ex.getMessage());
}
}
private void writeAll(List<WeatherData> wd, int simulationYears, double latitude, double longitude, double elevation) throws IOException {
String headPcp = "Swatc Daily Precipitation Data File" + "\n"
+ String.format("%-7s", "lat :") + String.format("%5s", latitude) + "\n"
+ String.format("%-7s", "lon :") + String.format("%5s", longitude) + "\n"
+ String.format("%-7s", "elev :") + String.format("%5d", (int) elevation);
String headTmp = "Swatc Daily Temperature Data File" + "\n"
+ String.format("%-7s", "lat :") + String.format("%10s", latitude) + "\n"
+ String.format("%-7s", "lon :") + String.format("%10s", longitude) + "\n"
+ String.format("%-7s", "elev :") + String.format("%10s", (int) elevation);
/*
* String head = "nbyr" + String.format("%10s", "tstep") +
* String.format("%10s", "lat") + String.format("%10s", "lon") +
* String.format("%10s", "elev");
*
*
* String head_vals = String.format("%4s", simulationYears) +
* String.format("%10s", "0") + String.format("%10s", latitude) +
* String.format("%10s", longitude) + String.format("%10s", elevation);
*/
try (PrintWriter pw = new PrintWriter(
Files.newBufferedWriter(workspace().getFile("tmp.cli").toPath()))) {
pw.println(headTmp);
//pw.println(head_vals);
wd.stream().forEachOrdered(s -> s.writeTemp(pw));
}
try (PrintWriter pw = new PrintWriter(
Files.newBufferedWriter(workspace().getFile("wnd.cli").toPath()))) {
pw.println("Swatc Wind Velocity Data File");
//pw.println(head_vals);
wd.stream().forEachOrdered(s -> s.writeWindSpeed(pw));
}
try (PrintWriter pw = new PrintWriter(
Files.newBufferedWriter(workspace().getFile("slr.cli").toPath()))) {
pw.println("Swatc Solar Radiation Data File");
//pw.println(head_vals);
wd.stream().forEachOrdered(s -> s.writeSolar(pw));
}
try (PrintWriter pw = new PrintWriter(
Files.newBufferedWriter(workspace().getFile("pcp.cli").toPath()))) {
pw.println(headPcp);
//pw.println(head_vals);
wd.stream().forEachOrdered(s -> s.writePrecip(pw));
}
try (PrintWriter pw = new PrintWriter(
Files.newBufferedWriter(workspace().getFile("hmd.cli").toPath()))) {
pw.println("Swatc Relative Humidity Data File");
//pw.println(head_vals);
wd.stream().forEachOrdered(s -> s.writeRH(pw));
}
}
static class WeatherData {
float precp;
float tmax;
float tmin;
float rh;
float rad;
float w_vl;
String date;
DecimalFormat df = new DecimalFormat("#.#####");
WeatherData(JSONArray tmp) {
int year;
int day;
try {
year = Integer.parseInt(tmp.getString(0));
day = Integer.parseInt(tmp.getString(1));
this.precp = Float.parseFloat(tmp.getString(2));
this.rad = Float.parseFloat(tmp.getString(3));
this.tmax = Float.parseFloat(tmp.getString(4));
this.tmin = Float.parseFloat(tmp.getString(5));
this.w_vl = Float.parseFloat(tmp.getString(6));
this.rh = Float.parseFloat(tmp.getString(7));
} catch (JSONException ex) {
throw new RuntimeException(ex.getMessage());
}
date = buildDate(year, day);
}
private String buildDate(int year, int day) {
return year + String.format("%3s", df.format(day));
}
void writePrecip(PrintWriter pw) {
pw.println(date + String.format("%5.1f", precp));
}
void writeTemp(PrintWriter pw) {
pw.println(date
+ String.format("%5.1f", tmax)
+ String.format("%5.1f", tmin));
}
void writeRH(PrintWriter pw) {
pw.println(date + String.format("%8.3f", rh));
}
void writeWindSpeed(PrintWriter pw) {
pw.println(date + String.format("%8.3f", w_vl));
}
void writeSolar(PrintWriter pw) {
pw.println(date + String.format("%8.3f", rad));
}
}
}