diff --git a/src/main/java/scratch/kevin/pointSources/DistCalcBenchmark.java b/src/main/java/scratch/kevin/pointSources/DistCalcBenchmark.java new file mode 100644 index 00000000..e4ecf5a7 --- /dev/null +++ b/src/main/java/scratch/kevin/pointSources/DistCalcBenchmark.java @@ -0,0 +1,134 @@ +package scratch.kevin.pointSources; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.jfree.data.Range; +import org.opensha.commons.calc.magScalingRelations.MagLengthRelationship; +import org.opensha.commons.calc.magScalingRelations.magScalingRelImpl.WC1994_MagLengthRelationship; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.geo.Location; +import org.opensha.commons.gui.plot.HeadlessGraphPanel; +import org.opensha.commons.gui.plot.PlotCurveCharacterstics; +import org.opensha.commons.gui.plot.PlotLineType; +import org.opensha.commons.gui.plot.PlotSpec; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.faultSurface.RuptureSurface; + +import com.google.common.base.Stopwatch; + +class DistCalcBenchmark { + + private enum SurfType { + PT_SURF_FOOTWALL("Point Surface (footwall)"), + PT_SURF_HANGING_WALL("Point Surface (hanging wall)"), + FINITE_QUAD("Finite Quad Surface"), + FINITE_GRIDDED("Finite Gridded Surface"); + + private String label; + + private SurfType(String label) { + this.label = label; + } + + public RuptureSurface buildSurface(PointSurfaceBuilder builder) { + switch (this) { + case PT_SURF_FOOTWALL: + builder.footwall(true); + return builder.buildPointSurface(); + case PT_SURF_HANGING_WALL: + builder.footwall(false); + return builder.buildPointSurface(); + case FINITE_GRIDDED: + return builder.buildGriddedSurface(); + case FINITE_QUAD: + return builder.buildQuadSurface(); + + default: + throw new IllegalStateException(); + } + } + } + + public static void main(String[] args) throws IOException { + PointSurfaceBuilder builder = new PointSurfaceBuilder(new Location(0d, 0d)); + + EvenlyDiscretizedFunc refFunc = new EvenlyDiscretizedFunc(5d, 8.5d, 30); + + SurfType[] types = SurfType.values(); + EvenlyDiscretizedFunc[] timeFuncs = new EvenlyDiscretizedFunc[types.length]; + for (int i=0; i= 0 ? refFunc.getX(i) : refFunc.getMaxX(); + System.out.println("Doing M"+(mag)); + + double length = WC94.getMedianLength(mag); + double aspectWidth = length / 1.5; + + builder.length(length); + builder.upperDepth(0); + builder.lowerDepth(Math.min(aspectWidth, 14d)); + + for (int t=0; t= 0) + timeFuncs[t].set(i, secs); + } + } + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + CPT cpt = GMT_CPT_Files.CATEGORICAL_BATLOW_UNIFORM.instance(); + double maxY = 0d; + for (int i=0; i rCut) return hypot2(rJB, zBot); + + // rRup when rJB is 0 -- we take the minimum the site-to-top-edge + // and site-to-normal of rupture for the site being directly over + // the down-dip edge of the rupture + double rRup0 = Math.min(hypot2(horzWidth, zTop), zBot * Math.cos(dipRad)); + // rRup at cutoff rJB + double rRupC = zBot / Math.cos(dipRad); + // scale linearly with rJB distance + return (rRupC - rRup0) * rJB / rCut + rRup0; + } + + public boolean isOnFootwall() { + return footwall; + } + + /** + * Same as {@code Math.hypot()} without regard to under/over flow. + */ + private static final double hypot2(double v1, double v2) { + return Math.sqrt(v1 * v1 + v2 * v2); + } +} \ No newline at end of file diff --git a/src/main/java/scratch/kevin/pointSources/PointSourceHazardComparison.java b/src/main/java/scratch/kevin/pointSources/PointSourceHazardComparison.java index f993d1e4..678fff38 100644 --- a/src/main/java/scratch/kevin/pointSources/PointSourceHazardComparison.java +++ b/src/main/java/scratch/kevin/pointSources/PointSourceHazardComparison.java @@ -1,8 +1,7 @@ package scratch.kevin.pointSources; -import static java.lang.Math.sin; - import java.awt.Color; +import java.awt.Font; import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; @@ -20,12 +19,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.function.IntConsumer; +import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; import org.apache.commons.math3.util.Precision; +import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.plot.DatasetRenderingOrder; import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.chart.ui.TextAnchor; import org.jfree.data.Range; import org.opensha.commons.calc.magScalingRelations.magScalingRelImpl.WC1994_MagLengthRelationship; import org.opensha.commons.data.Site; @@ -58,6 +59,8 @@ import org.opensha.sha.earthquake.FocalMechanism; import org.opensha.sha.earthquake.ProbEqkRupture; import org.opensha.sha.earthquake.ProbEqkSource; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceProvider; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc.ReturnPeriods; import org.opensha.sha.earthquake.rupForecastImpl.PointEqkSource; @@ -65,7 +68,10 @@ import org.opensha.sha.earthquake.rupForecastImpl.PointSourceNshm; import org.opensha.sha.earthquake.rupForecastImpl.PointSourceNshm.PointSurfaceNshm; import org.opensha.sha.earthquake.rupForecastImpl.PointToFiniteSource; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_SingleStates; +import org.opensha.sha.faultSurface.EvenlyGriddedSurface; import org.opensha.sha.faultSurface.PointSurface; +import org.opensha.sha.faultSurface.QuadSurface; import org.opensha.sha.faultSurface.RuptureSurface; import org.opensha.sha.faultSurface.utils.PtSrcDistCorr.Type; import org.opensha.sha.gui.infoTools.IMT_Info; @@ -79,6 +85,7 @@ import org.opensha.sha.util.FocalMech; import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; public class PointSourceHazardComparison { @@ -86,37 +93,37 @@ enum PointSourceType { TRUE_POINT_SOURCE("True Point Source", false, Type.NONE) { @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample) { + double aveRake, double aveDip, boolean isSupersample, Random r) { return new PointEqkSource(centerLoc, mfd, 1d, aveRake, aveDip); } }, POINT_SOURCE_13b_NO_CORR("PointSource13b (no distance correction)", false, Type.NONE) { @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample) { + double aveRake, double aveDip, boolean isSupersample, Random r) { return new PointSource13b(centerLoc, mfd, 1d, new double[] {5.0, 1.0}, mechWtMapForRake(aveRake)); } }, POINT_SOURCE_13b_NSHMP_CORR("PointSource13b (NSHMP08 distance correction)", false, Type.NSHMP08) { @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample) { + double aveRake, double aveDip, boolean isSupersample, Random r) { return new CorrOverrideProbEqkSource(POINT_SOURCE_13b_NO_CORR.buildSource( - centerLoc, mfd, aveRake, aveDip, isSupersample), Type.NSHMP08); + centerLoc, mfd, aveRake, aveDip, isSupersample, r), Type.NSHMP08); } }, POINT_SOURCE_NSHM("PointSourceNshm", false, Type.NONE) { // none is fine here, it's baked in @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample) { + double aveRake, double aveDip, boolean isSupersample, Random r) { return new PointSourceNshm(centerLoc, mfd, 1d, mechWtMapForRake(aveRake)); } }, APROX_SUPERSAMPLE_POINT_SOURCE_NSHM("Approx. Supersampled PointSourceNshm", false, Type.NONE) { // none is fine here, it's baked in @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample) { - ProbEqkSource source = POINT_SOURCE_NSHM.buildSource(centerLoc, mfd, aveRake, aveDip, isSupersample); + double aveRake, double aveDip, boolean isSupersample, Random r) { + ProbEqkSource source = POINT_SOURCE_NSHM.buildSource(centerLoc, mfd, aveRake, aveDip, isSupersample, r); if (!isSupersample) { // not externally supersampled, approximate it here List modRups = new ArrayList<>(); @@ -131,10 +138,9 @@ public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, } }, POINT_TO_FINITE("PointToFiniteSource", true, Type.NONE) { - private WC1994_MagLengthRelationship WC94 = new WC1994_MagLengthRelationship(); @Override public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, - double aveDip, boolean isSupersample) { + double aveDip, boolean isSupersample, Random r) { FocalMechanism focalMech = new FocalMechanism(Double.NaN, aveDip, aveRake); double dipRad = Math.toRadians(aveDip); List rups = new ArrayList<>(); @@ -143,21 +149,84 @@ public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double mag = mfd.getX(i); double depth = (float)mag <= 6.5f ? 5d : 1d; double length = WC94.getMedianLength(mag); - double aspectWidth = length / 1.5; - double ddWidth = (14.0 - depth) / Math.sin(dipRad); - ddWidth = Math.min(aspectWidth, ddWidth); - double lower = depth + ddWidth * Math.sin(dipRad); - - IncrementalMagFreqDist singleMFD = new IncrementalMagFreqDist(mag, mag, 1); - singleMFD.set(0, mfd.getY(i)); - - PointToFiniteSource source = new PointToFiniteSource(singleMFD, centerLoc, focalMech, depth, WC94, lower, 1d, singleMFD.getMinX(), false); - if (source0 == null) - source0 = source; - rups.addAll(source.getRuptureList()); + double aspectWidth = length / 1.5; + double ddWidth = (14.0 - depth) / Math.sin(dipRad); + ddWidth = Math.min(aspectWidth, ddWidth); + double lower = depth + ddWidth * Math.sin(dipRad); + + IncrementalMagFreqDist singleMFD = new IncrementalMagFreqDist(mag, mag, 1); + singleMFD.set(0, mfd.getY(i)); + + PointToFiniteSource source = new PointToFiniteSource(singleMFD, centerLoc, focalMech, depth, WC94, lower, 1d, singleMFD.getMinX(), false); + if (source0 == null) + source0 = source; + rups.addAll(source.getRuptureList()); } return new RupListSource(rups, source0); } + }, + SINGLE_QUAD_TRACE_CENTERED("Single Quad Surface, Trace Centered", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, null, mfd, aveRake, aveDip, r, true, 1); + } + }, + SINGLE_QUAD_SURF_CENTER("Single Quad Surface", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, null, mfd, aveRake, aveDip, r, false, 1); + } + }, + CROSSHAIR_QUAD("Crosshair Quad Surface", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, null, mfd, aveRake, aveDip, r, false, 2); + } + }, + TRIPLE_QUAD("3x Quad Surface", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, null, mfd, aveRake, aveDip, r, false, 3); + } + }, + QUAD_QUAD("4x Quad Surface", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, null, mfd, aveRake, aveDip, r, false, 4); + } + }, + QUAD_QUAD_RAND_CELL("4x Quad Surface, Random Cell Locations", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, isSupersample ? null : cellRegion(centerLoc), mfd, aveRake, aveDip, r, false, 4); + } + }, + SEXT_QUAD_RAND_CELL("6x Quad Surface, Random Cell Locations", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, isSupersample ? null : cellRegion(centerLoc), mfd, aveRake, aveDip, r, false, 6); + } + }, + OCT_QUAD_RAND_CELL("8x Quad Surface, Random Cell Locations", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, isSupersample ? null : cellRegion(centerLoc), mfd, aveRake, aveDip, r, false, 8); + } + }, + DODEC_QUAD_RAND_CELL("12x Quad Surface, Random Cell Locations", true, Type.NONE) { + @Override + public ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, double aveRake, + double aveDip, boolean isSupersample, Random r) { + return buildQuadSource(centerLoc, isSupersample ? null : cellRegion(centerLoc), mfd, aveRake, aveDip, r, false, 12); + } }; private String label; @@ -172,7 +241,7 @@ private PointSourceType(String label, boolean stochastic, Type distCorrType) { } public abstract ProbEqkSource buildSource(Location centerLoc, IncrementalMagFreqDist mfd, - double aveRake, double aveDip, boolean isSupersample); + double aveRake, double aveDip, boolean isSupersample, Random r); } private static Map mechWtMapForRake(double rake) { @@ -201,6 +270,42 @@ private static FocalMech mechForRake(double rake) { return match; } + private static WC1994_MagLengthRelationship WC94 = new WC1994_MagLengthRelationship(); + + private static Region cellRegion(Location loc) { + double half = 0.05; + return new Region(new Location(loc.lat-half, loc.lon-half), new Location(loc.lat+half, loc.lon+half)); + } + + private static ProbEqkSource buildQuadSource(Location centerLoc, Region cell, IncrementalMagFreqDist mfd, + double aveRake, double aveDip, Random r, boolean traceCentered, int numEach) { + PointSurfaceBuilder builder = new PointSurfaceBuilder(centerLoc); + builder.dip(aveDip); + builder.traceCentered(traceCentered); + builder.random(r); + builder.sampleFromCell(cell); + double dipRad = Math.toRadians(aveDip); + List rups = new ArrayList<>(mfd.size()*numEach); + for (int i=0; i sources; + private List> sourceCalls; public PointSourceCalcERF(PointSourceType type, Location loc, IncrementalMagFreqDist mfd, - double rake, double dip, int numPerStochastic) { + double rake, double dip, int numPerStochastic, Random r) { this.distCorrType = type.distCorrType; if (type.stochastic) { sources = new ArrayList<>(numPerStochastic); IncrementalMagFreqDist mfdEach = mfd.deepClone(); mfdEach.scale(1d/numPerStochastic); for (int i=0; i(type.stochastic ? numPerStochastic*locs.getNodeCount() : locs.getNodeCount()); @@ -315,21 +423,109 @@ public PointSourceCalcERF(PointSourceType type, GriddedRegion locs, IncrementalM IncrementalMagFreqDist subMFDEach = mfdEach.deepClone(); subMFDEach.scale(1d/numPerStochastic); for (int i=0; i(); + this.distCorrType = type.distCorrType; + GriddedRegion gridReg = gridProv.getGriddedRegion(); + for (int i=0; i maxDist) + continue; + IncrementalMagFreqDist mfd = gridProv.getMFD(i, 5.05d); + if (mfd == null || mfd.calcSumOfY_Vals() == 0d) + continue; + List locs; + IncrementalMagFreqDist fullMFDEach; + if (supersampleDisc > 0d) { + double halfSpacing = 0.5*gridReg.getSpacing(); + Region cell = new Region(new Location(centerLoc.lat-halfSpacing, centerLoc.lon-halfSpacing), + new Location(centerLoc.lat+halfSpacing, centerLoc.lon+halfSpacing)); + GriddedRegion superSampledCell = new GriddedRegion(cell, supersampleDisc, + new Location(0.5*supersampleDisc, 0.5*supersampleDisc)); + locs = superSampledCell.getNodeList(); + fullMFDEach = mfd.deepClone(); + fullMFDEach.scale(1d/locs.size()); } else { - sources.add(type.buildSource(loc, mfdEach, rake, dip, true)); + locs = List.of(centerLoc); + fullMFDEach = mfd; + } + for (FocalMech mech : FocalMech.values()) { + double fract; + switch (mech) { + case NORMAL: + fract = gridProv.getFracNormal(i); + break; + case REVERSE: + fract = gridProv.getFracReverse(i); + break; + case STRIKE_SLIP: + fract = gridProv.getFracStrikeSlip(i); + break; + + default: + throw new IllegalStateException(); + } + if (fract == 0d) + continue; + IncrementalMagFreqDist mfdEach = fullMFDEach.deepClone(); + mfdEach.scale(fract); + for (Location loc : locs) { + if (type.stochastic && numPerStochastic > 1) { + IncrementalMagFreqDist subMFDEach = mfdEach.deepClone(); + subMFDEach.scale(1d/numPerStochastic); + for (int j=0; j() { + + @Override + public ProbEqkSource call() throws Exception { + return type.buildSource(loc, subMFDEach, mech.rake(), mech.dip(), locs.size()>1, r); + } + }); + } else { + sourceCalls.add(new Callable() { + + @Override + public ProbEqkSource call() throws Exception { + return type.buildSource(loc, mfdEach, mech.rake(), mech.dip(), locs.size()>1, r); + } + }); + } + } + } + } + } + + public double calcTotalRate() { + Preconditions.checkNotNull(sources); + double tot = 0d; + for (ProbEqkSource source : sources) { + for (ProbEqkRupture rup : source) { + tot += rup.getMeanAnnualRate(1d); } } + return tot; } @Override public int getNumSources() { - return sources.size(); + return sources != null ? sources.size() : sourceCalls.size(); } @Override public ProbEqkSource getSource(int idx) { - return sources.get(idx); + try { + return sources != null ? sources.get(idx) : sourceCalls.get(idx).call(); + } catch (Exception e) { + throw ExceptionUtils.asRuntimeException(e); + } } @Override @@ -356,18 +552,105 @@ private GridType(String label, String prefix) { } } + enum RupSurfProps { + ZTOP("Top Depth (km)") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + return rup.getRuptureSurface().getAveRupTopDepth(); + } + }, + ZBOT("Bottom Depth (km)") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + RuptureSurface surf = rup.getRuptureSurface(); + return surf.getAveRupTopDepth() + surf.getAveWidth() * Math.sin(Math.toRadians(surf.getAveDip())); + } + }, + WIDTH("Width (km)") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + return rup.getRuptureSurface().getAveWidth(); + } + }, + LENGTH("Length (km)") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + return rup.getRuptureSurface().getAveLength(); + } + }, + DIP("Dip") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + return rup.getRuptureSurface().getAveDip(); + } + }, + RAKE("Rake") { + @Override + public double calcForRupture(ProbEqkRupture rup) { + return rup.getRuptureSurface().getAveDip(); + } + }; + + private String label; + + private RupSurfProps(String label) { + this.label = label; + } + + public abstract double calcForRupture(ProbEqkRupture rup); + } + + enum RupSurfMapProps { + FRACT_FOOTWALL("Fraction On Hanging Wall (rX>=0)") { + @Override + public double calcForRuptureAndLocation(ProbEqkRupture rup, Location siteLoc) { + if (rup.getRuptureSurface().getDistanceX(siteLoc) >= 0d) + return 1d; + return 0; + } + + @Override + public CPT getCPT() throws IOException { + return GMT_CPT_Files.MAX_SPECTRUM.instance().rescale(0d, 1d); + } + }; + + private String label; + + private RupSurfMapProps(String label) { + this.label = label; + } + + public abstract double calcForRuptureAndLocation(ProbEqkRupture rup, Location siteLoc); + + public abstract CPT getCPT() throws IOException; + } + private static final double SUPERSAMPLE_SPACING = 0.01; public static void main(String[] args) throws IOException { // PointSourceType mainType = PointSourceType.POINT_SOURCE_13b_NSHMP_CORR; PointSourceType mainType = PointSourceType.POINT_SOURCE_NSHM; +// PointSourceType mainType = PointSourceType.QUAD_QUAD; +// PointSourceType mainType = PointSourceType.QUAD_QUAD_RAND_CELL; +// PointSourceType mainType = PointSourceType.OCT_QUAD_RAND_CELL; +// PointSourceType mainType = PointSourceType.DODEC_QUAD_RAND_CELL; // PointSourceType mainType = PointSourceType.APROX_SUPERSAMPLE_POINT_SOURCE_NSHM; // PointSourceType mainType = PointSourceType.POINT_TO_FINITE; - PointSourceType compType = null; +// PointSourceType compType = null; + PointSourceType compType = PointSourceType.OCT_QUAD_RAND_CELL; // PointSourceType compType = PointSourceType.POINT_SOURCE_NSHM; // PointSourceType compType = PointSourceType.POINT_SOURCE_13b_NSHMP_CORR; // PointSourceType compType = PointSourceType.POINT_SOURCE_13b_NO_CORR; // PointSourceType compType = PointSourceType.POINT_TO_FINITE; +// PointSourceType compType = PointSourceType.POINT_TO_SIMPLE_QUAD; +// PointSourceType compType = PointSourceType.QUAD_QUAD_RAND_CELL; + + boolean doSingleCellHazard = true; + boolean doNSHMModelHazard = true; + boolean doHighRes = false; + boolean doSupersample = true; + boolean forceWriteIntermediate = true; AttenRelRef gmmRef = AttenRelRef.NGAWest_2014_AVG_NOIDRISS; double[] periods = {0d, 1d}; @@ -389,6 +672,8 @@ public static void main(String[] args) throws IOException { outputDir = new File(mainOutputDir, mainType.name()+"_vs_"+compType.name()); Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + boolean writeIntermediate = forceWriteIntermediate || !new File(outputDir, "index.html").exists(); + File resourcesDir = new File(outputDir, "resources"); Preconditions.checkState(resourcesDir.exists() || resourcesDir.mkdir()); @@ -403,34 +688,50 @@ public static void main(String[] args) throws IOException { EnumMap siteGrids = new EnumMap<>(GridType.class); siteGrids.put(GridType.COLOCATED, colocatedGridded); - EvenlyDiscretizedFunc distFunc = new EvenlyDiscretizedFunc(0d, 100d, 500); - List distFuncLocs = new ArrayList<>(); + EvenlyDiscretizedFunc distFunc = new EvenlyDiscretizedFunc(0d, 100d, 100); + List> distFuncLocs = new ArrayList<>(); + int numEachDist = 10; for (int i=0; i locs = new ArrayList<>(numEachDist); + double deltaEach = 2d*Math.PI/numEachDist; + for (int j=0; j lines = new ArrayList<>(); @@ -473,12 +774,14 @@ public static void main(String[] args) throws IOException { legendChars.add(scatterChars.get(0)); } } - for (Location loc : superSampledCell.getNodeList()) { - scatterLocs.add(loc); - scatterChars.add(superSampledChar); + if (doSupersample) { + for (Location loc : superSampledCell.getNodeList()) { + scatterLocs.add(loc); + scatterChars.add(superSampledChar); + } + legendItems.add("Supersampled Sources"); + legendChars.add(scatterChars.get(scatterChars.size()-1)); } - legendItems.add("Supersampled Sources"); - legendChars.add(scatterChars.get(scatterChars.size()-1)); scatterLocs.add(gridCenter); scatterChars.add(centerChar); legendItems.add("Source Center"); @@ -502,8 +805,6 @@ public static void main(String[] args) throws IOException { "![offset]("+resourcesDir.getName()+"/offset_site_grid.png)"); lines.addAll(table.build()); lines.add(""); - - DecimalFormat oDF = new DecimalFormat("0.##"); Deque calcDeque = new ArrayDeque<>(); Deque gmmDeque = new ArrayDeque<>(); ExecutorService exec = Executors.newFixedThreadPool(FaultSysTools.defaultNumThreads()); @@ -536,6 +837,46 @@ public static void main(String[] args) throws IOException { CPT pDiffCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-50d, 50d); + String[] perLabels = new String[periods.length]; + String[] perPrefixes = new String[periods.length]; + String[] perUnits = new String[periods.length]; + Range[] curveXRanges = new Range[periods.length]; + DiscretizedFunc[] xVals = new DiscretizedFunc[periods.length]; + DiscretizedFunc[] logXVals = new DiscretizedFunc[periods.length]; + CPT[] hazCPTs = new CPT[periods.length]; + for (int p=0; p 0d); + perLabels[p] = oDF.format(period)+"s SA"; + perPrefixes[p] = oDF.format(period)+"s"; + perUnits[p] = "g"; + xVals[p] = new IMT_Info().getDefaultHazardCurve(SA_Param.NAME); + curveXRanges[p] = new Range(1e-2, 1e1); + } + + hazCPTs[p] = GMT_CPT_Files.RAINBOW_UNIFORM.instance().rescale( + Math.log10(curveXRanges[p].getLowerBound()), Math.log10(curveXRanges[p].getUpperBound())); + logXVals[p] = new ArbitrarilyDiscretizedFunc(); + for (Point2D pt : xVals[p]) + logXVals[p].set(Math.log(pt.getX()), 0d); + } + + + Random rand = new Random(123456789l); + boolean[] falseTrue = {false,true}; boolean[] falseOnly = {false}; @@ -545,16 +886,25 @@ public static void main(String[] args) throws IOException { String mechPrefix = mech.name(); double dip = rakeToDipMap.get(rake); - PointSourceCalcERF centerERF = new PointSourceCalcERF(mainType, gridCenter, mfd, rake, dip, numPerStochasticCentered); - PointSourceCalcERF supersampledERF = new PointSourceCalcERF(mainType, superSampledCell, mfd, rake, dip, numPerStochasticSupersampled); + PointSourceCalcERF centerERF = new PointSourceCalcERF(mainType, gridCenter, mfd, rake, dip, numPerStochasticCentered, rand); + PointSourceCalcERF supersampledERF = doSupersample ? + new PointSourceCalcERF(mainType, superSampledCell, mfd, rake, dip, numPerStochasticSupersampled, rand) : null; + + System.out.println("Centered ERF, total rate: "+centerERF.calcTotalRate()); + if (doSupersample) + System.out.println("Supersampled ERF, total rate: "+supersampledERF.calcTotalRate()); PointSourceCalcERF compCenterERF = null; PointSourceCalcERF compSupersampledERF = null; boolean[] compBools; if (compType != null) { compBools = falseTrue; - compCenterERF = new PointSourceCalcERF(compType, gridCenter, mfd, rake, dip, numPerStochasticCentered); - compSupersampledERF = new PointSourceCalcERF(compType, superSampledCell, mfd, rake, dip, numPerStochasticSupersampled); + compCenterERF = new PointSourceCalcERF(compType, gridCenter, mfd, rake, dip, numPerStochasticCentered, rand); + if (doSupersample) + compSupersampledERF = new PointSourceCalcERF(compType, superSampledCell, mfd, rake, dip, numPerStochasticSupersampled, rand); + System.out.println("Comparison centered ERF, total rate: "+compCenterERF.calcTotalRate()); + if (doSupersample) + System.out.println("Comparison supersampled ERF, total rate: "+compSupersampledERF.calcTotalRate()); } else { compBools = falseOnly; } @@ -562,6 +912,9 @@ public static void main(String[] args) throws IOException { lines.add("## "+mechLabel); lines.add(topLink); lines.add(""); + lines.add("### "+mechLabel+" Distances"); + lines.add(topLink); lines.add(""); + table = MarkdownUtils.tableBuilder(); table.addLine("DistanceJB", "DistanceRup"); @@ -573,17 +926,19 @@ public static void main(String[] args) throws IOException { EvenlyDiscretizedFunc centeredRJBFunc = distFunc.deepClone(); EvenlyDiscretizedFunc centeredRRupFunc = distFunc.deepClone(); System.out.println("Calculating distances for M"+(float)mag+", "+mechLabel); - calcDistFuncs(centerERF, distFuncLocs, centeredRJBFunc, centeredRRupFunc, mag); + calcDistFuncsAtMag(centerERF, distFuncLocs, centeredRJBFunc, centeredRRupFunc, mag); EvenlyDiscretizedFunc supersampledRJBFunc = distFunc.deepClone(); EvenlyDiscretizedFunc supersampledRRupFunc = distFunc.deepClone(); - calcDistFuncs(supersampledERF, distFuncLocs, supersampledRJBFunc, supersampledRRupFunc, mag); + if (doSupersample) + calcDistFuncsAtMag(supersampledERF, distFuncLocs, supersampledRJBFunc, supersampledRRupFunc, mag); EvenlyDiscretizedFunc compCenteredRJBFunc = compType == null ? null : distFunc.deepClone(); EvenlyDiscretizedFunc compCenteredRRupFunc = compType == null ? null : distFunc.deepClone(); EvenlyDiscretizedFunc compSupersampledRJBFunc = compType == null ? null : distFunc.deepClone(); EvenlyDiscretizedFunc compSupersampledRRupFunc = compType == null ? null : distFunc.deepClone(); if (compType != null) { - calcDistFuncs(compCenterERF, distFuncLocs, compCenteredRJBFunc, compCenteredRRupFunc, mag); - calcDistFuncs(compSupersampledERF, distFuncLocs, compSupersampledRJBFunc, compSupersampledRRupFunc, mag); + calcDistFuncsAtMag(compCenterERF, distFuncLocs, compCenteredRJBFunc, compCenteredRRupFunc, mag); + if (doSupersample) + calcDistFuncsAtMag(compSupersampledERF, distFuncLocs, compSupersampledRJBFunc, compSupersampledRRupFunc, mag); } table.initNewLine(); @@ -610,14 +965,16 @@ public static void main(String[] args) throws IOException { chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, compColor)); } - supersampledFunc.setName("Supersampled Source"); - funcs.add(asDistRatio(supersampledFunc)); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); - - if (compType != null) { - compSupersampledFunc.setName("Comparison Supersampled Source"); - funcs.add(asDistRatio(compSupersampledFunc)); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + if (doSupersample) { + supersampledFunc.setName("Supersampled Source"); + funcs.add(asDistRatio(supersampledFunc)); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); + + if (compType != null) { + compSupersampledFunc.setName("Comparison Supersampled Source"); + funcs.add(asDistRatio(compSupersampledFunc)); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + } } String title = mechLabel+" M"+oDF.format(mag)+" Distance"+(rRup ? "Rup" : "JB")+" Comparison"; @@ -637,17 +994,19 @@ public static void main(String[] args) throws IOException { chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, compColor)); } - funcs.add(asDistDiff(supersampledFunc)); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); - - if (compType != null) { - funcs.add(asDistDiff(compSupersampledFunc)); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + if (doSupersample) { + funcs.add(asDistDiff(supersampledFunc)); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); + + if (compType != null) { + funcs.add(asDistDiff(compSupersampledFunc)); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + } } PlotSpec diffSpec = new PlotSpec(funcs, chars, title, xAxisLabel, rRup ? "DistanceRup Difference" : "DistanceJB Difference"); - diffSpec.setLegendInset(RectangleAnchor.TOP_RIGHT); + diffSpec.setLegendInset(RectangleAnchor.BOTTOM_RIGHT); HeadlessGraphPanel gp = PlotUtils.initHeadless(); @@ -663,155 +1022,436 @@ public static void main(String[] args) throws IOException { table.finalizeLine(); } - lines.addAll(table.build()); - lines.add(""); - - for (double period : periods) { - String perLabel, perPrefix, perUnits; - Range curveXRange; - DiscretizedFunc xVals; - if (period == -1d) { - perLabel = "PGV"; - perPrefix = "pgv"; - perUnits = "cm/s"; - xVals = new IMT_Info().getDefaultHazardCurve(PGV_Param.NAME); - curveXRange = new Range(1e-1, 1e2); - } else if (period == 0d) { - perLabel = "PGA"; - perPrefix = "pga"; - perUnits = "g"; - xVals = new IMT_Info().getDefaultHazardCurve(PGA_Param.NAME); - curveXRange = new Range(1e-2, 1e1); + // now at fixed distances as a function of mag + Range magRange = new Range(mfd.getMinX()-0.5*mfd.getDelta(), mfd.getMaxX()+0.5*mfd.getDelta()); + List magSpecsRRup = new ArrayList<>(distPlotDists.length); + List magSpecsRJB = new ArrayList<>(distPlotDists.length); + List magPlotYRanges = new ArrayList<>(distPlotDists.length); + for (double dist : distPlotDists) { + List distLocs = new ArrayList<>(dist == 0d ? 1 : numEachDist); + if (dist == 0d) { + distLocs.add(gridCenter); } else { - Preconditions.checkState(period > 0d); - perLabel = oDF.format(period)+"s SA"; - perPrefix = oDF.format(period)+"s"; - perUnits = "g"; - xVals = new IMT_Info().getDefaultHazardCurve(SA_Param.NAME); - curveXRange = new Range(1e-2, 1e1); + for (int i=0; i 1) { - lines.add("### "+mechLabel+", "+perLabel); - lines.add(topLink); lines.add(""); + EvenlyDiscretizedFunc centeredRJBFunc = mfd.deepClone(); + EvenlyDiscretizedFunc centeredRRupFunc = mfd.deepClone(); + System.out.println("Calculating distances for at fixed dist="+(float)dist+", "+mechLabel); + calcMagFuncsAtDist(centerERF, distLocs, centeredRJBFunc, centeredRRupFunc, dist); + EvenlyDiscretizedFunc supersampledRJBFunc = mfd.deepClone(); + EvenlyDiscretizedFunc supersampledRRupFunc = mfd.deepClone(); + if (doSupersample) + calcMagFuncsAtDist(supersampledERF, distLocs, supersampledRJBFunc, supersampledRRupFunc, dist); + EvenlyDiscretizedFunc compCenteredRJBFunc = compType == null ? null : mfd.deepClone(); + EvenlyDiscretizedFunc compCenteredRRupFunc = compType == null ? null : mfd.deepClone(); + EvenlyDiscretizedFunc compSupersampledRJBFunc = compType == null ? null : mfd.deepClone(); + EvenlyDiscretizedFunc compSupersampledRRupFunc = compType == null ? null : mfd.deepClone(); + if (compType != null) { + calcMagFuncsAtDist(compCenterERF, distLocs, compCenteredRJBFunc, compCenteredRRupFunc, dist); + if (doSupersample) + calcMagFuncsAtDist(compSupersampledERF, distLocs, compSupersampledRJBFunc, compSupersampledRRupFunc, dist); } - String mechPerPrefix = mechPrefix+"_"+perPrefix; - - Map centeredMaps = new EnumMap<>(GridType.class); - Map supersampledMaps = new EnumMap<>(GridType.class); - Map compCenteredMaps = compType == null ? null : new EnumMap<>(GridType.class); - Map compSupersampledMaps = compType == null ? null : new EnumMap<>(GridType.class); + double minY = Double.POSITIVE_INFINITY; + double maxY = 0d; - - for (GridType grid : siteGrids.keySet()) { - GriddedRegion siteGrid = siteGrids.get(grid); + for (boolean rRup : falseTrue) { + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); - for (boolean comp : compBools) { - PointSourceCalcERF myCenterERF = comp ? compCenterERF : centerERF; - PointSourceCalcERF mySupersampledERF = comp ? compSupersampledERF : supersampledERF; - System.out.println("Calculating "+grid.label+", centered, "+mechLabel+", "+perLabel+", comp="+comp); - List centeredCurves = calcCurves(siteGrid.getNodeList(), myCenterERF, gmmRef, - gmmDeque, calcDeque, period, xVals, logXVals, exec); - - System.out.println("Calculating "+grid.label+", supersampled, "+mechLabel+", "+perLabel+", comp="+comp); - List supersampledCurves = calcCurves(siteGrid.getNodeList(), mySupersampledERF, gmmRef, - gmmDeque, calcDeque, period, xVals, logXVals, exec); - - GriddedGeoDataSet[] myCenteredMaps = new GriddedGeoDataSet[rps.length]; - GriddedGeoDataSet[] mySupersampledMaps = new GriddedGeoDataSet[rps.length]; - - for (int r=0; r distFuncCenteredCurves = null; - List distFuncSupersampledCurves = null; - - DiscretizedFunc compColocatedCurve = null; - DiscretizedFunc compColocatedSupersampledCurve = null; - List compDistFuncCenteredCurves = null; - List compDistFuncSupersampledCurves = null; - - for (boolean comp : compBools) { - PointSourceCalcERF myCenterERF = comp ? compCenterERF : centerERF; - PointSourceCalcERF mySupersampledERF = comp ? compSupersampledERF : supersampledERF; - System.out.println("Calculating dist func, centered, "+mechLabel+", "+perLabel+", comp="+comp); - List calcDistFuncCenteredCurves = calcCurves(distFuncLocs, myCenterERF, gmmRef, - gmmDeque, calcDeque, period, xVals, logXVals, exec); + for (XY_DataSet func : funcs) { + minY = Math.min(minY, func.getMinY()); + maxY = Math.max(maxY, func.getMaxY()); + } - System.out.println("Calculating dist func, supersampled, "+mechLabel+", "+perLabel+", comp="+comp); - List calcDistFuncSupersampledCurves = calcCurves(distFuncLocs, mySupersampledERF, gmmRef, - gmmDeque, calcDeque, period, xVals, logXVals, exec); + String title = mechLabel+" Distance"+(rRup ? "Rup" : "JB")+" Comparison"; - if (comp) { - compColocatedCurve = calcDistFuncCenteredCurves.get(0); - compColocatedSupersampledCurve = calcDistFuncSupersampledCurves.get(0); - compDistFuncCenteredCurves = calcDistFuncCenteredCurves; - compDistFuncSupersampledCurves = calcDistFuncSupersampledCurves; - } else { - colocatedCurve = calcDistFuncCenteredCurves.get(0); - colocatedSupersampledCurve = calcDistFuncSupersampledCurves.get(0); - distFuncCenteredCurves = calcDistFuncCenteredCurves; - distFuncSupersampledCurves = calcDistFuncSupersampledCurves; - } + String xAxisLabel = "Magnitude"; + PlotSpec spec = new PlotSpec(funcs, chars, title, + xAxisLabel, (rRup ? "DistanceRup" : "DistanceJB")+" at "+oDF.format(dist)+" km"); + + if (dist == distPlotDists[distPlotDists.length-1]) + spec.setLegendInset(RectangleAnchor.BOTTOM_LEFT); + + if (rRup) + magSpecsRRup.add(spec); + else + magSpecsRJB.add(spec); } + double scalar = Math.max(1d, dist/20d); + maxY = Math.ceil(1.01*maxY/scalar)*scalar; + minY = Math.floor(0.99*minY/scalar)*scalar; + Range range = new Range(Math.max(0, minY), maxY); + magPlotYRanges.add(range); + + XYTextAnnotation ann = new XYTextAnnotation(oDF.format(dist)+" km", + magRange.getLowerBound() + 0.95*magRange.getLength(), + range.getLowerBound() + 0.975*range.getLength()); + ann.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 24)); + ann.setTextAnchor(TextAnchor.TOP_RIGHT); + magSpecsRJB.get(magSpecsRJB.size()-1).addPlotAnnotation(ann); + magSpecsRRup.get(magSpecsRRup.size()-1).addPlotAnnotation(ann); + } + + table.initNewLine(); + for (boolean rRup : falseTrue) { + List specs = rRup ? magSpecsRRup : magSpecsRJB; + HeadlessGraphPanel gp = PlotUtils.initHeadless(); + + gp.drawGraphPanel(specs, false, false, List.of(magRange), magPlotYRanges); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + String prefix = mechPrefix+"_fixed_"+(rRup ? "rRup" : "rJB"); + PlotUtils.writePlots(resourcesDir, prefix, gp, 800, 100+specs.size()*300, true, true, false); + + table.addColumn("![Curves]("+resourcesDir.getName()+"/"+prefix+".png)"); + } + table.finalizeLine(); + + lines.addAll(table.build()); + lines.add(""); + + if (writeIntermediate) + writeMarkdown(outputDir, lines, tocIndex); + + lines.add("### "+mechLabel+" Surface Properties"); + lines.add(topLink); lines.add(""); + + // now rupture properties as a function of magnitude + List> magPropSpecs = new ArrayList<>(); + List> magPropYRanges = new ArrayList<>(); + int numPerBundle = 3; + for (RupSurfProps prop : RupSurfProps.values()) { List funcs = new ArrayList<>(); List chars = new ArrayList<>(); - colocatedCurve.setName("Centered Source"); - funcs.add(colocatedCurve); + EvenlyDiscretizedFunc centeredFunc = calcMagProps(centerERF, mfd, prop); + + centeredFunc.setName("Centered Source"); + funcs.add(centeredFunc); chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, mainColor)); if (compType != null) { - compColocatedCurve.setName("Comparison Cenetered Source"); - funcs.add(compColocatedCurve); + EvenlyDiscretizedFunc compCenteredFunc = calcMagProps(compCenterERF, mfd, prop); + compCenteredFunc.setName("Comparison Cenetered Source"); + funcs.add(compCenteredFunc); chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, compColor)); } - colocatedSupersampledCurve.setName("Supersampled Source"); - funcs.add(colocatedSupersampledCurve); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); + double minY = Double.POSITIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + for (XY_DataSet func : funcs) { + minY = Math.min(minY, func.getMinY()); + maxY = Math.max(maxY, func.getMaxY()); + } - if (compType != null) { - compColocatedSupersampledCurve.setName("Comparison Supersampled Source"); - funcs.add(compColocatedSupersampledCurve); - chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + String title = mechLabel+" Rupture Properties"; + + List curSpecBundle; + List curRangeBundle; + if (magPropSpecs.isEmpty() || magPropSpecs.get(magPropSpecs.size()-1).size() == numPerBundle) { + curSpecBundle = new ArrayList<>(); + magPropSpecs.add(curSpecBundle); + curRangeBundle = new ArrayList<>(); + magPropYRanges.add(curRangeBundle); + } else { + curSpecBundle = magPropSpecs.get(magPropSpecs.size()-1); + curRangeBundle = magPropYRanges.get(magPropYRanges.size()-1); } - PlotSpec spec = new PlotSpec(funcs, chars, "Zero-Distance Hazard Curves", - perLabel+" ("+perUnits+")", "Annual Probability of Exceedance"); - spec.setLegendInset(RectangleAnchor.TOP_RIGHT); + String xAxisLabel = "Magnitude"; + PlotSpec spec = new PlotSpec(funcs, chars, title, xAxisLabel, prop.label); + if (curSpecBundle.isEmpty()) + spec.setLegendInset(RectangleAnchor.TOP_RIGHT); + + curSpecBundle.add(spec); + curRangeBundle.add(null); + } + + table = MarkdownUtils.tableBuilder(); + table.initNewLine(); + for (int i=0; i specs = magPropSpecs.get(i); + List yRanges = magPropYRanges.get(i); HeadlessGraphPanel gp = PlotUtils.initHeadless(); - gp.drawGraphPanel(spec, true, true, curveXRange, curveYRange); + gp.drawGraphPanel(specs, false, false, List.of(magRange), yRanges); gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); - PlotUtils.writePlots(resourcesDir, mechPerPrefix+"_curves", gp, 800, 800, true, true, false); + String prefix = mechPrefix+"_surf_props_"+i; + PlotUtils.writePlots(resourcesDir, prefix, gp, 800, 100+specs.size()*300, true, true, false); - lines.add("![Curves]("+resourcesDir.getName()+"/"+mechPerPrefix+"_curves.png)"); - lines.add(""); + table.addColumn("![Properties]("+resourcesDir.getName()+"/"+prefix+".png)"); + } + table.finalizeLine(); + + lines.addAll(table.build()); + lines.add(""); + + if (writeIntermediate) + writeMarkdown(outputDir, lines, tocIndex); + + for (RupSurfMapProps props : RupSurfMapProps.values()) { + System.out.println("Doing "+mechLabel+", "+props.label); + lines.add("### "+mechLabel+" "+props.label); + lines.add(topLink); lines.add(""); + + table = MarkdownUtils.tableBuilder(); + if (compType != null) + table.addLine(mainType.label, compType.label); + else + table.initNewLine(); + + CPT cpt = props.getCPT(); + + String propPrefix = mechPrefix+"_"+props.name(); + + for (GridType grid : siteGrids.keySet()) { + GriddedRegion siteGrid = siteGrids.get(grid); + + String gridPrefix = propPrefix+"_"+grid.prefix; + + GriddedGeoDataSet centeredXYZ = calcMapProps(centerERF, siteGrid, props); + + mapMaker.plotXYZData(centeredXYZ, cpt, props.label); + addRangeAnns(mapMaker, centeredXYZ, grid == GridType.COLOCATED ? gridCenterIndex : -1, true); + mapMaker.plot(resourcesDir, gridPrefix+"_centered", grid.label+", Centered Sources"); + mapMaker.clearAnnotations(); + + if (doSupersample) { + GriddedGeoDataSet supersampledXYZ = calcMapProps(supersampledERF, siteGrid, props); + addRangeAnns(mapMaker, supersampledXYZ, grid == GridType.COLOCATED ? gridCenterIndex : -1, true); + mapMaker.plotXYZData(supersampledXYZ, cpt, props.label); + mapMaker.plot(resourcesDir, gridPrefix+"_supersampled", grid.label+", Supersampled Sources"); + mapMaker.clearAnnotations(); + } + + if (compType != null) { + GriddedGeoDataSet compCenteredXYZ = calcMapProps(compCenterERF, siteGrid, props); + + mapMaker.plotXYZData(compCenteredXYZ, cpt, props.label); + addRangeAnns(mapMaker, compCenteredXYZ, grid == GridType.COLOCATED ? gridCenterIndex : -1, true); + mapMaker.plot(resourcesDir, gridPrefix+"_centered_comp", grid.label+", Centered Sources"); + mapMaker.clearAnnotations(); + + if (doSupersample) { + GriddedGeoDataSet compSupersampledXYZ = calcMapProps(compSupersampledERF, siteGrid, props); + addRangeAnns(mapMaker, compSupersampledXYZ, grid == GridType.COLOCATED ? gridCenterIndex : -1, true); + mapMaker.plotXYZData(compSupersampledXYZ, cpt, props.label); + mapMaker.plot(resourcesDir, gridPrefix+"_supersampled_comp", grid.label+", Supersampled Sources"); + mapMaker.clearAnnotations(); + } + } + + table.addColumn("![Map]("+resourcesDir.getName()+"/"+gridPrefix+"_centered.png)"); + + if (compType != null) { + table.addColumn("![Map]("+resourcesDir.getName()+"/"+gridPrefix+"_centered_comp.png)"); + table.finalizeLine(); + if (doSupersample) + table.initNewLine(); + } + + if (doSupersample) { + table.addColumn("![Map]("+resourcesDir.getName()+"/"+gridPrefix+"_supersampled.png)"); + + if (compType != null) + table.addColumn("![Map]("+resourcesDir.getName()+"/"+gridPrefix+"_supersampled_comp.png)"); + table.finalizeLine(); + } else if (compType != null) { + table.finalizeLine(); + } + } + + if (compType == null && !doSupersample) + table.finalizeLine(); + lines.addAll(table.build()); + lines.add(""); + + if (writeIntermediate) + writeMarkdown(outputDir, lines, tocIndex); + } + + if (!doSingleCellHazard) + continue; + + for (int p=0; p 1) { + lines.add("### "+mechLabel+", "+perLabels[p]); + lines.add(topLink); lines.add(""); + } + + String mechPerPrefix = mechPrefix+"_"+perPrefixes[p]; + + Map centeredMaps = new EnumMap<>(GridType.class); + Map supersampledMaps = new EnumMap<>(GridType.class); + Map compCenteredMaps = compType == null ? null : new EnumMap<>(GridType.class); + Map compSupersampledMaps = compType == null ? null : new EnumMap<>(GridType.class); + + for (GridType grid : siteGrids.keySet()) { + GriddedRegion siteGrid = siteGrids.get(grid); + + for (boolean comp : compBools) { + PointSourceCalcERF myCenterERF = comp ? compCenterERF : centerERF; + System.out.println("Calculating "+grid.label+", centered, "+mechLabel+", "+perLabels[p]+", comp="+comp); + List centeredCurves = calcCurves(siteGrid.getNodeList(), myCenterERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + + List supersampledCurves = null; + if (doSupersample) { + PointSourceCalcERF mySupersampledERF = comp ? compSupersampledERF : supersampledERF; + System.out.println("Calculating "+grid.label+", supersampled, "+mechLabel+", "+perLabels[p]+", comp="+comp); + supersampledCurves = calcCurves(siteGrid.getNodeList(), mySupersampledERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + } + + GriddedGeoDataSet[] myCenteredMaps = new GriddedGeoDataSet[rps.length]; + GriddedGeoDataSet[] mySupersampledMaps = doSupersample ? new GriddedGeoDataSet[rps.length] : null; + + for (int r=0; r distFuncCenteredCurves = null; + List distFuncSupersampledCurves = null; + + DiscretizedFunc compColocatedCurve = null; + DiscretizedFunc compColocatedSupersampledCurve = null; + List compDistFuncCenteredCurves = null; + List compDistFuncSupersampledCurves = null; + + for (boolean comp : compBools) { + PointSourceCalcERF myCenterERF = comp ? compCenterERF : centerERF; + PointSourceCalcERF mySupersampledERF = comp ? compSupersampledERF : supersampledERF; + + System.out.println("Calculating dist func, centered, "+mechLabel+", "+perLabels[p]+", comp="+comp); + List calcDistFuncCenteredCurves = calcAverageCurves(distFuncLocs, myCenterERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + + List calcDistFuncSupersampledCurves = null; + if (doSupersample) { + System.out.println("Calculating dist func, supersampled, "+mechLabel+", "+perLabels[p]+", comp="+comp); + calcDistFuncSupersampledCurves = calcAverageCurves(distFuncLocs, mySupersampledERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + } + + if (comp) { + compColocatedCurve = calcDistFuncCenteredCurves.get(0); + compDistFuncCenteredCurves = calcDistFuncCenteredCurves; + if (doSupersample) { + compDistFuncSupersampledCurves = calcDistFuncSupersampledCurves; + compColocatedSupersampledCurve = calcDistFuncSupersampledCurves.get(0); + } + } else { + colocatedCurve = calcDistFuncCenteredCurves.get(0); + distFuncCenteredCurves = calcDistFuncCenteredCurves; + if (doSupersample) { + distFuncSupersampledCurves = calcDistFuncSupersampledCurves; + colocatedSupersampledCurve = calcDistFuncSupersampledCurves.get(0); + } + } + } + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + colocatedCurve.setName("Centered Source"); + funcs.add(colocatedCurve); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, mainColor)); + + if (compType != null) { + compColocatedCurve.setName("Comparison Cenetered Source"); + funcs.add(compColocatedCurve); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, compColor)); + } + + if (doSupersample) { + colocatedSupersampledCurve.setName("Supersampled Source"); + funcs.add(colocatedSupersampledCurve); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, mainColor)); + + if (compType != null) { + compColocatedSupersampledCurve.setName("Comparison Supersampled Source"); + funcs.add(compColocatedSupersampledCurve); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, compColor)); + } + } + + PlotSpec spec = new PlotSpec(funcs, chars, "Zero-Distance Hazard Curves", + perLabels[p]+" ("+perUnits[p]+")", "Annual Probability of Exceedance"); + spec.setLegendInset(RectangleAnchor.TOP_RIGHT); + + HeadlessGraphPanel gp = PlotUtils.initHeadless(); + + gp.drawGraphPanel(spec, true, true, curveXRanges[p], curveYRange); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + + PlotUtils.writePlots(resourcesDir, mechPerPrefix+"_curves", gp, 800, 800, true, true, false); + + lines.add("![Curves]("+resourcesDir.getName()+"/"+mechPerPrefix+"_curves.png)"); + lines.add(""); table = MarkdownUtils.tableBuilder(); for (int r=0; r 1) { if (periods.length > 1) - lines.add("#### "+mechLabel+", "+perLabel+", "+rps[r].label); + lines.add("#### "+mechLabel+", "+perLabels[p]+", "+rps[r].label); else lines.add("### "+mechLabel+", "+rps[r].label); lines.add(topLink); lines.add(""); } String mapPrefix = mechPerPrefix+"_"+rps[r].name(); - String hazLabel = rps[r].label+", "+perLabel+" ("+perUnits+")"; - String hazChangeLabel = rps[r].label+", "+perLabel+", % Change"; + String hazLabel = rps[r].label+", "+perLabels[p]+" ("+perUnits[p]+")"; + String hazChangeLabel = rps[r].label+", "+perLabels[p]+", % Change"; for (GridType grid : siteGrids.keySet()) { @@ -883,7 +1525,8 @@ public static void main(String[] args) throws IOException { else table.initNewLine(); - for (boolean supersampled : falseTrue) { + boolean[] superBools = doSupersample ? falseTrue : falseOnly; + for (boolean supersampled : superBools) { String mainPrefix = mapPrefix; String title; GriddedGeoDataSet mainMap; @@ -902,67 +1545,421 @@ public static void main(String[] args) throws IOException { title += ", Centered Source"; } - mapMaker.plotXYZData(log10(mainMap), hazCPT, hazLabel); + mapMaker.plotXYZData(log10(mainMap), hazCPTs[p], hazLabel); mapMaker.plot(resourcesDir, mainPrefix, title); if (compType != null) table.initNewLine(); table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+".png)"); if (compType != null) { - mapMaker.plotXYZData(log10(compMap), hazCPT, hazLabel); + mapMaker.plotXYZData(log10(compMap), hazCPTs[p], hazLabel); mapMaker.plot(resourcesDir, mainPrefix+"_comp", title); table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+"_comp.png)"); GriddedGeoDataSet pDiff = mapPDiff(mainMap, compMap); mapMaker.plotXYZData(pDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, pDiff, grid == GridType.COLOCATED ? gridCenterIndex : -1, false); mapMaker.plot(resourcesDir, mainPrefix+"_comp_pDiff", title); table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+"_comp_pDiff.png)"); table.finalizeLine(); + + mapMaker.clearAnnotations(); } } - // now add centered vs colocated - String title = "Centered vs Supersampled Source"; - String diffPrefix = mapPrefix+"_centered_supersampled_pDiff"; + // now add centered vs supersampled + if (doSupersample) { + String title = "Centered vs Supersampled Source"; + String diffPrefix = mapPrefix+"_centered_supersampled_pDiff"; + + GriddedGeoDataSet pDiff = mapPDiff(centeredMaps.get(grid)[r], supersampledMaps.get(grid)[r]); + GriddedGeoDataSet compPDiff = null; + if (compType != null) + compPDiff = mapPDiff(compCenteredMaps.get(grid)[r], compSupersampledMaps.get(grid)[r]); + title += ", "+grid.label+" Sites"; + diffPrefix += "_"+grid.prefix; + + if (compType != null) + table.initNewLine(); + mapMaker.plotXYZData(pDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, pDiff, grid == GridType.COLOCATED ? gridCenterIndex : -1, false); + mapMaker.plot(resourcesDir, diffPrefix, title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+".png)"); + mapMaker.clearAnnotations(); + + if (compType != null) { + mapMaker.plotXYZData(compPDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, compPDiff, grid == GridType.COLOCATED ? gridCenterIndex : -1, false); + mapMaker.plot(resourcesDir, diffPrefix+"_comp", title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+"_comp.png)"); + mapMaker.clearAnnotations(); + + table.addColumn(""); + } + table.finalizeLine(); + } else if (compType == null) { + table.finalizeLine(); + } - GriddedGeoDataSet pDiff = mapPDiff(centeredMaps.get(grid)[r], supersampledMaps.get(grid)[r]); - GriddedGeoDataSet compPDiff = null; - if (compType != null) - compPDiff = mapPDiff(compCenteredMaps.get(grid)[r], compSupersampledMaps.get(grid)[r]); - title += ", "+grid.label+" Sites"; - diffPrefix += "_"+grid.prefix; + lines.addAll(table.build()); + lines.add(""); + } + } + + if (writeIntermediate) + writeMarkdown(outputDir, lines, tocIndex); + } + } + + if (doNSHMModelHazard) { + String modelLabel = "NSHM23"; + System.out.println("Doing "+modelLabel); + GridSourceProvider gridProv = FaultSystemSolution.load(new File("/home/kevin/OpenSHA/nshm23/batch_inversions/" + + "2024_02_02-nshm23_branches-WUS_FM_v3/results_WUS_FM_v3_branch_averaged_gridded.zip")).getGridSourceProvider(); + + lines.add("## "+modelLabel+" Gridded Seismicity Hazard"); + lines.add(topLink); lines.add(""); + +// calcRegion = NSHM23_SingleStates.UT.loadRegion(); + calcRegion = new Region(new Location(37, -120), new Location(39, -118)); + + colocatedGridded = new GriddedRegion(calcRegion, spacing, GriddedRegion.ANCHOR_0_0); + + siteGrids = new EnumMap<>(GridType.class); + siteGrids.put(GridType.COLOCATED, colocatedGridded); + + offsetCalcGridded = new GriddedRegion(calcRegion, spacing, new Location(halfSpacing, halfSpacing)); + siteGrids.put(GridType.OFFSET, offsetCalcGridded); + +// if (doHighRes) +// siteGrids.put(GridType.HIGH_RES, new GriddedRegion(calcRegion, spacing*0.2, GriddedRegion.ANCHOR_0_0)); + + String compName = compType == null ? null : compType.label; + if (compType == null && mainType.stochastic) { + // compare with another realization + compType = mainType; + compName = "Second Random Realization"; + } + + numPerStochasticCentered = 1; + numPerStochasticSupersampled = 1; + double maxDistOutside = 100d; + double modelSuperSampleSpacing = Math.max(0.02, SUPERSAMPLE_SPACING); +// double modelSuperSampleSpacing = SUPERSAMPLE_SPACING; + + System.out.println("Building "+modelLabel+" ERF, "+mainType.label); + PointSourceCalcERF centerERF = new PointSourceCalcERF(mainType, gridProv, 0d, + numPerStochasticCentered, rand, calcRegion, maxDistOutside); + PointSourceCalcERF supersampledERF = null; + if (doSupersample) { + System.out.println("Building "+modelLabel+" ERF, "+mainType.label+", Supersampled"); + supersampledERF = new PointSourceCalcERF(mainType, gridProv, modelSuperSampleSpacing, + numPerStochasticCentered, rand, calcRegion, maxDistOutside); + } + + PointSourceCalcERF compCenterERF = null; + PointSourceCalcERF compSupersampledERF = null; + boolean[] compBools; + if (compType != null) { + compBools = falseTrue; + System.out.println("Building "+modelLabel+" ERF, "+compName); + compCenterERF = new PointSourceCalcERF(compType, gridProv, 0d, + numPerStochasticCentered, rand, calcRegion, maxDistOutside); + if (doSupersample) { + System.out.println("Building "+modelLabel+" ERF, "+compName+", Supersampled"); + compSupersampledERF = new PointSourceCalcERF(compType, gridProv, modelSuperSampleSpacing, + numPerStochasticCentered, rand, calcRegion, maxDistOutside); + } + } else { + compBools = falseOnly; + } + + System.out.println("Done building ERFs"); + + for (int p=0; p 1) { + lines.add("### NSHM23 "+perLabels[p]); + lines.add(topLink); lines.add(""); + } + + String modelPerPrefix = "model_"+perPrefixes[p]; + + Map centeredMaps = new EnumMap<>(GridType.class); + Map supersampledMaps = new EnumMap<>(GridType.class); + Map compCenteredMaps = compType == null ? null : new EnumMap<>(GridType.class); + Map compSupersampledMaps = compType == null ? null : new EnumMap<>(GridType.class); + + table = MarkdownUtils.tableBuilder(); + table.initNewLine().addColumn(""); + for (GridType type : siteGrids.keySet()) + table.addColumn(type.label); + table.finalizeLine(); + + for (boolean comp : compBools) { + List centeredTimes = new ArrayList<>(); + List supersampledTimes = new ArrayList<>(); + for (GridType grid : siteGrids.keySet()) { + GriddedRegion siteGrid = siteGrids.get(grid); + PointSourceCalcERF myCenterERF = comp ? compCenterERF : centerERF; + PointSourceCalcERF mySupersampledERF = comp ? compSupersampledERF : supersampledERF; + System.out.println("Calculating "+grid.label+", centered, "+modelLabel+", "+perLabels[p]+", comp="+comp); + Stopwatch watch = Stopwatch.createStarted(); + List centeredCurves = calcCurves(siteGrid.getNodeList(), myCenterERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + watch.stop(); + double time = watch.elapsed(TimeUnit.MILLISECONDS)/1000d; + System.out.println("Took "+timeStr(time)); + centeredTimes.add(timeStr(time)+" ("+timeStr(time/siteGrid.getNodeCount())+"/curve)"); + + List supersampledCurves = null; + if (doSupersample) { + System.out.println("Calculating "+grid.label+", supersampled, "+modelLabel+", "+perLabels[p]+", comp="+comp); + watch = Stopwatch.createStarted(); + supersampledCurves = calcCurves(siteGrid.getNodeList(), mySupersampledERF, gmmRef, + gmmDeque, calcDeque, period, xVals[p], logXVals[p], exec); + watch.stop(); + time = watch.elapsed(TimeUnit.MILLISECONDS)/1000d; + System.out.println("Took "+timeStr(time)); + supersampledTimes.add(timeStr(time)+" ("+timeStr(time/siteGrid.getNodeCount())+"/curve)"); + } + + GriddedGeoDataSet[] myCenteredMaps = new GriddedGeoDataSet[rps.length]; + GriddedGeoDataSet[] mySupersampledMaps = doSupersample ? new GriddedGeoDataSet[rps.length] : null; + + for (int r=0; r 1) { + if (periods.length > 1) + lines.add("#### "+modelLabel+", "+perLabels[p]+", "+rps[r].label); + else + lines.add("### "+modelLabel+", "+rps[r].label); + lines.add(topLink); lines.add(""); + } + String mapPrefix = modelPerPrefix+"_"+rps[r].name(); + + String hazLabel = rps[r].label+", "+perLabels[p]+" ("+perUnits[p]+")"; + String hazChangeLabel = rps[r].label+", "+perLabels[p]+", % Change"; + + for (GridType grid : siteGrids.keySet()) { + lines.add("__"+grid.label+" Grid__"); + lines.add(""); + + table = MarkdownUtils.tableBuilder(); if (compType != null) + table.addLine(mainType.label, compName, "% Change"); + else table.initNewLine(); - mapMaker.plotXYZData(pDiff, pDiffCPT, hazChangeLabel); - mapMaker.plot(resourcesDir, diffPrefix, title); - table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+".png)"); - if (compType != null) { - mapMaker.plotXYZData(compPDiff, pDiffCPT, hazChangeLabel); - mapMaker.plot(resourcesDir, diffPrefix+"_comp", title); - table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+"_comp.png)"); + boolean[] superBools = doSupersample ? falseTrue : falseOnly; + for (boolean supersampled : superBools) { + String mainPrefix = mapPrefix; + String title; + GriddedGeoDataSet mainMap; + GriddedGeoDataSet compMap = null; - table.addColumn(""); + mainPrefix += "_"+grid.prefix; + title = grid.label+" Sites"; + mainMap = supersampled ? supersampledMaps.get(grid)[r] : centeredMaps.get(grid)[r]; + if (compType != null) + compMap = supersampled ? compSupersampledMaps.get(grid)[r] : compCenteredMaps.get(grid)[r]; + if (supersampled) { + mainPrefix += "_supersampled"; + title += ", Supersampled Source"; + } else { + mainPrefix += "_centered"; + title += ", Centered Source"; + } + + mapMaker.plotXYZData(log10(mainMap), hazCPTs[p], hazLabel); + mapMaker.plot(resourcesDir, mainPrefix, title); + + if (compType != null) + table.initNewLine(); + table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+".png)"); + if (compType != null) { + mapMaker.plotXYZData(log10(compMap), hazCPTs[p], hazLabel); + mapMaker.plot(resourcesDir, mainPrefix+"_comp", title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+"_comp.png)"); + + GriddedGeoDataSet pDiff = mapPDiff(mainMap, compMap); + mapMaker.plotXYZData(pDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, pDiff, -1, true); + mapMaker.plot(resourcesDir, mainPrefix+"_comp_pDiff", title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+mainPrefix+"_comp_pDiff.png)"); + table.finalizeLine(); + + mapMaker.clearAnnotations(); + } + } + + // now add centered vs supersampled + if (doSupersample) { + String title = "Centered vs Supersampled Source"; + String diffPrefix = mapPrefix+"_centered_supersampled_pDiff"; + + GriddedGeoDataSet pDiff = mapPDiff(centeredMaps.get(grid)[r], supersampledMaps.get(grid)[r]); + GriddedGeoDataSet compPDiff = null; + if (compType != null) + compPDiff = mapPDiff(compCenteredMaps.get(grid)[r], compSupersampledMaps.get(grid)[r]); + title += ", "+grid.label+" Sites"; + diffPrefix += "_"+grid.prefix; + + if (compType != null) + table.initNewLine(); + mapMaker.plotXYZData(pDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, pDiff, -1, true); + mapMaker.plot(resourcesDir, diffPrefix, title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+".png)"); + mapMaker.clearAnnotations(); + + if (compType != null) { + mapMaker.plotXYZData(compPDiff, pDiffCPT, hazChangeLabel); + addPDiffAnns(mapMaker, compPDiff, -1, true); + mapMaker.plot(resourcesDir, diffPrefix+"_comp", title); + table.addColumn("![map]("+resourcesDir.getName()+"/"+diffPrefix+"_comp.png)"); + mapMaker.clearAnnotations(); + + table.addColumn(""); + } + table.finalizeLine(); + } else if (compType == null) { + table.finalizeLine(); } - table.finalizeLine(); lines.addAll(table.build()); lines.add(""); } } + + if (writeIntermediate) + writeMarkdown(outputDir, lines, tocIndex); } } exec.shutdown(); + writeMarkdown(outputDir, lines, tocIndex); + } + + private static String timeStr(double secs) { + if (secs < 60d) + return oDF.format(secs)+" s"; + double mins = secs/60d; + if (mins < 60d) + return oDF.format(mins)+" m"; + double hours = mins / 60d; + return oDF.format(hours)+" h"; + } + + private static void writeMarkdown(File outputDir, List lines, int tocIndex) throws IOException { + lines = new ArrayList<>(lines); + // add TOC lines.addAll(tocIndex, MarkdownUtils.buildTOC(lines, 2)); lines.add(tocIndex, "## Table Of Contents"); // write markdown + System.out.println("Writing markdown and HTML to "+outputDir.getAbsolutePath()); MarkdownUtils.writeReadmeAndHTML(lines, outputDir); } + + + private static final DecimalFormat oDF = new DecimalFormat("0.##"); + private static final Font ANN_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 40); + private static final DecimalFormat TWO_DIGITS = new DecimalFormat("0.00"); + private static void addPDiffAnns(GeographicMapMaker mapMaker, GriddedGeoDataSet pDiff, + int centerIndex, boolean doAvg) { + addRangeAnns(mapMaker, pDiff, centerIndex, doAvg, "%"); + } + + private static void addRangeAnns(GeographicMapMaker mapMaker, GriddedGeoDataSet xyz, + int centerIndex, boolean doAvg) { + addRangeAnns(mapMaker, xyz, centerIndex, doAvg, ""); + } + + private static void addRangeAnns(GeographicMapMaker mapMaker, GriddedGeoDataSet xyz, + int centerIndex, boolean doAvg, String suffix) { + Range yRange = mapMaker.getYRange(); + Range xRange = mapMaker.getXRange(); + double x = xRange.getLowerBound() + 0.975*xRange.getLength(); + double y = yRange.getLowerBound() + 0.975*yRange.getLength(); + XYTextAnnotation ann = new XYTextAnnotation("["+TWO_DIGITS.format(xyz.getMinZ()) + +suffix+", "+TWO_DIGITS.format(xyz.getMaxZ())+suffix+"]", x, y); + ann.setFont(ANN_FONT); + ann.setTextAnchor(TextAnchor.TOP_RIGHT); + + mapMaker.addAnnotation(ann); + + if (centerIndex >= 0) { + y -= 0.075*yRange.getLength(); + ann = new XYTextAnnotation("Center: "+TWO_DIGITS.format(xyz.get(centerIndex))+suffix, x, y); + ann.setFont(ANN_FONT); + ann.setTextAnchor(TextAnchor.TOP_RIGHT); + + mapMaker.addAnnotation(ann); + } + + if (doAvg) { + y -= 0.075*yRange.getLength(); + double avg = 0d; + for (int i=0; i calcCurves(List siteLocs, PointSourceCalcERF erf, AttenRelRef gmmRef, Deque gmmDeque, Deque calcDeque, @@ -970,68 +1967,145 @@ private static List calcCurves(List siteLocs, PointSo DiscretizedFunc logXVals, ExecutorService exec) { List> futures = new ArrayList<>(siteLocs.size()); - for (Location siteLoc : siteLocs) { - futures.add(exec.submit(new Callable() { - - @Override - public DiscretizedFunc call() throws Exception { - HazardCurveCalculator calc = null; - synchronized (calcDeque) { - if (!calcDeque.isEmpty()) - calc = calcDeque.pop(); - } - if (calc == null) - calc = new HazardCurveCalculator(); - ScalarIMR gmm = null; - synchronized (gmmDeque) { - if (!gmmDeque.isEmpty()) - gmm = gmmDeque.pop(); - } - if (gmm == null) - gmm = gmmRef.get(); - if (period == -1d) { - gmm.setIntensityMeasure(PGV_Param.NAME); - } else if (period == 0d) { - gmm.setIntensityMeasure(PGA_Param.NAME); - } else { - Preconditions.checkState(period > 0d); - gmm.setIntensityMeasure(SA_Param.NAME); - SA_Param.setPeriodInSA_Param(gmm.getIntensityMeasure(), period); - } - DiscretizedFunc logCurve = logXVals.deepClone(); - - Site site = new Site(siteLoc); - site.addParameterList(gmm.getSiteParams()); - - calc.setPtSrcDistCorrType(erf.distCorrType); - calc.getHazardCurve(logCurve, site, gmm, erf); - - synchronized (calcDeque) { - calcDeque.push(calc); - } - synchronized (gmmDeque) { - gmmDeque.push(gmm); - } - - DiscretizedFunc ret = new ArbitrarilyDiscretizedFunc(); - for (int i=0; i ret = new ArrayList<>(); for (Future future : futures) { try { ret.add(future.get()); + System.out.print("."); + if (ret.size() % 100 == 0) + System.out.println(" "+ret.size()+" ("+pDF.format((double)ret.size()/(double)siteLocs.size())+")"); } catch (InterruptedException | ExecutionException e) { throw ExceptionUtils.asRuntimeException(e); } } + if (ret.size() % 100 != 0) + System.out.println(" "+ret.size()+" ("+pDF.format(1d)+")"); return ret; } + private static List calcAverageCurves(List> siteLocs, PointSourceCalcERF erf, + AttenRelRef gmmRef, Deque gmmDeque, Deque calcDeque, + double period, DiscretizedFunc xVals, + DiscretizedFunc logXVals, ExecutorService exec) { + List>> futures = new ArrayList<>(siteLocs.size()); + + for (List siteLocBundle : siteLocs) { + List> bundle = new ArrayList<>(siteLocBundle.size()); + futures.add(bundle); + for (Location siteLoc : siteLocBundle) + bundle.add(exec.submit(new CurveCalcCall(siteLoc, erf, gmmRef, gmmDeque, calcDeque, period, xVals, logXVals))); + } + + List ret = new ArrayList<>(); + for (List> bundle : futures) { + List curves = new ArrayList<>(bundle.size()); + for (Future future : bundle) { + try { + curves.add(future.get()); + } catch (InterruptedException | ExecutionException e) { + throw ExceptionUtils.asRuntimeException(e); + } + } + if (curves.size() == 1) { + ret.add(curves.get(0)); + } else { + double scalar = 1d/curves.size(); + DiscretizedFunc curve = xVals.deepClone(); + for (int x=0; x { + + private Location loc; + private PointSourceCalcERF erf; + private AttenRelRef gmmRef; + private Deque gmmDeque; + private Deque calcDeque; + private double period; + private DiscretizedFunc xVals; + private DiscretizedFunc logXVals; + + public CurveCalcCall(Location loc, PointSourceCalcERF erf, + AttenRelRef gmmRef, Deque gmmDeque, Deque calcDeque, + double period, DiscretizedFunc xVals, + DiscretizedFunc logXVals) { + this.loc = loc; + this.erf = erf; + this.gmmRef = gmmRef; + this.gmmDeque = gmmDeque; + this.calcDeque = calcDeque; + this.period = period; + this.xVals = xVals; + this.logXVals = logXVals; + + } + + @Override + public DiscretizedFunc call() throws Exception { + HazardCurveCalculator calc = null; + synchronized (calcDeque) { + if (!calcDeque.isEmpty()) + calc = calcDeque.pop(); + } + if (calc == null) + calc = new HazardCurveCalculator(); + ScalarIMR gmm = null; + synchronized (gmmDeque) { + if (!gmmDeque.isEmpty()) + gmm = gmmDeque.pop(); + } + if (gmm == null) + gmm = gmmRef.get(); + if (period == -1d) { + gmm.setIntensityMeasure(PGV_Param.NAME); + } else if (period == 0d) { + gmm.setIntensityMeasure(PGA_Param.NAME); + } else { + Preconditions.checkState(period > 0d); + gmm.setIntensityMeasure(SA_Param.NAME); + SA_Param.setPeriodInSA_Param(gmm.getIntensityMeasure(), period); + } + DiscretizedFunc logCurve = logXVals.deepClone(); + + Site site = new Site(loc); + site.addParameterList(gmm.getSiteParams()); + + calc.setPtSrcDistCorrType(erf.distCorrType); + calc.getHazardCurve(logCurve, site, gmm, erf); + + synchronized (calcDeque) { + calcDeque.push(calc); + } + synchronized (gmmDeque) { + gmmDeque.push(gmm); + } + + DiscretizedFunc ret = new ArbitrarilyDiscretizedFunc(); + for (int i=0; i curves, ReturnPeriods rp) { Preconditions.checkState(curves.size() == reg.getNodeCount()); GriddedGeoDataSet map = new GriddedGeoDataSet(reg); @@ -1110,31 +2184,78 @@ private static GriddedGeoDataSet mapPDiff(GriddedGeoDataSet numerator, GriddedGe return ret; } - private static void calcDistFuncs(PointSourceCalcERF erf, List distLocs, - EvenlyDiscretizedFunc rJB, EvenlyDiscretizedFunc rRup, double mag) { + private static List getRupsAtMag(PointSourceCalcERF erf, double mag) { List rupsAtMag = new ArrayList<>(); for (ProbEqkSource source : erf) for (ProbEqkRupture rup : source) if (Precision.equals(rup.getMag(), mag)) rupsAtMag.add(rup); Preconditions.checkState(!rupsAtMag.isEmpty()); - - IntStream.range(0, distLocs.size()).parallel().forEach(new IntConsumer() { - - @Override - public void accept(int i) { - List rJBs = new ArrayList<>(rupsAtMag.size()); - List rRups = new ArrayList<>(rupsAtMag.size()); - Location loc = distLocs.get(i); + return rupsAtMag; + } + + private static void calcDistFuncsAtMag(PointSourceCalcERF erf, List> distLocs, + EvenlyDiscretizedFunc rJB, EvenlyDiscretizedFunc rRup, double mag) { + List rupsAtMag = getRupsAtMag(erf, mag); + IntStream.range(0, distLocs.size()).parallel().forEach(i -> { + List rJBs = new ArrayList<>(rupsAtMag.size()); + List rRups = new ArrayList<>(rupsAtMag.size()); + for (Location loc : distLocs.get(i)) { for (ProbEqkRupture rup : rupsAtMag) { RuptureSurface surf = rup.getRuptureSurface(); rJBs.add(surf.getDistanceJB(loc)); rRups.add(surf.getDistanceRup(loc)); } - rJB.set(i, rJBs.stream().mapToDouble(D->D).average().getAsDouble()); - rRup.set(i, rRups.stream().mapToDouble(D->D).average().getAsDouble()); } + rJB.set(i, rJBs.stream().mapToDouble(D->D).average().getAsDouble()); + rRup.set(i, rRups.stream().mapToDouble(D->D).average().getAsDouble()); + }); + } + + private static void calcMagFuncsAtDist(PointSourceCalcERF erf, List distLocs, + EvenlyDiscretizedFunc rJB, EvenlyDiscretizedFunc rRup, double dist) { + IntStream.range(0, rJB.size()).parallel().forEach(i -> { + List rupsAtMag = getRupsAtMag(erf, rJB.getX(i)); + + List rJBs = new ArrayList<>(rupsAtMag.size()); + List rRups = new ArrayList<>(rupsAtMag.size()); + for (Location distLoc : distLocs) { + for (ProbEqkRupture rup : rupsAtMag) { + RuptureSurface surf = rup.getRuptureSurface(); + rJBs.add(surf.getDistanceJB(distLoc)); + rRups.add(surf.getDistanceRup(distLoc)); + } + } + rJB.set(i, rJBs.stream().mapToDouble(D->D).average().getAsDouble()); + rRup.set(i, rRups.stream().mapToDouble(D->D).average().getAsDouble()); + }); + } + + private static EvenlyDiscretizedFunc calcMagProps(PointSourceCalcERF erf, IncrementalMagFreqDist mfd, + RupSurfProps prop) { + EvenlyDiscretizedFunc ret = new EvenlyDiscretizedFunc(mfd.getMinX(), mfd.size(), mfd.getDelta()); + IntStream.range(0, mfd.size()).parallel().forEach(i -> { + List rupsAtMag = getRupsAtMag(erf, mfd.getX(i)); + List props = new ArrayList<>(rupsAtMag.size()); + for (ProbEqkRupture rup : rupsAtMag) + props.add(prop.calcForRupture(rup)); + ret.set(i, props.stream().mapToDouble(D->D).average().getAsDouble()); + }); + return ret; + } + + private static GriddedGeoDataSet calcMapProps(PointSourceCalcERF erf, GriddedRegion gridReg, + RupSurfMapProps prop) { + GriddedGeoDataSet xyz = new GriddedGeoDataSet(gridReg); + IntStream.range(0, gridReg.getNodeCount()).parallel().forEach(i -> { + Location loc = gridReg.getLocation(i); + List props = new ArrayList<>(); + for (ProbEqkSource source : erf) + for (ProbEqkRupture rup : source) + props.add(prop.calcForRuptureAndLocation(rup, loc)); + xyz.set(i, props.stream().mapToDouble(D->D).average().getAsDouble()); }); + return xyz; } private static EvenlyDiscretizedFunc asDistRatio(EvenlyDiscretizedFunc distFunc) { diff --git a/src/main/java/scratch/kevin/pointSources/PointSurfaceBuilder.java b/src/main/java/scratch/kevin/pointSources/PointSurfaceBuilder.java new file mode 100644 index 00000000..c36b7fa7 --- /dev/null +++ b/src/main/java/scratch/kevin/pointSources/PointSurfaceBuilder.java @@ -0,0 +1,430 @@ +package scratch.kevin.pointSources; + +import java.util.Random; + +import org.opensha.commons.calc.magScalingRelations.MagAreaRelationship; +import org.opensha.commons.calc.magScalingRelations.MagLengthRelationship; +import org.opensha.commons.calc.magScalingRelations.MagScalingRelationship; +import org.opensha.commons.calc.magScalingRelations.magScalingRelImpl.WC1994_MagLengthRelationship; +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.LocationUtils; +import org.opensha.commons.geo.Region; +import org.opensha.commons.util.FaultUtils; +import org.opensha.sha.faultSurface.EvenlyGriddedSurface; +import org.opensha.sha.faultSurface.FaultTrace; +import org.opensha.sha.faultSurface.FrankelGriddedSurface; +import org.opensha.sha.faultSurface.QuadSurface; +import org.opensha.sha.faultSurface.RuptureSurface; +import org.opensha.sha.faultSurface.utils.PtSrcDistCorr; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Range; + +public class PointSurfaceBuilder { + + // required/set on input + private Location loc; + private double zTop; + private double zBot; + + // optional + private Region sampleFromCell = null; + private Random rand; + private double mag = Double.NaN; + private double strike = Double.NaN; + private double dip = 90d; + private double length = Double.NaN; + private boolean footwall = true; + private boolean traceCentered = true; + + private MagScalingRelationship scale = WC94; + private double gridSpacing = 1d; + + // calculated on the fly + private double width = Double.NaN; + + private static final WC1994_MagLengthRelationship WC94 = new WC1994_MagLengthRelationship(); + + public PointSurfaceBuilder(Location loc) { + this.loc = loc; + zTop = loc.getDepth(); + zBot = loc.getDepth(); + } + + public PointSurfaceBuilder sampleFromCell(Region cell) { + this.sampleFromCell = cell; + return this; + } + + public PointSurfaceBuilder random(Random rand) { + this.rand = rand; + return this; + } + + private Random getRand() { + if (rand == null) + rand = new Random(Double.doubleToLongBits(loc.lat) + Double.doubleToLongBits(loc.lon)); + return rand; + } + + private Location getLoc() { + if (sampleFromCell != null) { + double minLat = sampleFromCell.getMinLat(); + double maxLat = sampleFromCell.getMaxLat(); + double latSpan = maxLat - minLat; + Preconditions.checkState(latSpan > 0d); + double minLon = sampleFromCell.getMinLon(); + double maxLon = sampleFromCell.getMaxLon(); + double lonSpan = maxLon - minLon; + Preconditions.checkState(lonSpan > 0d); + Random rand = getRand(); + boolean rectangular = sampleFromCell.isRectangular(); + int maxNumTries = 100; + int tries = 0; + while (true) { + double lat = minLat + rand.nextDouble(latSpan); + double lon = minLon + rand.nextDouble(lonSpan); + Location randLoc = new Location(lat, lon, loc.depth); + if (rectangular || sampleFromCell.contains(randLoc)) + return randLoc; + // outside + tries++; + Preconditions.checkState(tries <= maxNumTries, + "Couldn't randomly sample a location in the grid cell after %s tries", tries); + } + } + return loc; + } + + public PointSurfaceBuilder dip(double dip) { + FaultUtils.assertValidDip(dip); + this.dip = dip; + this.width = Double.NaN; + return this; + } + + /** + * Set the depth (both upper and lower to the same) in km + * @param depth + * @return + */ + public PointSurfaceBuilder singleDepth(double depth) { + FaultUtils.assertValidDepth(depth); + this.zTop = depth; + this.zBot = depth; + this.width = Double.NaN; + return this; + } + + /** + * Set the upper depth in km + * @param zTop + * @return + */ + public PointSurfaceBuilder upperDepth(double zTop) { + FaultUtils.assertValidDepth(zTop); + this.zTop = zTop; + this.width = Double.NaN; + return this; + } + + /** + * Set the lower depth in km + * @param zBot + * @return + */ + public PointSurfaceBuilder lowerDepth(double zBot) { + FaultUtils.assertValidDepth(zBot); + this.zBot = zBot; + this.width = Double.NaN; + return this; + } + + /** + * Sets the magnitude, used to infer the length if the length is not explicitly set + * @param mag + * @return + */ + public PointSurfaceBuilder magnitude(double mag) { + this.mag = mag; + return this; + } + + /** + * Sets the magnitude scaling relationship used to infer lengths (if length is not explicitly set) + * @param scale + * @return + */ + public PointSurfaceBuilder scaling(MagScalingRelationship scale) { + Preconditions.checkNotNull(scale); + this.scale = scale; + return this; + } + + /** + * Set the length in km, or NaN to infer from magnitude and scaling + * @param length + * @return + */ + public PointSurfaceBuilder length(double length) { + this.length = length; + return this; + } + + /** + * Sets the strike direction in decimal degrees, or NaN for no direction + * + * @param strike + * @return + */ + public PointSurfaceBuilder strike(double strike) { + this.strike = strike; + return this; + } + + /** + * Sets the footwall parameter, used with point representations + * @param footwall + * @return + */ + public PointSurfaceBuilder footwall(boolean footwall) { + this.footwall = footwall; + return this; + } + + /** + * Sets the grid spacing to be used when a gridded surface is built + * @param gridSpacing + * @return + */ + public PointSurfaceBuilder gridSpacing(double gridSpacing) { + this.gridSpacing = gridSpacing; + return this; + } + + /** + * Sets if the trace should be centered on the grid node (true), or if the middle of the surface should be (false). + * Only affects dipping ruptures. + * @param traceCentered + * @return + */ + public PointSurfaceBuilder traceCentered(boolean traceCentered) { + this.traceCentered = traceCentered; + return this; + } + + private double getCalcLength() { + if (Double.isFinite(length)) + return length; + if (Double.isFinite(mag)) { + // calculate from scaling relationship + if (scale instanceof MagLengthRelationship) { + return ((MagLengthRelationship)scale).getMedianLength(mag); + } else { + Preconditions.checkState(scale instanceof MagAreaRelationship); + double area = ((MagAreaRelationship)scale).getMedianArea(mag); + double width = getCalcWidth(); + if (width > 0) + return area/width; + else + // zero width, return zero + return 0d; + } + } else { + // can't calculate, set to zero + return 0d; + } + } + + private double getCalcWidth() { + Preconditions.checkState(zBot >= zTop, "zBOT must be >= zTOR"); + if (Double.isNaN(width)) { + if (dip == 90d) + width = zBot-zTop; + else + width = (zBot-zTop)/Math.sin(Math.toRadians(dip)); + } + return width; + } + + /** + * Builds a point surface representation where rJB is calculated according to the chosen {@link PtSrcDistCorr}, + * and other distances are calculated using the (possibly corrected) rJB, the footwall setting, and zTop/zBot/dip. + * @return + */ + public FiniteApproxPointSurface buildPointSurface() { + Preconditions.checkState(zBot >= zTop, "zBOT must be >= zTOR"); + + double length = getCalcLength(); + + return new FiniteApproxPointSurface(getLoc(), dip, zTop, zBot, footwall, length); + } + + private FaultTrace buildTrace(double strike) { + Preconditions.checkState(Double.isFinite(strike), "Can't build finite surface because strike=%s", strike); + double length = getCalcLength(); + Preconditions.checkState(length > 0, "Can't build finite surface because length=%s; " + + "set magnitude to infer length from scaling relationship", length); + double halfLen = 0.5*length; + double strikeRad = Math.toRadians(strike); + Location loc = getLoc(); + Location l0 = LocationUtils.location(loc, strikeRad-Math.PI, halfLen); + Location l1 = LocationUtils.location(loc, strikeRad, halfLen); + if (!traceCentered && zBot > zTop && dip < 90) { + // translate it so that the surface is centered rather than the trace + double horzWidth = (zBot-zTop)/Math.tan(Math.toRadians(dip)); + // move to the left (so that it dips to the right) + double transAz = strikeRad - 0.5*Math.PI; + l0 = LocationUtils.location(l0, transAz, 0.5*horzWidth); + l1 = LocationUtils.location(l1, transAz, 0.5*horzWidth); + } + l0 = new Location(l0.lat, l0.lon, zTop); + l1 = new Location(l1.lat, l1.lon, zTop); + FaultTrace trace = new FaultTrace(null); + trace.add(l0); + trace.add(l1); + return trace; + } + + private double[] getRandStrikes(int num, Range strikeRange) { + double[] strikes = new double[num]; + Random rand = getRand(); + if (strikeRange == null) { + // pick a random strike as the initial orientation, then evenly space relatively to that + double origStrike = rand.nextDouble(360d); + double delta = 360d/(double)num; + for (int i=0; i 0d); + for (int i=0; i1, additional strikes will be evenly distributed. + * @param num + * @return + */ + public QuadSurface[] buildRandQuadSurfaces(int num) { + return buildRandQuadSurfaces(num, null); + } + + /** + * Builds the given number of random strike quad surfaces. If strikeRange is non null, orientations will be randomly + * sampled from the given range. + * @param num + * @param strikeRange + * @return + */ + public QuadSurface[] buildRandQuadSurfaces(int num, Range strikeRange) { + QuadSurface[] ret = new QuadSurface[num]; + double[] strikes = getRandStrikes(num, strikeRange); + for (int i=0; i= zTop, "zBOT must be >= zTOR"); + FaultTrace trace = buildTrace(strike); + + return new FrankelGriddedSurface(trace, dip, zTop, zBot, gridSpacing); + } + + /** + * Builds the given number of random strike gridded surfaces. The initial orientation will be randomly sampled, then + * if num>1, additional strikes will be evenly distributed. + * @param num + * @return + */ + public EvenlyGriddedSurface[] buildRandGriddedSurfaces(int num) { + return buildRandGriddedSurfaces(num, null); + } + + /** + * Builds the given number of random strike gridded surfaces. If strikeRange is non null, orientations will be randomly + * sampled from the given range. + * @param num + * @param strikeRange + * @return + */ + public EvenlyGriddedSurface[] buildRandGriddedSurfaces(int num, Range strikeRange) { + EvenlyGriddedSurface[] ret = new EvenlyGriddedSurface[num]; + double[] strikes = getRandStrikes(num, strikeRange); + for (int i=0; i