teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.artifacts; felix@1047: felix@1047: import java.util.ArrayList; felix@1047: import java.util.List; felix@1047: felix@1047: import org.apache.log4j.Logger; felix@1047: felix@1047: import org.w3c.dom.Document; felix@1047: teichmann@5831: import org.dive4elements.artifactdatabase.data.DefaultStateData; teichmann@5831: import org.dive4elements.artifactdatabase.state.Facet; teichmann@5831: import org.dive4elements.artifactdatabase.state.FacetActivity; teichmann@5831: import org.dive4elements.artifactdatabase.state.DefaultOutput; teichmann@5831: import org.dive4elements.artifactdatabase.state.State; ingo@1095: teichmann@5831: import org.dive4elements.artifacts.Artifact; teichmann@5831: import org.dive4elements.artifacts.ArtifactFactory; teichmann@5831: import org.dive4elements.artifacts.CallMeta; felix@1078: felix@6038: import org.dive4elements.artifacts.common.ArtifactNamespaceContext; felix@6038: import org.dive4elements.artifacts.common.utils.XMLUtils; felix@6038: teichmann@5831: import org.dive4elements.river.model.Gauge; teichmann@5831: import org.dive4elements.river.model.MainValue; teichmann@5831: import org.dive4elements.river.model.River; felix@1101: tom@8331: import org.dive4elements.river.artifacts.access.RiverAccess; teichmann@5831: import org.dive4elements.river.artifacts.access.RangeAccess; teichmann@5831: import org.dive4elements.river.artifacts.model.Calculation; teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@5831: import org.dive4elements.river.artifacts.model.MainValuesQFacet; teichmann@5831: import org.dive4elements.river.artifacts.model.MainValuesWFacet; teichmann@5831: import org.dive4elements.river.artifacts.model.NamedDouble; teichmann@5831: import org.dive4elements.river.artifacts.model.WstValueTable; teichmann@5831: import org.dive4elements.river.artifacts.model.WstValueTableFactory; felix@1101: teichmann@5831: import org.dive4elements.river.artifacts.states.StaticState; teichmann@5831: import org.dive4elements.river.artifacts.resources.Resources; teichmann@5831: felix@1047: felix@1047: /** felix@4126: * Artifact to access main and extreme values of a river. teichmann@5867: * This artifact neglects (Static)D4EArtifacts capabilities of interaction felix@1072: * with the StateEngine by overriding the getState*-methods. felix@1047: */ felix@1047: public class MainValuesArtifact teichmann@5867: extends StaticD4EArtifact felix@1809: implements FacetTypes sascha@1059: { teichmann@8202: /** The log for this class. */ teichmann@8202: private static Logger log = Logger.getLogger(MainValuesArtifact.class); felix@1047: felix@1047: /** The name of the artifact. */ felix@1065: public static final String ARTIFACT_NAME = "mainvalue"; felix@1072: felix@1771: /** The name of the static state for this artifact. */ felix@1771: public static final String STATIC_STATE_NAME = "state.mainvalue.static"; felix@1771: felix@1078: /** One and only state to be in. */ felix@1078: protected transient State state = null; felix@1078: felix@1072: sascha@3558: static { sascha@3558: // TODO: Move to configuration. sascha@3558: FacetActivity.Registry.getInstance().register( sascha@3558: ARTIFACT_NAME, sascha@3558: new FacetActivity() { sascha@3558: @Override sascha@3558: public Boolean isInitialActive( sascha@3558: Artifact artifact, sascha@3558: Facet facet, sascha@3558: String outputName sascha@3558: ) { sascha@3558: return outputName.equals("computed_discharge_curve") aheinecke@6659: || outputName.equals("duration_curve") aheinecke@6659: || outputName.equals("discharge_curve") aheinecke@6686: || outputName.equals("fix_wq_curve") aheinecke@6686: || outputName.equals("historical_discharge_wq"); sascha@3558: } sascha@3558: }); sascha@3558: } sascha@3558: felix@5368: felix@1072: /** felix@1072: * Trivial Constructor. felix@1072: */ felix@1047: public MainValuesArtifact() { teichmann@8202: log.debug("MainValuesArtifact.MainValuesartifact()"); felix@1047: } felix@1047: felix@1072: felix@1047: /** felix@1047: * Gets called from factory, to set things up. felix@1047: */ felix@1047: @Override felix@1047: public void setup( felix@1047: String identifier, felix@1047: ArtifactFactory factory, felix@1047: Object context, felix@1047: CallMeta callMeta, rrenkert@7842: Document data, rrenkert@7842: List loadFacets) felix@1047: { teichmann@8202: log.debug("MainValuesArtifact.setup"); felix@1787: state = new StaticState(STATIC_STATE_NAME); felix@1787: felix@6038: initFromGaugeDoc(data, callMeta); felix@6038: felix@4126: List fs = new ArrayList(); bjoern@4497: addFacets(state.getID(), fs); felix@4126: spawnState(); rrenkert@7842: super.setup(identifier, factory, context, callMeta, data, loadFacets); felix@4126: String restriction = getDatacageIDValue(data); teichmann@8202: log.debug("mainvalue restriction " + restriction); felix@4126: boolean restricted = restriction.endsWith("q") || restriction.endsWith("w"); felix@4126: if (!restricted || restriction.endsWith("q")) { tom@8331: fs.add(new MainValuesQFacet( tom@8331: MAINVALUES_Q, tom@8331: Resources.getMsg( tom@8331: callMeta, tom@8331: "facet.discharge_curves.mainvalues.q"))); felix@4126: } felix@4126: if (!restricted || restriction.endsWith("w")) { tom@8331: fs.add(new MainValuesWFacet( tom@8331: MAINVALUES_W, tom@8331: Resources.getMsg( tom@8331: callMeta, tom@8331: "facet.discharge_curves.mainvalues.w"))); felix@4126: } felix@1080: } felix@1080: felix@7507: felix@6038: /** felix@6038: * The MainValueArtifact can be set up with a document giving the felix@6038: * river and gauge. This happens in context of GaugeDischargeArtifact. felix@6038: * In that case, initalize() is not called. felix@6038: */ felix@6038: private void initFromGaugeDoc(Document data, CallMeta callMeta) { felix@6038: String gaugeref = XMLUtils.xpathString( felix@6038: data, GaugeDischargeCurveArtifact.XPATH_GAUGE, felix@6038: ArtifactNamespaceContext.INSTANCE); felix@6038: String rivername = XMLUtils.xpathString( felix@6038: data, GaugeDischargeCurveArtifact.XPATH_RIVER, felix@6038: ArtifactNamespaceContext.INSTANCE); felix@6038: felix@6038: if (rivername == null || gaugeref == null || rivername.equals("") felix@6038: || gaugeref.equals("")) { teichmann@8202: log.debug("Not setting MainValuesArtifact up from gauge doc."); felix@6038: return; felix@6038: } felix@6038: felix@6038: addData("river", new DefaultStateData("river", felix@6038: Resources.getMsg(callMeta, felix@6038: "facet.gauge_discharge_curve.river", felix@6038: "Name of the river"), felix@6038: "String", rivername)); felix@6038: felix@6038: try { felix@6038: Long officialNumber = Long.valueOf(gaugeref); felix@6038: Gauge gauge = Gauge.getGaugeByOfficialNumber(officialNumber); felix@6038: addData("ld_locations", new DefaultStateData("ld_locations", null, null, felix@6038: String.valueOf(gauge.getStation()))); felix@6038: } catch (NumberFormatException nfe) { teichmann@8202: log.debug("MainValuesArtifact could not parse gaugeref from doc."); felix@6038: } felix@6038: } felix@6038: felix@1771: felix@1771: /** felix@7507: * Create "the" (one possible) state. felix@1771: */ felix@1112: protected State spawnState() { felix@1787: state = new StaticState(STATIC_STATE_NAME); bjoern@4497: List fs = (List) getFacets(STATIC_STATE_NAME); felix@1771: felix@1847: DefaultOutput mainValuesOutput = new DefaultOutput( felix@1765: "computed_discharge_curve", felix@1765: "output.computed_discharge_curve", "image/png", felix@1771: fs, felix@1765: "chart"); felix@1112: felix@1847: state.getOutputs().add(mainValuesOutput); felix@1112: return state; felix@1112: } felix@1112: felix@1080: felix@5368: /** Get important data from the 'calling' artifact. */ felix@1080: @Override felix@1080: protected void initialize(Artifact artifact, Object context, CallMeta meta) { teichmann@8202: log.debug("MainValuesArtifact.initialize"); teichmann@5867: D4EArtifact winfo = (D4EArtifact) artifact; tom@8331: River river = new RiverAccess(winfo).getRiver(); tom@8331: double [] locations = new RangeAccess(winfo).getKmRange(); felix@5290: felix@1847: if (locations != null) { felix@1847: double location = locations[0]; rrenkert@4937: addData("ld_locations", new DefaultStateData("ld_locations", null, null, felix@1085: String.valueOf(location))); felix@1847: } felix@1847: else { teichmann@8202: log.error("No location for mainvalues given."); felix@1847: } felix@1922: importData(winfo, "river"); felix@5371: // In the case of DischargeWQCurves, there are no locations, but a gauge. felix@5371: if (getDataAsString("ld_locations") == null) { felix@5371: // TODO its a tad difficult to remodel Range/Gauge-Access to felix@5371: // do this. felix@5371: String refGaugeID = winfo.getDataAsString("reference_gauge"); felix@5371: if (refGaugeID != null) { felix@5371: Gauge g = Gauge.getGaugeByOfficialNumber(Integer.parseInt(refGaugeID)); felix@5371: addData("ld_locations", new DefaultStateData("ld_locations", null, null, felix@5371: String.valueOf(g.getStation()))); felix@5371: } felix@5371: else { teichmann@8202: log.error("MainValuesArtifact: No location/gauge."); felix@5371: } felix@5371: } felix@1047: } felix@1047: felix@1047: felix@1047: /** felix@1072: * Get a list containing the one and only State. felix@1085: * @param context ignored. felix@1072: * @return list with one and only state. felix@1047: */ felix@1072: @Override felix@1072: protected List getStates(Object context) { felix@1072: ArrayList states = new ArrayList(); felix@1112: states.add(getState()); felix@1072: return states; felix@1072: } felix@1047: felix@1047: felix@1072: /** felix@1072: * Get the "current" state. felix@1072: * @param cc ignored. felix@1072: * @return the "current" state. felix@1072: */ felix@1072: @Override ingo@1654: public State getCurrentState(Object cc) { felix@1072: return getState(); felix@1072: } felix@1072: felix@1072: felix@1072: /** felix@1072: * Get the only possible state. felix@1072: * @return the state. felix@1072: */ felix@1072: protected State getState() { felix@1072: return getState(null, null); felix@1072: } felix@1072: felix@1072: felix@1072: /** felix@1072: * Get the state. felix@1072: * @param context ignored. felix@1072: * @param stateID ignored. felix@1072: * @return the state. felix@1072: */ felix@1072: @Override felix@1072: protected State getState(Object context, String stateID) { felix@1112: if (state != null) felix@1112: return state; felix@1112: else felix@1112: return spawnState(); felix@1078: } felix@1078: felix@6524: /** felix@6524: * Access the Gauge that the mainvalues are taken from. felix@6524: * @return Gauge that main values are taken from or null in case of felix@6524: * invalid parameterization. felix@6524: */ felix@6524: protected Gauge getGauge(double km) { tom@8331: River river = new RiverAccess((D4EArtifact)this).getRiver(); felix@6524: felix@6524: if (river == null) { teichmann@8202: log.error("River is null"); felix@6524: return null; felix@6524: } felix@6524: felix@6524: return river.determineGaugeByPosition(km); felix@6524: } felix@1093: felix@1085: /** felix@1101: * Get current location. felix@1101: * @return the location. felix@1089: */ felix@1101: public double getLocation() { rrenkert@4937: double location = Double.parseDouble(getDataAsString("ld_locations")); felix@1101: return location; felix@1089: } felix@1089: felix@1089: felix@1089: /** felix@1089: * Get a list of "Q" main values. tom@8331: * @param Array of length 1 (isn't it lovely?) giving the station for tom@8331: * which the main values should be returned felix@1089: * @return list of Q main values. felix@1089: */ tom@8331: public List getMainValuesQ(double[] kms, Object pnpObject) { tom@8331: if (kms.length > 1) { tom@8331: log.error("How did you dare to give an array of lenght >1! " + tom@8331: "DAS GEHT GARNICHT!!!! (we'll just take the first value)"); tom@8331: } felix@6533: List filteredList = new ArrayList(); felix@6533: Gauge gauge = getGauge(kms[0]); tom@8331: River river = new RiverAccess((D4EArtifact)this).getRiver(); tom@8331: WstValueTable interpolator = WstValueTableFactory.getTable(river); felix@6533: Calculation c = new Calculation(); felix@6533: double w_out[] = {0.0f}; felix@6533: double q_out[] = {0.0f}; tom@8331: double pnp = Double.NaN; tom@8331: felix@6533: if (gauge != null) { felix@6533: double gaugeStation = gauge.getStation().doubleValue(); felix@6533: List orig = gauge.getMainValues(); tom@8331: if (pnpObject instanceof Number) { tom@8331: pnp = Double.valueOf(pnpObject.toString()); tom@8331: } tom@8331: felix@6533: for (MainValue mv : orig) { felix@6533: if (mv.getMainValue().getType().getName().equals("Q")) { tom@8331: if (pnpObject instanceof Number) { felix@6533: q_out[0] = mv.getValue().doubleValue(); felix@6533: } felix@6533: else { felix@6533: interpolator.interpolate(mv.getValue().doubleValue(), felix@6533: gaugeStation, kms, w_out, q_out, c); felix@6533: } felix@6533: filteredList.add(new NamedDouble( felix@6533: mv.getMainValue().getName(), felix@6533: q_out[0] felix@6533: )); felix@6533: } felix@6533: } felix@6533: } felix@6533: return filteredList; felix@6533: } felix@6533: felix@6533: /** felix@6533: * Get a list of "Q" main values. felix@6533: * @return list of Q main values. felix@6533: */ tom@8331: public List getMainValuesQ(Object pnpObject) { tom@8331: double kms[] = {getLocation()}; tom@8331: return getMainValuesQ(kms, pnpObject); tom@8331: } tom@8331: tom@8331: tom@8331: public List getMainValuesW(double[] kms, Object pnpObject) { felix@1089: List filteredList = new ArrayList(); tom@8331: Gauge gauge = getGauge(kms[0]); tom@8331: River river = new RiverAccess((D4EArtifact)this).getRiver(); tom@8331: WstValueTable interpolator = WstValueTableFactory.getTable(river); felix@1101: Calculation c = new Calculation(); felix@1101: double w_out[] = {0.0f}; felix@1101: double q_out[] = {0.0f}; tom@8331: double pnp = Double.NaN; tom@8331: felix@1085: if (gauge != null) { felix@6533: double gaugeStation = gauge.getStation().doubleValue(); felix@1085: List orig = gauge.getMainValues(); tom@8331: if (pnpObject instanceof Number) { tom@8331: pnp = Double.valueOf(pnpObject.toString()); felix@1085: } felix@1089: felix@6524: for (MainValue mv : orig) { tom@8331: if (pnpObject instanceof Number) { felix@6524: if (mv.getMainValue().getType().getName().equals("W")) { tom@8331: filteredList.add(new NamedDouble( tom@8331: mv.getMainValue().getName(), tom@8331: mv.getValue().doubleValue()/100 + pnp tom@8331: )); felix@6524: } felix@6524: } else felix@6524: // We cannot interpolate the W values, so derive them felix@6524: // from given Q values. felix@6524: if (mv.getMainValue().getType().getName().equals("Q")) { felix@6524: interpolator.interpolate(mv.getValue().doubleValue(), felix@6524: gaugeStation, kms, w_out, q_out, c); felix@6524: felix@6524: filteredList.add(new NamedDouble( felix@6524: "W(" + mv.getMainValue().getName() +")", felix@6524: w_out[0] felix@6524: )); felix@6524: } felix@6524: } felix@6524: } felix@6524: return filteredList; felix@6524: } felix@6524: felix@6524: felix@5398: /** felix@6523: * Get a list of "W" main values. felix@6523: * @return list of W main values. felix@6523: */ tom@8331: public List getMainValuesW(Object pnpObject) { tom@8331: return getMainValuesW(new double[] {getLocation()}, pnpObject); felix@6523: } felix@6523: felix@6523: felix@6523: /** felix@5398: * Returns the name of this artifact ('mainvalue'). felix@5398: * felix@5398: * @return 'mainvalue' felix@5398: */ felix@5398: public String getName() { felix@5398: return ARTIFACT_NAME; felix@5398: } felix@1047: } felix@1809: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :