WEPPManagement.java [src/java/m/wepp] Revision: Date:
package m.wepp;
import csip.SessionLogger;
import csip.utils.Parallel;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import util.WEPPUtils;
import util.WeppConstants;
/**
* This class represents one management section on a hillslope. The management
* is composed of a list of operations (LMODOperation class). The output is the
* .rot files that are read by the c++ wepphillslopeserv program.
*
* @author jrf
*/
public class WEPPManagement {
public static final String DEFAULT_NAME = "wepp";
public static final String DEFAULT_EXT = ".rot";
public static final int MAX_LINE_LENGTH = 256;
public static final double LITER_TO_GAL = 0.264172;
public static final double HECTA_TO_ACRE = 2.47105;
float fuelTotal = 0;
float stirTotal = 0;
int rotYears = 0;
String description;
String name;
LMODWeppData dbs;
String initialCondFile;
String initialCondPlant;
String initialKey = "Default";
String version;
File defAnnualCrop;
File defPerennialCrop;
File defWoodySettings;
boolean crlmod31_format;
boolean hasIntervalsDefined = false;
String tranErrors = "";
WEPPModel wm;
boolean use_CRLMOD;
SessionLogger LOG;
List<LMODOperation> lmodOperations;
JSONObject debugData;
String initialConditionCrop;
/**
* Create a WEPP management instance.
*
* @param wm lower level WEPP functions.
* @param log access to CSIP LOG file
* @param debugData string of overrides
* @param use_CRLMOD whether CRLMOD data should be assumed.
*/
WEPPManagement(WEPPModel wm, SessionLogger log, JSONObject debugData,
boolean use_CRLMOD, String cropsURL, String operationsURL, String residueURL, String version) {
this.LOG = log;
this.wm = wm;
this.use_CRLMOD = use_CRLMOD;
this.debugData = debugData;
this.version = version;
lmodOperations = new ArrayList<>();
description = "WEPP file translated from LMOD.";
initialConditionCrop = "???";
dbs = new LMODWeppData(debugData, LOG, cropsURL, operationsURL, residueURL, version);
crlmod31_format = true;
if (cropsURL.endsWith("/2.0") || cropsURL.endsWith("/3.0")) {
crlmod31_format = false;
}
}
/**
* A general validation function, called on the Rotation before saving and
* exporting it to JSON. This function should check whether pointer names are
* correct, and dates are all valid and in-order.
*/
public void validate() {
}
/**
* Get any errors generated from this management.
*
* @return string of error messages
*/
public String getErrors() {
return tranErrors;
}
/**
* Creates the WEPP .rot file.
*
* @param rotFile Where to write data
* @return ROT file
* @throws IOException any errors creating file.
*/
public File getNativeFile(File rotFile) throws IOException {
writeROT(rotFile);
return rotFile;
}
/**
* Check all operations for processes that could be used in a crop calibration
* and mark the associated vegetation.
*
*/
private void markVegsToCal() {
for (LMODOperation op : lmodOperations) {
// check if operation has a process for harvest
if (op.hasCalRelatedProcess()) {
// get veg key
String harvPlant = op.getHarVegKey();
if (harvPlant != null) {
dbs.setVegHarvest(harvPlant, true);
}
}
}
}
/**
* Write the crop section of the .rot file. This is a list of crops with their
* parameters.
*
* @param writer where to write data to
*/
private void writeCropDB(PrintWriter writer) {
markVegsToCal();
String recs = dbs.printVegs();
writer.print(recs);
}
/**
* Write the operation section of the .rot file. This is a list of operations
* with their parameters.
*
* @param writer where to write data to
*/
private void writeOpDB(PrintWriter writer) {
String recs = dbs.printOps();
writer.print(recs);
}
/**
* Write the contour section of the .rot file. This is a list of contouring
* records and the parameters.
*
* @param writer where to write the data to
*/
private void writeContourDB(PrintWriter writer) {
String recs = dbs.printContours();
writer.print(recs);
writer.print("\n");
}
/**
* Write the residue section of the .rot file. This is a list of the residues
* used by this management and the parameters.
*
* @param writer where to write the data to.
*/
private void writeResidueDB(PrintWriter writer) {
String recs = dbs.printResidues();
writer.print(recs);
writer.print("\n");
}
/**
* Writes out initial condition section of the .rot file. The data written is
* a string of initial condition lines that was read from a template file.
*
* @param writer where to write the data to.
*/
private void writeInitialCondDB(PrintWriter writer) {
writer.print(initialCondFile);
writer.print("\n");
}
/**
* Write out the irrigation records if this management has irrigation.
*
* @param writer where to write the data to
* @param ty type of irrigation.
*/
private void writeIrrDB(PrintWriter writer, int ty) {
int count = dbs.getIrrCount(ty);
if (count > 0) {
String recs = dbs.printIrrs(ty);
writer.print(recs);
}
}
/**
* Adds contouring to the output .rot file
*
* @param writer where to write data to
* @param year year that contouring applies to
*/
private void insertContour(PrintWriter writer, int year) {
int mon = 1;
int day = 2;
String key = "CONT1";
String stl = String.format("%4d %2d %2d 1 Start-Contour\tContourDef.%s {}\n", mon, day, year, key);
writer.print(stl);
}
/**
* Adds irrigation to the output .rot file
*
* @param writer where to write data to
* @param year year this irrigation applies to
* @param key irrigation record key
*/
private void insertIrrigation(PrintWriter writer, int year, String key, int endday, int endyear) {
int mon = 1;
int day = 2;
String stl = String.format("%4d %2d %2d 1 Start-Irrigation\tIrrDef.%s {%d, %d}\n", mon, day, year, key, endday, endyear);
writer.print(stl);
}
/**
*
* Writes out the rotation file that the WEPP file builder program can
* process. This contains the final WEPP operation sequences along with all
* parameters.
*
* @param out output
* @throws IOException if content could not write out successfully.
*
*/
public void writeROT(File out) throws IOException {
validate();
try (PrintWriter writer = new PrintWriter(out)) {
writer.println("#");
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss aa yyyy");
writer.println("# WEPP rotation saved on: " + formatter.format(date));
writer.println("#");
writer.println("# File created by Java WEPP libraries");
writer.println("#");
//writer.println("# --- Original LMOD sequence ---");
writer.println("# --- Translated LMOD sequence ---");
int lastYear = 1;
fuelTotal = 0;
stirTotal = 0;
String curCrop = markGrowingPeriods();
markSinglePlant();
for (int i = 0; i < lmodOperations.size(); i++) {
LMODOperation lm = lmodOperations.get(i);
String st = lm.toString();
st = st.replace("\n", "\n# ");
writer.println("# " + st);
fuelTotal = fuelTotal + lm.getFuel();
stirTotal = stirTotal + lm.getSTIR();
lastYear = lm.getYear();
writer.printf("# Fuel=%f STIR=%f%n", (lm.getFuel() * LITER_TO_GAL) / (HECTA_TO_ACRE), lm.getSTIR());
}
writer.printf("# Total Fuel = %f%n", (fuelTotal * LITER_TO_GAL) / (HECTA_TO_ACRE));
writer.printf("# Total STIR = %f%n", stirTotal);
fuelTotal = fuelTotal / (float) lastYear;
stirTotal = stirTotal / (float) lastYear;
writer.printf("# Management Years = %d%n", lastYear);
writer.printf("Version = 2014.1%n");
writer.printf("Name = %s%n", name);
writer.println("Description {");
writer.println(description);
writer.println("}");
writer.printf("Color = 255 0 0%n");
writer.printf("LandUse = 1%n");
writer.printf("FuelUsage = %f%n", (fuelTotal * LITER_TO_GAL) / HECTA_TO_ACRE);
writer.printf("STIR = %f%n", stirTotal);
if (dbs.getVegCount() > 0) {
writer.println("CropDB {");
writeCropDB(writer);
writer.println("}");
}
writer.println();
writer.println("OperationsDB {");
writeOpDB(writer);
writer.println("}");
writer.println();
if (dbs.getResCount() > 0) {
writer.println("ResidueDB {");
writeResidueDB(writer);
writer.println("}");
}
if (dbs.getContCount() > 0) {
writer.println("ContourDB {");
writeContourDB(writer);
writer.println("}");
writer.println();
}
if (dbs.getIrrCount(0) > 0) {
writer.println("IrrigationDB {");
writeIrrDB(writer, 0);
writer.println("}");
}
if (dbs.getIrrCount(1) > 0) {
writer.println("DailyIrrDB {");
writeIrrDB(writer, 1);
writer.println("}");
}
writer.println("InitialConditionsDB {");
writeInitialCondDB(writer);
writer.println("}");
writer.println();
writer.println();
if (version.equals("2") || version.equals("3") || version.equals("3.1")) {
writer.printf("InitialConditions = IniCropDef.%s", initialKey);
} else {
int seneday;
String initCropKey;
seneday = dbs.getSenescenceDay(initialConditionCrop);
if (seneday > 0) {
writer.printf("InitialConditions = IniCropDef.%s {0.0 , %d}", initialKey, seneday);
} else {
writer.printf("InitialConditions = IniCropDef.%s", initialKey);
}
}
writer.println();
writer.println("Operations {");
int curYear = -1;
boolean firstTime = true;
boolean irrigationActive = false;
String irrigationKey = "";
int lastIrrYear = curYear;
int currentIndex = 0;
for (LMODOperation op : lmodOperations) {
if ((curYear != op.getYear() || firstTime) && ((dbs.getContCount() > 0))) {
if (firstTime) {
firstTime = false;
}
if (dbs.getContCount() > 0) {
insertContour(writer, op.getYear());
}
}
/*
if ((curYear != op.getYear()) && (irrigationActive)) {
if (lastIrrYear != -1) {
for (int k=lastIrrYear+1;k<=op.getYear();k++) {
insertIrrigation(writer, k, irrigationKey);
}
} else {
insertIrrigation(writer, op.getYear(), irrigationKey);
}
lastIrrYear = op.getYear();
}
*/
curCrop = op.getCurCrop(curCrop);
if (op.hasProcess("irrigation")) {
// depletion irrigation, look for when this ends
irrigationActive = true;
irrigationKey = op.getIrrigationKey();
int endday,endyear;
endday = endyear = 0;
int lastday, lastyear;
lastday = lastyear = 0;
LMODOperation op2;
for (int k=currentIndex;k<lmodOperations.size();k++) {
op2 = lmodOperations.get(k);
if (op2.hasProcess("irrigation-stop")) {
endday = op2.getJulianDay();
endyear = op2.getYear();
break;
} else {
lastday = op2.getJulianDay();
lastyear = op2.getYear();
}
}
if ((endday == 0) && (endyear == 0)) {
// not ending stop irrigation, use date of last operation
endday = lastday;
endyear = lastyear;
}
insertIrrigation(writer, op.getYear(), irrigationKey, endday, endyear);
} else {
String oline = op.toOpString(curCrop);
if (oline.isEmpty() == false) {
if (version.equals("2") || version.equals("3") || version.equals("3.1")) {
writer.print(oline);
} else {
if (!op.isPerennialMaturePlant()) {
writer.print(oline);
}
}
}
}
/*
if (op.hasProcess("irrigation")) {
irrigationActive = true;
irrigationKey = op.getIrrigationKey();
}
if (op.hasProcess("irrigation-stop")) {
irrigationActive = false;
irrigationKey = "";
}
*/
if (curYear != op.getYear()) {
lastIrrYear = curYear;
curYear = op.getYear();
}
currentIndex++;
}
writer.println("}");
}
}
/**
* TBD
*
*/
private void markSinglePlant() {
List<LMODOperation> remlist = new ArrayList<>();
String vkey = null;
for (LMODOperation op : lmodOperations) {
boolean startGrowth = op.hasProcess("plant");
if (startGrowth) {
vkey = op.getVegKey();
if (dbs.isPerennial(vkey)) {
// need plant operation to pass senescence date along, the
// default is 0 so not needed and can be removed.
if (dbs.getSenescenceDay(vkey) > 0) {
return;
}
for (int i = 0; i < remlist.size(); i++) {
if (!vkey.equals(remlist.get(i).getVegKey())) {
// this means there are different perennial plants, so keep
return;
}
}
remlist.add(op);
}
}
if (op.hasStopGrowthProcess(vkey)) {
return;
}
}
for (int i = 0; i < remlist.size(); i++) {
remlist.get(i).deletePlantProcess = true;
}
}
/**
* Go through all the operations and indicate where crop growth starts and
* ends.
*
* @return current crop growing at end of rotation
*/
private String markGrowingPeriods() {
boolean cropGrowing = false; // assume no crop growing.
// need to do this twice in case there is a winter annual that is planted
// at the end so growth wraps around to beginning.
String curCrop = "";
for (int i = 0; i < 2; i++) {
for (LMODOperation op : lmodOperations) {
boolean startGrowth = op.hasProcess("plant");
boolean endGrowth = op.hasStopGrowthProcess(curCrop);
//curCrop = op.getCurCrop(curCrop);
if ((startGrowth == false) && (cropGrowing == false)) {
op.setCropGrowing(false);
} else if ((startGrowth == true) && (endGrowth == true)) {
cropGrowing = true;
op.setCropGrowing(true);
op.setIncludeKill(true); // this assumes there is a kill-crop followed by
// a next-day followed by a planting
} else if ((startGrowth == true) && (endGrowth == false)) {
cropGrowing = true;
op.setCropGrowing(true);
} else if (endGrowth == true) {
if (cropGrowing) {
op.setIncludeKill(true);
}
op.setCropGrowing(false);
cropGrowing = false;
}
if (cropGrowing == true) {
op.setCropGrowing(true);
}
if (op.hasCalRelatedProcess()) {
op.setVegIfEmpty(curCrop);
}
curCrop = op.getCurCrop(curCrop);
}
}
return curCrop;
}
/**
* Converts CRLMOD JSON blob into an internal structure.
*
* @param baseCRLMODObject starting CRLMOD object
* @return new representation as a string
* @throws IOException if any
* @throws ParseException if any
* @throws JSONException if any
*/
protected String parseDataCSIPCRLMOD(JSONObject baseCRLMODObject) throws
IOException, ParseException, JSONException {
String newdata = "";
String name;
try {
JSONArray ev0 = baseCRLMODObject.getJSONArray("events");
JSONArray events = ev0.getJSONArray(0);
List<String> dates = new ArrayList<>();
List<String> ids = new ArrayList<>();
List<String> ops = new ArrayList<>();
List<String> vegs = new ArrayList<>();
List<Integer> veg_ids = new ArrayList<>();
List<Integer> yields = new ArrayList<>();
List<String> yieldUnits = new ArrayList<>();
List<String> residues = new ArrayList<>();
List<Integer> res_ids = new ArrayList<>();
List<Integer> res_amts = new ArrayList<>();
List<Boolean> intervals = new ArrayList<>();
//LOG.info("Looking at events:\n");
int yearBase = 1;
for (int i = 0; i < events.length(); i++) {
JSONObject ev = events.optJSONObject(i);
//LOG.info("Event Object: " + ev.toString());
String datestr = ev.getString("date");
String parts[] = datestr.split("-");
int yr = Integer.parseInt(parts[0]);
// WEPP expects years 1..N If we see a very large number it probably means that
// actual years are being sent, like 1986 2017. In this case adjust the years
// so they start at year 1. Note: that in a regular WEPP year numbers (1..N) the beginning
// years can be fallow, when real year values are sent no beginning fallow can be specified.
if (yr > 1000) {
if (i == 0) {
yearBase = yr;
}
yr = (yr - yearBase) + 1;
datestr = String.format("%04d", yr) + "-" + parts[1] + "-" + parts[2];
}
dates.add(datestr);
JSONObject op = ev.getJSONObject("operation");
String idstr = op.getString("id");
ids.add(idstr);
String namestr = op.getString("name");
ops.add(namestr);
double yld = 0;
double resa = 0;
if (!crlmod31_format) {
yld = ev.optDouble("yield");
resa = ev.optDouble("res_added");
}
JSONObject crop = ev.optJSONObject("crop");
if (crop != null) {
String id = crop.getString("id");
if (id.equals("")) {
vegs.add(null);
veg_ids.add(null);
yields.add(null);
yieldUnits.add(null);
} else {
if (crlmod31_format) {
yld = crop.optDouble("yield");
}
vegs.add(crop.getString("name"));
veg_ids.add(Integer.parseInt(crop.getString("id")));
String yunit = crop.getString("yieldUnit");
if (yunit == null) {
yieldUnits.add("???");
} else {
yieldUnits.add(yunit);
}
if (Double.isNaN(yld)) {
try {
int cyld = crop.getInt("defaultYield");
yields.add(cyld);
} catch (Exception e) {
// there is no yield or default value specified -
LOG.severe("Yield missing on: " + datestr);
}
} else {
yields.add((int) yld);
}
}
} else {
vegs.add(null);
veg_ids.add(null);
yields.add(null);
yieldUnits.add(null);
}
JSONObject res = ev.optJSONObject("residue");
if (res != null) {
String id = res.getString("id");
if (id.equals("")) {
res_ids.add(null);
residues.add(null);
res_amts.add(null);
} else {
if (crlmod31_format) {
resa = res.optDouble("res_added");
}
residues.add(res.getString("name"));
res_ids.add(Integer.parseInt(res.getString("id")));
res_amts.add((int) resa);
}
} else {
res_ids.add(null);
residues.add(null);
res_amts.add(null);
}
}
// build the new object
JSONObject newobj = new JSONObject();
JSONObject lmod_file = new JSONObject();
JSONObject lmod_data = new JSONObject();
JSONObject params = new JSONObject();
JSONArray param = new JSONArray();
lmod_file.put("path", "path");
lmod_file.put("name", "name");
// dates
JSONObject op_date = new JSONObject();
op_date.put("name", "OP_DATE");
JSONArray op_dates = new JSONArray();
for (int i = 0; i < dates.size(); i++) {
op_dates.put(dates.get(i));
}
op_date.put("data", op_dates);
param.put(op_date);
// yields
JSONObject harv_yields = new JSONObject();
harv_yields.put("name", "MAN_OP_VEG_NUM_HARV_UNITS");
JSONArray unitarr = new JSONArray();
for (int i = 0; i < yields.size(); i++) {
unitarr.put(yields.get(i));
}
harv_yields.put("data", unitarr);
param.put(harv_yields);
// operations
JSONObject my_ops = new JSONObject();
my_ops.put("name", "OP_PTR");
JSONArray oparr = new JSONArray();
for (int i = 0; i < ops.size(); i++) {
JSONObject oneop = new JSONObject();
if (ids.get(i) == null) {
oneop.put("file_key", ops.get(i));
} else {
oneop.put("file_key", ids.get(i).toString());
oneop.put("value", "operations\\" + ops.get(i));
}
oparr.put(oneop);
}
my_ops.put("data", oparr);
param.put(my_ops);
// crops
JSONObject my_vegs = new JSONObject();
my_vegs.put("name", "VEG_PTR");
JSONArray vegarr = new JSONArray();
for (int i = 0; i < vegs.size(); i++) {
JSONObject oneveg = new JSONObject();
if (vegs.get(i) == null) {
oneveg.put("file_key", JSONObject.NULL);
} else {
oneveg.put("file_key", veg_ids.get(i).toString());
oneveg.put("value", "vegetations\\" + vegs.get(i));
}
vegarr.put(oneveg);
}
my_vegs.put("data", vegarr);
param.put(my_vegs);
// residue amounts
JSONObject resobj = new JSONObject();
resobj.put("name", "RES_ADDED");
JSONArray reso = new JSONArray();
for (int i = 0; i < res_amts.size(); i++) {
reso.put(res_amts.get(i));
}
resobj.put("data", reso);
param.put(resobj);
// residue names
JSONObject my_ress = new JSONObject();
my_ress.put("name", "EXT_RES_PTR");
JSONArray resarr = new JSONArray();
for (int i = 0; i < residues.size(); i++) {
JSONObject oneres = new JSONObject();
if (residues.get(i) == null) {
oneres.put("file_key", JSONObject.NULL);
} else {
oneres.put("file_key", res_ids.get(i).toString());
oneres.put("value", "residues\\" + residues.get(i));
}
resarr.put(oneres);
}
my_ress.put("data", resarr);
param.put(my_ress);
params.put("param", param);
lmod_file.put("params", params);
lmod_data.put("lmod_file", lmod_file);
newobj.put("lmodData", lmod_data);
newdata = newobj.toString();
} catch (Exception e) {
LOG.info("translate2WEPP_CRLMOD error: could not convert management" + baseCRLMODObject.toString());
newdata = "";
}
LOG.info("converted from CRLMOD: " + newdata);
return newdata;
}
/**
* Parses the LMOD section of the request.
*
* @param jsonInput JSON string in LMOD format to parse
* @param errors Error messages if problems.
* @param useR2Names If the names in the management in JSON request are RUSLE2
* LMOD (true) or have been translated to WEPP in GUI
* @return boolean if there is no lmod_file in jsonInput, return false
* @throws IOException if any
* @throws ParseException if any
* @throws JSONException if any
*
*/
protected boolean parseDataCSIPLMOD(String jsonInput, List<String> errors, boolean useR2Names) throws IOException, ParseException, JSONException {
JSONObject baseLMODObject = new JSONObject(jsonInput);
JSONObject lma = null;
JSONObject lmf = null;
if (!baseLMODObject.has("lmodData")) {
if (baseLMODObject.has("lmod_file")) {
lmf = baseLMODObject.getJSONObject("lmod_file");
} else {
return false;
}
} else {
lma = new JSONObject(baseLMODObject.getString("lmodData"));
lmf = lma.getJSONObject("lmod_file");
}
if (lmf == null) {
return false;
}
String mname = lmf.optString("name");
if (mname != null) {
name = mname;
} else {
name = "???";
}
JSONObject plist = lmf.getJSONObject("params");
JSONArray params = plist.getJSONArray("param");
//JSONArray params = baseLMODObject.getJSONArray("params");
JSONArray extResidueType = null;
JSONArray dates = null;
JSONArray resAdded = null;
JSONArray yields = null;
JSONArray operations = null;
JSONArray vegetations = null;
JSONArray intervals = null;
for (int i = 0; i < params.length(); i++) {
JSONObject param = params.optJSONObject(i);
if (param.optString("name").equals("VEG_PTR")) {
vegetations = param.optJSONArray("data");
for (int j = 0; j < vegetations.length(); j++) {
JSONObject oobj = vegetations.getJSONObject(j);
String ostring = oobj.optString("file_key");
if (ostring.equals("null")) {
vegetations.put(j, (String) null);
} else {
ostring = oobj.optString("value");
if (ostring.startsWith("vegetations\\")) {
String s = ostring.replace("vegetations\\", "").trim();
if (s.startsWith("\\")) {
s = s.substring(1);
}
vegetations.put(j, s.trim());
}
}
}
}
if (param.optString("name").equals("EXT_RES_PTR")) {
extResidueType = param.optJSONArray("data");
for (int j = 0; j < extResidueType.length(); j++) {
JSONObject oobj = extResidueType.getJSONObject(j);
String ostring = oobj.optString("file_key");
if (ostring.equals("null")) {
extResidueType.put(j, (String) null);
} else {
ostring = oobj.optString("value");
if (ostring.startsWith("residues\\")) {
String s = ostring.replace("residues\\", "").trim();
if (s.startsWith("\\")) {
s = s.substring(1);
}
extResidueType.put(j, s.trim());
}
}
}
}
if (param.optString("name").equals("OP_DATE")) {
dates = param.optJSONArray("data");
}
if (param.optString("name").equals("RES_ADDED")) {
resAdded = param.optJSONArray("data");
}
if (param.optString("name").equals("MAN_OP_VEG_NUM_HARV_UNITS")) {
yields = param.optJSONArray("data");
}
if( param.optString( "name" ).equals( "INTERVAL" ) ) {
intervals = param.optJSONArray( "data" );
}
if (param.optString("name").equals("OP_PTR")) {
operations = param.optJSONArray("data");
for (int j = 0; j < operations.length(); j++) {
JSONObject oobj = operations.getJSONObject(j);
String ostring = oobj.optString("value");
if (ostring.startsWith("operations\\")) {
String s = ostring.replace("operations\\", "").trim();
if (s.startsWith("\\")) {
s = s.substring(1);
}
operations.put(j, s.trim());
}
}
}
}
// create the LMOD operations records
List<String> allResidues = new ArrayList<>();
List<String> allCrops = new ArrayList<>();
List<String> allOperations = new ArrayList<>();
for (int i = 0; i < dates.length(); i++) {
if (extResidueType != null) {
String resExtStr = extResidueType.optString(i);
if (!resExtStr.isEmpty()) {
allResidues.add(resExtStr);
}
}
// **** only add if the name is not already present ****
allOperations.add(operations.optString(i));
if (!vegetations.optString(i).isEmpty()) {
allCrops.add(vegetations.optString(i));
}
}
if (use_CRLMOD) {
try {
Parallel.run(
() -> { dbs.getOpBlobsCRLMOD(allOperations); },
() -> { dbs.getVegBlobsCRLMOD(allCrops); },
() -> { dbs.getResBlobsCRLMOD(allResidues); }
);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
for (int i = 0; i < dates.length(); i++) {
String resStr = (resAdded != null) ? resAdded.optString(i) : "";
String resExtStr = (extResidueType != null) ? extResidueType.optString(i) : "";
String yldStr = (yields != null) ? yields.optString(i) : "";
boolean isintv = false;
if (intervals == null) {
if (operations.optString(i).startsWith("Harvest")) {
isintv = true;
}
hasIntervalsDefined = false;
} else {
isintv = intervals.optBoolean( i );
hasIntervalsDefined = true;
}
LMODOperation lo = new LMODOperation(wm, dates.optString(i),
operations.optString(i), vegetations.optString(i), resExtStr,
resStr, yldStr, dbs, useR2Names, use_CRLMOD, isintv);
if (lo.getErrors() != null) {
tranErrors = tranErrors + lo.getErrors();
}
lmodOperations.add(lo);
}
// check if we need to move anything around
adjustYear0();
adjustFallTillage();
rotYears = getLastYear();
return true;
}
/**
* Get the year of the last operation in the rotation.
*
* @return last year used in management
*/
private int getLastYear() {
int sz = lmodOperations.size();
LMODOperation lmlast = lmodOperations.get(sz - 1);
return lmlast.getYear();
}
/**
* adjustFallTillage()
*
* Check date sequences to see it initial fall operations can be moved to the
* end of the rotation.
*
*/
private void adjustFallTillage() {
int year = 0;
boolean rotChanged = false;
LMODOperation lm = lmodOperations.get(0);
int firstYear = lm.getYear();
int sz = lmodOperations.size();
LMODOperation lmlast = lmodOperations.get(sz - 1);
int lastYear = lmlast.getYear();
int lastMon = lmlast.getMonth();
int lastDay = lmlast.getDay();
// first check if there are any plants in year 1, if there are do not
// adjust
ListIterator<LMODOperation> lo = lmodOperations.listIterator();
while (lo.hasNext()) {
lm = lo.next();
if (lm.getYear() == firstYear) {
if (lm.hasPlant() == true) {
// has a plant in first year, do not adjust
return;
}
}
}
lo = lmodOperations.listIterator();
while (lo.hasNext()) {
lm = lo.next();
int curMon = lm.getMonth();
int curDay = lm.getDay();
if (lm.getYear() == firstYear) {
if (curMon > lastMon) {
lm.changeDate(lastYear, curMon, curDay);
rotChanged = true;
} else if ((curMon == lastMon) && (curDay > lastDay)) {
lm.changeDate(lastYear, curMon, curDay);
rotChanged = true;
} else {
break;
}
} else {
break;
}
}
// sort list by date in case anything changed.
Collections.sort(lmodOperations);
// make sure the dates start at year 1
lm = lmodOperations.get(0);
firstYear = lm.getYear();
int chgAmt = 0;
if (firstYear != 1) {
if (firstYear > 0) {
chgAmt = firstYear - 1;
} else if (firstYear == 0) {
chgAmt = -1;
}
}
// only do this for year 0 errors. For other rotations that do not start at
// year 1 this may be correct.
if ((chgAmt == -1) || (rotChanged)) {
lo = lmodOperations.listIterator();
while (lo.hasNext()) {
lm = lo.next();
year = lm.getYear() - chgAmt;
int curMon = lm.getMonth();
int curDay = lm.getDay();
lm.changeDate(year, curMon, curDay);
}
}
}
/**
* adjustYear0()
*
* Some RUSLE2 templates have a starting year of 0, adjust so it will always
* start at year 1.
*/
private void adjustYear0() {
LMODOperation lm = lmodOperations.get(0);
if (lm.getYear() == 0) {
for (int i = 0; i < lmodOperations.size(); i++) {
lm = lmodOperations.get(i);
lm.adjustYears();
}
}
}
/**
* Get references to all the default initial conditions files.
*
* @param defAnnualCrop default annual crop used in initial condition
* @param defPerennialCrop default perennial crop used in initial condition
* @param defWoodySettings
*/
public void allInitial(File defAnnualCrop, File defPerennialCrop, File defWoodySettings) {
this.defAnnualCrop = defAnnualCrop;
this.defPerennialCrop = defPerennialCrop;
this.defWoodySettings = defWoodySettings;
}
/**
* Turns a csip-lmod object into a WEPPManagement directly by calling other
* functions.
*
* @param lmodObject The LMOD object, as a String object containing JSON
* @param contourObject JSON object contains contour
* @param slopeWidth slope width
* @param useR2Names If the names in the management in JSON request are RUSLE2
* LMOD (true) or have been translated to WEPP in GUI
* @param use_CRLMOD boolean value for whether to use crlmod
* @param use_IETFormat boolean value
* @param index index
* @return The WEPPManagement object created
* @throws SQLException if any
* @throws IOException if any
* @throws ParseException if any
* @throws JSONException if any
*/
public boolean convertLMOD(String lmodObject, JSONObject contourObject,
float slopeWidth, boolean useR2Names, boolean use_CRLMOD, boolean use_IETFormat,
int index, File saveFile) throws Exception {
boolean rc = false;
List<String> errors = new ArrayList<>();
if (use_IETFormat == true) {
//LOG.info("ORIGINAL CRLMOD: " + lmodObject);
lmodObject = parseDataCSIPCRLMOD(new JSONObject(lmodObject));
}
FileUtils.writeStringToFile(saveFile, lmodObject, "UTF-8");
if (parseDataCSIPLMOD(lmodObject, errors, useR2Names) == false) {
LOG.info("Error: Failed in parseDataCSIPLMOD\n");
}
// decide what intial condition to use
LMODOperation lastPlant = null;
boolean isFallow = true;
for (int i = 0; i < lmodOperations.size(); i++) {
LMODOperation lm = lmodOperations.get(i);
if (lm.hasProcess("plant")) {
lastPlant = lm;
}
if (lm.hasCalRelatedProcess()) {
isFallow = false;
}
if (lm.hasProcess( "initialplant" ) ) {
// use this, don't consider anything else
lastPlant = lm;
break;
}
}
if (lastPlant != null) {
String vegkey = lastPlant.getVegKey();
if (dbs.isPerennial(vegkey)) {
// perennial
// check if it is a woody veg, need to treat these different
try {
JSONObject wr = dbs.getWoodyVeg(lastPlant.vegName, defWoodySettings);
LOG.info("Vegetation for initial test:" + lastPlant.vegName + ":");
if (wr != null) {
LOG.info("Vegetation for initial test FOUND:" + lastPlant.vegName + ":");
LOG.info(wr.toString());
// defWoody - initial condition template
double cancov = wr.getDouble("cancov");
LOG.info("found cancov");
double inrcov = wr.getDouble("inrcov");
LOG.info("found inrcov");
double rilcov = wr.getDouble("rilcov");
LOG.info("found rilcov");
double usrril = wr.getDouble("usrril");
LOG.info("found usrril");
double usrintr = wr.getDouble("usrintr");
LOG.info("found usrintr");
addWoodyInitialCondition(WeppConstants.InitialConditions.WOODY, vegkey, cancov, inrcov, rilcov, usrril, usrintr, index);
} else {
addInitialCondition(WeppConstants.InitialConditions.PERENNIAL, vegkey, defPerennialCrop, 2, index);
}
} catch (Exception e) {
// extra woody params missing, default to a perennial
addInitialCondition(WeppConstants.InitialConditions.PERENNIAL, vegkey, defPerennialCrop, 2, index);
}
} else {
// annual crop
addInitialCondition(WeppConstants.InitialConditions.ANNUAL, vegkey, defAnnualCrop, 1, index);
}
} else {
// plant process, could be all fallow or assumed only some harvests
if (isFallow) {
addInitialCondition(WeppConstants.InitialConditions.FALLOW, null, defAnnualCrop, 3, index);
} else {
// assume some type of perennial but don't know what
addInitialCondition(WeppConstants.InitialConditions.PERENNIAL, null, defPerennialCrop, 2, index);
}
}
parseContours(contourObject, slopeWidth);
//rc = toRotation(ldata, initialCondition, initialConditionCrop,contouring,errors);
return rc;
}
/**
* Extract any contouring information.
*
* @param contourObj contour object
* @param len really width of slope
*/
private void parseContours(JSONObject contourObj, float len) {
try {
double grade = contourObj.getDouble("abs");
dbs.addContour((float) grade, len);
} catch (Exception e) {
e.printStackTrace(System.err);
// throw new RuntimeException(e);
}
return;
}
/**
* Update the initial condition template with the last crop growing in the
* rotation if possible.
*
* @param iniFile template initial condition file to use
* @param vegkey last vegetation growing
* @param iniCropFile template initial crop to use
* @param type general type of last crop growing
* @param index sequence of this management rotation
*/
private void addInitialCondition(WeppConstants.InitialConditions iniType,
String vegkey, File iniCropFile, int type, int index) {
try {
initialCondFile = WeppConstants.getInitialCondition(iniType);
if (vegkey == null) {
// no crop defined, use a generic code residue for initial conditions
String ifile = iniCropFile.getAbsolutePath();
byte[] data = Files.readAllBytes(Paths.get(ifile));
String blob = new String(data, Charset.defaultCharset());
// replace __CROP__ placeholder in intial conditions
if (type == 1) {
initialCondFile = initialCondFile.replace("__CROP__", "Corn");
initialConditionCrop = "Corn";
} else if (type == 2) {
initialCondFile = initialCondFile.replace("__CROP__", "Grass");
initialConditionCrop = "Grass";
} else if (type == 3) {
initialCondFile = initialCondFile.replace("__CROP__", "Corn");
initialConditionCrop = "Corn";
}
// crop to list
dbs.getVegs(blob);
} else {
// use the last crop planted as the initial crop
initialCondFile = initialCondFile.replace("__CROP__", vegkey);
initialConditionCrop = vegkey;
}
} catch (Exception e) {
initialCondFile = "???";
}
initialKey = "Default" + String.valueOf(index);
initialCondFile = initialCondFile.replace("__DEFAULT__", initialKey);
}
// addWoodyInitialCondition(defWoody,vegkey,cancov,inrcov,rilcov,2,index);
private void addWoodyInitialCondition(WeppConstants.InitialConditions iniType,
String vegkey, double cancov, double inrcov, double rilcov, double usrril, double usrintr, int index) {
try {
initialCondFile = WeppConstants.getInitialCondition(iniType);
initialCondFile = initialCondFile.replace("__CROP__", vegkey);
initialConditionCrop = vegkey;
} catch (Exception e) {
initialCondFile = "???";
}
initialKey = "Default" + String.valueOf(index);
initialCondFile = initialCondFile.replace("__DEFAULT__", initialKey);
initialCondFile = initialCondFile.replace("__CANOPYCOV__", String.valueOf(cancov));
initialCondFile = initialCondFile.replace("__INTERRILLCOV__", String.valueOf(inrcov));
initialCondFile = initialCondFile.replace("__RILLCOV__", String.valueOf(rilcov));
initialCondFile = initialCondFile.replace("__USRRIL__", String.valueOf(usrril));
initialCondFile = initialCondFile.replace("__USRINTR__", String.valueOf(usrintr));
// check if we are debugging and want to overwrite any of these
// parameters
if (debugData != null) {
initialCondFile = applyTempWoodyDatabase(initialCondFile);
}
LOG.info(initialCondFile);
}
/**
* Get a list of vegetations that need calibration.
*
* @return list of vegetation keys and names
*/
public String getVegDBS() {
return dbs.getVegsToCal();
}
/**
* Get name of this rotation
*
* @return string name of rotation
*/
public String getName() {
return name;
}
/**
* Generate a JSON structure that can be passed to the PDF report processor.
*
* @param name of this management
* @return JSON objec that can be added to report inputs
* @throws Exception anything
*/
public JSONObject createJSONSummary(String name, float modelversion) throws Exception {
JSONArray manSum = new JSONArray();
JSONArray yields = new JSONArray();
JSONArray intervals = new JSONArray();
JSONObject manAll = new JSONObject();
String[] monstrs = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
LMODOperation lm;
int mon, day, yr, idays;
String sdate, adate, startDate, endDate;
double fuelr, stirr;
boolean hasInterval = false;
String vegkeyName;
// newly added code for adding STIR sum value : STIRSum = sum of (STIR of startDate, STIR of endDate]. (start adding after start date)
JSONObject firstInterval = null;
boolean firstIntervalFlag = false; // a flag to indicate firstInterval
double firstSTIRSum = 0; // save the first part of STIRSum for the first interval.
double STIRSum = 0;
// adding fuel sum value: same as STIR sum.
double firstFuelSum = 0;
double fuelSum = 0;
boolean hasintv;
for (int i = 0; i < lmodOperations.size(); i++) {
lm = lmodOperations.get(i);
STIRSum += lm.getSTIR();
double fuel = (lm.getFuel() * LITER_TO_GAL) / (HECTA_TO_ACRE);
fuel = Math.round(fuel * 100.0) / 100.0;
fuelSum += fuel;
if (lm.hasCalRelatedProcess()) {
JSONObject na = new JSONObject();
na.put("name", name);
na.put("veg", lm.getHarVegName());
vegkeyName = lm.getHarVegKey();
if (vegkeyName == null) {
na.put("vegkey", "");
na.put("yldUnits", "");
na.put("targetyld", 0.0);
na.put("targetyldraw", 0.0);
na.put("yld", 0.0);
na.put("yldConv", 0.0);
na.put("moisture", 0.0);
na.put("calibrated", "No");
na.put( "date", lm.getDate());
na.put( "altdate", lm.getAltDate());
} else {
na.put("vegkey", lm.getHarVegKey());
na.put("yldUnits", lm.getYldUnits());
na.put("targetyld", lm.getTargetYieldConv());
na.put("targetyldraw", lm.getTargetYield());
na.put("yld", lm.getYield());
na.put("yldConv", lm.getYieldConvFactor());
na.put("moisture", lm.getMoisture() + 0.00001);
na.put("calibrated", dbs.getVegCalibStatus(vegkeyName));
na.put( "date", lm.getDate());
na.put( "altdate", lm.getAltDate());
}
yields.put(na);
}
if ((hasIntervalsDefined == false) || (modelversion < 4.0)) {
hasintv = lm.hasIntervalProcess();
} else {
hasintv = lm.interval;
}
if( hasintv ) {
JSONObject na = new JSONObject();
if ((hasIntervalsDefined == false) || (modelversion < 4.0)) {
startDate = findPreviousHarvest( i );
} else {
startDate = findPreviousInterval( i );
}
na.put("start", WEPPUtils.swapDate(startDate));
endDate = lm.getDate();
na.put("end", WEPPUtils.swapDate(endDate));
na.put("altstart", WEPPUtils.getAltDate(startDate));
na.put("altend", WEPPUtils.getAltDate(endDate));
//if (lm.tranVegName != null) {
// na.put("veg", lm.tranVegName);
//} else {
na.put("veg", lm.getHarVegName());
//}
na.put("loss", 0.0001);
idays = WEPPUtils.daysDiff(endDate, startDate, rotYears, getYears());
na.put("days", idays);
// code for STIRSum
if (!firstIntervalFlag) { // which means the current JSONObject na is the first benchmark interval
firstInterval = na;
firstSTIRSum = STIRSum;
firstIntervalFlag = true;
firstFuelSum = fuelSum;
} else {
na.put("STIRSum", STIRSum);
na.put("fuelSum", fuelSum);
}
// reset STIRSum value for next interval
STIRSum = 0;
fuelSum = 0;
intervals.put(na);
hasInterval = true;
}
// combine two STIRSums for the first interval
if (i == lmodOperations.size() - 1 && (firstInterval != null)) {
firstInterval.put("STIRSum", firstSTIRSum + STIRSum);
firstInterval.put("fuelSum", firstFuelSum + fuelSum);
}
}
if (hasInterval == false) {
// no crop intervals in this management, make a placeholder
JSONObject na = new JSONObject();
String lastCrop = "Unknown";
for (int i = 0; i < lmodOperations.size(); i++) {
lm = lmodOperations.get(i);
if (lm.hasPlant()) {
if (lm.tranVegName != null) {
lastCrop = lm.tranVegName;
} else {
lastCrop = lm.getVegName();
}
}
}
if (lastCrop == null) {
lastCrop = "Unknown";
}
lm = lmodOperations.get(0);
startDate = lm.getDate();
na.put("start", WEPPUtils.swapDate(startDate));
int last = lmodOperations.size() - 1;
lm = lmodOperations.get(last);
endDate = lm.getDate();
na.put("end", WEPPUtils.swapDate(endDate));
na.put("altstart", WEPPUtils.getAltDate(startDate));
na.put("altend", WEPPUtils.getAltDate(endDate));
na.put("veg", lastCrop); // search for a begin-growth/plant name? what if no crop?
na.put("loss", 0.0);
idays = WEPPUtils.daysDiff(endDate, startDate, rotYears, getYears());
na.put("days", idays);
na.put("STIRSum", STIRSum);
na.put("fuelSum", fuelSum);
intervals.put(na);
}
int lastyr = 1;
for (int i = 0; i < lmodOperations.size(); i++) {
lm = lmodOperations.get(i);
yr = lm.getYear();
mon = lm.getMonth();
day = lm.getDay();
sdate = String.format("%02d-%02d-%04d", mon, day, yr);
adate = String.format("%s %02d, %02d", monstrs[mon - 1], day, yr);
JSONObject oneOp = new JSONObject();
oneOp.put("date", sdate);
oneOp.put("altdate", adate);
oneOp.put("opName", lm.opName);
if (lm.tranVegName != null) {
oneOp.put("vegName", lm.tranVegName);
} else {
oneOp.put("vegName", lm.vegName);
}
oneOp.put("resname", lm.resName);
stirr = lm.getSTIR();
stirr = Math.round(stirr * 100.0) / 100.0;
oneOp.put("STIR", stirr);
fuelr = (lm.getFuel() * LITER_TO_GAL) / (HECTA_TO_ACRE);
fuelr = Math.round(fuelr * 100.0) / 100.0;
oneOp.put("Fuel", fuelr);
oneOp.put("cover", 0);
oneOp.put("resamt", 0);
manSum.put(oneOp);
lastyr = yr;
}
manAll.put("name", name);
manAll.put("years", lastyr);
manAll.put("yields", yields);
manAll.put("intervals", intervals);
manAll.put("operations", manSum);
//
//LOG.info("MANAGEMENT SUMMARY: " + manAll.toString());
return manAll;
}
/**
* Starting from a specific operation find the previous harvest.
*
* @param st starting index of operation
* @return date of harvest.
*/
String findPreviousHarvest(int st) {
LMODOperation lm;
for (int i = st - 1; i >= 0; i--) {
lm = lmodOperations.get(i);
if (lm.hasIntervalProcess()) {
return lm.incDayString();
}
}
// if we get continue from last operation
for (int i = lmodOperations.size() - 1; i > st; i--) {
lm = lmodOperations.get(i);
if (lm.hasIntervalProcess()) {
// found it
return lm.incDayString();
}
}
// if we get here it means there was only one harvest
// use date of this operation
lm = lmodOperations.get(st);
return lm.getDate();
}
/**
* Starting from a specific operation find the previous interval.
*
* @param st starting index of operation
* @return date of interval.
*/
String findPreviousInterval( int st )
{
LMODOperation lm;
for ( int i = st - 1; i >= 0; i-- )
{
lm = lmodOperations.get( i );
if( lm.interval )
{
return lm.incDayString();
}
}
// if we get continue from last operation
for ( int i = lmodOperations.size() - 1; i > st; i-- )
{
lm = lmodOperations.get( i );
if( lm.interval )
{
// found it
return lm.incDayString();
}
}
// if we get here it means there was only one interval
// use date of this operation
lm = lmodOperations.get( st );
return lm.getDate();
}
/**
* Get number of years in management
*
* @return number of years in rotation
*/
private int getYears() {
int idx = lmodOperations.size() - 1;
LMODOperation lm = lmodOperations.get(idx);
lm.getYear();
return lm.getYear();
}
/**
* Use the debug JSON to modify any woody initial condition records.
*
*/
public String applyTempWoodyDatabase(String iniCond) {
double fval;
int ival;
String updatedIniCond = iniCond;
LOG.info("Applying debug setting to woody initial conditions.");
try {
JSONObject rec = debugData.getJSONObject("woodyinicond");
for (int j = 0; j < rec.names().length(); j++) {
String ckey = rec.names().getString(j);
LOG.info("Woody parm:" + ckey);
switch (ckey) {
case "bdtill":
fval = rec.getDouble("bdtill");
updatedIniCond = changeIniVal(updatedIniCond, 7, 0, String.valueOf(fval));
break;
case "cancov":
fval = rec.getDouble("cancov");
updatedIniCond = changeIniVal(updatedIniCond, 7, 1, String.valueOf(fval));
break;
case "daydis":
ival = rec.getInt("daydis");
updatedIniCond = changeIniVal(updatedIniCond, 7, 2, String.valueOf(ival));
break;
case "dsharv":
ival = rec.getInt("daydis");
updatedIniCond = changeIniVal(updatedIniCond, 7, 3, String.valueOf(ival));
break;
case "frdp":
fval = rec.getDouble("frdp");
updatedIniCond = changeIniVal(updatedIniCond, 7, 4, String.valueOf(fval));
break;
case "inrcov":
fval = rec.getDouble("inrcov");
updatedIniCond = changeIniVal(updatedIniCond, 7, 5, String.valueOf(fval));
break;
case "imngmt":
fval = rec.getDouble("imngmt");
updatedIniCond = changeIniVal(updatedIniCond, 8, 0, String.valueOf(fval));
break;
case "rfcum":
fval = rec.getDouble("rfcum");
updatedIniCond = changeIniVal(updatedIniCond, 9, 0, String.valueOf(fval));
break;
case "rhinit":
fval = rec.getDouble("rhinit");
updatedIniCond = changeIniVal(updatedIniCond, 9, 1, String.valueOf(fval));
break;
case "rilcov":
fval = rec.getDouble("rilcov");
updatedIniCond = changeIniVal(updatedIniCond, 9, 2, String.valueOf(fval));
break;
case "rrinit":
fval = rec.getDouble("rrinit");
updatedIniCond = changeIniVal(updatedIniCond, 9, 3, String.valueOf(fval));
break;
case "rspace":
fval = rec.getDouble("rspace");
updatedIniCond = changeIniVal(updatedIniCond, 9, 4, String.valueOf(fval));
break;
case "snodpy":
fval = rec.getDouble("snodpy");
updatedIniCond = changeIniVal(updatedIniCond, 11, 0, String.valueOf(fval));
break;
case "thdp":
fval = rec.getDouble("thdp");
updatedIniCond = changeIniVal(updatedIniCond, 11, 1, String.valueOf(fval));
break;
case "tillay1":
fval = rec.getDouble("tillay1");
updatedIniCond = changeIniVal(updatedIniCond, 11, 2, String.valueOf(fval));
break;
case "tillay2":
fval = rec.getDouble("tillay2");
updatedIniCond = changeIniVal(updatedIniCond, 11, 3, String.valueOf(fval));
break;
case "width":
fval = rec.getDouble("width");
updatedIniCond = changeIniVal(updatedIniCond, 11, 4, String.valueOf(fval));
break;
case "sumrtm":
fval = rec.getDouble("sumrtm");
updatedIniCond = changeIniVal(updatedIniCond, 12, 0, String.valueOf(fval));
break;
case "sumsrm":
fval = rec.getDouble("sumsrm");
updatedIniCond = changeIniVal(updatedIniCond, 12, 1, String.valueOf(fval));
break;
case "usrintr":
fval = rec.getDouble("usrintr");
updatedIniCond = changeIniVal(updatedIniCond, 12, 2, String.valueOf(fval));
break;
case "usrril":
fval = rec.getDouble("usrril");
updatedIniCond = changeIniVal(updatedIniCond, 12, 3, String.valueOf(fval));
break;
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
// problem with debug syntax or keyword not found
}
return updatedIniCond;
}
public String changeIniVal(String src, int row, int col, String val) {
String newstr = src;
String[] lines = src.split("\n");
if (row < lines.length) {
String oneline = lines[row];
String[] vals = oneline.split(" ");
if (col < vals.length) {
vals[col] = val;
lines[row] = String.join(" ", vals);
newstr = String.join("\n", lines);
}
}
return newstr;
}
}