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

ucar.nc2.ft.fmrc.FmrcInvLite Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.nc2.ft.fmrc;

import thredds.featurecollection.FeatureCollectionConfig;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.util.Misc;
import java.io.FileNotFoundException;
import java.util.*;

/**
 * A lightweight, serializable version of FmrcInv
 *
 * @author caron
 * @since Apr 14, 2010
 */
public class FmrcInvLite implements java.io.Serializable {
  private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FmrcInvLite.class);
  private static final String BEST = "Best";

  // public for debugging
  public String collectionName;
  public CalendarDate base; // offsets are from here
  public int nruns; // runOffset[nruns]
  public double[] runOffset; // run time in offset hours since base
  public double[] forecastOffset; // all forecast times in offset hours since base, for "constant forecast" datasets
  public double[] offsets; // all the offset values, for "constant offset" datasets

  public List locationList = new ArrayList<>(); // dataset location, can be used in
                                                        // NetcdfDataset.acquireDataset()
  public Map locationMap = new HashMap<>(); // quick lookup of dataset location in locationList
  public List gridSets = new ArrayList<>(); // All Grids in Gridset have same time coordinate
  public List invList = new ArrayList<>(); // the actual inventory
                                                                  // share these, they are expensive!

  public FmrcInvLite(FmrcInv fmrcInv) {
    this.collectionName = fmrcInv.getName();
    this.base = fmrcInv.getBaseDate();

    // store forecasts as offsets instead of Dates
    List forecasts = fmrcInv.getForecastTimes();
    this.forecastOffset = new double[forecasts.size()];
    for (int i = 0; i < forecasts.size(); i++) {
      CalendarDate f = forecasts.get(i);
      this.forecastOffset[i] = FmrcInv.getOffsetInHours(base, f);
    }

    // for each run
    List fmrList = fmrcInv.getFmrInv();
    nruns = fmrList.size();
    runOffset = new double[nruns];

    int countIndex = 0;
    for (int run = 0; run < nruns; run++) {
      FmrInv fmr = fmrList.get(run);
      runOffset[run] = FmrcInv.getOffsetInHours(base, fmr.getRunDate());

      for (GridDatasetInv inv : fmr.getInventoryList()) {
        locationList.add(inv.getLocation());
        locationMap.put(inv.getLocation(), countIndex);
        countIndex++;
      }
    }

    // for each RunSeq
    for (FmrcInv.RunSeq runseq : fmrcInv.getRunSeqs()) {
      gridSets.add(new Gridset(runseq));
    }

    // calc the offsets
    TreeSet tree = new TreeSet<>();
    for (Gridset gridset : gridSets) {
      for (int run = 0; run < nruns; run++) {
        double baseOffset = runOffset[run];
        for (int time = 0; time < gridset.noffsets; time++) {
          double offset = gridset.timeOffset[run * gridset.noffsets + time];
          if (!Double.isNaN(offset))
            tree.add(offset - baseOffset);
        }
      }
    }
    offsets = new double[tree.size()];
    Iterator iter = tree.iterator();
    for (int i = 0; i < tree.size(); i++) {
      offsets[i] = iter.next();
    }

  }

  public int findRunIndex(CalendarDate want) {
    for (int i = 0; i < runOffset.length; i++)
      if (want.equals(FmrcInv.makeOffsetDate(base, runOffset[i])))
        return i;
    return -1;
  }

  public List getRunDates() {
    List result = new ArrayList<>(runOffset.length);
    for (double off : runOffset)
      result.add(FmrcInv.makeOffsetDate(base, off));
    return result;
  }

  public List getForecastDates() {
    List result = new ArrayList<>(forecastOffset.length);
    for (double f : forecastOffset)
      result.add(FmrcInv.makeOffsetDate(base, f));
    return result;
  }

  // for making constant offset datasets
  public double[] getForecastOffsets() {
    return offsets;
  }

  public Gridset.Grid findGrid(String gridName) {
    for (Gridset gridset : gridSets) {
      for (Gridset.Grid grid : gridset.grids) {
        if (gridName.equals(grid.name))
          return grid;
      }
    }
    return null;
  }

  public Gridset findGridset(String gridName) {
    for (Gridset gridset : gridSets) {
      for (Gridset.Grid grid : gridset.grids) {
        if (gridName.equals(grid.name))
          return gridset;
      }
    }
    return null;
  }

  // debugging
  public void showGridInfo(String gridName, Formatter out) {
    Gridset.Grid grid = findGrid(gridName);
    if (grid == null) {
      out.format("Cant find grid = %s%n", gridName);
      return;
    }

    Gridset gridset = grid.getGridset();
    out.format("%n=======================================%nFmrcLite.Grid%n");

    // show the 2D
    out.format("2D%n   run%n time  ");
    for (int i = 0; i < gridset.noffsets; i++)
      out.format("%6d ", i);
    out.format("%n");
    for (int run = 0; run < nruns; run++) {
      out.format("%6d", run);
      for (int time = 0; time < gridset.noffsets; time++) {
        out.format(" %6.0f", gridset.getTimeCoord(run, time));
      }
      out.format("%n");
    }
    out.format("%n");

    Gridset.GridInventory gridInv = grid.inv;
    out.format("%n=======================================%nFmrcLite.GridInventory Missing Data%n");

    // show missing inventory only
    for (int run = 0; run < nruns; run++) {
      boolean hasMissing = false;
      for (int time = 0; time < gridset.noffsets; time++)
        if (gridInv.getLocation(run, time) == 0)
          hasMissing = true;

      if (hasMissing) {
        out.format("run %6d timeIdx=", run);
        for (int time = 0; time < gridset.noffsets; time++) {
          if (gridInv.getLocation(run, time) == 0)
            out.format(" %6d", time);
        }
        out.format("%n");
      }
    }
    out.format("%n");

    out.format("%n=======================================%nFmrcLite.TimeInv Best%n");
    BestDatasetInventory best = new BestDatasetInventory(null);
    List bestInv = gridset.timeCoordMap.get(BEST);
    if (bestInv == null)
      bestInv = gridset.makeBest(null);
    FmrcInvLite.ValueB coords = best.getTimeCoords(gridset); // must call this to be sure data is there

    // show the best
    out.format("        ");
    for (int i = 0; i < bestInv.size(); i++)
      out.format(" %6d", i);
    out.format("%n");

    out.format(" coord =");
    for (TimeInv inv : bestInv)
      out.format(" %6.0f", inv.offset);
    out.format("%n");

    out.format(" run   =");
    for (TimeInv inv : bestInv)
      out.format(" %6d", inv.runIdx);
    out.format("%n");

    out.format(" idx   =");
    for (TimeInv inv : bestInv)
      out.format(" %6d", inv.timeIdx);
    out.format("%n");
  }

  // group of Grids with the same time coordinate
  public class Gridset implements java.io.Serializable {
    String gridsetName;
    List grids = new ArrayList<>();
    int noffsets;
    double[] timeOffset; // timeOffset(nruns,noffsets) in offset hours since base. this is the twoD time coordinate for
                         // this Gridset;
                         // Double.NaN for missing values; these are dense (a ragged array has missing all at end)
    double[] timeBounds; // timeBounds(nruns,noffsets,2) in offset hours since base. null means not an interval time
                         // coordinate

    Map> timeCoordMap = new HashMap<>();

    Gridset(FmrcInv.RunSeq runseq) {
      this.gridsetName = runseq.getName();
      List timeList = runseq.getTimes();
      boolean hasMissingTimes = (nruns != timeList.size()); // missing one or more variables in one or more runs
      noffsets = 0;
      for (TimeCoord tc : timeList)
        noffsets = Math.max(noffsets, tc.getNCoords());
      // noffsets = runseq.getUnionTimeCoord().getNCoords();

      // this is the twoD time coordinate for this Gridset
      timeOffset = new double[nruns * noffsets];
      for (int i = 0; i < timeOffset.length; i++)
        timeOffset[i] = Double.NaN;

      if (runseq.isInterval()) {
        timeBounds = new double[nruns * noffsets * 2];
        for (int i = 0; i < timeBounds.length; i++)
          timeBounds[i] = Double.NaN;
      }

      // fill twoD time coordinate from the sequence of time coordinates
      int runIdx = 0;
      for (TimeCoord timeCoord : timeList) {
        TimeCoord tc;
        if (hasMissingTimes) {
          tc = timeCoord;
          double tc_offset = FmrcInv.getOffsetInHours(base, tc.getRunDate());

          while (true) { // incr run till we find it
            double run_offset = runOffset[runIdx];
            if (Misc.nearlyEquals(run_offset, tc_offset)) {
              break;
            }
            runIdx++;
            if (log.isDebugEnabled()) {
              String missingDate = FmrcInv.makeOffsetDate(base, run_offset).toString();
              String wantDate = tc.getRunDate().toString();
              log.debug(collectionName + ": runseq missing time " + missingDate + " looking for " + wantDate
                  + " for var = " + runseq.getUberGrids().get(0).getName());
            }
          }

        } else { // common case
          tc = timeList.get(runIdx);
        }

        double run_offset = FmrcInv.getOffsetInHours(base, tc.getRunDate());
        double[] offsets = tc.getOffsetTimes();
        int ntimes = offsets.length;
        for (int time = 0; time < ntimes; time++) {
          timeOffset[runIdx * noffsets + time] = run_offset + offsets[time]; // offset == bound2 when its an interval
        }

        // optionally create 2D bounds
        if (runseq.isInterval()) {
          double[] bound1 = tc.getBound1();
          double[] bound2 = tc.getBound2();
          for (int time = 0; time < ntimes; time++) {
            timeBounds[2 * (runIdx * noffsets + time)] = run_offset + bound1[time];
            timeBounds[2 * (runIdx * noffsets + time) + 1] = run_offset + bound2[time];
          }
        }

        runIdx++;
      }

      for (FmrcInv.UberGrid ugrid : runseq.getUberGrids()) {
        grids.add(new Grid(ugrid.getName(), getInventory(ugrid)));
      }
    }

    // create GridInventory, see if it matches other Grids
    private GridInventory getInventory(FmrcInv.UberGrid ugrid) {
      GridInventory result = null;
      GridInventory need = new GridInventory(ugrid);

      // see if we already have it
      for (GridInventory got : invList) {
        if (got.equalData(need)) {
          result = got;
          break;
        }
      }
      if (result == null) {
        invList.add(need);
        result = need;
      }
      return result;
    }

    double getTimeCoord(int run, int time) {
      return timeOffset[run * noffsets + time];
    }

    private List makeBest(FeatureCollectionConfig.BestDataset bd) {
      Map map = new HashMap<>();

      for (int run = 0; run < nruns; run++) {
        for (int time = 0; time < noffsets; time++) {
          double baseOffset = timeOffset[run * noffsets + time]; // this is the offset from the global base
          if (Double.isNaN(baseOffset))
            continue;
          double orgOffset = baseOffset - runOffset[run]; // this is the offset from its own base
          if (bd != null && orgOffset < bd.greaterThan)
            continue; // skip it
          if (timeBounds == null)
            map.put(new TimeCoord.Tinv(baseOffset), new TimeInv(run, time, baseOffset)); // later ones override
          else {
            double b1 = timeBounds[2 * (run * noffsets + time)];
            double b2 = timeBounds[2 * (run * noffsets + time) + 1];
            map.put(new TimeCoord.Tinv(b1, b2), new TimeInv(run, time, b1, b2)); // hmmmmm ????
          }
        }
      }

      Collection values = map.values();
      int n = values.size();
      List best = Arrays.asList((TimeInv[]) values.toArray(new TimeInv[n]));
      Collections.sort(best);
      timeCoordMap.put(BEST, best);
      return best;
    }

    private List makeRun(int runIdx) {
      List result = new ArrayList<>(noffsets);
      for (int time = 0; time < noffsets; time++) {
        double offset = timeOffset[runIdx * noffsets + time];
        if (Double.isNaN(offset))
          continue;
        if (timeBounds == null)
          result.add(new TimeInv(runIdx, time, offset));
        else {
          double b1 = timeBounds[2 * (runIdx * noffsets + time)];
          double b2 = timeBounds[2 * (runIdx * noffsets + time) + 1];
          result.add(new TimeInv(runIdx, time, b1, b2));
        }
      }
      timeCoordMap.put("run" + runIdx, result);
      return result;
    }

    private List makeConstantForecast(double offset) {
      List result = new ArrayList<>(noffsets);
      for (int run = 0; run < nruns; run++) {
        for (int time = 0; time < noffsets; time++) { // search for all offsets that match - presumably 0 or 1 per run
          double baseOffset = timeOffset[run * noffsets + time];
          if (Double.isNaN(baseOffset))
            continue;
          if (Misc.nearlyEquals(baseOffset, offset))
            result.add(new TimeInv(run, time, offset - timeOffset[run * noffsets])); // use offset from start of run
        }
      }
      timeCoordMap.put("forecast" + offset, result);
      return result;
    }

    private List makeConstantOffset(double offset) {
      List result = new ArrayList<>(nruns);
      for (int run = 0; run < nruns; run++) {
        for (int time = 0; time < noffsets; time++) { // search for all offsets that match - presumably 0 or 1 per run
          double baseOffset = getTimeCoord(run, time);
          if (Double.isNaN(baseOffset))
            continue;
          double runOffset = baseOffset - FmrcInvLite.this.runOffset[run]; // subtract the base offset for this run
          if (Misc.nearlyEquals(runOffset, offset))
            result.add(new TimeInv(run, time, baseOffset));
        }
      }
      timeCoordMap.put("offset" + offset, result);
      return result;
    }

    public class Grid implements java.io.Serializable {
      String name;
      GridInventory inv; // shared

      Grid(String name, GridInventory inv) {
        this.name = name;
        this.inv = inv;
      }

      Gridset getGridset() {
        return Gridset.this;
      }

      TimeInventory.Instance getInstance(int runIdx, int timeIdx) {
        int locIdx = inv.getLocation(runIdx, timeIdx);
        if (locIdx == 0)
          return null;

        int invIndex = inv.getInvIndex(runIdx, timeIdx);
        return new TimeInstance(locationList.get(locIdx - 1), invIndex);
      }
    } // Grid

    // track inventory, shared amongst grids
    public class GridInventory implements java.io.Serializable {
      int[] location; // (run,time) file location (index+1 into locationList, 0 = missing)
      int[] invIndex; // (run,time) time index in file = 'location'

      /**
       * Create 2D location, time index representing the inventory for a Grid.
       * 
       * @param ugrid for this grid
       */
      GridInventory(FmrcInv.UberGrid ugrid) {
        this.location = new int[nruns * noffsets];
        this.invIndex = new int[nruns * noffsets];

        // loop over runDates
        int gridIdx = 0;
        List grids = ugrid.getRuns(); // must be sorted by rundate. extract needed info, do not
                                                           // keep reference

        for (int runIdx = 0; runIdx < nruns; runIdx++) {
          CalendarDate runDate = FmrcInv.makeOffsetDate(base, runOffset[runIdx]);

          // do we have a grid for this runDate?
          if (gridIdx >= grids.size()) {
            log.debug(collectionName + ": cant find " + ugrid.getName() + " for " + runDate); // could be normal
                                                                                              // condition
            break;
          }
          FmrInv.GridVariable grid = grids.get(gridIdx);
          if (!grid.getRunDate().equals(runDate))
            continue;
          gridIdx++; // for next loop

          // loop over actual inventory
          for (GridDatasetInv.Grid inv : grid.getInventory()) {
            double invOffset = FmrcInv.getOffsetInHours(base, inv.tc.getRunDate()); // offset of this file

            for (int i = 0; i < inv.tc.getNCoords(); i++) {
              int timeIdx;

              if (timeBounds == null) {
                timeIdx = findIndex(runIdx, invOffset + inv.tc.getOffsetTimes()[i]);
              } else {
                timeIdx = findBounds(runIdx, invOffset + inv.tc.getBound1()[i], invOffset + inv.tc.getBound2()[i]);
              }

              if (timeIdx >= 0) {
                location[runIdx * noffsets + timeIdx] = findLocation(inv.getLocation()) + 1;
                invIndex[runIdx * noffsets + timeIdx] = i;
              }
            } // loop over time coordinates

          } // loop over files
        } // loop over run
      }

      private boolean equalData(Object oo) {
        GridInventory o = (GridInventory) oo;
        if (o.location.length != location.length)
          return false;
        if (o.invIndex.length != invIndex.length)
          return false;
        for (int i = 0; i < location.length; i++)
          if (location[i] != o.location[i])
            return false;
        for (int i = 0; i < invIndex.length; i++)
          if (invIndex[i] != o.invIndex[i])
            return false;
        return true;
      }

      // LOOK linear search!
      private int findIndex(int runIdx, double want) {
        for (int j = 0; j < noffsets; j++)
          if (Misc.nearlyEquals(timeOffset[runIdx * noffsets + j], want))
            return j;
        return -1;
      }

      // LOOK linear search!
      private int findBounds(int runIdx, double b1, double b2) {
        for (int j = 0; j < noffsets; j++)
          if (Misc.nearlyEquals(timeBounds[2 * (runIdx * noffsets + j)], b1)
              && Misc.nearlyEquals(timeBounds[2 * (runIdx * noffsets + j) + 1], b2))
            return j;
        return -1;
      }

      private int findLocation(String location) {
        return locationMap.get(location);
      }

      int getLocation(int run, int time) {
        return location[run * noffsets + time];
      }

      int getInvIndex(int run, int time) {
        return invIndex[run * noffsets + time];
      }

    } // GridInventory

  } // Gridset

  // lightweight tracker of where a Grid lives
  static class TimeInstance implements TimeInventory.Instance {
    String location;
    int index; // time index in the file = 'location'

    TimeInstance(String location, int index) {
      this.location = location;
      this.index = index;
    }

    @Override
    public String getDatasetLocation() {
      return location;
    }

    @Override
    public int getDatasetIndex() {
      return index;
    }

    @Override
    public String toString() {
      return "TimeInstance{" + "location='" + location + '\'' + ", index=" + index + '}';
    }
  }

  // represents 1 time coord in a 2d time matrix, point or interval
  private static class TimeInv implements Comparable {
    int runIdx;
    int timeIdx;
    double offset; // hours since base or hours since run time
    double startIntv = Double.NaN;
    boolean isInterval;

    TimeInv(int runIdx, int timeIdx, double b1, double b2) {
      this.runIdx = runIdx;
      this.timeIdx = timeIdx;
      this.startIntv = b1;
      this.offset = b2;
      isInterval = true;
    }

    TimeInv(int runIdx, int timeIdx, double offset) {
      this.runIdx = runIdx;
      this.timeIdx = timeIdx;
      this.offset = offset;
    }

    @Override
    public int compareTo(TimeInv o) {
      if (Misc.nearlyEquals(offset, o.offset))
        return 0;
      if (!isInterval)
        return Double.compare(offset, o.offset);
      if (Misc.nearlyEquals(startIntv, o.startIntv))
        return 0;
      return Double.compare(startIntv, o.startIntv);
    }
  }

  // efficient representation of time coords - point or interval
  public static class ValueB {
    public double[] offset; // the forecast time
    public double[] bounds; // bounds of interval or null. shape = (ntimes, 2)

    public ValueB(List invs) {
      boolean isInterval = !invs.isEmpty() && invs.get(0).isInterval;
      offset = new double[invs.size()];

      if (isInterval) {
        bounds = new double[2 * invs.size()];
        for (int i = 0; i < invs.size(); i++) {
          TimeInv b = invs.get(i);
          offset[i] = b.offset;
          bounds[2 * i] = b.startIntv;
          bounds[2 * i + 1] = b.offset; // end of interval is also the forecast time
        }

      } else {
        for (int i = 0; i < invs.size(); i++) {
          TimeInv b = invs.get(i);
          offset[i] = b.offset;
        }
      }
    }
  }

  // public for debugging
  public TimeInventory makeBestDatasetInventory() {
    return new BestDatasetInventory(null);
  }

  TimeInventory makeBestDatasetInventory(FeatureCollectionConfig.BestDataset bd) {
    return new BestDatasetInventory(bd);
  }

  // public for debugging
  public TimeInventory makeRunTimeDatasetInventory(CalendarDate run) throws FileNotFoundException {
    return new RunTimeDatasetInventory(run);
  }

  // public for debugging
  public TimeInventory getConstantForecastDataset(CalendarDate time) throws FileNotFoundException {
    return new ConstantForecastDataset(time);
  }

  // public for debugging
  public TimeInventory getConstantOffsetDataset(double hour) throws FileNotFoundException {
    return new ConstantOffsetDataset(hour);
  }

  /*
   * The best dataset is based on the Gridset time coordinates, rather than the GridInventory. This means that
   * one can have missing values, instead of using the "next best" runtime.
   * The reason for this is so that all the fields come from the same runtime.
   * If we did implement NextBest, we would need to have different run_time coordinates whenever there were missing
   * values,
   * possible one for each variable, to accurately reflect where the data came from.
   */
  class BestDatasetInventory implements TimeInventory {
    FeatureCollectionConfig.BestDataset bd; // parameterized for offsets >= p. null means want all offsets

    BestDatasetInventory(FeatureCollectionConfig.BestDataset bd) {
      this.bd = bd;
    }

    @Override
    public String getName() {
      return (bd == null) ? BEST : bd.name;
    }

    @Override
    public int getTimeLength(Gridset gridset) {
      List best = gridset.timeCoordMap.get(getName());
      if (best == null)
        best = gridset.makeBest(bd);
      return best.size();
    }

    @Override
    public FmrcInvLite.ValueB getTimeCoords(Gridset gridset) {
      List best = gridset.timeCoordMap.get(getName());
      if (best == null)
        best = gridset.makeBest(bd);
      return new ValueB(best);
    }

    @Override
    public double[] getRunTimeCoords(Gridset gridset) {
      List best = gridset.timeCoordMap.get(getName());
      if (best == null)
        best = gridset.makeBest(bd);
      double[] result = new double[best.size()];
      for (int i = 0; i < best.size(); i++) {
        TimeInv b = best.get(i);
        result[i] = gridset.getTimeCoord(b.runIdx, 0); // the first one for the run given by runIdx
      }
      return result;
    }

    @Override
    public double[] getOffsetCoords(Gridset gridset) {
      List best = gridset.timeCoordMap.get(getName());
      if (best == null)
        best = gridset.makeBest(bd);

      double[] result = new double[best.size()];
      for (int i = 0; i < best.size(); i++) {
        TimeInv b = best.get(i);
        result[i] = b.offset - gridset.getTimeCoord(b.runIdx, 0); // offset from run start
      }
      return result;
    }

    @Override
    public Instance getInstance(Gridset.Grid grid, int timeIdx) {
      Gridset gridset = grid.getGridset();
      List best = gridset.timeCoordMap.get(getName());
      if (best == null)
        best = gridset.makeBest(bd);

      TimeInv b = best.get(timeIdx);
      int locIdx = grid.inv.getLocation(b.runIdx, b.timeIdx);
      if (locIdx == 0)
        return null;

      int invIndex = grid.inv.getInvIndex(b.runIdx, b.timeIdx);
      return new TimeInstance(locationList.get(locIdx - 1), invIndex);
    }
  }

  class RunTimeDatasetInventory implements TimeInventory {
    int runIdx = -1;

    RunTimeDatasetInventory(CalendarDate run) throws FileNotFoundException {
      double offset = FmrcInv.getOffsetInHours(base, run);
      for (int i = 0; i < runOffset.length; i++) {
        if (Misc.nearlyEquals(runOffset[i], offset)) {
          runIdx = i;
          break;
        }
      }
      if (runIdx < 0)
        throw new FileNotFoundException("No run date of " + run);
    }

    @Override
    public String getName() {
      return "Run " + FmrcInv.makeOffsetDate(base, runOffset[runIdx]);
    }

    @Override
    public int getTimeLength(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("run" + runIdx);
      if (coords == null)
        coords = gridset.makeRun(runIdx);
      return coords.size();
    }

    @Override
    public FmrcInvLite.ValueB getTimeCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("run" + runIdx);
      if (coords == null)
        coords = gridset.makeRun(runIdx);
      return new FmrcInvLite.ValueB(coords);
    }

    @Override
    public double[] getRunTimeCoords(Gridset gridset) {
      return null;
    }

    @Override
    public double[] getOffsetCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("run" + runIdx);
      if (coords == null)
        coords = gridset.makeRun(runIdx);

      double startRun = gridset.getTimeCoord(runIdx, 0);
      double[] result = new double[coords.size()];
      for (int i = 0; i < coords.size(); i++) {
        TimeInv b = coords.get(i);
        result[i] = b.offset - startRun;
      }
      return result;
    }

    @Override
    public Instance getInstance(Gridset.Grid grid, int timeIdx) {
      Gridset gridset = grid.getGridset();
      List coords = gridset.timeCoordMap.get("run" + runIdx);
      if (coords == null)
        coords = gridset.makeRun(runIdx);

      TimeInv b = coords.get(timeIdx);
      return grid.getInstance(b.runIdx, b.timeIdx);
    }
  }

  class ConstantForecastDataset implements TimeInventory {
    double offset;

    ConstantForecastDataset(CalendarDate time) throws FileNotFoundException {
      this.offset = FmrcInv.getOffsetInHours(base, time);
      for (CalendarDate d : getForecastDates())
        if (d.equals(time))
          return; // ok

      throw new FileNotFoundException("No forecast date of " + time); // we dont got it
    }

    @Override
    public String getName() {
      return "Constant Forecast " + FmrcInv.makeOffsetDate(base, offset);
    }

    @Override
    public int getTimeLength(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("forecast" + offset);
      if (coords == null)
        coords = gridset.makeConstantForecast(offset);
      return coords.size();
    }

    @Override
    public FmrcInvLite.ValueB getTimeCoords(Gridset gridset) {
      return null;
    }

    @Override
    public double[] getRunTimeCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("forecast" + offset);
      if (coords == null)
        coords = gridset.makeConstantForecast(offset);

      double[] result = new double[coords.size()];
      for (int i = 0; i < coords.size(); i++) {
        TimeInv b = coords.get(i);
        result[i] = gridset.getTimeCoord(b.runIdx, 0);
      }
      return result;
    }

    @Override
    public double[] getOffsetCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("forecast" + offset);
      if (coords == null)
        coords = gridset.makeConstantForecast(offset);

      double[] result = new double[coords.size()];
      for (int i = 0; i < coords.size(); i++) {
        TimeInv b = coords.get(i);
        result[i] = b.offset;
      }
      return result;
    }

    @Override
    public Instance getInstance(Gridset.Grid grid, int timeIdx) {
      Gridset gridset = grid.getGridset();
      List coords = gridset.timeCoordMap.get("forecast" + offset);
      if (coords == null)
        coords = gridset.makeConstantForecast(offset);

      TimeInv b = coords.get(timeIdx);
      return grid.getInstance(b.runIdx, b.timeIdx);
    }
  }

  class ConstantOffsetDataset implements TimeInventory {
    double offset;

    ConstantOffsetDataset(double offset) throws FileNotFoundException {
      this.offset = offset;
      boolean ok = false;
      double[] offsets = getForecastOffsets();
      for (double v : offsets) {
        if (Misc.nearlyEquals(v, offset)) {
          ok = true;
        }
      }

      if (!ok)
        throw new FileNotFoundException("No constant offset dataset for = " + offset);
    }

    @Override
    public String getName() {
      return "Constant Offset " + offset + " hours";
    }

    @Override
    public int getTimeLength(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("offset" + offset);
      if (coords == null)
        coords = gridset.makeConstantOffset(offset);
      return coords.size();
    }

    @Override
    public FmrcInvLite.ValueB getTimeCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("offset" + offset);
      if (coords == null)
        coords = gridset.makeConstantOffset(offset);
      return new FmrcInvLite.ValueB(coords);
    }

    @Override
    public double[] getRunTimeCoords(Gridset gridset) {
      List coords = gridset.timeCoordMap.get("offset" + offset);
      if (coords == null)
        coords = gridset.makeConstantOffset(offset);

      double[] result = new double[coords.size()];
      for (int i = 0; i < coords.size(); i++) {
        TimeInv b = coords.get(i);
        result[i] = gridset.getTimeCoord(b.runIdx, 0);
      }
      return result;
    }

    @Override
    public double[] getOffsetCoords(Gridset gridset) {
      return null;
    }

    @Override
    public Instance getInstance(Gridset.Grid grid, int timeIdx) {
      Gridset gridset = grid.getGridset();
      List coords = gridset.timeCoordMap.get("offset" + offset);
      if (coords == null)
        coords = gridset.makeConstantOffset(offset);

      TimeInv b = coords.get(timeIdx);
      return grid.getInstance(b.runIdx, b.timeIdx);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy