diff artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.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 0274c7444b2d
children 2b83d3a96703
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.java	Thu Aug 16 15:47:10 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.java	Thu Aug 16 16:27:53 2018 +0200
@@ -9,10 +9,7 @@
 package org.dive4elements.river.artifacts.model.fixings;
 
 import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.common.utils.StringUtils;
@@ -21,118 +18,39 @@
 import org.dive4elements.river.artifacts.math.fitting.FunctionFactory;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
-import org.dive4elements.river.artifacts.model.FixingsColumn;
-import org.dive4elements.river.artifacts.model.FixingsColumnFactory;
-import org.dive4elements.river.artifacts.model.FixingsOverview;
-import org.dive4elements.river.artifacts.model.FixingsOverview.Fixing;
-import org.dive4elements.river.artifacts.model.FixingsOverview.Fixing.Filter;
-import org.dive4elements.river.artifacts.model.FixingsOverview.IdsFilter;
-import org.dive4elements.river.artifacts.model.FixingsOverviewFactory;
 import org.dive4elements.river.artifacts.model.Parameters;
+import org.dive4elements.river.artifacts.model.fixings.FixingsOverview.IdsFilter;
 import org.dive4elements.river.utils.DoubleUtil;
-import org.dive4elements.river.utils.KMIndex;
 
 /** Calculation base class for fix. */
 public abstract class FixCalculation extends Calculation {
+
+    private static final long serialVersionUID = 1L;
+
     private static Logger log = Logger.getLogger(FixCalculation.class);
 
-    public static final double EPSILON = 1e-4;
-
-    public static final String[] STANDARD_COLUMNS = { "km", "chi_sqr", "max_q", "std-dev" };
+    private static final String[] STANDARD_COLUMNS = { "km", "chi_sqr", "max_q", "std-dev" };
 
     protected static class FitResult {
 
         private final Parameters parameters;
-        private final KMIndex<QWD[]> fixings;
 
-        public FitResult(final Parameters parameters, final KMIndex<QWD[]> fixings) {
+        private final FixResultColumns resultColumns;
+
+        public FitResult(final Parameters parameters, final FixResultColumns resultColumns) {
             this.parameters = parameters;
-            this.fixings = fixings;
+            this.resultColumns = resultColumns;
         }
 
         public Parameters getParameters() {
             return this.parameters;
         }
 
-        public KMIndex<QWD[]> getFixings() {
-            return this.fixings;
+        public FixResultColumns getResultColumns() {
+            return this.resultColumns;
         }
     }
 
-    /**
-     * Helper class to bundle the meta information of a column
-     * and the real data.
-     */
-    protected static class Column {
-
-        protected Fixing.Column meta;
-        protected FixingsColumn data;
-        protected int index;
-
-        public Column() {
-        }
-
-        public Column(final Fixing.Column meta, final FixingsColumn data, final int index) {
-            this.meta = meta;
-            this.data = data;
-            this.index = index;
-        }
-
-        public Date getDate() {
-            return this.meta.getStartTime();
-        }
-
-        public String getDescription() {
-            return this.meta.getDescription();
-        }
-
-        public int getIndex() {
-            return this.index;
-        }
-
-        public int getId() {
-            return this.meta.getId();
-        }
-
-        public boolean getQW(final double km, final double[] qs, final double[] ws, final int index) {
-            qs[index] = this.data.getQ(km);
-            return this.data.getW(km, ws, index);
-        }
-
-        public boolean getQW(final double km, final double[] wq) {
-            this.data.getW(km, wq, 0);
-            if (Double.isNaN(wq[0]))
-                return false;
-            wq[1] = this.data.getQ(km);
-            return !Double.isNaN(wq[1]);
-        }
-    } // class Column
-
-    /**
-     * Helper class to find the data belonging to meta info more quickly.
-     */
-    protected static class ColumnCache {
-
-        protected Map<Integer, Column> columns;
-
-        public ColumnCache() {
-            this.columns = new HashMap<>();
-        }
-
-        public Column getColumn(final Fixing.Column meta) {
-            final Integer key = meta.getId();
-            Column column = this.columns.get(key);
-            if (column == null) {
-                final FixingsColumn data = FixingsColumnFactory.getInstance().getColumnData(meta);
-                if (data != null) {
-                    column = new Column(meta, data, this.columns.size());
-                    this.columns.put(key, column);
-                }
-            }
-            return column;
-        }
-    } // class ColumnCache
-
     protected String river;
     protected double from;
     protected double to;
@@ -220,20 +138,20 @@
      * Create filter to accept only the chosen events.
      * This factored out out to be overwritten.
      */
-    protected Filter createFilter() {
+    protected FixingColumnFilter createFilter() {
         return new IdsFilter(this.events);
     }
 
-    protected List<Column> getEventColumns(final FixingsOverview overview, final ColumnCache cc) {
-        final Filter filter = createFilter();
-
-        final List<Fixing.Column> metas = overview.filter(null, filter);
+    protected List<FixingColumnWithData> getEventColumns(final FixingsOverview overview, final ColumnCache cc) {
+        final FixingColumnFilter filter = createFilter();
 
-        final List<Column> columns = new ArrayList<>(metas.size());
+        final List<FixingColumn> metas = overview.filter(null, filter);
 
-        for (final Fixing.Column meta : metas) {
+        final List<FixingColumnWithData> columns = new ArrayList<>(metas.size());
 
-            final Column data = cc.getColumn(meta);
+        for (final FixingColumn meta : metas) {
+
+            final FixingColumnWithData data = cc.getColumn(meta);
             if (data == null) {
                 addProblem("fix.cannot.load.data");
             } else {
@@ -245,36 +163,18 @@
     }
 
     // Fit a function to the given points from fixation.
-    protected FitResult doFitting(final FixingsOverview overview, final ColumnCache cc, final Function func) {
+    protected final FitResult doFitting(final FixingsOverview overview, final ColumnCache cc, final Function func) {
         final boolean debug = log.isDebugEnabled();
 
-        final List<Column> eventColumns = getEventColumns(overview, cc);
+        final FixResultColumns resultColumns = new FixResultColumns();
+
+        final List<FixingColumnWithData> eventColumns = getEventColumns(overview, cc);
 
         if (eventColumns.size() < 2) {
             addProblem("fix.too.less.data.columns");
             return null;
         }
 
-        final double[] qs = new double[eventColumns.size()];
-        final double[] ws = new double[qs.length];
-        final boolean[] interpolated = new boolean[ws.length];
-
-        final Fitting.QWDFactory qwdFactory = new Fitting.QWDFactory() {
-            @Override
-            public QWD create(final double q, final double w, double deltaW, boolean isOutlier) {
-                // Check all the event columns for close match
-                // and take the description and the date from meta.
-                for (int i = 0; i < qs.length; ++i) {
-                    if (Math.abs(qs[i] - q) < EPSILON && Math.abs(ws[i] - w) < EPSILON) {
-                        final Column column = eventColumns.get(i);
-                        return new QWD(qs[i], ws[i], column.getDescription(), column.getDate(), interpolated[i], deltaW, column.getId(), isOutlier); // Use database id here
-                    }
-                }
-                log.warn("cannot find column for (" + q + ", " + w + ")");
-                return new QWD(q, w, isOutlier);
-            }
-        };
-
         final String[] parameterNames = func.getParameterNames();
 
         final Parameters results = new Parameters(StringUtils.join(STANDARD_COLUMNS, parameterNames));
@@ -287,8 +187,6 @@
             log.debug("number of kms: " + kms.length);
         }
 
-        final KMIndex<QWD[]> fixings = new KMIndex<>();
-
         final int kmIndex = results.columnIndex("km");
         final int chiSqrIndex = results.columnIndex("chi_sqr");
         final int maxQIndex = results.columnIndex("max_q");
@@ -299,20 +197,13 @@
 
         for (final double km : kms) {
 
-            // Fill Qs and Ws from event columns.
-            for (int j = 0; j < ws.length; ++j) 
-                interpolated[j] = !eventColumns.get(j).getQW(km, qs, ws, j);
-
-            final Fitting fitting = Fitting.fit(func, qwdFactory, this.preprocessing, qs, ws);
+            final Fitting fitting = Fitting.fit(resultColumns, km, func, this.preprocessing, eventColumns);
             if (fitting == null) {
                 log.debug("Fitting for km: " + km + " failed");
                 ++numFailed;
                 addProblem(km, "fix.fitting.failed");
                 continue;
             }
-            
-            final QWD[] fixingsArray = fitting.getFixingsArray();
-            fixings.add(km, fixingsArray);
 
             final int row = results.newRow();
             final double[] values = fitting.getParameters();
@@ -338,9 +229,9 @@
             results.removeNaNs();
         }
 
-        fixings.sort();
+        resultColumns.sortAll();
 
-        return new FitResult(results, fixings);
+        return new FitResult(results, resultColumns);
     }
 
     public CalculationResult calculate() {
@@ -356,22 +247,10 @@
             addProblem("fix.invalid.function.name");
         }
 
-        if (hasProblems()) {
+        if (hasProblems())
             return new CalculationResult(this);
-        }
-        final CalculationResult result = innerCalculate(overview, func);
 
-        if (result != null) {
-            // Workaraound to deal with same dates in data set
-            final Object o = result.getData();
-            if (o instanceof FixResult) {
-                final FixResult fr = (FixResult) o;
-                fr.makeEventsDatesUnique();
-                fr.remapEventIndicesToRank();
-            }
-        }
-
-        return result;
+        return innerCalculate(overview, func);
     }
 
     protected abstract CalculationResult innerCalculate(FixingsOverview overview, Function function);

http://dive4elements.wald.intevation.org