package ucar.coord; import java.util.*; /** * Create shared coordinates across variables in the same group, * to form the set of group coordinates. * Use Coordinate.equals() to find unique coordinates. * * This is a builder helper class. * * @author John * @since 1/4/14 */ public class CoordinateSharer<T> { static private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CoordinateSharer.class); ////////////////////////////////////////// boolean isRuntimeUnion; /** * @param isRuntimeUnion if true, make union of runtimes, otherwise keep separate runtimes if distinct */ public CoordinateSharer(boolean isRuntimeUnion) { this.isRuntimeUnion = false; // isRuntimeUnion; LOOK turn this off until we can fix it } Set<Coordinate> runtimeBuilders = new HashSet<>(); Set<Coordinate> timeBuilders = new HashSet<>(); Set<Coordinate> timeIntvBuilders = new HashSet<>(); Set<Coordinate> vertBuilders = new HashSet<>(); Set<Coordinate> ensBuilders = new HashSet<>(); Set<Coordinate> time2DBuilders = new HashSet<>(); List<Coordinate> unionCoords = new ArrayList<>(); Map<Coordinate, Integer> coordMap; CoordinateRuntime.Builder2 runtimeAllBuilder; CoordinateTime2DUnionizer time2DUnionizer; CoordinateTime2DUnionizer timeIntv2DUnionizer; // CoordinateTime2D.Builder2 time2DAllBuilder; CoordinateRuntime runtimeAll; CoordinateTime2D time2Dall, timeIntv2Dall; public void addCoordinate(Coordinate coord) { switch (coord.getType()) { case runtime: runtimeBuilders.add(coord); // unique coordinates break; case time: timeBuilders.add(coord); break; case timeIntv: timeIntvBuilders.add(coord); break; case time2D: time2DBuilders.add(coord); break; case vert: vertBuilders.add(coord); break; case ens: ensBuilders.add(coord); break; } } // add each variable's list of coordinate // keep in Set, so it hold just the unique ones public void addCoords(List<Coordinate> coords) { CoordinateRuntime runtime = null; for (Coordinate coord : coords) { switch (coord.getType()) { case runtime: runtime = (CoordinateRuntime) coord; if (isRuntimeUnion) { // make union of all coords if (runtimeAllBuilder == null) runtimeAllBuilder = new CoordinateRuntime.Builder2(runtime.getTimeUnits()); runtimeAllBuilder.addAll(coord); } else runtimeBuilders.add(coord); // unique coordinates break; case time: timeBuilders.add(coord); break; case timeIntv: timeIntvBuilders.add(coord); break; case time2D: CoordinateTime2D time2D = (CoordinateTime2D) coord; if (isRuntimeUnion) { // make union of all coordsz if (time2D.isTimeInterval()) { if (timeIntv2DUnionizer == null) timeIntv2DUnionizer = new CoordinateTime2DUnionizer(time2D.isTimeInterval(), time2D.getTimeUnit(), coord.getCode(), true); timeIntv2DUnionizer.addAll(time2D); } else { if (time2DUnionizer == null) time2DUnionizer = new CoordinateTime2DUnionizer(time2D.isTimeInterval(), time2D.getTimeUnit(), coord.getCode(), true); time2DUnionizer.addAll(time2D); } //if (time2DAllBuilder == null) // boolean isTimeInterval, Grib2Customizer cust, CalendarPeriod timeUnit, int code // time2DAllBuilder = new CoordinateTime2D.Builder2(time2D.isTimeInterval(), null, time2D.getTimeUnit(), time2D.getCode()); // time2DAllBuilder.addAll(coord); } else { time2DBuilders.add(coord); } // debug CoordinateRuntime runtimeFrom2D = time2D.getRuntimeCoordinate(); if (!runtimeFrom2D.equals(runtime)) System.out.println("CoordinateSharer runtimes differ"); break; case vert: vertBuilders.add(coord); break; case ens: ensBuilders.add(coord); break; } } } //Map<CoordinateTime2D, CoordinateTime2D> resetSet; // new, new //Map<Coordinate, CoordinateTime2D> convert; // prev, new public void finish() { if (isRuntimeUnion) { // have to redo any time2D with runtimeAll runtimeAll = (CoordinateRuntime) runtimeAllBuilder.finish(); unionCoords.add(runtimeAll); if (time2DUnionizer != null) { time2DUnionizer.setRuntimeCoords(runtimeAll); // make sure there a single runtime time2Dall = (CoordinateTime2D) time2DUnionizer.finish(); unionCoords.add(time2Dall); } if (timeIntv2DUnionizer != null) { timeIntv2DUnionizer.setRuntimeCoords(runtimeAll); // make sure theres a single runtime timeIntv2Dall = (CoordinateTime2D) timeIntv2DUnionizer.finish(); unionCoords.add(timeIntv2Dall); } } else { // not runtimeUnion for (Coordinate coord : runtimeBuilders) unionCoords.add(coord); // try to regularize any time2D HashSet<CoordinateTime2D> coord2Dset = new HashSet<>(); for (Coordinate coord : time2DBuilders) { CoordinateTime2D coord2D = (CoordinateTime2D) coord; CoordinateTime2DUnionizer unionizer = new CoordinateTime2DUnionizer(coord2D.isTimeInterval(), coord2D.getTimeUnit(), coord2D.getCode(), true); unionizer.addAll(coord2D); unionizer.finish(); CoordinateTime2D result = (CoordinateTime2D) unionizer.getCoordinate(); // this tests for orthogonal and regular if (result.isOrthogonal() || result.isRegular()) { if (!coord2Dset.contains(result)) { // its possible that result is a duplicate CoordinateTime2D. unionCoords.add(result); // use the new one coord2Dset.add(result); } swap.put(coord, result); // track old, new swap } else { unionCoords.add(coord2D); // use the old one coord2Dset.add(coord2D); } } } for (Coordinate coord : timeBuilders) unionCoords.add(coord); for (Coordinate coord : timeIntvBuilders) unionCoords.add(coord); for (Coordinate coord : vertBuilders) unionCoords.add(coord); for (Coordinate coord : ensBuilders) unionCoords.add(coord); // fast lookup coordMap = new HashMap<>(); for (int i = 0; i < this.unionCoords.size(); i++) { coordMap.put(this.unionCoords.get(i), i); } } private Map<Coordinate, Coordinate> swap = new HashMap<>(); // this is the set of shared coordinates to be stored in the group public List<Coordinate> getUnionCoords() { return unionCoords; } /** * If using runtimeUnion, or time2D, you must reindex the CoordinateND * @param prev previous CoordinateND * @return new CoordinateND containing shared coordinates and sparseArray for the new coordinates * or the prev CoordinateND if reindexing not needed. */ public CoordinateND<T> reindexCoordND(CoordinateND<T> prev) { boolean needReindex = false; for (Coordinate coord : prev.getCoordinates()) { if (isRuntimeUnion && (coord.getType() == Coordinate.Type.runtime) && !coord.equals(runtimeAll)) needReindex = true; if (null != swap.get(coord)) // time2D got swapped needReindex = true; } if (!needReindex) return prev; // need to switch out the runtime and time2D List<Coordinate> coords = new ArrayList<>(); for (Coordinate prevCoord : prev.getCoordinates()) { if (isRuntimeUnion) { if (prevCoord.getType() == Coordinate.Type.runtime) { coords.add(runtimeAll); } else if (prevCoord.getType() == Coordinate.Type.time2D) { CoordinateTime2D time2D = (CoordinateTime2D) prevCoord; if (time2D.isTimeInterval()) coords.add(timeIntv2Dall); else coords.add(time2Dall); } else { coords.add(prevCoord); } } else { // normal case - runTime2D may have gotten modified Coordinate newCoord = swap.get(prevCoord); if (newCoord != null) coords.add(newCoord); else coords.add(prevCoord); } } return new CoordinateND.Builder<T>().reindex(coords, prev); } // find indexes into unionCoords of a variable's coordinates public List<Integer> reindex2shared(List<Coordinate> prev) { List<Integer> result = new ArrayList<>(); for (Coordinate coord : prev) { Coordinate swapCoord = swap.get(coord); if (swapCoord != null) // time2D got swapped coord = swapCoord; Integer idx = getIndexIntoShared(coord); // index into unionCoords if (idx == null) { Formatter f = new Formatter(); showInfo(f); f.format("%nprev:%n"); for (Coordinate c : prev) f.format(" %d == (%s) %s%n", c.hashCode(), c, c.getName()); System.out.printf("%s%n", f.toString()); logger.error("CoordinateSharer cant find coordinate "+ coord.getName(), new Throwable()); } else result.add(idx); } /* debug for (Coordinate coord : shared) { switch (coord.getType()) { case time2D: CoordinateTime2D time2Dprev = (CoordinateTime2D) coord; Integer idx = getIndexIntoShared(coord); CoordinateTime2D time2D = (CoordinateTime2D) unionCoords.get(idx); int ntimePrev = time2Dprev.getNtimes(); int ntimes = time2D.getNtimes(); if (ntimes != ntimePrev) System.out.printf("HEY CoordinateSharer.reindex2shared: ntimes %d != orgNtimes %d%n", ntimes, ntimePrev); } } Coordinate runtime = null; for (Integer idx : result) { Coordinate coord = unionCoords.get(idx); switch (coord.getType()) { case runtime: runtime = coord; break; case time2D: CoordinateTime2D time2D = (CoordinateTime2D) coord; CoordinateRuntime runtimeFrom2D = time2D.getRuntimeCoordinate(); if (!runtimeFrom2D.equals(runtime)) System.out.printf("HEY CoordinateSharer.reindex2shared: runtimeFrom2D %s != runtime %s%n", runtimeFrom2D, runtime); break; } } // end debug */ return result; } private Integer getIndexIntoShared(Coordinate prev) { // LOOK dont understand this, why cant you just use coordMap ?? if (isRuntimeUnion) { switch (prev.getType()) { case runtime: return coordMap.get(runtimeAll); case time2D: CoordinateTime2D time2D = (CoordinateTime2D) prev; if (time2D.isTimeInterval()) return coordMap.get(timeIntv2Dall); else return coordMap.get(time2Dall); default: return coordMap.get(prev); } } return coordMap.get(prev); } public void showInfo(Formatter sb) { sb.format("unionCoords:%n"); for (Coordinate coord : this.unionCoords) sb.format(" %d == (%s) %s%n", coord.hashCode(), coord, coord.getName()); sb.format("%ncoordMap:%n"); for (Coordinate coord : this.coordMap.keySet()) sb.format(" %d == (%s) %s%n", coord.hashCode(), coord, coord.getName()); sb.format("%ntime2DBuilders:%n"); for (Coordinate coord : this.time2DBuilders) sb.format(" %d == (%s) %s%n", coord.hashCode(), coord, coord.getName()); sb.format("%nswap:%n"); for (Map.Entry<Coordinate, Coordinate> entry : this.swap.entrySet()) sb.format(" %d (%s) %s -> %d (%s) %s%n", entry.getKey().hashCode(), entry.getKey(), entry.getKey().getName(), entry.getValue().hashCode(), entry.getValue(), entry.getValue().getName()); } }