diff artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java @ 9415:9744ce3c3853

Rework of fixanalysis computation and dWt and WQ facets. Got rid of strange remapping and bitshifting code by explicitely saving the column information and using it in the facets. The facets also put the valid station range into their xml-metadata
author gernotbelger
date Thu, 16 Aug 2018 16:27:53 +0200
parents ddcd52d239cd
children 2b83d3a96703
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java	Thu Aug 16 15:47:10 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java	Thu Aug 16 16:27:53 2018 +0200
@@ -8,56 +8,47 @@
 
 package org.dive4elements.river.artifacts.model.fixings;
 
-import org.dive4elements.river.artifacts.access.FixAnalysisAccess;
+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.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.FixingsOverview.AndFilter;
-import org.dive4elements.river.artifacts.model.FixingsOverview.DateRangeFilter;
-
-import org.dive4elements.river.artifacts.model.FixingsOverview.Fixing.Filter;
-
-import org.dive4elements.river.artifacts.model.FixingsOverview.Fixing;
-import org.dive4elements.river.artifacts.model.FixingsOverview.IdsFilter;
-import org.dive4elements.river.artifacts.model.FixingsOverview.KmFilter;
-import org.dive4elements.river.artifacts.model.FixingsOverview.SectorFilter;
-
-import org.dive4elements.river.artifacts.model.FixingsOverview;
 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;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+public class FixAnalysisCalculation extends FixCalculation {
 
-import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+    private static final long serialVersionUID = 1L;
 
-import org.apache.log4j.Logger;
-
-public class FixAnalysisCalculation
-extends      FixCalculation
-{
     private static Logger log = Logger.getLogger(FixAnalysisCalculation.class);
 
-    protected DateRange    referencePeriod;
-    protected DateRange [] analysisPeriods;
+    private DateRange referencePeriod;
+
+    private DateRange[] analysisPeriods;
 
     public FixAnalysisCalculation() {
     }
 
-    public FixAnalysisCalculation(FixAnalysisAccess access) {
+    public FixAnalysisCalculation(final FixAnalysisAccess access) {
+
         super(access);
 
-        DateRange    referencePeriod = access.getReferencePeriod();
-        DateRange [] analysisPeriods = access.getAnalysisPeriods();
+        final DateRange referencePeriod = access.getReferencePeriod();
+        final DateRange[] analysisPeriods = access.getAnalysisPeriods();
 
         if (referencePeriod == null) {
             addProblem("fix.missing.reference.period");
@@ -74,132 +65,93 @@
     }
 
     @Override
-    public CalculationResult innerCalculate(
-        FixingsOverview overview,
-        Function        func
-    ) {
-        ColumnCache cc = new ColumnCache();
-
-        FitResult fitResult = doFitting(overview, cc, func);
-
-        if (fitResult == null) {
-            return new CalculationResult(this);
-        }
+    public CalculationResult innerCalculate(final FixingsOverview overview, final Function func) {
+        final ColumnCache cc = new ColumnCache();
 
-        KMIndex<AnalysisPeriod []> analysisPeriods =
-            calculateAnalysisPeriods(
-                func,
-                fitResult.getParameters(),
-                overview,
-                cc);
-
-        analysisPeriods.sort();
+        final FitResult fitResult = doFitting(overview, cc, func);
 
-        FixAnalysisResult far = new FixAnalysisResult(
-            fitResult.getParameters(),
-            fitResult.getFixings(),
-            analysisPeriods);
+        if (fitResult == null)
+            return new CalculationResult(this);
 
-        // Workaraound to deal with same dates in data set
-        far.makeAnalysisEventsUnique();
-        for (int i = 0; i < this.analysisPeriods.length; ++i) {
-            far.remapAnalysisEventsIndicesToRank(i);
-        }
+        final Parameters parameters = fitResult.getParameters();
 
+        final AnalysisPeriodEventResults eventResults = new AnalysisPeriodEventResults();
+        final KMIndex<AnalysisPeriod[]> kmResults = new KMIndex<>(parameters.size());
+
+        calculateAnalysisPeriods(func, 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 Filter createFilter() {
-        Filter ids = super.createFilter();
-        DateRangeFilter rdf = new DateRangeFilter(
-            referencePeriod.getFrom(),
-            referencePeriod.getTo());
+    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);
     }
 
-    protected KMIndex<AnalysisPeriod []> calculateAnalysisPeriods(
-        Function        function,
-        Parameters      parameters,
-        FixingsOverview overview,
-        ColumnCache     cc
-    ) {
-        Range range = new Range(from, to);
-
-        int kmIndex   = parameters.columnIndex("km");
-        int maxQIndex = parameters.columnIndex("max_q");
-
-        final double [] ws = new double[1];
-        final double [] qs = new double[1];
-
-        int [] parameterIndices =
-            parameters.columnIndices(function.getParameterNames());
-
-        double [] parameterValues = new double[parameterIndices.length];
+    private void calculateAnalysisPeriods(final Function function, final Parameters parameters, final FixingsOverview overview, final ColumnCache cc,
+            final AnalysisPeriodEventResults eventResults, final KMIndex<AnalysisPeriod[]> kmResults) {
 
-        DateAverager dateAverager = new DateAverager();
-
-        KMIndex<AnalysisPeriod []> results =
-            new KMIndex<AnalysisPeriod []>(parameters.size());
-
-        IdsFilter idsFilter = new IdsFilter(events);
+        final Range range = new Range(this.from, this.to);
 
-        TIntIntHashMap [] col2indices =
-            new TIntIntHashMap[analysisPeriods.length];
-
-        DateRangeFilter [] drfs = new DateRangeFilter[analysisPeriods.length];
+        final int kmIndex = parameters.columnIndex("km");
+        final int maxQIndex = parameters.columnIndex("max_q");
 
-        boolean debug = log.isDebugEnabled();
+        final double[] ws = new double[1];
 
-        for (int i = 0; i < analysisPeriods.length; ++i) {
+        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(
-                analysisPeriods[i].getFrom(),
-                analysisPeriods[i].getTo());
+            drfs[i] = new DateRangeFilter(this.analysisPeriods[i].getFrom(), this.analysisPeriods[i].getTo());
 
             if (debug) {
-                log.debug("Analysis period " + (i+1) + " date range: " +
-                    analysisPeriods[i].getFrom() + " - " +
-                    analysisPeriods[i].getTo());
+                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) {
-            double km = parameters.get(row, kmIndex);
+            final double km = parameters.get(row, kmIndex);
             parameters.get(row, parameterIndices, parameterValues);
 
             // This is the parameterized function for a given km.
-            org.dive4elements.river.artifacts.math.Function instance =
-                function.instantiate(parameterValues);
-
-            KmFilter kmFilter = new KmFilter(km);
-
-            ArrayList<AnalysisPeriod> periodResults =
-                new ArrayList<AnalysisPeriod>(analysisPeriods.length);
+            final org.dive4elements.river.artifacts.math.Function instance = function.instantiate(parameterValues);
 
-            for (int ap = 0; ap < analysisPeriods.length; ++ap) {
-                DateRange analysisPeriod = analysisPeriods[ap];
-                TIntIntHashMap col2index = col2indices[ap];
+            final KmFilter kmFilter = new KmFilter(km);
 
-                DateRangeFilter drf = drfs[ap];
+            final List<AnalysisPeriod> periodResults = new ArrayList<>(this.analysisPeriods.length);
 
-                QWD []    qSectorAverages = new QWD[4];
-                double [] qSectorStdDevs  = new double[4];
+            for (int ap = 0; ap < this.analysisPeriods.length; ++ap) {
+                final DateRange analysisPeriod = this.analysisPeriods[ap];
 
-                ArrayList<QWD> allQWDs = new ArrayList<QWD>();
+                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 = qSectorStart;
-                     qSector <= qSectorEnd;
-                     ++qSector
-                ) {
-                    Filter filter = new AndFilter()
-                        .add(kmFilter)
-                        .add(new SectorFilter(qSector))
-                        .add(drf)
-                        .add(idsFilter);
+                for (int qSector = this.qSectorStart; qSector <= this.qSectorEnd; ++qSector) {
+                    final FixingColumnFilter filter = new AndFilter().add(kmFilter).add(new SectorFilter(qSector)).add(drf).add(idsFilter);
 
-                    List<Fixing.Column> metas = overview.filter(range, filter);
+                    final List<FixingColumn> metas = overview.filter(range, filter);
 
                     if (metas.isEmpty()) {
                         // No fixings for km and analysis period
@@ -209,53 +161,42 @@
                     double sumQ = 0.0;
                     double sumW = 0.0;
 
-                    StandardDeviation stdDev = new StandardDeviation();
+                    final StandardDeviation stdDev = new StandardDeviation();
 
-                    List<QWD> qwds = new ArrayList<QWD>(metas.size());
+                    final List<QWD> qwds = new ArrayList<>(metas.size());
 
                     dateAverager.clear();
 
-                    for (Fixing.Column meta: metas) {
+                    for (final FixingColumn meta : metas) {
                         if (meta.findQSector(km) != qSector) {
                             // Ignore not matching sectors.
                             continue;
                         }
 
-                        final Column column = cc.getColumn(meta);
-                        if (column == null )
-                            continue;
-
-                        boolean interpolated = !column.getQW(km, qs, ws, 0);
-                        // FIXME: it was like this before... check if this has an effekt on the calculation
-                        interpolated = true;
-
-                        final double w = ws[0];
-                        final double q = qs[0];
-                        if( Double.isNaN(w) || Double.isNaN(q))
+                        final FixingColumnWithData column = cc.getColumn(meta);
+                        if (column == null)
                             continue;
 
-                        double fw = instance.value(q);
-                        if (Double.isNaN(fw)) {
+                        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;
-                        }
 
-                        double dw = (w - fw)*100.0;
+                        final double fw = instance.value(q);
+                        if (Double.isNaN(fw))
+                            continue;
 
-                        
+                        final double dw = (w - fw) * 100.0;
+
                         stdDev.increment(dw);
 
-                        Date date = column.getDate();
-                        String description = column.getDescription();
-                        
-                        
-                        QWD qwd = new QWD(
-                            q, w,
-                            description,
-                            date, interpolated,
-                            dw, getIndex(col2index, column.getIndex()),
-                            false);
+                        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;
@@ -264,71 +205,58 @@
                     }
 
                     // Calulate average per Q sector.
-                    int N = qwds.size();
+                    final int N = qwds.size();
                     if (N > 0) {
                         allQWDs.addAll(qwds);
-                        double avgW = sumW / N;
-                        double avgQ = sumQ / N;
+                        final double avgW = sumW / N;
+                        final double avgQ = sumQ / N;
 
-                        double avgFw = instance.value(avgQ);
+                        final double avgFw = instance.value(avgQ);
                         if (!Double.isNaN(avgFw)) {
-                            double avgDw = (avgW - avgFw)*100.0;
-                            Date avgDate = dateAverager.getAverage();
+                            final double avgDw = (avgW - avgFw) * 100.0;
+                            final Date avgDate = dateAverager.getAverage();
 
-                            String avgDescription = "avg.deltawt." + qSector;
-
-                            QWD avgQWD = new QWD(
-                                avgQ, avgW, avgDescription,
-                                avgDate, true, avgDw, 0, false);
+                            final QWD avgQWD = new QWD(avgQ, avgW, avgDate, true, avgDw, false);
 
                             qSectorAverages[qSector] = avgQWD;
                         }
                         qSectorStdDevs[qSector] = stdDev.getResult();
-                    }
-                    else {
+                    } else {
                         qSectorStdDevs[qSector] = Double.NaN;
                     }
                 } // for all Q sectors
 
-                QWD [] aqwds = allQWDs.toArray(new QWD[allQWDs.size()]);
+                /* 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();
+                }
 
-                AnalysisPeriod periodResult = new AnalysisPeriod(
-                    analysisPeriod,
-                    aqwds,
-                    qSectorAverages,
-                    qSectorStdDevs);
+                final AnalysisPeriod periodResult = new AnalysisPeriod(analysisPeriod, qSectorAverages, qSectorStdDevs, maxQ);
                 periodResults.add(periodResult);
             }
 
             double maxQ = -Double.MAX_VALUE;
-            for (AnalysisPeriod ap: periodResults) {
-                double q = ap.getMaxQ();
+            for (final AnalysisPeriod ap : periodResults) {
+                final double q = ap.getMaxQ();
                 if (q > maxQ) {
                     maxQ = q;
                 }
             }
 
-            double oldMaxQ = parameters.get(row, maxQIndex);
+            final double oldMaxQ = parameters.get(row, maxQIndex);
             if (oldMaxQ < maxQ) {
                 parameters.set(row, maxQIndex, maxQ);
             }
 
-            AnalysisPeriod [] rap = new AnalysisPeriod[periodResults.size()];
+            final AnalysisPeriod[] rap = new AnalysisPeriod[periodResults.size()];
             periodResults.toArray(rap);
-            results.add(km, rap);
+            kmResults.add(km, rap);
         }
-
-        return results;
     }
-
-    /** Returns the mapped value of colIdx or the size of the hashmap. */
-    private static final int getIndex(TIntIntHashMap map, int colIdx) {
-        if (map.containsKey(colIdx)) {
-            return map.get(colIdx);
-        }
-        int index = map.size();
-        map.put(colIdx, index);
-        return index;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file

http://dive4elements.wald.intevation.org