All Downloads are FREE. Search and download functionalities are using the official Maven repository.

decodes.cwms.rating.CwmsRatingMultIndep Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
/**
 * $Id$
 * 
 * $Log$
 * Revision 1.12  2017/10/23 13:36:01  mmaloney
 * Log stack trace on rating exceptions.
 *
 * Revision 1.11  2017/08/22 19:32:16  mmaloney
 * Improve comments
 *
 * Revision 1.10  2017/02/16 14:41:26  mmaloney
 * Close CwmsRatingDao in final block.
 *
 * Revision 1.9  2017/02/09 17:23:42  mmaloney
 * Allow locationOverride to contain wildcards.
 *
 * Revision 1.8  2016/12/16 14:22:01  mmaloney
 * Added locationOverride property.
 *
 * Revision 1.7  2016/09/29 18:54:36  mmaloney
 * CWMS-8979 Allow Database Process Record to override decodes.properties and
 * user.properties setting. Command line arg -Dsettings=appName, where appName is the
 * name of a process record. Properties assigned to the app will override the file(s).
 *
 * Revision 1.6  2016/01/13 15:15:04  mmaloney
 * rating retrieval
 *
 * Revision 1.5  2015/07/14 17:53:54  mmaloney
 * Added 'useDepLocation' property with default=false.
 * Set to true to use the dep param location for building rating spec.
 *
 * Revision 1.4  2015/01/06 02:09:11  mmaloney
 * dev
 *
 * Revision 1.3  2015/01/05 21:04:39  mmaloney
 * Automatically convert units to the dataUnits reported by the RatingSet.
 *
 * Revision 1.2  2014/12/18 21:52:21  mmaloney
 * In error messages, print the specId.
 *
 * Revision 1.1.1.1  2014/05/19 15:28:59  mmaloney
 * OPENDCS 6.0 Initial Checkin
 *
 * Revision 1.8  2012/11/20 21:17:18  mmaloney
 * Implemented cache for ratings.
 *
 * Revision 1.7  2012/11/20 19:50:00  mmaloney
 * dev
 *
 * Revision 1.6  2012/11/20 16:29:52  mmaloney
 * fixed typos in variable names.
 *
 * Revision 1.5  2012/11/12 20:13:52  mmaloney
 * Do the rating in the time slice method. Not after.
 *
 * Revision 1.4  2012/11/12 19:36:04  mmaloney
 * Use version of method that passes officeID.
 * The one without office ID always returns a RatingSpec with no Ratings in it.
 *
 * Revision 1.3  2012/11/09 21:50:24  mmaloney
 * fixed init
 *
 * Revision 1.2  2012/11/09 21:10:42  mmaloney
 * Fixed imports.
 *
 * Revision 1.1  2012/11/09 21:06:20  mmaloney
 * Checked in Rating Algorithms.
 *
 * This software was written by Cove Software, LLC ("COVE") under contract 
 * to the United States Government. 
 * 
 * No warranty is provided or implied other than specific contractual terms
 * between COVE and the U.S. Government
 * 
 * Copyright 2016 U.S. Army Corps of Engineers, Hydrologic Engineering Center.
 * All rights reserved.
 */
package decodes.cwms.rating;

import java.io.PrintStream;
import java.sql.Connection;
import java.util.Date;

import ilex.util.Logger;
import ilex.var.NamedVariable;
import decodes.cwms.CwmsTimeSeriesDb;
import decodes.db.Constants;
import decodes.db.SiteName;
import decodes.tsdb.DbCompException;
import decodes.tsdb.algo.AWAlgoType;
import decodes.tsdb.ParmRef;

//AW:IMPORTS
import hec.data.RatingException;
import hec.data.cwmsRating.RatingSet;
import hec.lang.Const;

import java.util.ArrayList;

import decodes.tsdb.TimeSeriesIdentifier;
//AW:IMPORTS_END
import decodes.util.TSUtil;

//AW:JAVADOC
/**
Implements CWMS rating computations.
Uses the CWMS API provided by HEC to do the rating.
*/
//AW:JAVADOC_END
public class CwmsRatingMultIndep
	extends decodes.tsdb.algo.AW_AlgorithmBase
{
//AW:INPUTS
	public double indep1;	//AW:TYPECODE=i
	public double indep2;	//AW:TYPECODE=i
	public double indep3;	//AW:TYPECODE=i
	public double indep4;	//AW:TYPECODE=i
	public double indep5;	//AW:TYPECODE=i
	public double indep6;	//AW:TYPECODE=i
	public double indep7;	//AW:TYPECODE=i
	public double indep8;	//AW:TYPECODE=i
	public double indep9;	//AW:TYPECODE=i

	String _inputNames[] = { "indep1", "indep2", "indep3", "indep4", "indep5", 
		"indep6", "indep7", "indep8", "indep9" };
//AW:INPUTS_END

//AW:LOCALVARS
	public static final String module = "CwmsRatingMultIndep";
	RatingSet ratingSet = null;
	Date beginTime = null;
	Date endTime = null;
	ArrayList indepTimes = new ArrayList();
//	ArrayList indep1Values = new ArrayList();
//	ArrayList indep2Values = null;
//	ArrayList indep3Values = null;
//	ArrayList indep4Values = null;
//	ArrayList indep5Values = null;
//	ArrayList indep6Values = null;
//	ArrayList indep7Values = null;
//	ArrayList indep8Values = null;
//	ArrayList indep9Values = null;
	int numIndeps = 1;
	String specId = "";
	String indep1SiteName = null;

	private ArrayList> valueSetsA = null;

	
	private String buildIndepSpec()
		throws DbCompException
	{
		ParmRef parmRef = getParmRef("indep1");
		if (parmRef == null)
			throw new DbCompException("No time series mapped to indep1");
		TimeSeriesIdentifier tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		if (tsid == null)
			throw new DbCompException("No time series identifier associated with indep1");
		
		indep1SiteName = tsid.getSiteName();
		String indepSpecId = tsid.getDataType().getCode();
		
		parmRef = getParmRef("indep2");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep2_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep2");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep2Values = new ArrayList();
		numIndeps = 2;
		
		parmRef = getParmRef("indep3");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep3_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep3");
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep3Values = new ArrayList();
		numIndeps = 3;

		parmRef = getParmRef("indep4");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep4_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep4");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep4Values = new ArrayList();
		numIndeps = 4;

		parmRef = getParmRef("indep5");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep5_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep5");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep5Values = new ArrayList();
		numIndeps = 5;

		parmRef = getParmRef("indep6");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep6_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep6");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep6Values = new ArrayList();
		numIndeps = 6;

		parmRef = getParmRef("indep7");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep7_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep7");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep7Values = new ArrayList();
		numIndeps = 7;

		parmRef = getParmRef("indep8");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep8_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep8");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep8Values = new ArrayList();
		numIndeps = 8;

		parmRef = getParmRef("indep9");
		if (parmRef == null || parmRef.timeSeries == null
		 || parmRef.timeSeries.getTimeSeriesIdentifier() == null)
		{
			if (!indep9_MISSING.equalsIgnoreCase("ignore"))
				throw new DbCompException("No time series mapped to indep9");
			
			return indepSpecId;
		}
		tsid = parmRef.timeSeries.getTimeSeriesIdentifier();
		indepSpecId = indepSpecId + "," + tsid.getDataType().getCode();
//		indep9Values = new ArrayList();
		numIndeps = 9;

		return indepSpecId;
	}
//AW:LOCALVARS_END

//AW:OUTPUTS
	public NamedVariable dep = new NamedVariable("dep", 0);
	String _outputNames[] = { "dep" };
//AW:OUTPUTS_END

//AW:PROPERTIES
	public String templateVersion = "USGS-EXSA";
	public String specVersion = "Production";
	public String indep1_MISSING = "fail";
	public String indep2_MISSING = "ignore";
	public String indep3_MISSING = "ignore";
	public String indep4_MISSING = "ignore";
	public String indep5_MISSING = "ignore";
	public String indep6_MISSING = "ignore";
	public String indep7_MISSING = "ignore";
	public String indep8_MISSING = "ignore";
	public String indep9_MISSING = "ignore";
	public boolean useDepLocation = false;
	public String locationOverride = "";

	public String _propertyNames[] = { "templateVersion", "specVersion",
		"indep1_MISSING", "indep2_MISSING", "indep3_MISSING", "indep4_MISSING", "indep5_MISSING",
		"indep6_MISSING", "indep7_MISSING", "indep8_MISSING", "indep9_MISSING", 
		"useDepLocation", "locationOverride" };
//AW:PROPERTIES_END

	// Allow javac to generate a no-args constructor.

	/**
	 * Algorithm-specific initialization provided by the subclass.
	 */
	protected void initAWAlgorithm( )
		throws DbCompException
	{
//AW:INIT
		_awAlgoType = AWAlgoType.TIME_SLICE;
//AW:INIT_END

//AW:USERINIT
//AW:USERINIT_END
	}
	
	/**
	 * This method is called once before iterating all time slices.
	 */
	protected void beforeTimeSlices()
		throws DbCompException
	{
//AW:BEFORE_TIMESLICES
		specId = buildIndepSpec();
		
		ParmRef depParmRef = getParmRef("dep");
		String specLocation = indep1SiteName;
		if (useDepLocation)
		{
			SiteName depSiteName = depParmRef.compParm.getSiteName(Constants.snt_CWMS);
			if (depSiteName == null)
				debug1("No dependent site name available, using site from indep1");
			else
				specLocation = depSiteName.getNameValue();
		}
		
		if (locationOverride != null && locationOverride.length() > 0)
		{
			if (locationOverride.contains("*"))
				specLocation = CwmsTimeSeriesDb.morph(specLocation, locationOverride);
			else
				specLocation = locationOverride;
		}
		
		specId = specLocation
			+ "." + specId + ";" + depParmRef.compParm.getDataType().getCode() + "."
			+ templateVersion + "." + specVersion;

		// Retrieve the RatingSet object
		try (CwmsRatingDao crd = new CwmsRatingDao((CwmsTimeSeriesDb)tsdb))
		{
			Date earliestBaseTime = baseTimes.first();
			if (earliestBaseTime == null)
				earliestBaseTime = new Date();
			ratingSet = crd.getRatingSet(specId);
			
			// As per instructions from Mike Perryman: I must find out what the native units
			// for the rating are and convert before calling the Java rating. The Java rating
			// method assumes that data are already in correct units.
			String punits[] = ratingSet.getDataUnits();
			for(int pidx = 0; pidx < punits.length-1 && pidx < 9; pidx++)
			{
				if (punits[pidx] == null)
					continue;
				String pname = "indep" + (pidx+1);
				ParmRef indepParmRef = getParmRef(pname);
				if (indepParmRef == null || indepParmRef.timeSeries == null 
				 || indepParmRef.timeSeries.getUnitsAbbr() == null)
					continue;

				if (!indepParmRef.timeSeries.getUnitsAbbr().equalsIgnoreCase(punits[pidx]))
				{
					debug1(module + " Converting " + pname + " units for time series " 
						+ indepParmRef.timeSeries.getTimeSeriesIdentifier().getUniqueString() + " from "
						+ indepParmRef.timeSeries.getUnitsAbbr() + " to " + punits[pidx]);
					TSUtil.convertUnits(indepParmRef.timeSeries, punits[pidx]);
				}
			}
			
			// Likewise for the dependent param:
			if (punits.length > 1 && punits[punits.length-1] != null
			 && depParmRef.timeSeries.getUnitsAbbr() != null
			 && !depParmRef.timeSeries.getUnitsAbbr().equalsIgnoreCase(punits[punits.length-1]))
			{
				debug1(module + " Converting dep units from "
					+ depParmRef.timeSeries.getUnitsAbbr() + " to " + punits[punits.length-1]);
				TSUtil.convertUnits(depParmRef.timeSeries, punits[punits.length-1]);
			}

		}
		catch (RatingException ex)
		{
			String m = "Cannot read rating for '" + specId + "': " + ex;
			warning(m);
			ex.printStackTrace(Logger.instance().getLogOutput() != null 
				? Logger.instance().getLogOutput() : System.err);
			throw new DbCompException(m);
		}

		indepTimes.clear();

		// MJM 2017 10/31 Array list of indeps, for each indep and arraylist of values.
		valueSetsA = new ArrayList>();
		for(int idx = 0; idx < numIndeps; idx++)
			valueSetsA.add(new ArrayList());
		

		
//AW:BEFORE_TIMESLICES_END
	}

	/**
	 * Do the algorithm for a single time slice.
	 * AW will fill in user-supplied code here.
	 * Base class will set inputs prior to calling this method.
	 * User code should call one of the setOutput methods for a time-slice
	 * output variable.
	 *
	 * @throw DbCompException (or subclass thereof) if execution of this
	 *        algorithm is to be aborted.
	 */
	protected void doAWTimeSlice()
		throws DbCompException
	{
//AW:TIMESLICE
		if (ratingSet == null)
			throw new DbCompException("No rating set!");
		
		// If any non-ignored params are missing in this time-slice, skip it.
		if ((isMissing("indep1") && indep1_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 2 && isMissing("indep2") && indep2_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 3 && isMissing("indep3") && indep3_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 4 && isMissing("indep4") && indep4_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 5 && isMissing("indep5") && indep5_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 6 && isMissing("indep6") && indep6_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 7 && isMissing("indep7") && indep7_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 8 && isMissing("indep8") && indep8_MISSING.equalsIgnoreCase("fail"))
		 || (numIndeps >= 9 && isMissing("indep9") && indep9_MISSING.equalsIgnoreCase("fail")))
			return;

		// MJM 10/31/2017 Modified to save values and do array rating in after method.
		indepTimes.add(_timeSliceBaseTime.getTime());
		valueSetsA.get(0).add(indep1);
		if (numIndeps >= 2) valueSetsA.get(1).add(indep2);
		if (numIndeps >= 3) valueSetsA.get(2).add(indep3);
		if (numIndeps >= 4) valueSetsA.get(3).add(indep4);
		if (numIndeps >= 5) valueSetsA.get(4).add(indep5);
		if (numIndeps >= 6) valueSetsA.get(5).add(indep6);
		if (numIndeps >= 7) valueSetsA.get(6).add(indep7);
		if (numIndeps >= 8) valueSetsA.get(7).add(indep8);
		if (numIndeps >= 9) valueSetsA.get(8).add(indep9);
		
		
		
//		double valueSet[] = new double[numIndeps];
//		valueSet[0] = indep1;
//		if (numIndeps >= 2) valueSet[1] = indep2;
//		if (numIndeps >= 3) valueSet[2] = indep3;
//		if (numIndeps >= 4) valueSet[3] = indep4;
//		if (numIndeps >= 5) valueSet[4] = indep5;
//		if (numIndeps >= 6) valueSet[5] = indep6;
//		if (numIndeps >= 7) valueSet[6] = indep7;
//		if (numIndeps >= 8) valueSet[7] = indep8;
//		if (numIndeps >= 9) valueSet[8] = indep9;
		
		
		
		
//		try
//		{
//			double output = ratingSet.rateOne(valueSet, _timeSliceBaseTime.getTime());
//			setOutput(dep, output);
//			if (Logger.instance().getMinLogPriority() == Logger.E_DEBUG3)
//			{
//				StringBuilder sb = new StringBuilder();
//				for(int i=0; i0?", ":"") + "i" + (i+1) + "=" + valueSet[i]);
//				sb.append(" -- output=" + output);
//				debug3(sb.toString());
//			}
//		}
//		catch (RatingException ex)
//		{
//			warning("Rating failure specId='" + specId + "': " + ex);
//			if (Logger.instance().getLogOutput() != null)
//				ex.printStackTrace(Logger.instance().getLogOutput());
//		}
////AW:TIMESLICE_END
	}

	/**
	 * This method is called once after iterating all time slices.
	 */
	protected void afterTimeSlices()
	{
//AW:AFTER_TIMESLICES
		
		// Convert nested ArrayLists to double[TIMES][VALUES].
		// Note that the dimensions are reversed from the nested array lists.
		double[][] valueSets = new double[indepTimes.size()][numIndeps];
		for(int valIdx = 0; valIdx < indepTimes.size(); valIdx++)
			for(int indepIdx = 0; indepIdx < numIndeps; indepIdx++)
				valueSets[valIdx][indepIdx] = valueSetsA.get(indepIdx).get(valIdx);
		
		long valueTimes[] = new long[indepTimes.size()];
		for(int valIdx = 0; valIdx < indepTimes.size(); valIdx++)
			valueTimes[valIdx] = indepTimes.get(valIdx);
		
		Connection conn = tsdb.getConnection();
		try
		{
			debug1("Calling rate with " + valueSets.length + " inputs and " 
				+ valueTimes.length + " values each.");
			
			double depVals[] = ratingSet.rate(conn, valueTimes, valueSets);
			
			for(int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy