Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java @ 9627:f51e23eb036a
zu pos 20
author | dnt_bjoernsen <d.tironi@bjoernsen.de> |
---|---|
date | Mon, 14 Oct 2019 16:27:31 +0200 |
parents | 2b83d3a96703 |
children |
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde * Software engineering by Intevation GmbH * * This file is Free Software under the GNU AGPL (>=v3) * and comes with ABSOLUTELY NO WARRANTY! Check out the * documentation coming with Dive4Elements River for details. */ package org.dive4elements.river.artifacts.model.fixings; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.access.FixAnalysisAccess; import org.dive4elements.river.artifacts.math.fitting.Function; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.DateRange; import org.dive4elements.river.artifacts.model.Parameters; import org.dive4elements.river.artifacts.model.Range; import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.AndFilter; import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.DateRangeFilter; import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.IdsFilter; import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.KmFilter; import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.SectorFilter; import org.dive4elements.river.utils.DateAverager; import org.dive4elements.river.utils.KMIndex; import gnu.trove.TIntIntHashMap; public class FixAnalysisCalculation extends FixCalculation { private static final long serialVersionUID = 1L; private static Logger log = Logger.getLogger(FixAnalysisCalculation.class); private DateRange referencePeriod; private DateRange[] analysisPeriods; public FixAnalysisCalculation() { } public FixAnalysisCalculation(final FixAnalysisAccess access) { super(access); final DateRange referencePeriod = access.getReferencePeriod(); final DateRange[] analysisPeriods = access.getAnalysisPeriods(); if (referencePeriod == null) { addProblem("fix.missing.reference.period"); } if (analysisPeriods == null || analysisPeriods.length < 1) { addProblem("fix.missing.analysis.periods"); } if (!hasProblems()) { this.referencePeriod = referencePeriod; this.analysisPeriods = analysisPeriods; } } @Override protected CalculationResult innerCalculate(final FixingsOverview overview, final Function function, final CallMeta meta) { final ColumnCache cc = new ColumnCache(); final FitResult fitResult = doFitting(overview, cc, function); if (fitResult == null) return new CalculationResult(this); final Parameters parameters = fitResult.getParameters(); final AnalysisPeriodEventResults eventResults = new AnalysisPeriodEventResults(); final KMIndex<AnalysisPeriod[]> kmResults = new KMIndex<>(parameters.size()); calculateAnalysisPeriods(function, parameters, overview, cc, eventResults, kmResults); eventResults.sortAll(); kmResults.sort(); final FixAnalysisResult far = new FixAnalysisResult(parameters, fitResult.getResultColumns(), kmResults, eventResults); return new CalculationResult(far, this); } @Override protected FixingColumnFilter createFilter() { final FixingColumnFilter ids = super.createFilter(); final DateRangeFilter rdf = new DateRangeFilter(this.referencePeriod.getFrom(), this.referencePeriod.getTo()); return new AndFilter().add(rdf).add(ids); } private void calculateAnalysisPeriods(final Function function, final Parameters parameters, final FixingsOverview overview, final ColumnCache cc, final AnalysisPeriodEventResults eventResults, final KMIndex<AnalysisPeriod[]> kmResults) { final Range range = new Range(this.from, this.to); final int kmIndex = parameters.columnIndex("km"); final int maxQIndex = parameters.columnIndex("max_q"); final double[] ws = new double[1]; final int[] parameterIndices = parameters.columnIndices(function.getParameterNames()); final double[] parameterValues = new double[parameterIndices.length]; final DateAverager dateAverager = new DateAverager(); final IdsFilter idsFilter = new IdsFilter(this.events); final TIntIntHashMap[] col2indices = new TIntIntHashMap[this.analysisPeriods.length]; final DateRangeFilter[] drfs = new DateRangeFilter[this.analysisPeriods.length]; final boolean debug = log.isDebugEnabled(); for (int i = 0; i < this.analysisPeriods.length; ++i) { col2indices[i] = new TIntIntHashMap(); drfs[i] = new DateRangeFilter(this.analysisPeriods[i].getFrom(), this.analysisPeriods[i].getTo()); if (debug) { log.debug("Analysis period " + (i + 1) + " date range: " + this.analysisPeriods[i].getFrom() + " - " + this.analysisPeriods[i].getTo()); } } for (int row = 0, R = parameters.size(); row < R; ++row) { final double km = parameters.get(row, kmIndex); parameters.get(row, parameterIndices, parameterValues); // This is the parameterized function for a given km. final org.dive4elements.river.artifacts.math.Function instance = function.instantiate(parameterValues); final KmFilter kmFilter = new KmFilter(km); final List<AnalysisPeriod> periodResults = new ArrayList<>(this.analysisPeriods.length); for (int ap = 0; ap < this.analysisPeriods.length; ++ap) { final DateRange analysisPeriod = this.analysisPeriods[ap]; final DateRangeFilter drf = drfs[ap]; final QWD[] qSectorAverages = new QWD[4]; final double[] qSectorStdDevs = new double[4]; final ArrayList<QWD> allQWDs = new ArrayList<>(); // for all Q sectors. for (int qSector = this.qSectorStart; qSector <= this.qSectorEnd; ++qSector) { final FixingColumnFilter filter = new AndFilter().add(kmFilter).add(new SectorFilter(qSector)).add(drf).add(idsFilter); final List<FixingColumn> metas = overview.filter(range, filter); if (metas.isEmpty()) { // No fixings for km and analysis period continue; } double sumQ = 0.0; double sumW = 0.0; final StandardDeviation stdDev = new StandardDeviation(); final List<QWD> qwds = new ArrayList<>(metas.size()); dateAverager.clear(); for (final FixingColumn meta : metas) { if (meta.findQSector(km) != qSector) { // Ignore not matching sectors. continue; } final FixingColumnWithData column = cc.getColumn(meta); if (column == null) continue; final double q = column.getQ(km); final boolean interpolated = !column.getW(km, ws, 0); final double w = ws[0]; if (Double.isNaN(w) || Double.isNaN(q)) continue; final double fw = instance.value(q); if (Double.isNaN(fw)) continue; final double dw = (w - fw) * 100.0; stdDev.increment(dw); final Date date = column.getDate(); final QWD qwd = new QWD(q, w, date, interpolated, dw, false); qwds.add(qwd); eventResults.addQWD(ap, km, column, qwd); sumW += w; sumQ += q; dateAverager.add(date); } // Calulate average per Q sector. final int N = qwds.size(); if (N > 0) { allQWDs.addAll(qwds); final double avgW = sumW / N; final double avgQ = sumQ / N; final double avgFw = instance.value(avgQ); if (!Double.isNaN(avgFw)) { final double avgDw = (avgW - avgFw) * 100.0; final Date avgDate = dateAverager.getAverage(); final QWD avgQWD = new QWD(avgQ, avgW, avgDate, true, avgDw, false); qSectorAverages[qSector] = avgQWD; } qSectorStdDevs[qSector] = stdDev.getResult(); } else { qSectorStdDevs[qSector] = Double.NaN; } } // for all Q sectors /* calculate max q for this period */ double maxQ = -Double.MAX_VALUE; for (final QWD qwd : allQWDs) { if (qwd.getQ() > maxQ) maxQ = qwd.getQ(); } for (final QWD qwd : qSectorAverages) { if (qwd != null && qwd.getQ() > maxQ) maxQ = qwd.getQ(); } final AnalysisPeriod periodResult = new AnalysisPeriod(analysisPeriod, qSectorAverages, qSectorStdDevs, maxQ); periodResults.add(periodResult); } double maxQ = -Double.MAX_VALUE; for (final AnalysisPeriod ap : periodResults) { final double q = ap.getMaxQ(); if (q > maxQ) { maxQ = q; } } final double oldMaxQ = parameters.get(row, maxQIndex); if (oldMaxQ < maxQ) { parameters.set(row, maxQIndex, maxQ); } final AnalysisPeriod[] rap = new AnalysisPeriod[periodResults.size()]; periodResults.toArray(rap); kmResults.add(km, rap); } } }