GridmetV1_1.java [src/java/d/weather] Revision: default Date:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package d.weather;
import csip.Config;
import csip.ModelDataService;
import csip.api.client.ModelDataServiceCall;
import csip.api.server.ServiceException;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
//import csip.utils.CheckPointing;
import gisobjects.GISObject;
import gisobjects.GISObjectFactory;
import gisobjects.db.GISEngineFactory;
import java.io.PrintWriter;
import java.sql.Connection;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ws.rs.Path;
import m.ghg.ApplicationResources;
import static m.ghg.ApplicationResources.GISDB_SQLSVR;
import static m.ghg.ApplicationResources.GRIDMET_URL_KEY;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
@Name("DayCent Weather")
@Description("Provide Daycent weather input.")
@Path("d/weather/gridmet/1.1")
@Resource(from = ApplicationResources.class)
@Resource(from = soils.db.DBResources.class)
public class GridmetV1_1 extends ModelDataService {
// Request JSON name defines
static final String DEFAULT_DAYCENT_CLIMATE_FILE = "dayCentWeather.IN";
static final String WEATHER_FILE_KEY = "weather_file";
static final String WEATHER_DURATION_KEY = "weather_duration";
static final String STARTING_YEAR_KEY = "starting_year";
int weatherDuration;
int startingYear;
int endingYear;
JSONObject aoa_geometry;
static final String gridmetURL = Config.getString(GRIDMET_URL_KEY);
@Override
protected void preProcess() throws ServiceException {
if (gridmetURL == null) {
throw new ServiceException("gridmet service url not set!");
}
aoa_geometry = parameter().getJSON(soils.AoA.AOA_GEOMETRY);
weatherDuration = parameter().getInt(WEATHER_DURATION_KEY, 50);
startingYear = parameter().getInt(STARTING_YEAR_KEY, 2000);
endingYear = startingYear + weatherDuration;
}
@Override
protected void doProcess() throws Exception {
double[] latlon = {Double.NaN, Double.NaN};
// Get centroid of shape, if it is not a point already. (If it's a point, the centroid is the point)
try (Connection conn = resources().getJDBC(GISDB_SQLSVR)) {
GISObject shape = GISObjectFactory.createGISObject(aoa_geometry, GISEngineFactory.createGISEngine(conn));
// getLat/Lon functions get point value or the centroid of the shape.
latlon[0] = shape.getLatitude();
latlon[1] = shape.getLongitude();
}
if (Double.isNaN(latlon[0]) || Double.isNaN(latlon[1])) {
throw new ServiceException("Could not get the latitude and longitude of the AoI");
}
getClimateData(gridmetURL, latlon[0], latlon[1], weatherDuration);
toDaycentClimateInput();
// cp.check("conv");
// System.out.println(cp);
}
@Override
protected void postProcess() throws Exception {
results().put(workspace().getFile(DEFAULT_DAYCENT_CLIMATE_FILE), "DayCent weather file");
}
void getClimateData(String url, double lat, double lon, int years) throws Exception {
ModelDataServiceCall r = new ModelDataServiceCall()
.put("units", "metric")
.put("start_date", startingYear + "-01-01")
.put("end_date", endingYear + "-12-31")
// .put("duration", years)
.put("input_zone_features", aoa_geometry)
// .put("duration", years)
.put("input_zone_features", new JSONObject(
"{ 'type': 'FeatureCollection',"
+ " 'features': [{"
+ " 'type': 'Feature',"
+ " 'properties': {"
+ " 'name': 'loc',"
+ " 'gid': 1"
+ " },"
+ " 'geometry': {"
+ " 'type': 'Point',"
+ " 'coordinates': ["
+ " " + lon + "," + lat
+ " ]"
+ " }"
+ " }]"
+ "}"))
.withDefaultLogger()
.url(url)
.call();
if (r.serviceFinished()) {
r.download("1.json", workspace().getFile("loc.json"));
} else {
throw new ServiceException("Gridmet service error: " + r.getError());
}
}
void toDaycentClimateInput() throws Exception {
JSONArray a = new JSONArray(workspace().readString("loc.json"));
Integer doy_count = 1;
Integer oldyy = Integer.MIN_VALUE;
String prevTmax = "";
String prevTmin = "";
try (PrintWriter w = new PrintWriter(workspace().getFile(DEFAULT_DAYCENT_CLIMATE_FILE))) {
for (int i = 0; i < a.length(); i++) {
JSONArray row = a.getJSONArray(i);
String[] date = row.get(0).toString().split("-");
int dd = Integer.parseInt(date[2]);
int mm = Integer.parseInt(date[1]);
int yy = Integer.parseInt(date[0]);
if (yy > oldyy) {
doy_count = 1;
oldyy = yy;
}
String doy = doy_count.toString();
doy_count++;
String tmax = row.get(10).toString();
String tmin = row.get(9).toString();
if (Double.parseDouble(tmax) < Double.parseDouble(tmin)) {
if (prevTmax.isEmpty() || prevTmin.isEmpty()) {
String msg = "Need at least one iteration to initialize previous step tmax and tmin";
throw new NullPointerException(msg);
}
tmax = prevTmax;
tmin = prevTmin;
} else {
prevTmax = tmax;
prevTmin = tmin;
}
Double precip = Double.parseDouble(row.get(3).toString()) / 10; // precip in cm
Double rad = Double.parseDouble(row.get(7).toString()) / 0.484583; // W m-2 to Langleys/day
Double relhum = 0.5 * (Double.parseDouble(row.get(4).toString()) + Double.parseDouble(row.get(5).toString()));
if (relhum > 100.0) {
relhum = 100.0;
}
Double wind = Double.parseDouble(row.get(12).toString()) * 2.237; // m/s to mph
w.println(dd + " "
+ mm + " "
+ yy + " "
+ doy + " "
+ tmax + " "
+ tmin + " "
+ space4format(precip) + " "
+ space4format(rad) + " "
+ space4format(relhum) + " "
+ space4format(wind));
}
}
}
private String space4format(double value) {
DecimalFormat df1 = new DecimalFormat("0.00");
return String.format("%1$-4s", df1.format(value));
}
}