WEPPUtils.java [src/java/util] 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 util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.codehaus.jettison.json.JSONObject;
/**
*
* @author od
*/
public class WEPPUtils {
/**
* Round a double.
*
* @param value value to round
* @param places number of decimal places to round to
* @return new value
*/
public static double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
/**
* Get soil loss between a specific date range. Account for wrapping.
*
* @param startDt starting date as an index
* @param endDt ending date as an index
* @param sloss array of soil loss
* @param lossPts number of points in array
* @return summed soil loss between indices
*/
public static double getLoss(int startDt, int endDt, double[] sloss, int lossPts) {
double loss = 0.0;
if (startDt < endDt) {
for (int i = startDt; i < endDt; i++) {
loss = loss + sloss[i];
}
} else {
// take start to end of array
for (int i = startDt; i < lossPts; i++) {
loss = loss + sloss[i];
}
// take beginning to endDt
for (int i = 0; i < endDt; i++) {
loss = loss + sloss[i];
}
}
if (loss < -999) {
loss = -999;
}
return loss;
}
/**
* Subtracts one from the date string.
*
* @param date original date
* @return new date one day earlier
*/
public static String decDay(String date) {
String dstr;
String[] dparts = date.split("-");
int year = Integer.parseInt(dparts[2]);
int mon = Integer.parseInt(dparts[0]);
int day = Integer.parseInt(dparts[1]);
GregorianCalendar gc = new GregorianCalendar(2001, mon - 1, day);
gc.add(Calendar.DAY_OF_MONTH, -1);
day = gc.get(Calendar.DAY_OF_MONTH);
mon = gc.get(Calendar.MONTH) + 1;
int nyr = gc.get(Calendar.YEAR);
year = year + (nyr - 2001);
dstr = String.format("%02d-%02d-%04d", mon, day, year);
return dstr;
}
/**
* Builds soil loss arrays so they have the same length.
*
* @param sloss this OFE soil loss
* @param slossPrev previous OFE soil loss
* @param years number of years in this rotation
* @param prevYears number of years in previous OFE rotation
* @return soil loss array based on years
*/
public static double[] buildLoss(double[] sloss, double[] slossPrev, int years, int prevYears) {
int toCopy;
double[] updSloss;
updSloss = new double[sloss.length];
// if current range is less than previous just delete unused entries
if (years < prevYears) {
System.arraycopy(slossPrev, 0, updSloss, 0, sloss.length);
} else {
// need to repeat to fill up the list
int copied = 0;
while (copied < updSloss.length) {
toCopy = updSloss.length - slossPrev.length;
if (toCopy > slossPrev.length) {
toCopy = slossPrev.length;
}
System.arraycopy(slossPrev, 0, updSloss, copied, toCopy);
copied = copied + toCopy;
}
}
return updSloss;
}
/**
* Convert soil loss / sediment deposition from tons/acre/year to inches/year
* formula: [ (Z tons/acre) x (2000 lbs/ton) x (1 acre / 43560 ft^2) / (100
* lbs / ft^3) ] x (12 inches / ft) = inches of detachment or deposition per
* year
*
* @param data to convert in t/ac/year
* @return inches/year of soil loss
*/
public static double convertUnit(double data) {
double res = (data * 2000 * ((double) 1 / 43560) / 100) * 12;
return res;
}
/**
* Convert the date into a string that has the month name. Used in the report
* formats.
*
* @param date string to reformat
* @return new date formatted with name for month
*/
public static String getAltDate(String date) {
String adate;
String[] monstrs
= {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
String mdate[] = date.split("-");
int yr = Integer.parseInt(mdate[0]);
int mon = Integer.parseInt(mdate[1]);
int day = Integer.parseInt(mdate[2]);
adate = String.format("%s %02d, %02d", monstrs[mon - 1], day, yr);
return adate;
}
/**
* Change data format from yyyy-mm-dd to mm-dd-yyyy
*
* @param date to change
* @return string containing new date format.
*/
public static String swapDate(String date) {
String mdate[] = date.split("-");
// switch from yyyy-mm-dd to mm-dd-yyyy
return String.format("%s-%s-%s", mdate[1], mdate[2], mdate[0]);
}
/**
* Get number of days difference between start and end dates as strings.
*
* @param endd ending date
* @param startd starting dates
* @return number of days between the two dates.
*/
public static int daysDiff(String endd, String startd, int rotYears, int years) {
int days = 0;
String[] dparts = endd.split("-");
int year = Integer.parseInt(dparts[0]);
int mon = Integer.parseInt(dparts[1]);
int day = Integer.parseInt(dparts[2]);
GregorianCalendar gcend = new GregorianCalendar();
gcend.set(GregorianCalendar.DAY_OF_MONTH, day);
gcend.set(GregorianCalendar.MONTH, mon);
gcend.set(GregorianCalendar.YEAR, 2001 + year); // use 2001 as a non-leap year
dparts = startd.split("-");
year = Integer.parseInt(dparts[0]);
mon = Integer.parseInt(dparts[1]);
day = Integer.parseInt(dparts[2]);
GregorianCalendar gcst = new GregorianCalendar();
gcst.set(GregorianCalendar.DAY_OF_MONTH, day);
gcst.set(GregorianCalendar.MONTH, mon);
gcst.set(GregorianCalendar.YEAR, 2001 + year); // use 2001 as a non-leap year
if (gcend.getTime().getTime() > gcst.getTime().getTime()) {
days = daysBetween(gcst.getTime(), gcend.getTime()) + 1;
} else {
if (gcend.getTime().getTime() == gcst.getTime().getTime()) {
// same date, number of days is the length of rotation * 365
days = 365 * rotYears;
} else {
// wrapped around, need to get two sets of days
// first one is start of run to current end date
GregorianCalendar gctmp = new GregorianCalendar();
gctmp.set(GregorianCalendar.DAY_OF_MONTH, 1);
gctmp.set(GregorianCalendar.MONTH, 0);
gctmp.set(GregorianCalendar.YEAR, 2001); // use 2001 as a non-leap year
days = daysBetween(gctmp.getTime(), gcend.getTime()) + 1;
// second part is starting date until end of rotation
gctmp.set(GregorianCalendar.DAY_OF_MONTH, 31);
gctmp.set(GregorianCalendar.MONTH, 11);
gctmp.set(GregorianCalendar.YEAR, 2001 + (years - 1));
days = days + daysBetween(gcst.getTime(), gctmp.getTime()) + 1;
}
}
if (days == 0) {
if (endd.equals(startd)) {
days = 365 * year;
}
}
return days;
}
/**
* Get number of days between two dates.
*
* @param d1 starting date
* @param d2 ending date
* @return number of days between
*/
public static int daysBetween(Date d1, Date d2) {
return (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
}
public static JSONObject doStats(Double[] items) throws Exception {
double min = 9999;
double max = -9999;
double mean, median, stddev, coefvar;
double total, numsquared, diff;
total = 0.0;
for (int i = 0; i < items.length; i++) {
if (items[i] < min) {
min = items[i];
}
if (items[i] > max) {
max = items[i];
}
total += items[i];
}
mean = total / items.length;
numsquared = 0;
for (int i = 0; i < items.length; i++) {
diff = items[i] - mean;
numsquared += (diff * diff);
}
stddev = numsquared / (double) items.length;
stddev = Math.sqrt(stddev);
if (mean == 0.0) {
coefvar = 0;
} else {
coefvar = stddev / mean;
}
Arrays.sort(items);
if ((items.length % 2) == 0) {
// even number
int right = items.length / 2;
int left = (items.length / 2) - 1;
median = (items[left] + items[right]) / 2;
} else {
int mid = items.length / 2;
median = items[mid];
}
JSONObject obj = new JSONObject();
obj.put("min", min);
obj.put("max", max);
obj.put("mean", mean);
obj.put("median", median);
obj.put("stddev", stddev);
obj.put("coefvar", coefvar);
return obj;
}
}