diff --git a/src/main/java/org/opensha/nshmp/shaded/model/NshmErf.java b/src/main/java/org/opensha/nshmp/shaded/model/NshmErf.java index b1b33244..1aa78264 100644 --- a/src/main/java/org/opensha/nshmp/shaded/model/NshmErf.java +++ b/src/main/java/org/opensha/nshmp/shaded/model/NshmErf.java @@ -11,22 +11,28 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.EnumMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.apache.commons.numbers.core.Precision; import org.opensha.commons.data.TimeSpan; import org.opensha.sha.earthquake.AbstractERF; import org.opensha.sha.earthquake.ProbEqkSource; import org.opensha.sha.earthquake.param.IncludeBackgroundOption; +import org.opensha.sha.imr.attenRelImpl.nshmp.NSHMP_GMM_Wrapper; import org.opensha.sha.util.TectonicRegionType; +import com.google.common.base.Preconditions; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import org.opensha.nshmp.shaded.data.NshmpIndexing; +import org.opensha.nshmp.shaded.gmm.NshmpGmm; import org.opensha.nshmp.shaded.model.NshmpSystemRuptureSet.SystemRupture; import org.opensha.nshmp.shaded.tree.NshmpBranch; @@ -43,6 +49,7 @@ public class NshmErf extends AbstractERF { private final boolean volcanic; private final boolean grid; private final boolean faults; + private Set trts; public NshmErf(Path path, Set trts, IncludeBackgroundOption gridOption) { @@ -52,6 +59,7 @@ public NshmErf(Path path, Set trts, public NshmErf(NshmpHazardModel model, Set trts, IncludeBackgroundOption gridOption) { this.model = model; + this.trts = trts; allSources = new ArrayList<>(); sourceMap = MultimapBuilder .enumKeys(TectonicRegionType.class) @@ -69,6 +77,8 @@ public NshmErf(NshmpHazardModel model, Set trts, init(); } + + private static final boolean PROCESS_TRT_OVERRIDES = true; private void init() { @@ -79,37 +89,134 @@ private void init() { // nshmp-haz initializers Multimap trees = model.trees(); + if (PROCESS_TRT_OVERRIDES) { + List trtMappedRuptureSets = parseTRTOverrides(trees); + for (NshmpTRTBranch trtBranch : trtMappedRuptureSets) { + if (!trts.isEmpty() && !trts.contains(trtBranch.trt)) + continue; + List sources = initBranch(trtBranch.branch); + sources.forEach(s -> s.setTectonicRegionType(trtBranch.trt)); + allSources.addAll(sources); + sourceMap.putAll(trtBranch.trt, sources); + } + allSources.sort(new Comparator() { + @Override + public int compare(NshmSource o1, NshmSource o2) { + return Integer.compare(o1.getNSHM_ID(), o2.getNSHM_ID()); + } + }); + } else { + for (Entry entry : trees.entries()) { + NshmpTectonicSetting setting = entry.getKey(); + NshmpSourceTree tree = entry.getValue(); + NshmpSourceType type = tree.type(); + + TectonicRegionType trt = NshmUtil.tectonicSettingToType(setting, type); + if (!trts.isEmpty() && !trts.contains(trt)) + continue; + List sources = initTree(tree); + sources.forEach(s -> s.setTectonicRegionType(trt)); + allSources.addAll(sources); + sourceMap.putAll(trt, sources); + } + } + } + + private record NshmpTRTBranch(TectonicRegionType trt, NshmpBranch branch) {} + + /** + * Map each branch to a tectonic region type, also processing any GMM-overrides that Peter might sneak in there + * to change the TRT within a different NshmpTectonicSetting + * @param trees + * @return + */ + private static List parseTRTOverrides( + Multimap trees) { + List ret = new ArrayList<>(); + for (Entry entry : trees.entries()) { - NshmpTectonicSetting setting = entry.getKey(); NshmpSourceTree tree = entry.getValue(); NshmpSourceType type = tree.type(); - - if (setting == NshmpTectonicSetting.SUBDUCTION) { - if ((type == NshmpSourceType.INTERFACE || type == NshmpSourceType.INTERFACE_CLUSTER - || type == NshmpSourceType.INTERFACE_GRID || type == NshmpSourceType.INTERFACE_SYSTEM) && !subInterface) { + TectonicRegionType origTRT = NshmUtil.tectonicSettingToType(setting, type); + + System.out.println("Processing tree "+tree.id()+". "+tree.name()+" ("+origTRT.name()+")"); + + for (NshmpBranch branch : tree) { + if (origTRT == VOLCANIC) { + // copy over as is, no current GMM type for volcanic + ret.add(new NshmpTRTBranch(origTRT, branch)); continue; } - if ((type == NshmpSourceType.SLAB || type == NshmpSourceType.INTRASLAB_GRID) && !subSlab) { - continue; + NshmpRuptureSet rs = branch.value(); + System.out.println("\tProcessing RS "+rs.id()+". "+rs.name()+" ("+origTRT.name()+")"); + NshmpGmmTree gmmTree = rs.gmmTree(); + double weightOrig = 0d; + double weightOverrideSum = 0d; + Map overrideWeights = new EnumMap<>(TectonicRegionType.class); + for (NshmpBranch gmm : gmmTree.tree()) { + TectonicRegionType gmmTRT = NSHMP_GMM_Wrapper.trtForType(gmm.value().type()); + if (gmmTRT != origTRT) { + // we have a GMM TRT override + weightOverrideSum += gmm.weight(); + if (overrideWeights.containsKey(gmmTRT)) + overrideWeights.put(gmmTRT, overrideWeights.get(gmmTRT)+gmm.weight()); + else + overrideWeights.put(gmmTRT, gmm.weight()); + } else { + weightOrig += gmm.weight(); + } + } + if (weightOverrideSum > 0d) { + // we have overrides to process + Preconditions.checkState(Precision.equals(weightOverrideSum + weightOrig, 1d, 1e-4)); + System.err.println("Detected a GMM TRT override for source "+rs.id()+". "+rs.name()+" with original TRT="+origTRT.name()); + if (weightOrig > 0d) { + System.err.println("\t"+origTRT.name()+":\t"+weightOrig); + ret.add(new NshmpTRTBranch(origTRT, new WeightScaledBranch(branch, weightOrig, origTRT))); + } + for (TectonicRegionType trt : overrideWeights.keySet()) { + double weight = overrideWeights.get(trt); + System.err.println("\t"+trt.name()+":\t"+weight); + ret.add(new NshmpTRTBranch(trt, new WeightScaledBranch(branch, weight, trt))); + } + } else { + // copy over as is + ret.add(new NshmpTRTBranch(origTRT, branch)); } } - if (setting == NshmpTectonicSetting.STABLE_CRUST && !stableCrust) { - continue; - } - if (setting == NshmpTectonicSetting.ACTIVE_CRUST && !activeCrust) { - continue; - } - if (setting == NshmpTectonicSetting.VOLCANIC && !volcanic) { - continue; - } + } + + return ret; + } + + private static class WeightScaledBranch implements NshmpBranch { + + private NshmpBranch upstream; + private double scale; + private TectonicRegionType trt; + + public WeightScaledBranch(NshmpBranch upstream, double scale, TectonicRegionType trt) { + this.upstream = upstream; + this.scale = scale; + this.trt = trt; + } + + @Override + public String id() { + return upstream.id()+"-"+trt.name(); + } + + @Override + public NshmpRuptureSet value() { + return upstream.value(); + } - TectonicRegionType trt = NshmUtil.tectonicSettingToType(setting, type); - List sources = initTree(tree); - sources.forEach(s -> s.setTectonicRegionType(trt)); - allSources.addAll(sources); - sourceMap.putAll(trt, sources); + @Override + public double weight() { + return upstream.weight()*scale; } + } public List allSources() { @@ -152,6 +259,14 @@ public int compare(NshmSource o1, NshmSource o2) { return sources; } + private List initBranch(NshmpBranch branch) { + List sources = new ArrayList<>(); + double duration = getTimeSpan().getDuration(); + sources.addAll(sourcesFromBranch(branch, duration)); + + return sources; + } + private List sourcesFromBranch( NshmpBranch branch, double duration) { diff --git a/src/main/java/org/opensha/nshmp/shaded/model/NshmSource.java b/src/main/java/org/opensha/nshmp/shaded/model/NshmSource.java index 9aafb9b6..aeefb277 100644 --- a/src/main/java/org/opensha/nshmp/shaded/model/NshmSource.java +++ b/src/main/java/org/opensha/nshmp/shaded/model/NshmSource.java @@ -49,11 +49,7 @@ public RuptureSurface getSourceSurface() { throw new UnsupportedOperationException(); } - public Object getDelegate() { - return delegate; - } - - static class Fault extends NshmSource { + public static class Fault extends NshmSource { private final List ruptures; @@ -99,7 +95,7 @@ public void setDuration(double duration) { } } - static class Point extends NshmSource { + public static class Point extends NshmSource { final double weight; double duration; @@ -142,7 +138,7 @@ public void setDuration(double duration) { } } - static class System extends NshmSource { + public static class System extends NshmSource { final List surfaces; final NshmRupture rupture; diff --git a/src/main/java/org/opensha/nshmp/shaded/model/NshmSurface.java b/src/main/java/org/opensha/nshmp/shaded/model/NshmSurface.java index 01255398..f8fd2f46 100644 --- a/src/main/java/org/opensha/nshmp/shaded/model/NshmSurface.java +++ b/src/main/java/org/opensha/nshmp/shaded/model/NshmSurface.java @@ -11,6 +11,8 @@ import org.opensha.sha.faultSurface.RuptureSurface; import org.opensha.sha.faultSurface.cache.CacheEnabledSurface; import org.opensha.sha.faultSurface.cache.SurfaceDistances; +import org.opensha.sha.faultSurface.utils.ptSrcCorr.PointSourceDistanceCorrection; +import org.opensha.sha.util.TectonicRegionType; import org.opensha.nshmp.shaded.fault.surface.NshmpDefaultGriddedSurface; import org.opensha.nshmp.shaded.fault.surface.NshmpGriddedSurface; @@ -36,6 +38,64 @@ public class NshmSurface implements CacheEnabledSurface { public NshmSurface(org.opensha.nshmp.shaded.fault.surface.NshmpRuptureSurface delegate) { this.delegate = delegate; } + + /** + * This creates a point surface that will work with existing OpenSHA point-source optimizations + * @param delegate + * @return + */ + public static org.opensha.sha.faultSurface.PointSurface buildPointSurface( + org.opensha.nshmp.shaded.fault.surface.NshmpRuptureSurface delegate) { + // this is the point surface + double len = 0d; + try { + len = delegate.length(); + } catch (Exception e) {} + org.opensha.sha.faultSurface.PointSurface surf = new org.opensha.sha.faultSurface.PointSurface( + NshmUtil.toOpenShaLocation(delegate.centroid()), delegate.dip(), delegate.depth(), + delegate.depth() + delegate.width()*Math.sin(Math.toRadians(delegate.dip())), len); + return new org.opensha.sha.faultSurface.PointSurface.DistanceCorrecting( + surf, new DelegatePointSourceCorrection(delegate), null, Double.NaN); + } + + /** + * Delegate point source correction that passes through to NSHMP-haz. This is required for point source + * optimizations to work with wrapped point sources. As part of that, equals/hashCode have to be constant + * for all delegate corrections. + */ + private static class DelegatePointSourceCorrection implements PointSourceDistanceCorrection.Single { + + private org.opensha.nshmp.shaded.fault.surface.NshmpRuptureSurface delegate; + + private DelegatePointSourceCorrection(org.opensha.nshmp.shaded.fault.surface.NshmpRuptureSurface delegate) { + this.delegate = delegate; + } + + @Override + public SurfaceDistances getCorrectedDistance(Location location, org.opensha.sha.faultSurface.PointSurface surf, + TectonicRegionType trt, double mag, double horzDist) { + NshmpDistance distance = delegate.distanceTo(NshmUtil.fromOpenShaLocation(location)); + return new SurfaceDistances.Precomputed(location, distance.rRup, distance.rJB, distance.rX); + } + + private static final int hashCode = DelegatePointSourceCorrection.class.hashCode(); + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { +// return obj instanceof DelegatePointSourceCorrection; + if (!(obj instanceof DelegatePointSourceCorrection)) + return false; + DelegatePointSourceCorrection other = (DelegatePointSourceCorrection)obj; +// System.out.println("Delegate classes:\t"+delegate.getClass()+"\t"+other.delegate.getClass()); + return other.delegate.getClass().equals(delegate.getClass()); + } + + } // return nshmp-haz rupture centroid as OpenSHA location for // use in computing min distance to a fault system subsection diff --git a/src/main/java/scratch/kevin/BranchScratch.java b/src/main/java/scratch/kevin/BranchScratch.java index c4a66a4c..8c1092a5 100644 --- a/src/main/java/scratch/kevin/BranchScratch.java +++ b/src/main/java/scratch/kevin/BranchScratch.java @@ -1,6 +1,7 @@ package scratch.kevin; import java.awt.Color; +import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -8,7 +9,9 @@ import org.jfree.data.Range; import org.opensha.commons.data.CSVFile; +import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.LightFixedXFunc; import org.opensha.commons.geo.Location; import org.opensha.commons.geo.Region; import org.opensha.commons.gui.plot.HeadlessGraphPanel; @@ -16,16 +19,26 @@ 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.logicTree.LogicTree; import org.opensha.sha.earthquake.ProbEqkRupture; import org.opensha.sha.earthquake.ProbEqkSource; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.modules.ModSectMinMags; +import org.opensha.sha.earthquake.faultSysSolution.modules.RupMFDsModule; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; import org.opensha.sha.earthquake.rupForecastImpl.WGCEP_UCERF_2_Final.UCERF2; import org.opensha.sha.earthquake.rupForecastImpl.WGCEP_UCERF_2_Final.MeanUCERF2.MeanUCERF2; +import org.opensha.sha.earthquake.rupForecastImpl.prvi25.erf.NSHM25_PRVI_BranchAveragedERF; +import org.opensha.sha.earthquake.util.GriddedSeismicitySettings; import org.opensha.sha.faultSurface.FaultSection; +import org.opensha.sha.faultSurface.PointSurface; +import org.opensha.sha.faultSurface.RuptureSurface; import org.opensha.sha.magdist.IncrementalMagFreqDist; +import scratch.UCERF3.erf.mean.MeanUCERF3; +import scratch.UCERF3.inversion.InversionFaultSystemRupSet; + public class BranchScratch { private static void test1() throws IOException { @@ -105,13 +118,93 @@ private static void test2() throws IOException { } } + private static void test3() throws IOException { + NSHM25_PRVI_BranchAveragedERF erf = new NSHM25_PRVI_BranchAveragedERF(); +// erf.setGriddedSeismicitySettings(GriddedSeismicitySettings.DEFAULT.forDistanceCorrection(null)); + erf.updateForecast(); + long numRups = 0l; + long numPtRups = 0l; + long numPtRupsWithCorr = 0l; + for (ProbEqkSource source : erf) { + numRups += source.getNumRuptures(); + for (ProbEqkRupture rup : source) { + RuptureSurface surf = rup.getRuptureSurface(); + if (surf instanceof PointSurface) { + numPtRups++; + PointSurface ptSurf = (PointSurface)surf; + if (ptSurf instanceof PointSurface.DistanceCorrectable || ptSurf instanceof PointSurface.DistanceCorrectionAttached) + numPtRupsWithCorr++; + } + } + } + System.out.println("Have "+numRups+" total rups"); + System.out.println("\t"+numPtRups+" are point sources"); + System.out.println("\t"+numPtRupsWithCorr+" are point sources w/ dist corrs"); + } + + private static void test4() throws IOException { +// File storeDir = MeanUCERF3.getStoreDir(); +// File solFile = MeanUCERF3.checkDownload( +// new File(storeDir, "cached_FM3_1_dep100.0_depMean_rakeMean.zip")).join(); + File solFile = new File("/home/kevin/OpenSHA/fss_inversions/2021_11_30-u3_branches-orig_calcs-5h/results_FM3_1_branch_averaged.zip"); + FaultSystemSolution sol = FaultSystemSolution.load(solFile); + FaultSystemRupSet rupSet = sol.getRupSet(); + RupMFDsModule mfds = rupSet.getModule(RupMFDsModule.class); + ModSectMinMags modMags = rupSet.getModule(ModSectMinMags.class); + System.out.println("Sol type: "+sol.getClass()); + System.out.println("Rup set type: "+rupSet.getClass()); + System.out.println("Inv type? "+(rupSet instanceof InversionFaultSystemRupSet)); + if (modMags == null) { + System.out.println("No mod mags"); + } else { + System.out.println("Mod mags type: "+modMags.getClass()+"; name="+modMags.getName()); + } + + System.out.println("Has MFDs? "+(mfds != null)); + for (int s=0; s 0) { + totRate += pt.getY(); + rupMinMag = Math.min(rupMinMag, pt.getX()); + } + } + minMag = Math.min(minMag, rupMinMag); + if (modMags == null || !modMags.isRupBelowSectMinMag(rupIndex)) + minIncludedMag = Math.min(minIncludedMag, rupMinMag); + } + if (minMag < 5.9d) { +// if (minMag < 6d) { + FaultSection sect = rupSet.getFaultSectionData(s); + String prefix = s+". "+sect.getSectionName()+" (parent="+sect.getParentSectionId()+"):"; + if (modMags == null) + System.out.println(prefix+"\tminMag="+(float)minMag+"\trate="+(float)totRate+"\tRI="+(float)(1d/totRate)); + else + System.out.println(prefix+"\tminMag="+(float)minMag+"\tminIncludedMag="+(float)minIncludedMag + +"\trate="+(float)totRate+"\tRI="+(float)(1d/totRate)); + } + } + } + + private static void test5() throws IOException { + File treeFile = new File("/home/kevin/OpenSHA/fss_inversions/2026_07_17-nshm27-AMSAM-20000samples-mcs/logic_tree_analysis.json"); + LogicTree.read(treeFile); + } + /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { try { - test2(); + test5(); } catch (Throwable t) { t.printStackTrace(); System.exit(1); diff --git a/src/main/java/scratch/kevin/HazardMapScriptCreator.java b/src/main/java/scratch/kevin/HazardMapScriptCreator.java index 61547cbc..31b02c07 100644 --- a/src/main/java/scratch/kevin/HazardMapScriptCreator.java +++ b/src/main/java/scratch/kevin/HazardMapScriptCreator.java @@ -153,7 +153,7 @@ public static void main(String[] args) throws IOException { List script = mpj.buildScript(MPJHazardCurveDriver.class.getName(), cliArgs); USC_HPCC_ScriptWriter writer = new USC_HPCC_ScriptWriter(); - script = writer.buildScript(script, mins, nodes, ppn, queue); + script = writer.buildScript(script, mins, nodes, ppn, -1, queue); File pbsFile = new File(localJobDir, jobName+".pbs"); System.out.println("Writing "+pbsFile.getAbsolutePath()); diff --git a/src/main/java/scratch/kevin/MPJ_HPC_DebugScriptGen.java b/src/main/java/scratch/kevin/MPJ_HPC_DebugScriptGen.java index 21756ce4..e6832e62 100644 --- a/src/main/java/scratch/kevin/MPJ_HPC_DebugScriptGen.java +++ b/src/main/java/scratch/kevin/MPJ_HPC_DebugScriptGen.java @@ -69,7 +69,7 @@ public static void main(String[] args) throws IOException { script = fmpjWrite.buildScript(className, myArgs); else script = mpjWrite.buildScript(className, myArgs); - script = pbsWrite.buildScript(script, mins, nodes, ppn, queue); + script = pbsWrite.buildScript(script, mins, nodes, ppn, -1, queue); pbsWrite.writeScript(new File(localDir, prefix+".pbs"), script); } diff --git a/src/main/java/scratch/kevin/MorganSTREC_ScriptGen.java b/src/main/java/scratch/kevin/MorganSTREC_ScriptGen.java index 801a17a5..c27ec4b7 100644 --- a/src/main/java/scratch/kevin/MorganSTREC_ScriptGen.java +++ b/src/main/java/scratch/kevin/MorganSTREC_ScriptGen.java @@ -69,7 +69,7 @@ public static void main(String[] args) throws IOException { runNum = "0"+runNum; File opbsFile = new File(writeDir, "job"+runNum+".pbs"); - pbsWrite.writeScript(opbsFile, script, mins, nodes, ppn, queue); + pbsWrite.writeScript(opbsFile, script, mins, nodes, ppn, -1, queue); } for (int i=0; i script = mpjWrite.buildScript(MPJ_BBP_RupGenSim.class.getName(), argz); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, "bbp_parallel.pbs"), script); } diff --git a/src/main/java/scratch/kevin/bbp/ShakeMoviePlotter.java b/src/main/java/scratch/kevin/bbp/ShakeMoviePlotter.java index 6c16fbf6..3d986873 100644 --- a/src/main/java/scratch/kevin/bbp/ShakeMoviePlotter.java +++ b/src/main/java/scratch/kevin/bbp/ShakeMoviePlotter.java @@ -342,10 +342,6 @@ else if (xRange.getLength() > 0.75) } - private static Color getWithAlpha(Color c, int alpha) { - return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); - } - private static DecimalFormat timeDF = new DecimalFormat("0.0#"); public static void main(String[] args) throws ZipException, IOException, DocumentException { diff --git a/src/main/java/scratch/kevin/bbp/SpectraPlotter.java b/src/main/java/scratch/kevin/bbp/SpectraPlotter.java index e8b6b730..b1f6d217 100644 --- a/src/main/java/scratch/kevin/bbp/SpectraPlotter.java +++ b/src/main/java/scratch/kevin/bbp/SpectraPlotter.java @@ -19,6 +19,7 @@ import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.data.Range; import org.jfree.chart.ui.TextAnchor; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.calc.FractileCurveCalculator; import org.opensha.commons.data.Site; import org.opensha.commons.data.function.AbstractXY_DataSet; @@ -885,7 +886,7 @@ public static void plotRotDRatioPeriodDependence(List rds, Li rangeFuncs.add(rangeFunc); rangeChars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(c.getRed(), c.getGreen(), c.getBlue(), 50))); + ColorUtils.transparent(c, 50))); meanFunc.setName((float)period+"s"); funcs.add(meanFunc); @@ -1033,7 +1034,7 @@ public static void plotRotDRatioScatter(List rds, List> levels = new ArrayList<>(); + levels.add(LogicTreeLevel.forEnum(DefModelEnum.class, "Deformation Model", "Deformation Model")); + levels.add(LogicTreeLevel.forEnum(ScaleEnum.class, "Scaling Relationship", "Scaling Relationship")); + levels.add(new ContinuousDistributionSampledLevel( + "GR b-value", "GR b-value", UniformContinuousDistribution.of(0d, 1d), "Sample ", "Sample", "Sample")); + levels.add(new ContinuousDistributionSampledLevel( + "Off-fault Mmax", "Off-fault Mmax", TruncatedNormalDistribution.of(7.6, 0.2, 7.15, 8.05), -1, "Sample ", "Sample", "Sample")); + + SamplingMethod[] sms = { + SamplingMethod.MONTE_CARLO, + SamplingMethod.LATIN_HYPERCUBE, + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE, + SamplingMethod.SOBOL, + SamplingMethod.OWEN_SCRAMBLED_SOBOL, + }; + +// long seed = 123456789l; + long seed = 12345678l; + + // put olive last (yuck) + Color[] tab10 = { + Colors.tab_blue, + Colors.tab_orange, + Colors.tab_green, + Colors.tab_red, + Colors.tab_purple, + Colors.tab_brown, + Colors.tab_pink, + Colors.tab_aqua, + Colors.tab_olive, + }; +// CPT tab10cpt = GMT_CPT_Files.CATEGORICAL_TAB10_NOGRAY.instance(); +// Color[] tab10 = new Color[tab10cpt.size()]; +// for (int i=0; i nodeColors = new HashMap<>(); + int colorI = 0; + for (LogicTreeLevel level : levels) { + if (!(level instanceof ContinuousDistributionSampledLevel)) { + for (LogicTreeNode node : level.getNodes()) + nodeColors.put(node, tab10[colorI++ % tab10.length]); + } + } + + Color[] distColors = new Color[levels.size()]; + CPT[] distCPTs = new CPT[levels.size()]; + boolean useDistCPTforPDF = true; + + for (int l=0; l tree = LogicTree.buildSampled(levels, samples, seed, sm); + if (sm == SamplingMethod.MONTE_CARLO) { + // write tree plot + LogicTreeFigureWriter tfw = new LogicTreeFigureWriter(tree, false, true); + tfw.write(outputDir, "logic_tree", true, true); + } + + for (int l=0; l level = levels.get(l); + + String samplePrefix = level.getFilePrefix()+"_samples_"+sm.name(); + + if (level instanceof ContinuousDistributionSampledLevel) { + ContinuousDistributionSampledLevel distLevel = (ContinuousDistributionSampledLevel)level; + ContinuousDistribution dist = distLevel.getDistribution(); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + Range xRange = new Range(dist.getSupportLowerBound(), dist.getSupportUpperBound()); + EvenlyDiscretizedFunc densityFunc = new EvenlyDiscretizedFunc(xRange.getLowerBound(), xRange.getUpperBound(), 1000); + for (int i=0; i> nodes = distLevel.getNodes(); + + double maxY; + if (samples < 200) { + maxY = Math.max(2d, densityFunc.getMaxY()*1.1); + + funcs.add(densityFunc); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 0.5f, Color.GRAY)); + + if (sm == SamplingMethod.LATIN_HYPERCUBE || sm == SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE) { + // draw ticks + double tickDelta = maxY*0.05; + EvenlyDiscretizedFunc binEdges = new EvenlyDiscretizedFunc( + 0d, 1d, nodes.size()+1); + PlotCurveCharacterstics tickChar = new PlotCurveCharacterstics(PlotLineType.SOLID, 0.7f, Color.BLACK); + for (int i=0; i node : nodes) { + DefaultXY_DataSet xy = new DefaultXY_DataSet(); + double x = node.getValue(); + double y = dist.density(x); + xy.set(x, y); + + Color color = useDistCPTforPDF ? distCPTs[l].getColor(dist.cumulativeProbability(x)) : distColors[l]; + + funcs.add(xy); + chars.add(new PlotCurveCharacterstics(PlotSymbol.FILLED_CIRCLE, symbolWidth, color)); + + funcs.add(xy); + chars.add(new PlotCurveCharacterstics(PlotSymbol.CIRCLE, symbolWidth, distColors[l].darker().darker())); + } + } else { + maxY = Math.max(2d, densityFunc.getMaxY()*1.5); + double length = dist.getSupportUpperBound() - dist.getSupportLowerBound(); + int bins = 100; + double binWidth = length / bins; + EvenlyDiscretizedFunc hist = new EvenlyDiscretizedFunc(dist.getSupportLowerBound()+0.5*binWidth, bins, binWidth); + for (SimpleValuedNode node : nodes) + hist.add(hist.getClosestXIndex(node.getValue()), 1d); + + hist.scale(1d/(samples*binWidth)); + + funcs.add(hist); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, distColors[l])); + + funcs.add(densityFunc); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, Color.BLACK)); + } + + PlotSpec plot = new PlotSpec(funcs, chars, sm.getName(), level.getName(), "PDF Density"); + + Range yRange = new Range(0d, maxY); + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + gp.drawGraphPanel(plot, false, false, xRange, yRange); + PlotUtils.setYTick(gp, 0.5); + + PlotUtils.writePrintPlots(outputDir, samplePrefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH*0.5, 3d, dpi, true, true, false); + } else { + List nodes = level.getNodes(); + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + List anns = new ArrayList<>(); + + int maxCount = 0; + + Font nameFont = new Font(Font.SANS_SERIF, Font.BOLD, 10); + Font countFont = new Font(Font.SANS_SERIF, Font.BOLD, 10); + Font subNameFont = new Font(Font.SANS_SERIF, Font.BOLD, 8); + Font subCountFont = new Font(Font.SANS_SERIF, Font.BOLD, 8); + + double offset = samples*0.01; + + for (int i=0; i branch : tree) + if (branch.getValue(l).equals(node)) + count++; + maxCount = Integer.max(count, maxCount); + EvenlyDiscretizedFunc hist = new EvenlyDiscretizedFunc(0.5, nodes.size(), 1d); + hist.set(i, (double)count); + + funcs.add(hist); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, nodeColors.get(node))); + + XYTextAnnotation ann = new XYTextAnnotation(node.getShortName(), hist.getX(i), count+offset); + ann.setFont(nameFont); + ann.setTextAnchor(TextAnchor.BASELINE_CENTER); + anns.add(ann); + + ann = new XYTextAnnotation(count+"", hist.getX(i), offset); + ann.setFont(countFont); + ann.setTextAnchor(TextAnchor.BASELINE_CENTER); + anns.add(ann); + } + + PlotSpec plot = new PlotSpec(funcs, chars, sm.getName(), level.getName(), "Sample Count"); + plot.setPlotAnnotations(anns); + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + double maxY = switch (nodes.size()){ + case 2: + yield 0.65*samples; + case 3: + yield 0.45*samples; + default: + yield maxCount*1.2d; + }; + gp.drawGraphPanel(plot, false, false, new Range(0d, nodes.size()), new Range(0d, maxY)); + PlotUtils.setAxisVisible(gp, false, true); + PlotUtils.setGridLinesVisible(gp, false, true); + + PlotUtils.writePrintPlots(outputDir, samplePrefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH*0.5, 3d, dpi, true, true, false); + + for (int m=0; m oLevel = levels.get(m); + if (l == m || oLevel instanceof ContinuousDistributionSampledLevel) + continue; + + String pairPrefix = level.getFilePrefix()+"_and_"+oLevel.getFilePrefix()+"_samples_"+sm.name(); + + funcs.clear(); + chars.clear(); + anns.clear(); + + List oNodes = levels.get(m).getNodes(); + + for (int i=0; i branch : tree) + if (branch.getValue(l).equals(node) && branch.getValue(m).equals(oNode)) + subCount++; + + int countStart = count; + int countEnd = count+subCount; + EvenlyDiscretizedFunc hist = new EvenlyDiscretizedFunc(0.5, nodes.size(), 1d); + hist.set(i, (double)countEnd); + + funcs.add(hist); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, nodeColors.get(oNode))); + + XYTextAnnotation ann = new XYTextAnnotation(oNode.getShortName(), x, countEnd); + ann.setFont(subNameFont); + ann.setTextAnchor(TextAnchor.TOP_CENTER); + anns.add(ann); + + ann = new XYTextAnnotation(subCount+"", x, countStart+0.5*offset); + ann.setFont(subCountFont); + ann.setTextAnchor(TextAnchor.BASELINE_CENTER); + anns.add(ann); + + count = countEnd; + } + + XYTextAnnotation ann = new XYTextAnnotation(node.getShortName(), x, count+offset); + ann.setFont(nameFont); + ann.setTextAnchor(TextAnchor.BASELINE_CENTER); + anns.add(ann); + } + + plot = new PlotSpec(funcs, chars, sm.getName(), level.getName(), "Sample Count"); + plot.setPlotAnnotations(anns); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + gp.drawGraphPanel(plot, false, false, new Range(0d, nodes.size()), new Range(0d, maxY)); + PlotUtils.setAxisVisible(gp, false, true); + PlotUtils.setGridLinesVisible(gp, false, true); + + PlotUtils.writePrintPlots(outputDir, pairPrefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH*0.5, 3d, dpi, true, true, false); + } + } + } + + if (samples <= 32) { + // build branch vector plot + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + List anns = new ArrayList<>(); + + BasicStroke outlineStroke = new BasicStroke(1f); +// Font indexOrigFont = new Font(Font.SANS_SERIF, Font.PLAIN, 10); +// Font indexSwappedFont = new Font(Font.SANS_SERIF, Font.BOLD, 10); + + + Font indexOrigFont = null; + Font indexSwappedFont = new Font(Font.SANS_SERIF, Font.PLAIN, 10); + + List origBranchIndexes = null; + if (sm ==SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE) { + // do the optimization manually + LogicTreePointSetMapper mapper = new LogicTreePointSetMapper<>(levels); + PointSet pointSet = SamplingMethod.LATIN_HYPERCUBE.prepare(samples, mapper.getSamplingDimensions(), seed); + + LogicTree tree2 = LogicTree.buildSampled(levels, samples, seed, SamplingMethod.LATIN_HYPERCUBE); + + PermutedPointSet permuted = PermutedPointSet.independentDimensions(pointSet); + long iterations = Integer.max(100000, samples*100); + PointSetObjective objective = ProjectionDiscrepancyScorer + .quantized(SamplingMethod.PAIRWISE_CONTINUOUS_BINS).objective(); + SwapSession session = objective.prepare(permuted); + System.out.println("Pairwise-optimizing sample of size "+pointSet.size()+" with "+iterations+" iterations"); + System.out.println("\tInitial objective:\t"+(float)session.getCurrentValue()); + PointSetHillClimber.optimize(session, iterations, new Random(new Random(seed).nextLong())); + System.out.println("\tDONE; final objective:\t"+(float)session.getCurrentValue()); + +// permuted.get(dpi, colorI) + +// origBranchIndexes = iter.getOriginalBranchIndexes(); + origBranchIndexes = new ArrayList<>(samples); + for (int n=0; n branch = tree.getBranch(n); + + double x0 = n-0.4; + double x1 = n+0.4; + + for (int l=0; l level = levels.get(l); + LogicTreeNode node = branch.getValue(l); + + Color color; + if (level instanceof ContinuousDistributionSampledLevel) { + ContinuousDistribution dist = ((ContinuousDistributionSampledLevel)level).getDistribution(); + double value = ((ValuedLogicTreeNode)node).getValue(); + color = distCPTs[l].getColor(dist.cumulativeProbability(value)); + } else { + color = nodeColors.get(node); + } + + double y1 = (levels.size()-l); + double y0 = y1-1; + double y = y0+0.5; +// double y0 = l; +// double y1 = l+1; +// double y = l+0.5; + + if (origBranchIndexes == null) { + anns.add(new XYBoxAnnotation(x0, y0, x1, y1, outlineStroke, Color.BLACK, color)); + } else { + int index = origBranchIndexes.get(n)[l]; + XYTextAnnotation indexAnn = new XYTextAnnotation(index+"", x, y); + indexAnn.setTextAnchor(TextAnchor.CENTER); + if (index == n) { + if (indexOrigFont != null) { + indexAnn.setFont(indexOrigFont); + anns.add(indexAnn); + } + anns.add(new XYBoxAnnotation(x0, y0, x1, y1, outlineStroke, Color.BLACK, + ColorUtils.transparent(color, 60))); + } else { + anns.add(new XYBoxAnnotation(x0, y0, x1, y1, outlineStroke, Color.BLACK, color)); + indexAnn.setFont(indexSwappedFont); + anns.add(indexAnn); + } + } + + + } + } + + PlotSpec plot = new PlotSpec(funcs, chars, sm.getName(), "Branch Index", " "); + plot.setPlotAnnotations(anns); + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + gp.drawGraphPanel(plot, false, false, new Range(-0.5d, samples-0.5), new Range(-0.05d, levels.size()+0.05)); + PlotUtils.setAxisVisible(gp, true, false); + PlotUtils.setGridLinesVisible(gp, false, false); + + PlotUtils.writePrintPlots(outputDir, "branches_"+sm.name(), gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH, 3d, dpi, true, true, false); + } + } + } + + private enum DefModelEnum implements LogicTreeNode.FixedWeightNode { + GEOLOGIC("Geologic", 0.5), + GEODETIC("Geodetic", 0.5); + + private String name; + private double weight; + + private DefModelEnum(String name, double weight) { + this.name = name; + this.weight = weight; + } + + @Override + public String getFilePrefix() { + return name(); + } + + @Override + public String getShortName() { + return name; + } + + @Override + public String getName() { + return name; + } + + @Override + public double getNodeWeight() { + return weight; + } + } + + private enum ScaleEnum implements LogicTreeNode.FixedWeightNode { + LOGA_4p1("LogA+4.1", 1d/4d), + LOGA_4p2("LogA+4.2", 1d/4d), + LOGA_4p3("LogA+4.3", 1d/4d), + WIDTH_LIMITED("Wdth-Lmtd", 1d/4d); + + private String name; + private double weight; + + private ScaleEnum(String name, double weight) { + this.name = name; + this.weight = weight; + } + + @Override + public String getFilePrefix() { + return name(); + } + + @Override + public String getShortName() { + return name; + } + + @Override + public String getName() { + return name; + } + + @Override + public double getNodeWeight() { + return weight; + } + } + +} diff --git a/src/main/java/scratch/kevin/miscFigures/CompoundAveDipTests.java b/src/main/java/scratch/kevin/miscFigures/CompoundAveDipTests.java new file mode 100644 index 00000000..9e7776f1 --- /dev/null +++ b/src/main/java/scratch/kevin/miscFigures/CompoundAveDipTests.java @@ -0,0 +1,86 @@ +package scratch.kevin.miscFigures; + +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.LocationUtils; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.ClusterRupture; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.FaultSubsectionCluster; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.Jump; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.util.RupCartoonGenerator; +import org.opensha.sha.faultSurface.CompoundSurface; +import org.opensha.sha.faultSurface.FaultSection; +import org.opensha.sha.faultSurface.FaultTrace; +import org.opensha.sha.faultSurface.GeoJSONFaultSection; +import org.opensha.sha.faultSurface.RuptureSurface; + +public class CompoundAveDipTests { + + public static void main(String[] args) throws IOException { + List sects = new ArrayList<>(); + HashMap flips = new HashMap<>(); + sects.add(new GeoJSONFaultSection.Builder(sects.size(), "Fault 1", + FaultTrace.of(new Location(0d, 0.48d), new Location(0d, 0d))) + .dip(60).lowerDepth(10).upperDepth(0).rake(0) + .build()); + flips.put(sects.get(sects.size()-1).getSectionId(), true); + sects.add(new GeoJSONFaultSection.Builder(sects.size(), "Fault 2", + FaultTrace.of(new Location(0d, 0.52d), new Location(0d, 1d))) + .dip(45).lowerDepth(10).upperDepth(0).rake(0) + .build()); + + List surfs = new ArrayList<>(); + for (GeoJSONFaultSection sect : sects) + surfs.add(sect.getFaultSurface(1d)); + + CompoundSurface.Simple surf = new CompoundSurface.Simple(surfs, sects); + + ClusterRupture cRup = null; + int subSectIndex = 0; + for (GeoJSONFaultSection sect : sects) { + double ddw = sect.getOrigDownDipWidth(); + List subSects = sect.getSubSectionsList(ddw/2d, subSectIndex); + if (flips.containsKey(sect.getSectionId())) { + subSects = new ArrayList<>(subSects); + Collections.reverse(subSects); + } + subSectIndex += subSects.size(); + if (cRup == null) { + cRup = new ClusterRupture(new FaultSubsectionCluster(subSects)); + } else { + FaultSubsectionCluster prev = cRup.clusters[cRup.clusters.length-1]; + FaultSection from = null; + FaultSection to = null; + double minDist = Double.POSITIVE_INFINITY; + for (FaultSection testFrom : prev.subSects) { + for (FaultSection testTo : subSects) { + double dist = Double.POSITIVE_INFINITY; + for (Location l1 : testFrom.getFaultTrace()) + for (Location l2 : testTo.getFaultTrace()) + dist = Math.min(dist, LocationUtils.horzDistanceFast(l2, l1)); + if (dist < minDist) { + minDist = dist; + from = testFrom; + to = testTo; + } + } + } + cRup = cRup.take(new Jump(from, prev, to, new FaultSubsectionCluster(subSects), 0)); + } + } + + DecimalFormat dipDF = new DecimalFormat("0"); + String title = "Oriented dip: "+dipDF.format(surf.getAveOrientedDip())+"; Average dip: "+dipDF.format(surf.getAveDip()); + + RupCartoonGenerator.plotRupture(new File("/tmp"), "compound_dip_example", cRup, title, false, false); + + + } + +} diff --git a/src/main/java/scratch/kevin/miscFigures/SCECStatewide.java b/src/main/java/scratch/kevin/miscFigures/SCECStatewide.java index cb8af376..c48cffba 100644 --- a/src/main/java/scratch/kevin/miscFigures/SCECStatewide.java +++ b/src/main/java/scratch/kevin/miscFigures/SCECStatewide.java @@ -24,6 +24,7 @@ import org.opensha.commons.gui.plot.PlotSymbol; import org.opensha.commons.gui.plot.PlotUtils; import org.opensha.commons.mapping.PoliticalBoundariesData; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.FaultUtils; import org.opensha.commons.util.Interpolate; import org.opensha.commons.util.cpt.CPT; @@ -221,7 +222,7 @@ else if (prob >= probCPT.getMaxValue()) color = Color.WHITE; } else { weight = (dist-minSaturateDist)/(maxPlotDist-minSaturateDist); - color = blend(Color.WHITE, color, weight); + color = ColorUtils.blend(color, Color.WHITE, weight); } // Preconditions.checkState(weight >= 0d && weight <= 1d, "Bad weight: %s", weight); // color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(255d*weight)); @@ -229,7 +230,7 @@ else if (prob >= probCPT.getMaxValue()) // int alpha = cpt.getColor((float)distScalar).getAlpha(); //// color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); // double weight = (double)alpha -// color = blend(scecRed, color, alpha) +// color = ColorUtils.blend(color, scecRed, alpha) } chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, (float)thickness, color)); } @@ -325,11 +326,4 @@ private static void writePlot(File outputDir, String prefix, HeadlessGraphPanel PlotUtils.writePlots(outputDir, prefix, gp, 1200, true, true, true, false); } - private static Color blend(Color c1, Color c2, double weight) { - float r = (float)((weight*c1.getRed() + (1d-weight)*c2.getRed())/255d); - float g = (float)((weight*c1.getGreen() + (1d-weight)*c2.getGreen())/255d); - float b = (float)((weight*c1.getBlue() + (1d-weight)*c2.getBlue())/255d); - return new Color(r, g, b); - } - } diff --git a/src/main/java/scratch/kevin/miscFigures/SimulatedAnnealingExampleAnimation.java b/src/main/java/scratch/kevin/miscFigures/SimulatedAnnealingExampleAnimation.java index d3972ede..ae4afd5b 100644 --- a/src/main/java/scratch/kevin/miscFigures/SimulatedAnnealingExampleAnimation.java +++ b/src/main/java/scratch/kevin/miscFigures/SimulatedAnnealingExampleAnimation.java @@ -33,6 +33,7 @@ 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.util.ColorUtils; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; import org.opensha.sha.earthquake.faultSysSolution.RupSetScalingRelationship; @@ -225,7 +226,7 @@ else if (y > 0) private static Color TARGET_COLOR = Color.GRAY; private static Color SOL_COLOR = Color.BLACK; private static float LINE_THICKNESS = 4f; - private static Color UNCERT_COLOR = new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 100); + private static Color UNCERT_COLOR = ColorUtils.transparent(Color.CYAN, 100); private static boolean PLOT_UNCERT = false; private static PlotSpec buildSlipPlot(FaultSystemRupSet rupSet, diff --git a/src/main/java/scratch/kevin/miscFigures/U3vsPopulationMap.java b/src/main/java/scratch/kevin/miscFigures/U3vsPopulationMap.java index 5676f809..9f301c83 100644 --- a/src/main/java/scratch/kevin/miscFigures/U3vsPopulationMap.java +++ b/src/main/java/scratch/kevin/miscFigures/U3vsPopulationMap.java @@ -21,6 +21,7 @@ import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; import org.opensha.commons.mapping.gmt.elements.PSXYPolygon; import org.opensha.commons.mapping.gmt.elements.TopographicSlopeFile; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.DataUtils.MinMaxAveTracker; import org.opensha.commons.util.cpt.CPT; import org.opensha.commons.util.cpt.CPTVal; @@ -152,8 +153,8 @@ public static void main(String[] args) throws IOException, GMT_MapException { // for (int i=0; i script = mpjWrite.buildScript(MPJ_LogicTreeInversionRunner.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "ba_regen.slurm"), script, mins, nodes, remoteToalThreads, queue); + pbsWrite.writeScript(new File(localDir, "ba_regen.slurm"), script, mins, nodes, remoteToalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/nshm23/BValSweepHazardComparison.java b/src/main/java/scratch/kevin/nshm23/BValSweepHazardComparison.java index 0203593a..7d3ba646 100644 --- a/src/main/java/scratch/kevin/nshm23/BValSweepHazardComparison.java +++ b/src/main/java/scratch/kevin/nshm23/BValSweepHazardComparison.java @@ -14,6 +14,7 @@ import org.opensha.commons.geo.GriddedRegion; import org.opensha.commons.geo.Region; import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.MarkdownUtils; import org.opensha.commons.util.cpt.CPT; import org.opensha.commons.util.cpt.CPTVal; @@ -129,8 +130,8 @@ public static void main(String[] args) throws IOException { bValCPT.setBelowMinColor(bValCPT.getMinColor().darker()); bValCPT.setAboveMaxColor(bValCPT.getMaxColor().darker()); for (CPTVal c : bValCPT) { - c.minColor = saturate(c.minColor); - c.maxColor = saturate(c.maxColor); + c.minColor = ColorUtils.saturate(c.minColor, 1); + c.maxColor = ColorUtils.saturate(c.maxColor, 1); } bValCPT.add(0, new CPTVal((float)(minB-0.02), bValCPT.getBelowMinColor(), (float)minB, bValCPT.getBelowMinColor())); bValCPT.add(new CPTVal((float)maxB, bValCPT.getAboveMaxColor(), (float)(maxB+0.02), bValCPT.getAboveMaxColor())); @@ -227,20 +228,4 @@ private static SolHazardMapCalc getCalcCurves(File hazardDir, FaultSystemSolutio return calc; } - private static final int saturation_steps = 1; - - private static Color saturate(Color c) { - int r = c.getRed(); - int g = c.getGreen(); - int b = c.getBlue(); - - for (int i=0; i classpath = new ArrayList<>(); - classpath.add(new File(dirPath+"/opensha-dev-all.jar")); + classpath.add(new File(dirPath+"/opensha-all.jar")); parallelMPJWrite.setClasspath(classpath); List singleClasspath = new ArrayList<>(classpath); @@ -336,7 +363,7 @@ else if (!supersampleQuick) System.out.println("Writing "+jobFile.getAbsolutePath()); - pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, queue); + pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/nshm23/FaultSlipRateInvestigations.java b/src/main/java/scratch/kevin/nshm23/FaultSlipRateInvestigations.java index 03961d5e..1a5365a5 100644 --- a/src/main/java/scratch/kevin/nshm23/FaultSlipRateInvestigations.java +++ b/src/main/java/scratch/kevin/nshm23/FaultSlipRateInvestigations.java @@ -18,8 +18,11 @@ public static void main(String[] args) throws IOException { NSHM23_FaultModels fm = NSHM23_FaultModels.WUS_FM_v3; FaultModels u3FM = FaultModels.FM3_1; - int nshm23_id = FaultSectionUtils.findSectionID(fm.getFaultSections(), "Silver", "Creek"); - int u3_id = FaultSectionUtils.findSectionID(u3FM.getFaultSections(), "Silver", "Creek"); +// int nshm23_id = FaultSectionUtils.findSectionID(fm.getFaultSections(), "Silver", "Creek"); +// int u3_id = FaultSectionUtils.findSectionID(u3FM.getFaultSections(), "Silver", "Creek"); + + int nshm23_id = FaultSectionUtils.findSectionID(fm.getFaultSections(), "Rose", "Canyon"); + int u3_id = FaultSectionUtils.findSectionID(u3FM.getFaultSections(), "Rose", "Canyon"); double u3Avg = avgSlipRate(DeformationModels.MEAN_UCERF3.build(u3FM, DeformationModels.MEAN_UCERF3, null), u3_id); NSHM23_DeformationModels[] dms = NSHM23_DeformationModels.values(); diff --git a/src/main/java/scratch/kevin/nshm23/GMM_LogicTreeBranchAttach.java b/src/main/java/scratch/kevin/nshm23/GMM_LogicTreeBranchAttach.java index 2a1018e0..65653c47 100644 --- a/src/main/java/scratch/kevin/nshm23/GMM_LogicTreeBranchAttach.java +++ b/src/main/java/scratch/kevin/nshm23/GMM_LogicTreeBranchAttach.java @@ -56,7 +56,7 @@ public static void main(String[] args) throws IOException { LogicTree origTree = slt.getLogicTree(); if (samples > 0) - origTree = origTree.sample(samples, true, new Random((long)origTree.size()*(long)samples)); + origTree = origTree.sample(samples, true, (long)origTree.size()*(long)samples); FileBuilder builder = new SolutionLogicTree.FileBuilder(slt.getProcessor(), resultsModFile); @@ -119,7 +119,7 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) int nodeRounds = (int)Math.ceil((double)finalTree.getLogicTree().size()/(double)(nodes)); int mins = minsEach*nodeRounds + 60; nodes = Integer.min(40, nodes); - pbsWrite.writeScript(new File(destDir, "batch_hazard.slurm"), script, mins, nodes, remoteToalThreads, queue); + pbsWrite.writeScript(new File(destDir, "batch_hazard.slurm"), script, mins, nodes, remoteToalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/nshm23/GridSourceGeneralVersionValidations.java b/src/main/java/scratch/kevin/nshm23/GridSourceGeneralVersionValidations.java new file mode 100644 index 00000000..bd1ec00e --- /dev/null +++ b/src/main/java/scratch/kevin/nshm23/GridSourceGeneralVersionValidations.java @@ -0,0 +1,374 @@ +package scratch.kevin.nshm23; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Supplier; + +import org.apache.commons.math3.util.Precision; +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.util.modules.AverageableModule.AveragingAccumulator; +import org.opensha.commons.util.modules.ModuleContainer; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.modules.FaultGridAssociations; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList.GriddedRupture; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceProvider; +import org.opensha.sha.earthquake.faultSysSolution.modules.SolutionLogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.NSHM23_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_LogicTreeBranch; +import org.opensha.sha.magdist.IncrementalMagFreqDist; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; + +public class GridSourceGeneralVersionValidations { + + public static void main(String[] args) throws IOException { + ModuleContainer.VERBOSE_DEFAULT = false; + + SolutionLogicTree slt = SolutionLogicTree.load(new File("/home/kevin/OpenSHA/nshm23/batch_inversions/" + + "2024_02_02-nshm23_branches-WUS_FM_v3/results.zip")); + LogicTree faultTree = slt.getLogicTree(); + LogicTree gridTree = LogicTree.buildExhaustive(NSHM23_LogicTreeBranch.levelsOffFault, true); + int numTestBranches = 2; + AveragingAccumulator origListAvg = null; + AveragingAccumulator newListAvg = null; + boolean convertToPrecomputed = true; + boolean averageWithPrev = true; + +// final int threads = 1; + final int threads = 16; + ExecutorService exec = threads > 1 ? Executors.newFixedThreadPool(threads) : Executors.newSingleThreadExecutor(); + + NSHM23_InvConfigFactory factory = new NSHM23_InvConfigFactory(); + for (int i=0; i faultBranch = faultTree.getBranch(i); + double faultWeight = faultBranch.getBranchWeight(); + System.out.println("Processing branch "+i+": "+faultBranch); + FaultSystemSolution sol = slt.forBranch(faultBranch); + + factory.preGridBuildHook(sol, faultBranch); + + final int branchIndex = i; + + List> futures = new ArrayList<>(gridTree.size()); + for (int g=0; g gridBranch = gridTree.getBranch(g); + Supplier supplier = () -> { + try { + if (threads < 2) + System.out.println("Building original for "+branchIndex+"-"+gridBranchIndex+": "+gridBranch); + GridSourceList origGridList = factory.buildGridSourceProvider(sol, gridBranch); + if (threads < 2) + System.out.println("Building updated for "+branchIndex+"-"+gridBranchIndex+": "+gridBranch); + GridSourceList modGridList = NSHM23_InvConfigFactory.buildUpdatedGridSourceProv(sol, gridBranch); + System.out.println("Done building for "+branchIndex+"-"+gridBranchIndex+": "+gridBranch); + if (convertToPrecomputed && origGridList instanceof GridSourceList.DynamicallyBuilt) { + // do the conversion + EnumMap>> trtRupLists = new EnumMap<>(TectonicRegionType.class); + for (TectonicRegionType trt : origGridList.getTectonicRegionTypes()) { + List> rupLists = new ArrayList<>(); + trtRupLists.put(trt, rupLists); + for (int gridIndex=0; gridIndex origSubAvg = null; + AveragingAccumulator modSubAvg = null; + + AveragingAccumulator origPrevAvg = null; + AveragingAccumulator modPrevAvg = null; + + for (int b=0; b gridBranch = gridTree.getBranch(b); + double gridWeight = gridBranch.getBranchWeight(); + GridSourceList[] provs = futures.get(b).join(); + futures.set(b, null); + GridSourceList origProv = provs[0]; + GridSourceList modList = provs[1]; + + System.out.println("Built for "+b+"/"+gridTree.size()+" "+gridBranch+", validating..."); + validate(origProv, modList, false); + + if (origSubAvg == null) + origSubAvg = origProv.averagingAccumulator(); + origSubAvg.process(origProv, gridWeight); + if (modSubAvg == null) + modSubAvg = modList.averagingAccumulator(); + modSubAvg.process(modList, gridWeight); + + if (averageWithPrev) { + if (b > 0) { + System.out.println("Averaging with prior and comparing"); + origPrevAvg.process(origProv, gridWeight); + GridSourceList mfdWithPrev = (GridSourceList)origPrevAvg.getAverage(); + modPrevAvg.process(modList, gridWeight); + GridSourceList listWithPrev = (GridSourceList)modPrevAvg.getAverage(); + validate(mfdWithPrev, listWithPrev, false); + } + + if (b < gridTree.size()-1) { + origPrevAvg = origProv.averagingAccumulator(); + origPrevAvg.process(origProv, gridWeight); + modPrevAvg = modList.averagingAccumulator(); + modPrevAvg.process(modList, gridWeight); + } + } + } + + GridSourceList avgOfOrig = (GridSourceList)origSubAvg.getAverage(); + GridSourceList avgOfMod = (GridSourceList)modSubAvg.getAverage(); + System.out.println("Built all for "+faultBranch+", validating averages"); + validate(avgOfOrig, avgOfMod, false); + if (origListAvg == null) + origListAvg = avgOfOrig.averagingAccumulator(); + origListAvg.process(avgOfOrig, faultWeight); + if (newListAvg == null) + newListAvg = avgOfMod.averagingAccumulator(); + newListAvg.process(avgOfMod, faultWeight); + } + + exec.shutdown(); + + System.out.println("Built all, validating averages"); + GridSourceList avgOfOrig = (GridSourceList)origListAvg.getAverage(); + GridSourceList avgOfMod = (GridSourceList)newListAvg.getAverage(); + validate(avgOfOrig, avgOfMod, true); + + System.out.println("DONE"); + System.exit(0); + } + + private static void validate(GridSourceList origList, GridSourceList modList, boolean verbose) { + for (int i=0; i refMFD.size()) + refMFD = mfdSubSeis1; + if (refMFD != null) { + System.out.println("MFDs\tUnAssoc1\tUnAssoc2\tSubSeis1\tSubSeis2\tSumEach1\tSumEach2"); + for (int x=0; x x) + unassoc1 = mfdUnassoc1.getY(x); + double unassoc2 = 0d; + if (mfdUnassoc2 != null && mfdUnassoc2.size() > x) + unassoc2 = mfdUnassoc2.getY(x); + double subSeis1 = 0d; + if (mfdSubSeis1 != null && mfdSubSeis1.size() > x) + subSeis1 = mfdSubSeis1.getY(x); + double subSeis2 = 0d; + if (mfdSubSeis2 != null && mfdSubSeis2.size() > x) + subSeis2 = mfdSubSeis2.getY(x); + + System.out.println((float)refMFD.getX(x)+"\t"+(float)unassoc1+"\t"+(float)unassoc2 + +"\t"+(float)subSeis1+"\t"+(float)subSeis2 + +"\t"+(float)(unassoc1+subSeis1)+"\t"+(float)(unassoc2+subSeis2)); + } + } + System.out.flush(); + e.printStackTrace(); + System.exit(1); + } + + // now verify the ruptures themselves + try { + assertEquals(origList, modList, i); + } catch (Exception e) { + System.out.println("Failed for Grid Node "+i+"/"+modList.getNumLocations()); + System.out.flush(); + e.printStackTrace(); + System.exit(1); + } + } + System.out.println("Validated!"); + } + + private static List getSorted(List rups) { + if (rups == null) + return new ArrayList<>(); + List ret = new ArrayList<>(rups); + ret.sort(gridRupComp); + for (int i=ret.size(); --i>=0;) + if (ret.get(i).properties.magnitude < 2.5d) + ret.remove(i); + return ret; + } + + private static Comparator gridRupComp = new Comparator() { + + @Override + public int compare(GriddedRupture o1, GriddedRupture o2) { + // magnitude first + int cmp = Float.compare((float)o1.properties.magnitude, (float)o2.properties.magnitude); + if (cmp != 0) + return cmp; + // rake + cmp = Float.compare((float)o1.properties.rake, (float)o2.properties.rake); + if (cmp != 0) + return cmp; + return o1.compareTo(o2); + } + }; + + private static boolean mfdEquals(double v1, double v2) { + return equalsWithTol(v1, v2, 1e-3, 0d, 1e-10); + } + + private static boolean rateEquals(double v1, double v2) { + return equalsWithTol(v1, v2, 1e-3, 1e-10, 1e-15); + } + + private static boolean assocEquals(double v1, double v2) { + return equalsWithTol(v1, v2, 1e-3, 1e-6, 1e-10); + } + + private static boolean equalsWithTol(double v1, double v2, double relativeTol, double absTol, + double ignoreBelowThresh) { + if (v1 < ignoreBelowThresh && v2 < ignoreBelowThresh) + return true; + if (relativeTol > 0 && !Precision.equalsWithRelativeTolerance(v1, v2, relativeTol)) + return false; + if (absTol > 0 && !Precision.equals(v1, v2, absTol)) + return false; + return true; + } + + private static void assertEquals(IncrementalMagFreqDist mfd1, IncrementalMagFreqDist mfd2, int gridIndex, boolean assoc) { + if (mfd1 == null || mfd1.calcSumOfY_Vals() == 0d) { + Preconditions.checkState(mfd2 == null || mfd2.calcSumOfY_Vals() == 0d, + "GridIndex=%s, assoc=%s: MFDList is null, SourceList is %s", gridIndex, assoc, mfd2); + } else { + double delta = Math.max(mfd1.getDelta(), mfd2.getDelta()); + + for (int i=0; i= (float)0.5*delta) { + Preconditions.checkState(x1 > x2, "x1=%s, x2=%s, delta=%s", x1, x2, delta); + x2 = x1; + y2 = 0d; + } else { + y2 = mfd2.getY(i2); + } + Preconditions.checkState(mfdEquals(y1, y2) || y1 < 1e-10 && y2 < 1e-10, + "Mismatch at GridIndex=%s, assoc=%s:\tMFDProv[%s]=%s\tSourceList[%s]=%s", + gridIndex, assoc, (float)x1, (float)y1, (float)x2, (float)y2); + } + for (int i=mfd1.size(); i= (float)0.5*mfd2.getDelta()) { + Preconditions.checkState(x1 > x2); + x2 = x1; + y2 = 0d; + } else { + y2 = mfd1.getY(i2); + } + Preconditions.checkState(mfdEquals(y1, y2) || y1 < 1e-10 && y2 < 1e-10, + "Mismatch at GridIndex=%s, assoc=%s:\tMFDProv[%s]=%s\tSourceList[%s]=%s", + gridIndex, assoc, (float)x2, (float)y2, (float)x1, (float)y1); + } + } + } + + private static void assertEquals(GridSourceList gridList1, GridSourceList gridList2, int gridIndex) { + List origRups = getSorted(gridList1.getRuptures(null, gridIndex)); + List modRups = getSorted(gridList2.getRuptures(null, gridIndex)); + + double totRate1 = origRups.stream().mapToDouble(R->R.rate).sum(); + double totRate2 = modRups.stream().mapToDouble(R->R.rate).sum(); + + Preconditions.checkState(origRups.size() == modRups.size(), + "Original list has %s rups (totRate=%s), mod has %s (totRate=%s); gridIndex=%s", + origRups.size(), totRate1, modRups.size(), totRate2, gridIndex); + + for (int i=0; i buildForSolution(FaultSystemSolution refSol, Fault // do gridded for (int s=0; s branch = NSHM26_LogicTree.DEFAULT_GNMI_SUBDUCTION_INTERFACE; +// LogicTreeBranch branch = NSHM27_LogicTree.buildDefault( +// NSHM27_SeismicityRegions.GNMI, TectonicRegionType.SUBDUCTION_INTERFACE, false); +//// LogicTreeBranch branch = NSHM27_LogicTree.buildDefault( +//// NSHM27_SeismicityRegions.GNMI, TectonicRegionType.ACTIVE_SHALLOW, false); // dirName += "-gnmi"; - LogicTreeBranch branch = NSHM26_LogicTree.DEFAULT_AMSAM_SUBDUCTION_INTERFACE; + NSHM27_LogicTree.INTERFACE_B_HINGED_WEIGHT = 1d; + LogicTreeBranch branch = NSHM27_LogicTree.buildDefault( + NSHM27_SeismicityRegions.AMSAM, TectonicRegionType.SUBDUCTION_INTERFACE, false); dirName += "-amsam"; + + if (branch.hasValue(NSHM27_InterfaceFaultModels.class) ) { + branch.setValue(NSHM27_InterfaceObsSeisDMAdjustment.NONE); +// branch.setValue(NSHM27_InterfaceObsSeisDMAdjustment.AVERAGE); +// branch.setValue(NSHM27_InterfaceObsSeisDMAdjustment.SECTION_SPECIFIC); +// branch.setValue(NSHM27_InterfaceObsSeisDMAdjustment.EXTRAPOLATE); + branch.setValue(NSHM27_InterfaceMinSubSects.TWO); +// branch.setValue(NSHM27_InterfaceDeformationModels.Aggregated.LOW_COUPLING); + branch.setValue(NSHM27_InterfaceDeformationModels.Aggregated.PREF_COUPLING); +// branch.setValue(NSHM27_InterfaceDeformationModels.Aggregated.HIGH_COUPLING); +// branch.setValue(NSHM27_InterfaceCouplingDepthModels.DOUBLE_TAPER); + branch.setValue(NSHM27_InterfaceCouplingDepthModels.AVERAGE); + } else { + branch.setValue(NSHM27_CrustalDeformationModels.Aggregated.AVERAGE); + } +// branch.setValue(NSHM27_SeisRateModelBranch.AVERAGE); + branch.setValue(NSHM27_SeisRateModelBranch.PREFFERRED); - branch.setValue(PRVI25_SubductionBValues.B_1p0); +// writeGridProv = false; + writeGridProv = true; + +// double b = 1d; +//// double b = 0.5d; +//// double b = 0d; +// dirName += "-b"+(float)b; +// +//// // hinged b-value tests +//// FaultSystemRupSet tempRupSet = factory.buildRuptureSet(branch, threads); +//// new NSHM27_InvConfigFactory().getSolutionLogicTreeProcessor().processRupSet(tempRupSet, branch); +//// double b = NSHM27_InvConfigFactory.calcInterfaceHingedBValue(tempRupSet, branch); +//// dirName += "-hingedB"+(float)b; +// +// for (int l=0; l level = branch.getLevel(l); +// if (level instanceof SectionSupraSeisBValues.FixedValueLevel) { +// ((SectionSupraSeisBValues.FixedValueLevel)level).setValue(b); +// branch.setValue(level.getNodes().get(0)); +// } +// } + + plotLevel = PlotLevel.REVIEW; + +// branch.setValue(PRVI25_SubductionBValues.B_1p0); // branch.setValue(NSHM23_SegmentationModels.NONE); // branch.setValue(SupraSeisBValues.B_0p0); @@ -350,7 +411,7 @@ public static void main(String[] args) throws IOException { for (int i=0; i 0d) { + if (!(node instanceof RandomlyGeneratedNode) && node.getNodeWeight(branch) > 0d) { // only include its name if there are other alternatives (unless we have chosen a zero-weight option) boolean hasOthers = false; for (LogicTreeNode oNode : branch.getLevel(i).getNodes()) { @@ -378,16 +439,22 @@ public static void main(String[] args) throws IOException { System.out.println("Will save results in: "+outputDir.getAbsolutePath()); FaultSystemSolution solution; - if (writeRS) { - FaultSystemRupSet rupSet = factory.buildRuptureSet(branch, threads); - - Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); - - rupSet.write(new File(outputDir, "rupSet.zip")); - - solution = Inversions.run(rupSet, factory, branch, threads, null); - } else { - solution = Inversions.run(factory, branch, threads); + try { + if (writeRS) { + FaultSystemRupSet rupSet = factory.buildRuptureSet(branch, threads); + + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + + rupSet.write(new File(outputDir, "rupSet.zip")); + + solution = Inversions.run(rupSet, factory, branch, threads, null); + } else { + solution = Inversions.run(factory, branch, threads); + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + throw new IllegalStateException(); } Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); @@ -402,6 +469,13 @@ public static void main(String[] args) throws IOException { solution.write(new File(outputDir, "solution.zip")); + if (plotLevel != null) { + ReportPageGen reportGen = new ReportPageGen(solution.getRupSet(), solution, "Solution", + new File(outputDir, "report"), ReportPageGen.getDefaultSolutionPlots(plotLevel)); + reportGen.setReplot(true); + reportGen.generatePage(); + } + // System.out.println("Currently loaded modules:"); // IncrementalMagFreqDist target1 = null; // for (OpenSHA_Module module : solution.getRupSet().getModules(false)) { diff --git a/src/main/java/scratch/kevin/nshm23/InvFileDeadlockScriptWriter.java b/src/main/java/scratch/kevin/nshm23/InvFileDeadlockScriptWriter.java index c13dee46..05290cd4 100644 --- a/src/main/java/scratch/kevin/nshm23/InvFileDeadlockScriptWriter.java +++ b/src/main/java/scratch/kevin/nshm23/InvFileDeadlockScriptWriter.java @@ -159,7 +159,7 @@ public static void main(String[] args) throws IOException { argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(remoteInversionsPerBundle).build(); List script = mpjWrite.buildScript(MPJ_LogicTreeInversionRunner.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, localDir.getName()+".slurm"), script, minsEach, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, localDir.getName()+".slurm"), script, minsEach, nodes, remoteTotalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/nshm23/InversionDebugForSingleFault.java b/src/main/java/scratch/kevin/nshm23/InversionDebugForSingleFault.java index 106e5876..4bf40727 100644 --- a/src/main/java/scratch/kevin/nshm23/InversionDebugForSingleFault.java +++ b/src/main/java/scratch/kevin/nshm23/InversionDebugForSingleFault.java @@ -36,7 +36,7 @@ public static void main(String[] args) throws IOException { LogicTreeBranch branch = rupSet.requireModule(LogicTreeBranch.class); ClusterRuptures cRups = rupSet.requireModule(ClusterRuptures.class); - BinaryRuptureProbabilityCalc exclusion = NSHM23_InvConfigFactory.getExclusionModel( + BinaryRuptureProbabilityCalc exclusion = NSHM23_InvConfigFactory.buildExclusionModel( rupSet, branch, cRups); double rateSum = 0d; diff --git a/src/main/java/scratch/kevin/nshm23/LogicTreeBranchAverageWriter.java b/src/main/java/scratch/kevin/nshm23/LogicTreeBranchAverageWriter.java index 8b92eb46..fceb0ad6 100644 --- a/src/main/java/scratch/kevin/nshm23/LogicTreeBranchAverageWriter.java +++ b/src/main/java/scratch/kevin/nshm23/LogicTreeBranchAverageWriter.java @@ -61,6 +61,8 @@ public static void main(String[] args) throws IOException { HashSet> restrictBAClasses = null; LogicTreeNode[] restrictNodes = null; + LogicTree analysisTree = null; + List>> skipModules = null; int totThreads = FaultSysTools.defaultNumThreads(); @@ -152,7 +154,7 @@ public static void main(String[] args) throws IOException { HazardMapPlot.SPACING_DEFAULT = 0.2; } else { - CommandLine cmd = FaultSysTools.parseOptions(createOptions(), args, ReportPageGen.class); + CommandLine cmd = FaultSysTools.parseOptions(createOptions(), args, LogicTreeBranchAverageWriter.class); File inputFile = new File(cmd.getOptionValue("input-file")); Preconditions.checkArgument(inputFile.exists(), "Input file doesn't exist: %s", inputFile.getAbsolutePath()); @@ -171,6 +173,10 @@ public static void main(String[] args) throws IOException { slt = SolutionLogicTree.load(inputFile); } + if (cmd.hasOption("analysis-logic-tree")) { + analysisTree = LogicTree.read(new File(cmd.getOptionValue("analysis-logic-tree"))); + } + if (cmd.hasOption("branch-averaged-file")) fullBAFile = new File(cmd.getOptionValue("branch-averaged-file")); @@ -210,10 +216,13 @@ public static void main(String[] args) throws IOException { FaultSystemSolution fullBA = fullBAFile == null ? null : FaultSystemSolution.load(fullBAFile); boolean compWithLoaded = false; - LogicTree tree = slt.getLogicTree(); + LogicTree sltTree = slt.getLogicTree(); - if (restrictNodes != null && restrictNodes.length > 0) - tree = tree.matchingAll(restrictNodes); + if (restrictNodes != null && restrictNodes.length > 0) { + Preconditions.checkState(analysisTree == null); + sltTree = sltTree.matchingAll(restrictNodes); + } + LogicTree outTree = analysisTree == null ? sltTree : analysisTree; // tree = tree.matchingAll(SupraSeisBValues.B_0p0, DeformationModels.GEOLOGIC, // SubSectConstraintModels.TOT_NUCL_RATE, SegmentationModels.SHAW_R0_3); @@ -225,13 +234,13 @@ public static void main(String[] args) throws IOException { // compWithLoaded = true; Map, HashSet> levelNodes = new HashMap<>(); - List> levels = tree.getLevels(); + List> levels = outTree.getLevels(); for (LogicTreeLevel level : levels) levelNodes.put(level, new HashSet<>()); Map> nodeLevels = new HashMap<>(); - for (LogicTreeBranch branch : tree) { + for (LogicTreeBranch branch : outTree) { for (int i=0; i> moduleClass : skipModules) creator.skipModule(moduleClass); @@ -265,19 +274,33 @@ public static void main(String[] args) throws IOException { int maxTasks = Integer.min(asyncThreads * 2, asyncThreads + 2); ExecutorService exec = ExecutorUtils.newBlockingThreadPool(asyncThreads, maxTasks); - int count = 0; List> futures = new ArrayList<>(); - for (LogicTreeBranch branch : tree) { - System.out.println("Processing branch "+(count++)+"/"+tree.size()+": "+branch); - FaultSystemSolution sol = slt.forBranch(branch); + for (int index=0; index outBranch = outTree.getBranch(index); + System.out.println("Processing branch "+index+"/"+outTree.size()+": "+outBranch); + LogicTreeBranch inBranch; + if (sltTree == outTree || sltTree.size() == outTree.size()) { + inBranch = sltTree.getBranch(index); + } else { + // need to match + String fName = outBranch.buildFileName(); + inBranch = null; + for (LogicTreeBranch oBranch : sltTree) { + if (oBranch.buildFileName().equals(fName)) { + Preconditions.checkState(inBranch == null); + inBranch = oBranch; + } + } + } + FaultSystemSolution sol = slt.forBranch(inBranch); futures.add(exec.submit(new Runnable() { @Override public void run() { - for (LogicTreeNode node : branch) + for (LogicTreeNode node : outBranch) if (nodeBACreators.containsKey(node)) - nodeBACreators.get(node).addSolution(sol, branch); + nodeBACreators.get(node).addSolution(sol, outBranch); } })); } @@ -383,6 +406,8 @@ public static Options createOptions() { + "for comparison in reports"); ops.addOption("lt", "logic-tree", true, "Path to logic tree JSON file, required if a results directory is " + "supplied with --input-file"); + ops.addOption(null, "analysis-logic-tree", true, "Path to separate logic tree used for analysis that should be used " + + "for writing the results."); ops.addRequiredOption("od", "output-dir", true, "Path to output directory"); ops.addOption(FaultSysTools.threadsOption()); ops.addOption("at", "async-threads", true, "Maximum number of asynchronous load/process threads, lower to " diff --git a/src/main/java/scratch/kevin/nshm23/LogicTreePopulationHazardCurveCalc.java b/src/main/java/scratch/kevin/nshm23/LogicTreePopulationHazardCurveCalc.java index d93381c9..4f96bbf0 100644 --- a/src/main/java/scratch/kevin/nshm23/LogicTreePopulationHazardCurveCalc.java +++ b/src/main/java/scratch/kevin/nshm23/LogicTreePopulationHazardCurveCalc.java @@ -104,7 +104,7 @@ public static void main(String[] args) throws IOException { int exit = 0; try { mapper = new LogicTreeHazardCompare(solTree, tree, - hazardFile, rps, periods, spacing); + hazardFile, rps, periods, spacing, false, false); LogicTree compTree = null; if (compHazardFile != null) { @@ -120,7 +120,7 @@ public static void main(String[] args) throws IOException { // compTree.setWeightProvider(new BranchWeightProvider.CurrentWeights()); } comp = new LogicTreeHazardCompare(compSolTree, compTree, - compHazardFile, rps, periods, spacing); + compHazardFile, rps, periods, spacing, false, false); } Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); diff --git a/src/main/java/scratch/kevin/nshm23/MPJ_LogicTreeInversionRunnerScriptWriter.java b/src/main/java/scratch/kevin/nshm23/MPJ_LogicTreeInversionRunnerScriptWriter.java index 9555c7d6..dc8ece2d 100644 --- a/src/main/java/scratch/kevin/nshm23/MPJ_LogicTreeInversionRunnerScriptWriter.java +++ b/src/main/java/scratch/kevin/nshm23/MPJ_LogicTreeInversionRunnerScriptWriter.java @@ -32,8 +32,9 @@ import org.opensha.commons.logicTree.LogicTree; import org.opensha.commons.logicTree.LogicTreeBranch; import org.opensha.commons.logicTree.LogicTreeLevel; -import org.opensha.commons.logicTree.LogicTreeLevel.RandomlySampledLevel; -import org.opensha.commons.logicTree.LogicTreeNode.RandomlySampledNode; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomlyGeneratedLevel; +import org.opensha.commons.logicTree.LogicTreeNode.RandomlyGeneratedNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; import org.opensha.commons.logicTree.LogicTreeNode; import org.opensha.commons.util.ClassUtils; import org.opensha.sha.earthquake.faultSysSolution.RupSetFaultModel; @@ -83,6 +84,10 @@ import org.opensha.sha.earthquake.rupForecastImpl.nshm23.prior2018.NSHM18_FaultModels; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.prior2018.NSHM18_LogicTreeBranch; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.util.NSHM23_RegionLoader; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_MapRegions; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_LogicTree; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionFaultModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.util.PRVI25_RegionLoader; @@ -92,6 +97,7 @@ import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalFaultModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalRandomlySampledDeformationModelLevel; import org.opensha.sha.util.NEHRP_TestCity; +import org.opensha.sha.util.TectonicRegionType; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -125,6 +131,7 @@ public static void main(String[] args) throws IOException { Double forceHazardGridSpacing = null; GriddedRegion forceHazardReg = null; long randSeed = 12345678l; + boolean parallelBA = false; Double vs30 = null; Double sigmaTrunc = null; @@ -166,11 +173,13 @@ public static void main(String[] args) throws IOException { AttenRelRef[] gmpes = null; - List> individualRandomLevels = new ArrayList<>(); + List> individualRandomLevels = new ArrayList<>(); int samplingBranchCountMultiplier = 1; + LogicTree customTree = null; + LogicTree analysisTree = null; String dirName = new SimpleDateFormat("yyyy_MM_dd").format(new Date()); -// String dirName = "2024_12_12"; +// String dirName = "2026_03_27"; String dirSuffix = null; /* @@ -262,363 +271,363 @@ public static void main(String[] args) throws IOException { * NSHM23 logic tree * TODO (this is a just a marker to find this part quickly, not an actual todo) */ -// List> levels = NSHM23_U3_HybridLogicTreeBranch.levels; -// dirName += "-nshm23_u3_hybrid_branches"; -// double avgNumRups = 325000; - - List> levels = NSHM23_LogicTreeBranch.levelsOnFault; - dirName += "-nshm23_branches"; - double avgNumRups = 600000; - - dirSuffix = "-gridded_rebuild"; - -// List> levels = NSHM18_LogicTreeBranch.levels; -// dirName += "-nshm18_branches-wc_94"; -// double avgNumRups = 500000; - -// List> levels = NSHM18_LogicTreeBranch.levelsNewScale; -// dirName += "-nshm18_branches-new_scale"; -// double avgNumRups = 500000; - -// levels = new ArrayList<>(levels); -// for (int i=levels.size(); --i>=0;) -// if (levels.get(i).getType().isAssignableFrom(ShawSegmentationModels.class) -// || levels.get(i).getType().isAssignableFrom(NSHM23_SegmentationModels.class) -// || levels.get(i).getType().isAssignableFrom(SegmentationMFD_Adjustment.class) -// || levels.get(i).getType().isAssignableFrom(DistDependSegShift.class)) -// levels.remove(i); -// dirName += "-no_seg"; -//// levels.add(NSHM23_LogicTreeBranch.RUPS_THROUGH_CREEPING); -//// dirName += "-creep_branches"; -//// levels.add(NSHM23_LogicTreeBranch.MAX_DIST); -//// dirName += "-strict_cutoff_seg"; strictSeg = true; - - -// dirName += "-pre_zero_slip_parent_fix"; -// dirName += "-reweight_seg_2_3_4"; - -// levels = new ArrayList<>(levels); -// int origSize = levels.size(); -// for (int i=levels.size(); --i>=0;) -// if (levels.get(i).getType().isAssignableFrom(ScalingRelationships.class)) -// levels.remove(i); -// Preconditions.checkState(levels.size() < origSize); -// levels.add(NSHM23_LogicTreeBranch.SCALE); -// dirName += "-new_scale_rels"; -// dirName += "-full_set"; - -// levels = new ArrayList<>(levels); -// boolean dmReplaced = false; -// for (int l=levels.size(); --l >= 0;) { -// LogicTreeLevel level = levels.get(l); -// System.out.println("Level "+l+": name='"+level.getName()+"'; type='"+level.getType()+"'"); -// if (NSHM23_DeformationModels.class.isAssignableFrom(level.getType())) { -// dmReplaced = true; -// levels.set(l, LogicTreeLevel.forEnum(DevinModDeformationModels.class, "Custom Deformation Model", "CustomDM")); -// } else if (SlipAlongRuptureModels.class.isAssignableFrom(level.getType())) { -// levels.remove(l); -// } -// } -// Preconditions.checkState(dmReplaced); -// levels.add(LogicTreeLevel.forEnum(TaperOverrideSlipAlongRuptureModels.class, "Taper-Override Slip Along Rupture Models", "SlipAlong")); -// dirName += "-devin_tapered_slip_tests"; - - Class factoryClass = NSHM23_InvConfigFactory.class; - -// Class factoryClass = NSHM23_InvConfigFactory.MFDUncert0p1.class; -// dirName += "-mfd_uncert_0p1"; - -// Class factoryClass = NSHM23_InvConfigFactory.ConstantSlipRateStdDev0p1.class; -// dirName += "-const_slip_sd_0p1"; - -// Class factoryClass = NSHM23_InvConfigFactory.ConstantSlipRateStdDev0p2.class; -// dirName += "-const_slip_sd_0p2"; - -// Class factoryClass = NSHM23_InvConfigFactory.FullSysInv.class; -// dirName += "-full_sys_inv"; - -// Class factoryClass = NSHM23_InvConfigFactory.ClusterSpecific.class; -// dirName += "-cluster_specific_inversion"; - -// Class factoryClass = NSHM23_InvConfigFactory.SegWeight100.class; -// dirName += "-seg_weight_100"; - -// Class factoryClass = NSHM23_InvConfigFactory.SegWeight1000.class; -// dirName += "-seg_weight_1000"; - -// Class factoryClass = NSHM23_InvConfigFactory.SegWeight10000.class; -// dirName += "-seg_weight_10000"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevWeightAdjust.class; -// dirName += "-no_reweight_use_prev"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevWeightAdjustFullSys.class; -// dirName += "-full_sys_inv-no_reweight_use_prev"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedOrigWeights.class; -// dirName += "-no_reweight_use_orig"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedOrigWeightsFullSys.class; -// dirName += "-full_sys_inv-no_reweight_use_orig"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAvgWeights.class; -// dirName += "-no_reweight_use_prev_avg"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAvgWeightsFullSys.class; -// dirName += "-full_sys_inv-no_reweight_use_prev_avg"; - -// Class factoryClass = NSHM23_InvConfigFactory.NoPaleoParkfield.class; -// dirName += "-no_paleo_parkfield"; - -// Class factoryClass = NSHM23_InvConfigFactory.NoMFDScaleAdjust.class; -// dirName += "-no_scale_adj_mfds"; - -// Class factoryClass = NSHM23_InvConfigFactory.NoIncompatibleDataAdjust.class; -// dirName += "-no_mfd_sigma_data_adj"; - -// Class factoryClass = NSHM23_InvConfigFactory.ScaleLowerDepth1p3.class; -// dirName += "-scaleLowerDepth1.3"; - -// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAsInitial.class; -// dirName += "-prev_as_initial"; - -// Class factoryClass = NSHM23_InvConfigFactory.NoAvg.class; -// dirName += "-no_avg"; - -// Class factoryClass = NSHM23_InvConfigFactory.ForceNewPaleo.class; -// dirName += "-new_paleo"; - -// Class factoryClass = NSHM23_InvConfigFactory.NewScaleUseOrigWidths.class; -// dirName += "-use_orig_widths"; - - // also set nonzero weights! -// Class factoryClass = NSHM23_InvConfigFactory.ForceWideSegBranches.class; -// dirName += "-wide_seg_branches"; - -// Class factoryClass = NSHM23_InvConfigFactory.ForceNoGhostTransient.class; -// dirName += "-no_ghost_trans"; - -// Class factoryClass = NSHM23_InvConfigFactory.ScaleSurfSlipUseActualWidths.class; -// dirName += "-surf_slip_use_actual_w"; - -// Class factoryClass = NSHM23_InvConfigFactory.RemoveIsolatedFaults.class; -// dirName += "-remove_isolated_faults"; - -// Class factoryClass = NSHM23_InvConfigFactory.RemoveProxyFaults.class; -// dirName += "-remove_proxy_faults"; - -// Class factoryClass = NSHM23_InvConfigFactory.NoPaleoSlip.class; -// dirName += "-no_paleo_slip"; - -// Class factoryClass = NSHM23_InvConfigFactory.PaleoSlipInequality.class; -// dirName += "-paleo_slip_ineq"; - -// Class factoryClass = NSHM23_InvConfigFactory.TenThousandItersPerRup.class; -// dirName += "-10000ip"; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OriginalWeights.class; -// dirName += "-dm_orig_weights"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierlMinimizationWeights.class; -// dirName += "-dm_outlier_minimize_weights"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = false; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc2p0.class; -// dirName += "-dm_outlier_sub_yc_2"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc3p5.class; -// dirName += "-dm_outlier_sub_yc_3p5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc5p0.class; -// dirName += "-dm_outlier_sub_yc_5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc2p0.class; -// dirName += "-dm_outlier_log_sub_yc_2"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc3p5.class; -// dirName += "-dm_outlier_log_sub_yc_3p5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc5p0.class; -// dirName += "-dm_outlier_log_sub_yc_5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; - -// Class factoryClass = NSHM23_InvConfigFactory.SegModelLimitMaxLen.class; -// dirName += "-seg_limit_max_length"; - -// Class factoryClass = NSHM23_InvConfigFactory.SlipRateStdDevCeil0p1.class; -// dirName += "-slip_rate_sd_ceil_0p1"; - -// Class factoryClass = NSHM23_InvConfigFactory.SegModelMaxLen600.class; -// dirName += "-seg_limit_max_length_600"; - -// Class factoryClass = NSHM23_InvConfigFactory.SparseGRDontSpreadSingleToMulti.class; -// dirName += "-sparse_gr_dont_spread_single_multi"; - -// Class factoryClass = NSHM23_InvConfigFactory.ModDepthGV08.class; -// dirName += "-gv_08_mod_depth"; - -// Class factoryClass = NSHM23_InvConfigFactory.OrigDraftScaling.class; -// dirName += "-orig_draft_scaling"; - -// Class factoryClass = NSHM23_InvConfigFactory.ModScalingAdd4p3.class; -// dirName += "-mod_scaling"; - -// Class factoryClass = NSHM23_InvConfigFactory.NSHM18_UseU3Paleo.class; -// dirName += "-u3_paleo"; - -// Class factoryClass = NSHM23_InvConfigFactory.ModPitasPointDDW.class; -// dirName += "-mod_pitas_ddw"; - -// Class factoryClass = DefModSamplingEnabledInvConfig.ConnDistB0p5MidSegCorr.class; -// dirName += "-dm_sampling"; -// individualRandomLevels.add(new RandomDefModSampleLevel()); - -// Class factoryClass = DefModSamplingEnabledInvConfig.ConnDistB0p5MidSegCorrCapSigma.class; -// dirName += "-dm_sampling_cap_sigma"; -// individualRandomLevels.add(new RandomDefModSampleLevel()); - -// levels = new ArrayList<>(levels); -// boolean randB = true; -// boolean randSeg = true; -// int origSize = levels.size(); -// for (int i=levels.size(); --i>=0;) { -// if (randB && SupraSeisBValues.class.isAssignableFrom(levels.get(i).getType())) -// levels.remove(i); -// if (randSeg && SegmentationModelBranchNode.class.isAssignableFrom(levels.get(i).getType())) -// levels.remove(i); -// } -// Preconditions.checkState(levels.size() < origSize); -// if (randB) { -// samplingBranchCountMultiplier *= 5; // there were originally 5 each -// dirName += "-randB"; -// individualRandomLevels.add(new RandomBValSampler.Level()); -// } -// if (randSeg) { -// samplingBranchCountMultiplier *= 5; // there were originally 5 each -// dirName += "-randSeg"; -// individualRandomLevels.add(new RandomSegModelSampler.Level()); -// } - -// dirName += "-mini_one_fifth"; -// samplingBranchCountMultiplier /= 5; - -// dirName += "-u3_perturb"; -// extraArgs.add("--perturb "+GenerationFunctionType.UNIFORM_0p001.name()); -// dirName += "-exp_perturb"; -// extraArgs.add("--perturb "+GenerationFunctionType.EXPONENTIAL_SCALE.name()); -// dirName += "-limit_zeros"; -// extraArgs.add("--non-negativity "+NonnegativityConstraintType.LIMIT_ZERO_RATES.name()); -// dirName += "-classic_sa"; -// extraArgs.add("--cooling-schedule "+CoolingScheduleType.CLASSICAL_SA.name()); - -// levels = new ArrayList<>(levels); -// levels.add(NSHM23_LogicTreeBranch.SINGLE_STATES); -// dirName += "-single_state"; - -// dirName += "-mod_west_valley_ddw"; - -// dirName += "-mod_dm_weights"; - - forceHazardGridSpacing = 0.1; - - forceRequiredNonzeroWeight = true; - LogicTreeNode[] required = { - // FAULT MODELS -// FaultModels.FM3_1, -// FaultModels.FM3_2, -// NSHM18_FaultModels.NSHM18_WUS_NoCA, -// NSHM18_FaultModels.NSHM18_WUS_PlusU3_FM_3p1, -// NSHM23_FaultModels.FM_v1p4, -// NSHM23_FaultModels.FM_v2, - NSHM23_FaultModels.WUS_FM_v3, -// PRVI25_FaultModels.PRVI_FM_INITIAL, - -// // SINGLE STATE -// NSHM23_SingleStates.NM, -// NSHM23_SingleStates.UT, - - // RUPTURE SETS -// RupturePlausibilityModels.COULOMB, // default -// RupturePlausibilityModels.COULOMB_5km, -// RupturePlausibilityModels.AZIMUTHAL, -// RupturePlausibilityModels.SEGMENTED, -// RupturePlausibilityModels.UCERF3, -// RupturePlausibilityModels.UCERF3_REDUCED, - - // DEFORMATION MODELS -// U3_UncertAddDeformationModels.U3_ZENG, -// U3_UncertAddDeformationModels.U3_MEAN, -// NSHM18_DeformationModels.BRANCH_AVERAGED, -// NSHM23_DeformationModels.AVERAGE, -// NSHM23_DeformationModels.GEOLOGIC, -// NSHM23_DeformationModels.EVANS, -// NSHM23_DeformationModels.MEDIAN, -// DevinModDeformationModels.GEO_AVG_FROM_DEVIN, -// DevinModDeformationModels.GEO_FROM_DEVIN, - - // SCALING RELATIONSHIPS -// ScalingRelationships.SHAW_2009_MOD, -// ScalingRelationships.MEAN_UCERF3, -// NSHM23_ScalingRelationships.AVERAGE, -// NSHM23_ScalingRelationships.LOGA_C4p2_SQRT_LEN, -// NSHM23_ScalingRelationships.WIDTH_LIMITED_CSD, - - // SLIP ALONG RUPTURE -// NSHM23_SlipAlongRuptureModels.UNIFORM, -// NSHM23_SlipAlongRuptureModels.TAPERED, -// SlipAlongRuptureModels.UNIFORM, -// SlipAlongRuptureModels.TAPERED, -// TaperOverrideSlipAlongRuptureModels.UNIFORM, -// TaperOverrideSlipAlongRuptureModels.TAPER_OVERRIDE_COMBINED, -// TaperOverrideSlipAlongRuptureModels.TAPER_OVERRIDE_INDIVIDUAL, - - // SUB-SECT CONSTRAINT -// SubSectConstraintModels.TOT_NUCL_RATE, // default -// SubSectConstraintModels.NUCL_MFD, - - // SUB-SEIS MO REDUCTION -// SubSeisMoRateReductions.SUB_B_1, -// SubSeisMoRateReductions.NONE, // default -// SubSeisMoRateReductions.SYSTEM_AVG, -// SubSeisMoRateReductions.SYSTEM_AVG_SUB_B_1, - - // SUPRA-SEIS-B -// SupraSeisBValues.B_0p5, -// SupraSeisBValues.AVERAGE, - - // PALEO UNCERT -// NSHM23_PaleoUncertainties.EVEN_FIT, - - // SEGMENTATION -// SegmentationModels.SHAW_R0_3, -// NSHM23_SegmentationModels.AVERAGE, -// NSHM23_SegmentationModels.MID, -// NSHM23_SegmentationModels.CLASSIC, -// NSHM23_SegmentationModels.CLASSIC_FULL, - - // SEG-SHIFT -// DistDependSegShift.NONE, -// DistDependSegShift.ONE_KM, -// DistDependSegShift.TWO_KM, -// DistDependSegShift.THREE_KM, - - // SEG ADJUSTMENT -// SegmentationMFD_Adjustment.NONE, -// SegmentationMFD_Adjustment.JUMP_PROB_THRESHOLD_AVG, -// SegmentationMFD_Adjustment.REL_GR_THRESHOLD_AVG_SINGLE_ITER, -// SegmentationMFD_Adjustment.REL_GR_THRESHOLD_AVG, // default -// SegmentationMFD_Adjustment.CAPPED_REDIST, -// SegmentationMFD_Adjustment.CAPPED_REDIST_SELF_CONTAINED, -// SegmentationMFD_Adjustment.GREEDY, -// SegmentationMFD_Adjustment.GREEDY_SELF_CONTAINED, -// SegmentationMFD_Adjustment.JUMP_PROB_THRESHOLD_AVG_MATCH_STRICT, - - // CREEPING SECTION -// RupsThroughCreepingSect.INCLUDE, -// RupsThroughCreepingSect.EXCLUDE, - }; -// LogicTreeNode[] required = { FaultModels.FM3_1, SubSeisMoRateReductionNode.SYSTEM_AVG }; -// LogicTreeNode[] required = { FaultModels.FM3_1, SubSeisMoRateReductionNode.FAULT_SPECIFIC }; -// Class sortBy = SubSectConstraintModels.class; - Class sortBy = NSHM23_SegmentationModels.class; +//// List> levels = NSHM23_U3_HybridLogicTreeBranch.levels; +//// dirName += "-nshm23_u3_hybrid_branches"; +//// double avgNumRups = 325000; +// +// List> levels = NSHM23_LogicTreeBranch.levelsOnFault; +// dirName += "-nshm23_branches"; +// double avgNumRups = 600000; +// +// dirSuffix = "-gridded_rebuild"; +// +//// List> levels = NSHM18_LogicTreeBranch.levels; +//// dirName += "-nshm18_branches-wc_94"; +//// double avgNumRups = 500000; +// +//// List> levels = NSHM18_LogicTreeBranch.levelsNewScale; +//// dirName += "-nshm18_branches-new_scale"; +//// double avgNumRups = 500000; +// +//// levels = new ArrayList<>(levels); +//// for (int i=levels.size(); --i>=0;) +//// if (levels.get(i).getType().isAssignableFrom(ShawSegmentationModels.class) +//// || levels.get(i).getType().isAssignableFrom(NSHM23_SegmentationModels.class) +//// || levels.get(i).getType().isAssignableFrom(SegmentationMFD_Adjustment.class) +//// || levels.get(i).getType().isAssignableFrom(DistDependSegShift.class)) +//// levels.remove(i); +//// dirName += "-no_seg"; +////// levels.add(NSHM23_LogicTreeBranch.RUPS_THROUGH_CREEPING); +////// dirName += "-creep_branches"; +////// levels.add(NSHM23_LogicTreeBranch.MAX_DIST); +////// dirName += "-strict_cutoff_seg"; strictSeg = true; +// +// +//// dirName += "-pre_zero_slip_parent_fix"; +//// dirName += "-reweight_seg_2_3_4"; +// +//// levels = new ArrayList<>(levels); +//// int origSize = levels.size(); +//// for (int i=levels.size(); --i>=0;) +//// if (levels.get(i).getType().isAssignableFrom(ScalingRelationships.class)) +//// levels.remove(i); +//// Preconditions.checkState(levels.size() < origSize); +//// levels.add(NSHM23_LogicTreeBranch.SCALE); +//// dirName += "-new_scale_rels"; +//// dirName += "-full_set"; +// +//// levels = new ArrayList<>(levels); +//// boolean dmReplaced = false; +//// for (int l=levels.size(); --l >= 0;) { +//// LogicTreeLevel level = levels.get(l); +//// System.out.println("Level "+l+": name='"+level.getName()+"'; type='"+level.getType()+"'"); +//// if (NSHM23_DeformationModels.class.isAssignableFrom(level.getType())) { +//// dmReplaced = true; +//// levels.set(l, LogicTreeLevel.forEnum(DevinModDeformationModels.class, "Custom Deformation Model", "CustomDM")); +//// } else if (SlipAlongRuptureModels.class.isAssignableFrom(level.getType())) { +//// levels.remove(l); +//// } +//// } +//// Preconditions.checkState(dmReplaced); +//// levels.add(LogicTreeLevel.forEnum(TaperOverrideSlipAlongRuptureModels.class, "Taper-Override Slip Along Rupture Models", "SlipAlong")); +//// dirName += "-devin_tapered_slip_tests"; +// +// Class factoryClass = NSHM23_InvConfigFactory.class; +// +//// Class factoryClass = NSHM23_InvConfigFactory.MFDUncert0p1.class; +//// dirName += "-mfd_uncert_0p1"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ConstantSlipRateStdDev0p1.class; +//// dirName += "-const_slip_sd_0p1"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ConstantSlipRateStdDev0p2.class; +//// dirName += "-const_slip_sd_0p2"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.FullSysInv.class; +//// dirName += "-full_sys_inv"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ClusterSpecific.class; +//// dirName += "-cluster_specific_inversion"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SegWeight100.class; +//// dirName += "-seg_weight_100"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SegWeight1000.class; +//// dirName += "-seg_weight_1000"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SegWeight10000.class; +//// dirName += "-seg_weight_10000"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevWeightAdjust.class; +//// dirName += "-no_reweight_use_prev"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevWeightAdjustFullSys.class; +//// dirName += "-full_sys_inv-no_reweight_use_prev"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedOrigWeights.class; +//// dirName += "-no_reweight_use_orig"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedOrigWeightsFullSys.class; +//// dirName += "-full_sys_inv-no_reweight_use_orig"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAvgWeights.class; +//// dirName += "-no_reweight_use_prev_avg"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAvgWeightsFullSys.class; +//// dirName += "-full_sys_inv-no_reweight_use_prev_avg"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NoPaleoParkfield.class; +//// dirName += "-no_paleo_parkfield"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NoMFDScaleAdjust.class; +//// dirName += "-no_scale_adj_mfds"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NoIncompatibleDataAdjust.class; +//// dirName += "-no_mfd_sigma_data_adj"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ScaleLowerDepth1p3.class; +//// dirName += "-scaleLowerDepth1.3"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.HardcodedPrevAsInitial.class; +//// dirName += "-prev_as_initial"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NoAvg.class; +//// dirName += "-no_avg"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ForceNewPaleo.class; +//// dirName += "-new_paleo"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NewScaleUseOrigWidths.class; +//// dirName += "-use_orig_widths"; +// +// // also set nonzero weights! +//// Class factoryClass = NSHM23_InvConfigFactory.ForceWideSegBranches.class; +//// dirName += "-wide_seg_branches"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ForceNoGhostTransient.class; +//// dirName += "-no_ghost_trans"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ScaleSurfSlipUseActualWidths.class; +//// dirName += "-surf_slip_use_actual_w"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.RemoveIsolatedFaults.class; +//// dirName += "-remove_isolated_faults"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.RemoveProxyFaults.class; +//// dirName += "-remove_proxy_faults"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NoPaleoSlip.class; +//// dirName += "-no_paleo_slip"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.PaleoSlipInequality.class; +//// dirName += "-paleo_slip_ineq"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.TenThousandItersPerRup.class; +//// dirName += "-10000ip"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OriginalWeights.class; +//// dirName += "-dm_orig_weights"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierlMinimizationWeights.class; +//// dirName += "-dm_outlier_minimize_weights"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = false; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc2p0.class; +//// dirName += "-dm_outlier_sub_yc_2"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc3p5.class; +//// dirName += "-dm_outlier_sub_yc_3p5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierReplacementYc5p0.class; +//// dirName += "-dm_outlier_sub_yc_5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc2p0.class; +//// dirName += "-dm_outlier_log_sub_yc_2"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc3p5.class; +//// dirName += "-dm_outlier_log_sub_yc_3p5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.DM_OutlierLogReplacementYc5p0.class; +//// dirName += "-dm_outlier_log_sub_yc_5"; NSHM23_DeformationModels.ORIGINAL_WEIGHTS = true; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SegModelLimitMaxLen.class; +//// dirName += "-seg_limit_max_length"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SlipRateStdDevCeil0p1.class; +//// dirName += "-slip_rate_sd_ceil_0p1"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SegModelMaxLen600.class; +//// dirName += "-seg_limit_max_length_600"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.SparseGRDontSpreadSingleToMulti.class; +//// dirName += "-sparse_gr_dont_spread_single_multi"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ModDepthGV08.class; +//// dirName += "-gv_08_mod_depth"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.OrigDraftScaling.class; +//// dirName += "-orig_draft_scaling"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ModScalingAdd4p3.class; +//// dirName += "-mod_scaling"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.NSHM18_UseU3Paleo.class; +//// dirName += "-u3_paleo"; +// +//// Class factoryClass = NSHM23_InvConfigFactory.ModPitasPointDDW.class; +//// dirName += "-mod_pitas_ddw"; +// +//// Class factoryClass = DefModSamplingEnabledInvConfig.ConnDistB0p5MidSegCorr.class; +//// dirName += "-dm_sampling"; +//// individualRandomLevels.add(new RandomDefModSampleLevel()); +// +//// Class factoryClass = DefModSamplingEnabledInvConfig.ConnDistB0p5MidSegCorrCapSigma.class; +//// dirName += "-dm_sampling_cap_sigma"; +//// individualRandomLevels.add(new RandomDefModSampleLevel()); +// +//// levels = new ArrayList<>(levels); +//// boolean randB = true; +//// boolean randSeg = true; +//// int origSize = levels.size(); +//// for (int i=levels.size(); --i>=0;) { +//// if (randB && SupraSeisBValues.class.isAssignableFrom(levels.get(i).getType())) +//// levels.remove(i); +//// if (randSeg && SegmentationModelBranchNode.class.isAssignableFrom(levels.get(i).getType())) +//// levels.remove(i); +//// } +//// Preconditions.checkState(levels.size() < origSize); +//// if (randB) { +//// samplingBranchCountMultiplier *= 5; // there were originally 5 each +//// dirName += "-randB"; +//// individualRandomLevels.add(new RandomBValSampler.Level()); +//// } +//// if (randSeg) { +//// samplingBranchCountMultiplier *= 5; // there were originally 5 each +//// dirName += "-randSeg"; +//// individualRandomLevels.add(new RandomSegModelSampler.Level()); +//// } +// +//// dirName += "-mini_one_fifth"; +//// samplingBranchCountMultiplier /= 5; +// +//// dirName += "-u3_perturb"; +//// extraArgs.add("--perturb "+GenerationFunctionType.UNIFORM_0p001.name()); +//// dirName += "-exp_perturb"; +//// extraArgs.add("--perturb "+GenerationFunctionType.EXPONENTIAL_SCALE.name()); +//// dirName += "-limit_zeros"; +//// extraArgs.add("--non-negativity "+NonnegativityConstraintType.LIMIT_ZERO_RATES.name()); +//// dirName += "-classic_sa"; +//// extraArgs.add("--cooling-schedule "+CoolingScheduleType.CLASSICAL_SA.name()); +// +//// levels = new ArrayList<>(levels); +//// levels.add(NSHM23_LogicTreeBranch.SINGLE_STATES); +//// dirName += "-single_state"; +// +//// dirName += "-mod_west_valley_ddw"; +// +//// dirName += "-mod_dm_weights"; +// +// forceHazardGridSpacing = 0.1; +// +// forceRequiredNonzeroWeight = true; +// LogicTreeNode[] required = { +// // FAULT MODELS +//// FaultModels.FM3_1, +//// FaultModels.FM3_2, +//// NSHM18_FaultModels.NSHM18_WUS_NoCA, +//// NSHM18_FaultModels.NSHM18_WUS_PlusU3_FM_3p1, +//// NSHM23_FaultModels.FM_v1p4, +//// NSHM23_FaultModels.FM_v2, +// NSHM23_FaultModels.WUS_FM_v3, +//// PRVI25_FaultModels.PRVI_FM_INITIAL, +// +//// // SINGLE STATE +//// NSHM23_SingleStates.NM, +//// NSHM23_SingleStates.UT, +// +// // RUPTURE SETS +//// RupturePlausibilityModels.COULOMB, // default +//// RupturePlausibilityModels.COULOMB_5km, +//// RupturePlausibilityModels.AZIMUTHAL, +//// RupturePlausibilityModels.SEGMENTED, +//// RupturePlausibilityModels.UCERF3, +//// RupturePlausibilityModels.UCERF3_REDUCED, +// +// // DEFORMATION MODELS +//// U3_UncertAddDeformationModels.U3_ZENG, +//// U3_UncertAddDeformationModels.U3_MEAN, +//// NSHM18_DeformationModels.BRANCH_AVERAGED, +//// NSHM23_DeformationModels.AVERAGE, +//// NSHM23_DeformationModels.GEOLOGIC, +//// NSHM23_DeformationModels.EVANS, +//// NSHM23_DeformationModels.MEDIAN, +//// DevinModDeformationModels.GEO_AVG_FROM_DEVIN, +//// DevinModDeformationModels.GEO_FROM_DEVIN, +// +// // SCALING RELATIONSHIPS +//// ScalingRelationships.SHAW_2009_MOD, +//// ScalingRelationships.MEAN_UCERF3, +//// NSHM23_ScalingRelationships.AVERAGE, +//// NSHM23_ScalingRelationships.LOGA_C4p2_SQRT_LEN, +//// NSHM23_ScalingRelationships.WIDTH_LIMITED_CSD, +// +// // SLIP ALONG RUPTURE +//// NSHM23_SlipAlongRuptureModels.UNIFORM, +//// NSHM23_SlipAlongRuptureModels.TAPERED, +//// SlipAlongRuptureModels.UNIFORM, +//// SlipAlongRuptureModels.TAPERED, +//// TaperOverrideSlipAlongRuptureModels.UNIFORM, +//// TaperOverrideSlipAlongRuptureModels.TAPER_OVERRIDE_COMBINED, +//// TaperOverrideSlipAlongRuptureModels.TAPER_OVERRIDE_INDIVIDUAL, +// +// // SUB-SECT CONSTRAINT +//// SubSectConstraintModels.TOT_NUCL_RATE, // default +//// SubSectConstraintModels.NUCL_MFD, +// +// // SUB-SEIS MO REDUCTION +//// SubSeisMoRateReductions.SUB_B_1, +//// SubSeisMoRateReductions.NONE, // default +//// SubSeisMoRateReductions.SYSTEM_AVG, +//// SubSeisMoRateReductions.SYSTEM_AVG_SUB_B_1, +// +// // SUPRA-SEIS-B +//// SupraSeisBValues.B_0p5, +//// SupraSeisBValues.AVERAGE, +// +// // PALEO UNCERT +//// NSHM23_PaleoUncertainties.EVEN_FIT, +// +// // SEGMENTATION +//// SegmentationModels.SHAW_R0_3, +//// NSHM23_SegmentationModels.AVERAGE, +//// NSHM23_SegmentationModels.MID, +//// NSHM23_SegmentationModels.CLASSIC, +//// NSHM23_SegmentationModels.CLASSIC_FULL, +// +// // SEG-SHIFT +//// DistDependSegShift.NONE, +//// DistDependSegShift.ONE_KM, +//// DistDependSegShift.TWO_KM, +//// DistDependSegShift.THREE_KM, +// +// // SEG ADJUSTMENT +//// SegmentationMFD_Adjustment.NONE, +//// SegmentationMFD_Adjustment.JUMP_PROB_THRESHOLD_AVG, +//// SegmentationMFD_Adjustment.REL_GR_THRESHOLD_AVG_SINGLE_ITER, +//// SegmentationMFD_Adjustment.REL_GR_THRESHOLD_AVG, // default +//// SegmentationMFD_Adjustment.CAPPED_REDIST, +//// SegmentationMFD_Adjustment.CAPPED_REDIST_SELF_CONTAINED, +//// SegmentationMFD_Adjustment.GREEDY, +//// SegmentationMFD_Adjustment.GREEDY_SELF_CONTAINED, +//// SegmentationMFD_Adjustment.JUMP_PROB_THRESHOLD_AVG_MATCH_STRICT, +// +// // CREEPING SECTION +//// RupsThroughCreepingSect.INCLUDE, +//// RupsThroughCreepingSect.EXCLUDE, +// }; +//// LogicTreeNode[] required = { FaultModels.FM3_1, SubSeisMoRateReductionNode.SYSTEM_AVG }; +//// LogicTreeNode[] required = { FaultModels.FM3_1, SubSeisMoRateReductionNode.FAULT_SPECIFIC }; +//// Class sortBy = SubSectConstraintModels.class; +// Class sortBy = NSHM23_SegmentationModels.class; /* * END NSHM23 logic tree */ @@ -734,6 +743,82 @@ public static void main(String[] args) throws IOException { /* * END PRVI25 logic tree */ + + /* + * NSHM27 logic tree + * TODO (this is a just a marker to find this part quickly, not an actual todo) + */ + + NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.AMSAM; +// NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.GNMI; +// int numBranchSamples = 100; +// int numBranchSamples = 1000; +// int numBranchSamples = 2000; + int numBranchSamples = 5000; +// int numBranchSamples = 10000; +// int numBranchSamples = 20000; +// int numBranchSamples = 100000; + TectonicRegionType trt = null; + + parallelBA = true; + boolean deterministicSeed = false; + + SamplingMethod samplingMethod = SamplingMethod.MONTE_CARLO; +// SamplingMethod samplingMethod = SamplingMethod.LATIN_HYPERCUBE; +// SamplingMethod samplingMethod = SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE; + + if (trt == null) { + customTree = NSHM27_LogicTree.buildMultiRegimeTree(seisReg, numBranchSamples, deterministicSeed, samplingMethod); + analysisTree = LogicTree.unrollTRTs(customTree); + Preconditions.checkNotNull(analysisTree); + } else { + customTree = NSHM27_LogicTree.buildLogicTree(seisReg, trt, numBranchSamples, deterministicSeed, samplingMethod); + analysisTree = customTree; + } + analysisTree = LogicTree.applyBinning(analysisTree); + Preconditions.checkNotNull(analysisTree); + + hazardGridded = true; + + List> levels = new ArrayList<>(customTree.getLevels()); + dirName += "-nshm27-"+seisReg.name()+"-"+numBranchSamples+"samples"; + if (samplingMethod == SamplingMethod.MONTE_CARLO) + dirName += "-mcs"; + else if (samplingMethod == SamplingMethod.LATIN_HYPERCUBE) + dirName += "-lhs"; + else if (samplingMethod == SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE) + dirName += "-lhs_pairwise"; + if (!deterministicSeed) + dirName += "-unique_seed"; + if (trt != null) + dirName += "-"+trt.name(); + double avgNumRups = 200000; + // TODO + System.err.println("WARNING: still using PRVI GMMs"); + gmpes = new AttenRelRef[] { AttenRelRef.USGS_PRVI_ACTIVE, AttenRelRef.USGS_PRVI_SLAB, AttenRelRef.USGS_PRVI_INTERFACE }; + +// // full seis region +// Region mapRegion = seisReg.load(); + // smaller map region + Region mapRegion = NSHM27_MapRegions.valueOf(seisReg.name()).load(); + + forceHazardReg = new GriddedRegion(mapRegion, 0.1, GriddedRegion.ANCHOR_0_0); +// forceHazardReg = new GriddedRegion(mapRegion, 0.2, GriddedRegion.ANCHOR_0_0); dirName += "-haz0.2deg"; +// forceHazardReg = new GriddedRegion(mapRegion, 0.025, GriddedRegion.ANCHOR_0_0); + sigmaTrunc = 3d; + + Class factoryClass = NSHM27_InvConfigFactory.class; + + forceHazardGridSpacing = 0.1; + nodeBAskipSectBySect = false; + + forceRequiredNonzeroWeight = true; + LogicTreeNode[] required = null; + Class sortBy = null; + /* + * END NSHM26 logic tree + */ + // TODO this is the end of the configurable section System.out.println("Instantiating factory class: "+factoryClass.getName()); @@ -746,7 +831,9 @@ public static void main(String[] args) throws IOException { } LogicTree logicTree; - if (forceRequiredNonzeroWeight) + if (customTree != null) + logicTree = customTree; + else if (forceRequiredNonzeroWeight) logicTree = LogicTree.buildExhaustive(levels, true, new BranchWeightProvider.NodeWeightOverrides(required, 1d), required); else logicTree = LogicTree.buildExhaustive(levels, true, required); @@ -779,8 +866,6 @@ public static void main(String[] args) throws IOException { // int numSamples = 450; // int numSamples = 36*10; - Random rand = new Random(randSeed); - if (required != null && required.length > 0) { for (LogicTreeNode node : required) dirName += "-"+node.getFilePrefix(); @@ -797,10 +882,13 @@ public static void main(String[] args) throws IOException { int numBranches = logicTree.size()*samplingBranchCountMultiplier; System.out.println("\tnumBranches = "+logicTree.size()+" x "+samplingBranchCountMultiplier+" = "+numBranches); - List> levelNodes = new ArrayList<>(); - for (RandomlySampledLevel level : individualRandomLevels) { - level.buildNodes(rand, numBranches, 1d); + Random rand = new Random(randSeed); + + List> levelNodes = new ArrayList<>(); + for (RandomlyGeneratedLevel level : individualRandomLevels) { +// level.build(rand.nextLong(), numBranches); levelNodes.add(level.getNodes()); + throw new IllegalStateException("Need to revive if needed"); } List> modBranches = new ArrayList<>(); @@ -811,7 +899,7 @@ public static void main(String[] args) throws IOException { for (LogicTreeNode val : branch) modValues.add(val); int randIndex = modBranches.size(); - for (List randNodes : levelNodes) + for (List randNodes : levelNodes) modValues.add(randNodes.get(randIndex)); LogicTreeBranch modBranch = new LogicTreeBranch<>(modLevels, modValues); modBranch.setOrigBranchWeight(branch.getOrigBranchWeight()); @@ -864,10 +952,10 @@ public static void main(String[] args) throws IOException { logicTree.setWeightProvider(new BranchWeightProvider.OriginalWeights()); } else { System.out.println("Still doing random downsampling"); - logicTree = logicTree.sample(numSamples, true, rand); + logicTree = logicTree.sample(numSamples, true, randSeed); } } else { - logicTree = logicTree.sample(numSamples, true, rand); + logicTree = logicTree.sample(numSamples, true, randSeed); } } else { System.out.println("Won't sample logic tree, as tree has "+logicTree.size()+" values, which is fewer " @@ -949,6 +1037,17 @@ else if (v2 == null) File localLogicTree = new File(localDir, "logic_tree.json"); logicTree.write(localLogicTree); + String ltPath = dirPath+"/"+localLogicTree.getName(); + + String ltAnalPath = null; + if (analysisTree != null) { + Preconditions.checkState(analysisTree.size() == logicTree.size()); + for (int i=0; i 1) argz += " --runs-per-branch "+runsPerBranch; + if (parallelBA) + argz += " --parallel-ba"; for (String arg : extraArgs) argz += " "+arg; argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(remoteInversionsPerBundle).build(); @@ -986,12 +1086,14 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) System.out.println("Total job time: "+mins+" mins = "+(float)((double)mins/60d)+" hours"); // make sure to not exceed 1 week mins = Integer.min(mins, 60*24*7 - 1); - pbsWrite.writeScript(new File(localDir, "batch_inversion.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "batch_inversion.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); Map baFiles = AbstractAsyncLogicTreeWriter.getBranchAverageSolutionFileMap(new File("results"), logicTree); // now write hazard script argz = "--input-file "+resultsPath+".zip"; + if (ltAnalPath != null) + argz += " --analysis-logic-tree "+ltAnalPath; argz += " --output-dir "+resultsPath; if (gmpes != null) for (AttenRelRef gmpe : gmpes) @@ -1054,7 +1156,7 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) if (queue != null && queue.equals("scec")) // run hazard in the high priority queue queue = "scec_hiprio"; - pbsWrite.writeScript(new File(localDir, "batch_hazard.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "batch_hazard.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); JavaShellScriptWriter javaWrite = new JavaShellScriptWriter( mpjWrite.getJavaBin(), remoteTotalMemGB*1024, classpath); @@ -1062,7 +1164,8 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) for (String varName : envVars.keySet()) javaWrite.setEnvVar(varName, envVars.get(varName)); - boolean griddedJob = GridSourceProviderFactory.class.isAssignableFrom(factoryClass); + boolean griddedJob = GridSourceProviderFactory.class.isAssignableFrom(factoryClass) + && !(GridSourceProviderFactory.Single.class.isAssignableFrom(factoryClass)); if (griddedJob) { LogicTree gridTree = ((GridSourceProviderFactory)factory).getGridSourceTree(logicTree); System.out.println("Will do gridded seismicity jobs. Grid tree has "+gridTree.size() @@ -1106,7 +1209,7 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) int gridThreads = Integer.max(1, remoteTotalThreads/2); argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(1).threads(gridThreads).build(); script = mpjWrite.buildScript(MPJ_GridSeisBranchBuilder.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "batch_grid_calc.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "batch_grid_calc.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); String griddedBAName = null; if (baFiles != null && baFiles.size() == 1) @@ -1118,7 +1221,7 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) if (griddedBAName != null) argz += " "+dirPath+"/"+griddedBAName; script = javaWrite.buildScript(TrueMeanSolutionCreator.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "true_mean_builder.slurm"), script, mins, 1, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "true_mean_builder.slurm"), script, mins, 1, remoteTotalThreads, -1, queue); // now add hazard calc jobs with gridded for (int i=0; i<5; i++) { @@ -1193,7 +1296,7 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) int myMins = mins; if (i == 1) myMins = Integer.min(mins*5, 60*24*7 - 1); - pbsWrite.writeScript(jobFile, script, myMins, myNodes, remoteTotalThreads, queue); + pbsWrite.writeScript(jobFile, script, myMins, myNodes, remoteTotalThreads, -1, queue); } // write out gridded seismicity combiner script @@ -1207,12 +1310,12 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) argz += " "+resultsPath+"_hazard.zip"; script = javaWrite.buildScript(FaultAndGriddedSeparateTreeHazardCombiner.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "fault_grid_hazard_combine.slurm"), script, mins, 1, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "fault_grid_hazard_combine.slurm"), script, mins, 1, remoteTotalThreads, -1, queue); } else { // true mean without gridded argz = resultsPath+".zip true_mean_solution.zip"; script = javaWrite.buildScript(TrueMeanSolutionCreator.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "true_mean_builder.slurm"), script, mins, 1, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "true_mean_builder.slurm"), script, mins, 1, remoteTotalThreads, -1, queue); } // site hazard job @@ -1244,19 +1347,27 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) csv.writeToFile(localSitesFile); argz = "--input-file "+resultsPath+".zip"; + if (ltAnalPath != null) + argz += " --analysis-logic-tree "+ltAnalPath; argz += " --output-dir "+resultsPath+"_hazard_sites"; argz += " --sites-file "+dirPath+"/"+localSitesFile.getName(); argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(1).threads(remoteTotalThreads).build(); - argz += " --gridded-seis EXCLUDE"; + if (hazardGridded) + argz += " --gridded-seis INCLUDE"; + else + argz += " --gridded-seis EXCLUDE"; argz += extraHazardArgs; if (gmpes != null) for (AttenRelRef gmpe : gmpes) argz += " --gmpe "+gmpe.name(); script = mpjWrite.buildScript(MPJ_SiteLogicTreeHazardCurveCalc.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "batch_hazard_sites.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "batch_hazard_sites.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); if (griddedJob) { + Preconditions.checkState(!hazardGridded); argz = "--input-file "+resultsPath; + if (ltAnalPath != null) + argz += " --analysis-logic-tree "+ltAnalPath; argz += " --logic-tree "+dirPath+"/logic_tree_full_gridded.json"; argz += " --output-dir "+resultsPath+"_hazard_sites_full_gridded"; argz += " --sites-file "+dirPath+"/"+localSitesFile.getName(); @@ -1267,28 +1378,30 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) argz += " --gmpe "+gmpe.name(); argz += " "+MPJTaskCalculator.argumentBuilder().minDispatch(2).maxDispatch(10).threads(remoteTotalThreads).build(); script = mpjWrite.buildScript(MPJ_SiteLogicTreeHazardCurveCalc.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "batch_hazard_sites_full_gridded.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "batch_hazard_sites_full_gridded.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); } } } // write node branch averaged script - Map>> baPrefixes = AbstractAsyncLogicTreeWriter.getBranchAveragePrefixes(logicTree); + Map>> baPrefixes = AbstractAsyncLogicTreeWriter.getBranchAveragePrefixes( + analysisTree == null ? logicTree : analysisTree); List baLTPaths = new ArrayList<>(); List baJobSuffixes = new ArrayList<>(); List baOutDirs = new ArrayList<>(); if (baPrefixes.size() > 1) { // need to write them out piecewise + List> baLevels = analysisTree == null ? levels : analysisTree.getLevels(); for (String baPrefix : baPrefixes.keySet()) { List> plainBranches = new ArrayList<>(); for (LogicTreeBranch branch : baPrefixes.get(baPrefix)) { - LogicTreeBranch plainBranch = new LogicTreeBranch<>(levels); + LogicTreeBranch plainBranch = new LogicTreeBranch<>(baLevels); for (int i=0; i subLT = LogicTree.fromExisting(levels, plainBranches); + LogicTree subLT = LogicTree.fromExisting(baLevels, plainBranches); File subLogicTreeFile = new File(localDir, "sub_logic_tree_"+baPrefix+".json"); subLT.write(subLogicTreeFile); String subLTPath = dirPath+"/"+subLogicTreeFile.getName(); @@ -1298,7 +1411,10 @@ else if (mpjWrite instanceof FastMPJShellScriptWriter) } } else { // can do the full tree - baLTPaths.add(ltPath); + if (ltAnalPath != null) + baLTPaths.add(ltAnalPath); + else + baLTPaths.add(ltPath); baOutDirs.add(dirPath+"/node_branch_averaged"); baJobSuffixes.add(""); } @@ -1312,7 +1428,12 @@ else if (baFiles.size() == 1) else baFile = baFiles.get(baJobSuffixes.get(n)); argz = "--input-file "+resultsPath; - argz += " --logic-tree "+baLTPaths.get(n); + if (analysisTree == null) { + argz += " --logic-tree "+baLTPaths.get(n); + } else { + argz += " --logic-tree "+ltPath; + argz += " --analysis-logic-tree "+baLTPaths.get(n); + } argz += " --output-dir "+baOutDirs.get(n); argz += " --threads "+Integer.min(8, remoteTotalThreads); argz += " --async-threads "+nodeBAAsyncThreads; @@ -1321,7 +1442,7 @@ else if (baFiles.size() == 1) argz += " --branch-averaged-file "+dirPath+"/"+baFile.getName(); script = javaWrite.buildScript(LogicTreeBranchAverageWriter.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "full_node_ba"+baJobSuffixes.get(n)+".slurm"), script, mins, 1, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, "full_node_ba"+baJobSuffixes.get(n)+".slurm"), script, mins, 1, remoteTotalThreads, -1, queue); // // write out individual node BA scripts (useful if the tree is enormous // File baIndvLocalDir = new File(localDir, "indv_node_ba_scripts"); @@ -1353,23 +1474,29 @@ else if (baFiles.size() == 1) if (logicTree.size() > 20) { // write out parallel version - int totNum = MPJ_LogicTreeBranchAverageBuilder.buildCombinations(logicTree, 1).size(); - Preconditions.checkState(totNum > 1); - int myNodes = Integer.min(nodes, totNum); - - argz = "--input-dir "+resultsPath; - argz += " --logic-tree "+baLTPaths.get(n); - argz += " --output-dir "+baOutDirs.get(n); - if (nodeBAskipSectBySect) - argz += " --skip-sect-by-sect"; - argz += " --plot-level "+PlotLevel.REVIEW.name(); - argz += " --depth 1"; - if (baFile != null) - argz += " --compare-to "+dirPath+"/"+baFile.getName(); - argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(1).threads(remoteTotalThreads).build(); - script = mpjWrite.buildScript(MPJ_LogicTreeBranchAverageBuilder.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, "batch_node_ba"+baJobSuffixes.get(n)+".slurm"), - script, mins, myNodes, remoteTotalThreads, queue); + int totNum = MPJ_LogicTreeBranchAverageBuilder.buildCombinations(analysisTree == null ? logicTree : analysisTree, 1).size(); + if (totNum > 0) { + int myNodes = Integer.min(nodes, totNum); + + argz = "--input-dir "+resultsPath; + if (analysisTree == null) { + argz += " --logic-tree "+baLTPaths.get(n); + } else { + argz += " --logic-tree "+ltPath; + argz += " --analysis-logic-tree "+baLTPaths.get(n); + } + argz += " --output-dir "+baOutDirs.get(n); + if (nodeBAskipSectBySect) + argz += " --skip-sect-by-sect"; + argz += " --plot-level "+PlotLevel.REVIEW.name(); + argz += " --depth 1"; + if (baFile != null) + argz += " --compare-to "+dirPath+"/"+baFile.getName(); + argz += " "+MPJTaskCalculator.argumentBuilder().exactDispatch(1).threads(remoteTotalThreads).build(); + script = mpjWrite.buildScript(MPJ_LogicTreeBranchAverageBuilder.class.getName(), argz); + pbsWrite.writeScript(new File(localDir, "batch_node_ba"+baJobSuffixes.get(n)+".slurm"), + script, mins, myNodes, remoteTotalThreads, -1, queue); + } } } @@ -1435,7 +1562,7 @@ else if (baFiles.size() == 1) int transNodes = Integer.min(16, nodes); pbsWrite.writeScript(new File(modLocalDir, "batch_strict_branch_translate.slurm"), script, mins, transNodes, - remoteTotalThreads, queue); + remoteTotalThreads, -1, queue); // now write hazard script argz = "--input-file "+modResultsPath+".zip"; @@ -1444,7 +1571,7 @@ else if (baFiles.size() == 1) script = mpjWrite.buildScript(MPJ_LogicTreeHazardCalc.class.getName(), argz); nodes = Integer.min(40, nodes); - pbsWrite.writeScript(new File(modLocalDir, "batch_hazard.slurm"), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(modLocalDir, "batch_hazard.slurm"), script, mins, nodes, remoteTotalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/nshm23/MPJ_StrictSegLogicTreeTranslation.java b/src/main/java/scratch/kevin/nshm23/MPJ_StrictSegLogicTreeTranslation.java index 4b90d4a1..1adc9a21 100644 --- a/src/main/java/scratch/kevin/nshm23/MPJ_StrictSegLogicTreeTranslation.java +++ b/src/main/java/scratch/kevin/nshm23/MPJ_StrictSegLogicTreeTranslation.java @@ -100,7 +100,7 @@ public MPJ_StrictSegLogicTreeTranslation(CommandLine cmd) throws IOException { private class AsyncLogicTreeWriter extends AbstractAsyncLogicTreeWriter { public AsyncLogicTreeWriter(SolutionProcessor processor) { - super(outputDir, processor, outputTree); + super(outputDir, processor, outputTree, true, size); } @Override diff --git a/src/main/java/scratch/kevin/nshm23/MultiRunSummaryCompare.java b/src/main/java/scratch/kevin/nshm23/MultiRunSummaryCompare.java index e0548adf..03123364 100644 --- a/src/main/java/scratch/kevin/nshm23/MultiRunSummaryCompare.java +++ b/src/main/java/scratch/kevin/nshm23/MultiRunSummaryCompare.java @@ -15,6 +15,7 @@ import org.jfree.chart.plot.DatasetRenderingOrder; import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; import org.opensha.commons.data.uncertainty.UncertainArbDiscFunc; @@ -455,7 +456,7 @@ public static void main(String[] args) throws IOException { incrFuncs.add(sigmaIncrBounds); chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(color.getRed(), color.getGreen(), color.getBlue(), 60))); + ColorUtils.transparent(color, 60))); } } } @@ -640,7 +641,7 @@ private static LogicTreeHazardCompare loadHaz(File dir, String name) throws IOEx } if (hasFM32) tree = tree.matchingAll(FaultModels.FM3_1); - return new LogicTreeHazardCompare(slt, tree, new File(dir, "results_hazard.zip"), rps, periods, spacing); + return new LogicTreeHazardCompare(slt, tree, new File(dir, "results_hazard.zip"), rps, periods, spacing, false, false); } private static FaultSystemSolution loadBA_Sol(File dir) throws IOException { diff --git a/src/main/java/scratch/kevin/nshm23/NSHM23LogicTreeFigure.java b/src/main/java/scratch/kevin/nshm23/NSHM23LogicTreeFigure.java new file mode 100644 index 00000000..650f9162 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm23/NSHM23LogicTreeFigure.java @@ -0,0 +1,26 @@ +package scratch.kevin.nshm23; + +import java.io.File; +import java.io.IOException; + +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeFigureWriter; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_LogicTreeBranch; + +public class NSHM23LogicTreeFigure { + + public static void main(String[] args) throws IOException { + LogicTree tree = LogicTree.buildExhaustive(NSHM23_LogicTreeBranch.levelsOnFault, true); + LogicTreeFigureWriter treeFig = new LogicTreeFigureWriter(tree, false, true); + treeFig.write(new File("/tmp/"), "nshm23_on_fault", true, false); + + tree = LogicTree.buildExhaustive(NSHM23_LogicTreeBranch.levelsOffFault, true); + treeFig = new LogicTreeFigureWriter(tree, false, true); + treeFig.write(new File("/tmp/"), "nshm23_off_fault", true, false); + + tree = LogicTree.buildExhaustive(NSHM23_LogicTreeBranch.levelsCombined, true); + treeFig = new LogicTreeFigureWriter(tree, false, true); + treeFig.write(new File("/tmp/"), "nshm23_combined", true, false); + } + +} diff --git a/src/main/java/scratch/kevin/nshm23/RandSamplingTreeAddSamples.java b/src/main/java/scratch/kevin/nshm23/RandSamplingTreeAddSamples.java index 8c961b5e..6d296bcf 100644 --- a/src/main/java/scratch/kevin/nshm23/RandSamplingTreeAddSamples.java +++ b/src/main/java/scratch/kevin/nshm23/RandSamplingTreeAddSamples.java @@ -14,9 +14,9 @@ import org.opensha.commons.logicTree.LogicTree; import org.opensha.commons.logicTree.LogicTreeBranch; import org.opensha.commons.logicTree.LogicTreeLevel; -import org.opensha.commons.logicTree.LogicTreeLevel.RandomlySampledLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomlyGeneratedLevel; import org.opensha.commons.logicTree.LogicTreeNode; -import org.opensha.commons.logicTree.LogicTreeNode.RandomlySampledNode; +import org.opensha.commons.logicTree.LogicTreeNode.RandomlyGeneratedNode; import org.opensha.commons.util.ExceptionUtils; import com.google.common.base.Preconditions; @@ -44,17 +44,17 @@ public static void main(String[] args) throws IOException { Random rand = new Random(987654321l); int numLevels = origTree.getLevels().size(); - List> randNodeStacks = new ArrayList<>(); + List> randNodeStacks = new ArrayList<>(); for (int l=0; l sourceLevel = origTree.getLevels().get(l); - if (sourceLevel instanceof RandomlySampledLevel) { + if (sourceLevel instanceof RandomlyGeneratedLevel) { System.out.println("Building node list for "+sourceLevel.getName()); HashSet prevSeeds = new HashSet<>(newSize); List seeds = new ArrayList<>(); // add the original nodes for (LogicTreeNode sourceNode : sourceLevel.getNodes()) { - Preconditions.checkState(sourceNode instanceof RandomlySampledNode); - RandomlySampledNode randNode = (RandomlySampledNode)sourceNode; + Preconditions.checkState(sourceNode instanceof RandomlyGeneratedNode); + RandomlyGeneratedNode randNode = (RandomlyGeneratedNode)sourceNode; Preconditions.checkState(!prevSeeds.contains(randNode.getSeed())); prevSeeds.add(randNode.getSeed()); seeds.add(randNode.getSeed()); @@ -67,12 +67,13 @@ public static void main(String[] args) throws IOException { seeds.add(seed); } try { - Constructor constructor = ((RandomlySampledLevel)sourceLevel).getClass().getConstructor(); + Constructor constructor = ((RandomlyGeneratedLevel)sourceLevel).getClass().getConstructor(); constructor.setAccessible(true); - RandomlySampledLevel modLevel = constructor.newInstance(); - modLevel.buildNodes(seeds, 1d); + RandomlyGeneratedLevel modLevel = constructor.newInstance(); +// modLevel.buildNodes(seeds, 1d); // TODO modLevels.add(modLevel); randNodeStacks.add(new LinkedList<>(modLevel.getNodes())); + throw new IllegalStateException("Not implemented"); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw ExceptionUtils.asRuntimeException(e); @@ -93,10 +94,10 @@ public static void main(String[] args) throws IOException { LogicTreeBranch modBranch = new LogicTreeBranch<>(modLevels); for (int l=0; l prevSolModules = sol.getModules(true); + sol = new FaultSystemSolution(rupSet, sol.getRateForAllRups()); + for (OpenSHA_Module module : prevSolModules) + sol.addModule(module); + } + + // remove rup MFDs (not used by Peter) + sol.removeModuleInstances(RupMFDsModule.class); + + // now update the grid list + if (sol.getGridSourceProvider() != null) { GridSourceList origGridList = sol.requireModule(GridSourceList.class); - sol.setGridSourceProvider(updateGridList(origGridList)); + System.out.println("Orig grid list Mmin="+(float)minMag(origGridList)); + sol.setGridSourceProvider(updateGridList(origGridList, stableToActiveFract, stableStaysStableFract, applyStablePropsToOverlapActive)); } sol.write(outFile); } - private static GridSourceList updateGridList(GridSourceList origGridList) { - double ACTIVE_FRACT = 2d/3d; - double STABLE_FRACT = 1d/3d; - - + private static double minMag(GridSourceList gridList) { + double minMag = Double.POSITIVE_INFINITY; + for (int l=0; l>> trtRuptureLists = new EnumMap<>(TectonicRegionType.class); List> activeList = new ArrayList<>(); trtRuptureLists.put(TectonicRegionType.ACTIVE_SHALLOW, activeList); List> stableList = new ArrayList<>(); trtRuptureLists.put(TectonicRegionType.STABLE_SHALLOW, stableList); - Map activePropsCache = new HashMap<>(); + NSHM23_WUS_FiniteRuptureConverter converter = new NSHM23_WUS_FiniteRuptureConverter(); + GriddedRupturePropertiesCache cache = new GriddedRupturePropertiesCache(); + + FocalMech mech = FocalMech.STRIKE_SLIP; for (int l=0; lR.rate).sum(); List activeRups = origGridList.getRuptures(TectonicRegionType.ACTIVE_SHALLOW, l); List stableRups = origGridList.getRuptures(TectonicRegionType.STABLE_SHALLOW, l); - if (stableRups != null) { - activeRups = new ArrayList<>(activeRups); + if (!stableRups.isEmpty()) { + double sumStable = stableRups.stream().mapToDouble(R->R.rate).sum(); + double sumActive = activeRups.stream().mapToDouble(R->R.rate).sum(); + Preconditions.checkState(activeRups.isEmpty(), "Already has both active and stable?" + + "\n\tStable:\t%s rups\trate=%s\n\tActive:\t%s rups\trate=%s", + stableRups.size(), (float)sumStable, activeRups.size(), (float)sumActive); + activeRups = new ArrayList<>(stableRups.size()); List modStableRups = new ArrayList<>(stableRups.size()); for (GriddedRupture rup : stableRups) { - GriddedRuptureProperties props = rup.properties; - GriddedRuptureProperties activeProps = new GriddedRuptureProperties( - props.magnitude, props.rake, props.dip, props.strike, props.strikeRange, - props.upperDepth, props.lowerDepth, props.length, props.hypocentralDepth, - props.hypocentralDAS, TectonicRegionType.ACTIVE_SHALLOW); - if (activePropsCache.containsKey(activeProps)) - activeProps = activePropsCache.get(activeProps); - else - activePropsCache.put(activeProps, activeProps); - - activeRups.add(new GriddedRupture(l, rup.location, activeProps, - rup.rate*ACTIVE_FRACT, rup.associatedSections, rup.associatedSectionFracts)); - modStableRups.add(new GriddedRupture(l, rup.location, props, - rup.rate*STABLE_FRACT, rup.associatedSections, rup.associatedSectionFracts)); + Preconditions.checkState((float)mech.rake() == (float)rup.properties.rake); + Preconditions.checkState((float)mech.dip() == (float)rup.properties.dip); + if (stabletoActiveFract > 0d) { + if (applyStablePropsToOverlapActive) { + // NSHMP-haz treats the "active" sources in the overlap zone as a GMM-override only, i.e., + // it continues to use the stable grid properties with Ztor=5 for all magnitudes + + // build it as stable first + GriddedRupture tempRup = converter.buildFiniteRupture(l, rup.location, rup.properties.magnitude, rup.rate*stabletoActiveFract, + mech, TectonicRegionType.STABLE_SHALLOW, rup.associatedSections, rup.associatedSectionFracts, cache); + + // now convert to active + GriddedRuptureProperties props = new GriddedRupturePropertiesBuilder(tempRup.properties) + .tectonicRegionType(TectonicRegionType.ACTIVE_SHALLOW).build(); + props = cache.getCached(props); + activeRups.add(new GriddedRupture(l, tempRup.location, props, tempRup.rate, tempRup.associatedSections, tempRup.associatedSectionFracts)); + } else { + // this is probably the right way, but not how Peter does it + activeRups.add(converter.buildFiniteRupture(l, rup.location, rup.properties.magnitude, rup.rate*stabletoActiveFract, + mech, TectonicRegionType.ACTIVE_SHALLOW, rup.associatedSections, rup.associatedSectionFracts, cache)); + } + } + // this will also correct the zTOR for nshmp-haz that puts everything at 5km (even M>6.5) + if (stableStaysStableFract > 0d) + modStableRups.add(converter.buildFiniteRupture(l, rup.location, rup.properties.magnitude, rup.rate*stableStaysStableFract, + mech, TectonicRegionType.STABLE_SHALLOW, rup.associatedSections, rup.associatedSectionFracts, cache)); } stableRups = modStableRups; @@ -93,6 +156,8 @@ private static GridSourceList updateGridList(GridSourceList origGridList) { activeList.add(activeRups); stableList.add(stableRups); + double newSumRate = activeRups.stream().mapToDouble(R->R.rate).sum() + stableRups.stream().mapToDouble(R->R.rate).sum(); + Preconditions.checkState((float)newSumRate == (float)origSumRate); } return new GridSourceList.Precomputed(origGridList.getGriddedRegion(), trtRuptureLists); diff --git a/src/main/java/scratch/kevin/nshm23/bbpScaling/ValidationEventsScalingWriter.java b/src/main/java/scratch/kevin/nshm23/bbpScaling/ValidationEventsScalingWriter.java new file mode 100644 index 00000000..18e444e0 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm23/bbpScaling/ValidationEventsScalingWriter.java @@ -0,0 +1,126 @@ +package scratch.kevin.nshm23.bbpScaling; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.math3.util.Precision; +import org.opensha.commons.data.CSVFile; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_ScalingRelationships; + +public class ValidationEventsScalingWriter { + + public static void main(String[] args) throws IOException { + NSHM23_ScalingRelationships[] scales = { + NSHM23_ScalingRelationships.AVERAGE, + NSHM23_ScalingRelationships.LOGA_C4p1, + NSHM23_ScalingRelationships.LOGA_C4p2, + NSHM23_ScalingRelationships.LOGA_C4p3, + NSHM23_ScalingRelationships.WIDTH_LIMITED, + NSHM23_ScalingRelationships.WIDTH_LIMITED_CSD, + NSHM23_ScalingRelationships.LOGA_C4p2_SQRT_LEN + }; + + List names = new ArrayList<>(); + List mags = new ArrayList<>(); + List lengths = new ArrayList<>(); + List widths = new ArrayList<>(); + + names.add("ch_v14_2_2"); + mags.add(5.4); + lengths.add(6.3); + widths.add(4.6); + + names.add("m5_5_rv_socal"); + mags.add(5.5); + lengths.add(5.62); + widths.add(5.62); + + names.add("m6_2_ss_socal"); + mags.add(6.2); + lengths.add(17.8); + widths.add(8.9); + + names.add("m6_6_rv_socal"); + mags.add(6.6); + lengths.add(28.2); + widths.add(14.1); + + names.add("m6_6_ss_socal"); + mags.add(6.6); + lengths.add(28.2); + widths.add(14.1); + + names.add("nr_v14_02_1"); + mags.add(6.7); + lengths.add(20d); + widths.add(27d); + + names.add("landers"); + mags.add(7.22); + lengths.add(80d); + widths.add(21d); + + names.add("ridgecrest_m6p4"); + mags.add(6.47); + lengths.add(16d); + widths.add(12d); + + names.add("ridgecrest_m7p2"); + mags.add(7.06); + lengths.add(52d); + widths.add(12d); + + names.add("whittier"); + mags.add(5.89); + lengths.add(10d); + widths.add(10d); + + CSVFile csv = new CSVFile<>(true); + + List header = new ArrayList<>(); + header.add("Event"); + header.add("Original Magnitude"); + header.add("Original Length"); + header.add("Original DDW"); + for (NSHM23_ScalingRelationships scale : scales) { + header.add(scale.getShortName()+" Magnitude"); + header.add(scale.getShortName()+" DDW for Original Magnitude"); + } + csv.addLine(header); + + for (int i=0; i line = new ArrayList<>(header.size()); + double mag = mags.get(i); + double length = lengths.get(i); + double width = widths.get(i); + line.add(names.get(i)); + line.add((float)mag+""); + line.add((float)length+""); + line.add((float)width+""); + + for (NSHM23_ScalingRelationships scale : scales) { + double scaledMag = scale.getMag(length*width*1e6, length*1e3, width*1e3, width*1e3, Double.NaN); + line.add((float)scaledMag+""); + double scaledWidth = width; + double testMag = scaledMag; + int iter = 0; + while (!Precision.equals(testMag, mag, 0.001)) { + double deltaMag = mag - testMag; + // width in km and mag aren't too far away in units + scaledWidth += 0.1*deltaMag; + testMag = scale.getMag(length*scaledWidth*1e6, length*1e3, scaledWidth*1e3, scaledWidth*1e3, Double.NaN); +// System.out.println("iter "+iter+" testMag="+testMag+", scaledWidth="+scaledWidth+", origScaleMag="+scaledMag+", origMag="+mag+", origWidth="+width); + iter++; +// if (iter > 50) +// System.exit(0); + } + line.add((float)scaledWidth+""); + } + csv.addLine(line); + } + csv.writeToFile(new File("/tmp/bbp_validation_events_nshm23_scaling.csv")); + } + +} diff --git a/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleLevel.java b/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleLevel.java index 1a2f9539..82bede27 100644 --- a/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleLevel.java +++ b/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleLevel.java @@ -2,40 +2,36 @@ import java.util.Random; -import org.opensha.commons.logicTree.LogicTreeLevel.RandomlySampledLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomlyGeneratedLevel; -public class RandomDefModSampleLevel extends RandomlySampledLevel { +public class RandomDefModSampleLevel extends RandomlyGeneratedLevel { - public RandomDefModSampleLevel() { - + public RandomDefModSampleLevel(String name, String shortName) { + super(name, shortName); } public RandomDefModSampleLevel(int numSamples) { - this(numSamples, new Random()); + this(numSamples, new Random().nextLong()); } - public RandomDefModSampleLevel(int numSamples, Random r) { - buildNodes(r, numSamples); + public RandomDefModSampleLevel(int numSamples, long seed) { + super("Random Deformation Model Sample", "DMSample", + "Deformation Model Sample ", "DMSample", "DMSample"); + double[] samples = new double[numSamples]; + Random r = new Random(seed); + for (int i=0; i getType() { + return RandomDefModSampleNode.class; } @Override - public Class getType() { - return RandomDefModSampleNode.class; + public RandomDefModSampleNode build(Long seed, double weight, String name, String shortName, String filePrefix) { + return new RandomDefModSampleNode(name, shortName, filePrefix, weight, seed); } } diff --git a/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleNode.java b/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleNode.java index 858c8a55..fc2bf10c 100644 --- a/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleNode.java +++ b/src/main/java/scratch/kevin/nshm23/dmCovarianceTests/RandomDefModSampleNode.java @@ -5,7 +5,7 @@ import org.opensha.commons.logicTree.Affects; import org.opensha.commons.logicTree.DoesNotAffect; import org.opensha.commons.logicTree.LogicTreeBranch; -import org.opensha.commons.logicTree.LogicTreeNode.RandomlySampledNode; +import org.opensha.commons.logicTree.LogicTreeNode.RandomlyGeneratedNode; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; @@ -13,72 +13,13 @@ @DoesNotAffect(FaultSystemRupSet.RUP_SECTS_FILE_NAME) @DoesNotAffect(FaultSystemRupSet.RUP_PROPS_FILE_NAME) @Affects(FaultSystemSolution.RATES_FILE_NAME) -public class RandomDefModSampleNode implements RandomlySampledNode { +public class RandomDefModSampleNode extends RandomlyGeneratedNode { - private String name; - private String shortName; - private String prefix; - private double weight; - private long seed; - - @SuppressWarnings("unused") // for deserialization - private RandomDefModSampleNode() {} - - RandomDefModSampleNode(int index, long seed, double weight) { - init("Deformation Model Sample "+index, "DMSample"+index, "DMSample"+index, weight, seed); - } - - @Override - public double getNodeWeight(LogicTreeBranch fullBranch) { - return weight; - } - - @Override - public String getFilePrefix() { - return prefix; - } - - @Override - public String getShortName() { - return shortName; - } - - @Override - public String getName() { - return name; - } - - @Override - public long getSeed() { - return seed; - } - - @Override - public void init(String name, String shortName, String prefix, double weight, long seed) { - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - } - - @Override - public int hashCode() { - return Objects.hash(name, prefix, seed, shortName, weight); + private RandomDefModSampleNode() { + super(); } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RandomDefModSampleNode other = (RandomDefModSampleNode) obj; - return Objects.equals(name, other.name) && Objects.equals(prefix, other.prefix) && seed == other.seed - && Objects.equals(shortName, other.shortName) - && Double.doubleToLongBits(weight) == Double.doubleToLongBits(other.weight); + public RandomDefModSampleNode(String name, String shortName, String prefix, double weight, long seed) { + super(name, shortName, prefix, weight, seed); } - } diff --git a/src/main/java/scratch/kevin/nshm23/figures/BValPlusSegModelMFDPlot.java b/src/main/java/scratch/kevin/nshm23/figures/BValPlusSegModelMFDPlot.java index 021d57c3..0fe6c38f 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/BValPlusSegModelMFDPlot.java +++ b/src/main/java/scratch/kevin/nshm23/figures/BValPlusSegModelMFDPlot.java @@ -19,6 +19,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbDiscrEmpiricalDistFunc; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; @@ -200,7 +201,7 @@ public static void main(String[] args) throws IOException { obsColor = new Color(125, 80, 145); // "indigo" PlotCurveCharacterstics obsChar = new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, obsColor); PlotCurveCharacterstics obsBoundsChar = new PlotCurveCharacterstics( - PlotLineType.SHADED_UNCERTAIN, 1f, new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 40)); + PlotLineType.SHADED_UNCERTAIN, 1f, ColorUtils.transparent(obsColor, 40)); bValIncrFuncs.add(observedIncr); bValIncrChars.add(obsChar); if (includeObsUncert) { @@ -279,7 +280,7 @@ public IncrementalMagFreqDist get() { color = segModelCPT.getColor((float)s); else color = bValCPT.getColor((float)b); - color = new Color(color.getRed(), color.getGreen(), color.getBlue(), indvTrans); + color = ColorUtils.transparent(color, indvTrans); PlotCurveCharacterstics pChar = new PlotCurveCharacterstics(PlotLineType.SOLID, 1.5f, color); allCurves[b][s] = mfd; diff --git a/src/main/java/scratch/kevin/nshm23/figures/BranchChoiceMFDsPlot.java b/src/main/java/scratch/kevin/nshm23/figures/BranchChoiceMFDsPlot.java index e3d01a98..39bb0e5e 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/BranchChoiceMFDsPlot.java +++ b/src/main/java/scratch/kevin/nshm23/figures/BranchChoiceMFDsPlot.java @@ -8,6 +8,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; import org.opensha.commons.data.uncertainty.UncertainArbDiscFunc; @@ -119,10 +120,10 @@ public static void main(String[] args) throws IOException { incrFuncs.add(dataForBounds); incrChars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 60))); + ColorUtils.transparent(obsColor, 60))); cmlFuncs.add(cmlBounded); cmlChars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 60))); + ColorUtils.transparent(obsColor, 60))); LogicTreeNode[] nodes = nodesList.get(i); String prefix = prefixes.get(i); @@ -158,7 +159,7 @@ public static void main(String[] args) throws IOException { for (int j=startCopyIndex; j> levels = new ArrayList<>(); levels.add(null); diff --git a/src/main/java/scratch/kevin/nshm23/figures/ObservedUncertainMFDComparisons.java b/src/main/java/scratch/kevin/nshm23/figures/ObservedUncertainMFDComparisons.java index a6ac90c4..4dcb8137 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/ObservedUncertainMFDComparisons.java +++ b/src/main/java/scratch/kevin/nshm23/figures/ObservedUncertainMFDComparisons.java @@ -14,6 +14,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; @@ -185,7 +186,7 @@ public static void main(String[] args) throws IOException { PlotCurveCharacterstics estBoundsChar = new PlotCurveCharacterstics(PlotLineType.DASHED, 1f, Color.GRAY); Color obsColor = new Color(125, 80, 145); // "indigo" - Color obsTransColor = new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 60); + Color obsTransColor = ColorUtils.transparent(obsColor, 60); List> levels = new ArrayList<>(); levels.add(null); @@ -402,7 +403,7 @@ public static void main(String[] args) throws IOException { chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, color)); if (modelTotBounds != null) { - Color transColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 80); + Color transColor = ColorUtils.transparent(color, 80); modelTotBounds.setName("Model Total "+((UncertainBoundedDiscretizedFunc)modelTotBounds).getBoundName()); funcs.add(modelTotBounds); chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 3f, transColor)); diff --git a/src/main/java/scratch/kevin/nshm23/figures/Regional_MFD_Plots.java b/src/main/java/scratch/kevin/nshm23/figures/Regional_MFD_Plots.java index b64b3223..ec4ca3d7 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/Regional_MFD_Plots.java +++ b/src/main/java/scratch/kevin/nshm23/figures/Regional_MFD_Plots.java @@ -24,6 +24,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.CSVFile; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; import org.opensha.commons.data.function.XY_DataSet; @@ -399,7 +400,7 @@ private static void writePlot(NSHM23_BaseRegion aReg, EvenlyDiscretizedFunc refM incrFuncs.add(dataForBounds); incrChars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 60))); + ColorUtils.transparent(obsColor, 60))); EvenlyDiscretizedFunc upperCumulative = getCmlAsFakeIncr(dataBounds.getUpper()); EvenlyDiscretizedFunc lowerCumulative = getCmlAsFakeIncr(dataBounds.getLower()); @@ -413,7 +414,7 @@ private static void writePlot(NSHM23_BaseRegion aReg, EvenlyDiscretizedFunc refM cmlBounded.setName(dataBounds.getBoundName()); cmlFuncs.add(cmlBounded); cmlChars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, - new Color(obsColor.getRed(), obsColor.getGreen(), obsColor.getBlue(), 60))); + ColorUtils.transparent(obsColor, 60))); } Preconditions.checkState(incrFuncs.size() == cmlFuncs.size()); diff --git a/src/main/java/scratch/kevin/nshm23/figures/SlipRateScattersPaleoSects.java b/src/main/java/scratch/kevin/nshm23/figures/SlipRateScattersPaleoSects.java index 3d7ddf20..c037bf35 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/SlipRateScattersPaleoSects.java +++ b/src/main/java/scratch/kevin/nshm23/figures/SlipRateScattersPaleoSects.java @@ -17,6 +17,7 @@ import org.apache.commons.math3.stat.correlation.Covariance; import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.CSVFile; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DefaultXY_DataSet; @@ -428,7 +429,7 @@ else if (prefix.contains("under")) funcs.add(0, fit); chars.add(0, new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, - new Color(color.getRed(), color.getGreen(), color.getBlue(), 120))); + ColorUtils.transparent(color, 120))); } PlotSpec spec = new PlotSpec(funcs, chars, " ", "Slip Rate Fit z-score", "Paleoseismic Rate Fit z-score"); diff --git a/src/main/java/scratch/kevin/nshm23/figures/SupraBValFigure.java b/src/main/java/scratch/kevin/nshm23/figures/SupraBValFigure.java index fd9b49e3..1b4887dd 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/SupraBValFigure.java +++ b/src/main/java/scratch/kevin/nshm23/figures/SupraBValFigure.java @@ -11,6 +11,7 @@ import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.calc.FaultMomentCalc; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DefaultXY_DataSet; @@ -230,10 +231,10 @@ public static void main(String[] args) throws IOException { grPlusCharXY2.set(transBCrossover, totRateGR2); funcs.add(grPlusCharXY1); chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 2f, - new Color(darkGreen.getRed(), darkGreen.getGreen(), darkGreen.getBlue(), 120))); + ColorUtils.transparent(darkGreen, 120))); funcs.add(grPlusCharXY2); chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 2f, - new Color(brightGreen.getRed(), brightGreen.getGreen(), brightGreen.getBlue(), 120))); + ColorUtils.transparent(brightGreen, 120))); DefaultXY_DataSet grDot1 = new DefaultXY_DataSet(); grDot1.set(grB1, totRateGR1); DefaultXY_DataSet grDot2 = new DefaultXY_DataSet(); diff --git a/src/main/java/scratch/kevin/nshm23/figures/WestCacheConnectivityFigures.java b/src/main/java/scratch/kevin/nshm23/figures/WestCacheConnectivityFigures.java index 376b973a..4465108b 100644 --- a/src/main/java/scratch/kevin/nshm23/figures/WestCacheConnectivityFigures.java +++ b/src/main/java/scratch/kevin/nshm23/figures/WestCacheConnectivityFigures.java @@ -16,6 +16,7 @@ import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DefaultXY_DataSet; import org.opensha.commons.data.function.XY_DataSet; @@ -145,7 +146,7 @@ public static void main(String[] args) throws IOException { List chars = new ArrayList<>(); Color grColor = Color.CYAN; - grColor = new Color(grColor.getRed(), grColor.getGreen(), grColor.getBlue(), 100); + grColor = ColorUtils.transparent(grColor, 100); IncrementalMagFreqDist redistBins = new IncrementalMagFreqDist(pureGR.getMinX(), pureGR.size(), pureGR.getDelta()); for (int i=0; i extraTokens = new ArrayList<>(); + // start with WUS-only + String regToken = "WUS"; + Region reg = NSHM23_RegionLoader.loadFullConterminousWUS(); + double spacing = 0.1; + String linkFromDir = "2024_02_02-nshm23_branches-WUS_FM_v3"; + String solFileName = "results_WUS_FM_v3_branch_averaged_gridded_simplified_revised2026.zip"; + +// String solFileName = "results_WUS_FM_v3_branch_averaged_gridded_simplified_revised2026_origRakes.zip"; +// extraTokens.add("origRakes"); + + File localMainDir = new File("/home/kevin/OpenSHA/fss_inversions"); + + GriddedRegion gridReg = new GriddedRegion(reg, spacing, GriddedRegion.ANCHOR_0_0); + // add site data + SiteDataValueListList siteData = new SiteDataValueListList(); + String[] dataTypes = { + CONUS_SiteDataProvider.TYPE_DEPTH_TO_1_0, + CONUS_SiteDataProvider.TYPE_DEPTH_TO_2_5, + CONUS_SiteDataProvider.TYPE_SEDIMENT_THICKNESS + }; + for (String type : dataTypes) { + CONUS_SiteDataProvider prov = new CONUS_SiteDataProvider(type, CONUS_Versions.NSHM23); + addDataIfAny(siteData, prov, gridReg.getNodeList()); + } + gridReg.setSiteData(siteData); + + Map gmpes = new EnumMap<>(TectonicRegionType.class); + gmpes.put(TectonicRegionType.ACTIVE_SHALLOW, AttenRelRef.USGS_NSHM23_ACTIVE); + gmpes.put(TectonicRegionType.STABLE_SHALLOW, AttenRelRef.USGS_NSHM23_STABLE_R2); + + extraTokens.add("origNGAW2"); + gmpes.put(TectonicRegionType.ACTIVE_SHALLOW, AttenRelRef.NGAWest_2014_AVG_NOIDRISS); + + Double maxDist = null; // use TRT defaults + boolean nshmpIMLs = false; + boolean disablePointOptimize = false; + + extraTokens.add("maxDist300"); + maxDist = 300d; + +// disablePointOptimize = true; +// extraTokens.add("noPointOptimize"); + + nshmpIMLs = true; + extraTokens.add("nshmpIMLs"); + + SolHazardMapCalc.loadSites(gridReg, gmpes); + + HPCSite hpcSite = HPCSite.USC_CARC_FMPJ; + File remoteMainDir = new File("/project2/scec_608/kmilner/fss_inversions"); + + HPCConfig hpc = HPCConfig.builder(hpcSite) + .localMainDir(localMainDir) + .remoteMainDir(remoteMainDir) + .build(); + + HazardConfig hazard = HazardConfig.builder() + .region(gridReg) + .sigmaTruncation(3d) + .gmpes(gmpes.values()) + .vs30(760d) + .maxDistance(maxDist) + .disablePointOptimizations(disablePointOptimize) + .setUseNSHMP_IMLs(nshmpIMLs) + .build(); + + + RunConfig run = RunConfig.builder() + .baseName("nshm23") + .addNameToken("hazard_validation") + .addNameToken(regToken) + .addNameTokens(extraTokens) + .build(); + + MPJ_BranchAveragedHazardScriptWriter.Request request = MPJ_BranchAveragedHazardScriptWriter.Request.builder() + .distanceCorrection(PointSourceDistanceCorrections.NSHM_2013) + .backgroundOptions(IncludeBackgroundOption.values()) + .run(run) + .linkFromDirectoryName(linkFromDir) + .solutionFileName(solFileName) + .noMFDs(true) + .supersamplingMode(SupersamplingMode.FULL) + .hazard(hazard) + .hpc(hpc) + .build(); + + new MPJ_BranchAveragedHazardScriptWriter().writeScripts(request); + } + + private static void addDataIfAny(SiteDataValueListList siteData, SiteData prov, LocationList locs) throws IOException { + SiteDataValueList data = prov.getAnnotatedValues(locs); + int count = 0; + for (int i=0; i 0) + siteData.add(data); + } + +} diff --git a/src/main/java/scratch/kevin/nshm23/hazardValidation/ComparisonPageGen.java b/src/main/java/scratch/kevin/nshm23/hazardValidation/ComparisonPageGen.java new file mode 100644 index 00000000..353aa4b4 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm23/hazardValidation/ComparisonPageGen.java @@ -0,0 +1,1256 @@ +package scratch.kevin.nshm23.hazardValidation; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import org.apache.commons.math3.stat.StatUtils; +import org.apache.commons.math3.util.Precision; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.data.Site; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.HistogramFunction; +import org.opensha.commons.data.function.LightFixedXFunc; +import org.opensha.commons.data.function.XY_DataSet; +import org.opensha.commons.data.siteData.SiteDataValue; +import org.opensha.commons.data.siteData.SiteDataValueListList; +import org.opensha.commons.data.xyz.GriddedGeoDataSet; +import org.opensha.commons.geo.GriddedRegion; +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.LocationList; +import org.opensha.commons.geo.LocationUtils; +import org.opensha.commons.geo.Region; +import org.opensha.commons.geo.json.Feature; +import org.opensha.commons.gui.plot.GeographicMapMaker; +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.param.Parameter; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.MarkdownUtils; +import org.opensha.commons.util.MarkdownUtils.TableBuilder; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.calc.HazardCurveCalculator; +import org.opensha.sha.calc.sourceFilters.FixedDistanceCutoffFilter; +import org.opensha.sha.calc.sourceFilters.SourceFilterManager; +import org.opensha.sha.calc.sourceFilters.SourceFilters; +import org.opensha.sha.earthquake.AbstractERF; +import org.opensha.sha.earthquake.ProbEqkRupture; +import org.opensha.sha.earthquake.ProbEqkSource; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.erf.BaseFaultSystemSolutionERF; +import org.opensha.sha.earthquake.faultSysSolution.modules.ClusterRuptures; +import org.opensha.sha.earthquake.faultSysSolution.modules.RupMFDsModule; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.ClusterRupture; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.util.RupCartoonGenerator; +import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc; +import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc.ReturnPeriods; +import org.opensha.sha.earthquake.param.IncludeBackgroundOption; +import org.opensha.sha.earthquake.param.IncludeBackgroundParam; +import org.opensha.sha.earthquake.param.UseRupMFDsParam; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.util.NSHM23_RegionLoader; +import org.opensha.sha.earthquake.util.GridCellSupersamplingSettings; +import org.opensha.sha.earthquake.util.GriddedSeismicitySettings; +import org.opensha.sha.faultSurface.RuptureSurface; +import org.opensha.sha.imr.AttenRelRef; +import org.opensha.sha.imr.ScalarIMR; +import org.opensha.sha.imr.attenRelImpl.nshmp.NSHMP_GMM_Wrapper; +import org.opensha.sha.imr.param.IntensityMeasureParams.PGA_Param; +import org.opensha.sha.imr.param.IntensityMeasureParams.SA_Param; +import org.opensha.sha.imr.param.OtherParams.SigmaTruncLevelParam; +import org.opensha.sha.imr.param.OtherParams.SigmaTruncTypeParam; +import org.opensha.sha.util.SiteTranslator; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Doubles; + +import org.opensha.nshmp.shaded.gmm.NshmpGmm; +import org.opensha.nshmp.shaded.gmm.NshmpGmmInput; +import org.opensha.nshmp.shaded.model.NshmpHazardModel; +import org.opensha.nshmp.shaded.model.NshmErf; +import net.mahdilamb.colormap.Colors; +import scratch.kevin.nshm23.hazardValidation.WrapperRupSetRupMapper.WrapperMatch; + +public class ComparisonPageGen { + + public static void main(String[] args) throws IOException { + String imtName = "PGA"; + String imtDir = "PGA"; + double period = 0d; + +// String imtName = "1s SA"; +// String imtDir = "SA1P0"; +// double period = 1d; + + double closestDist = Double.POSITIVE_INFINITY; + for (Location loc : NSHM23_RegionLoader.GridSystemRegions.CEUS_STABLE.load().getBorder()) + if (loc.lat < 49d) + closestDist = Math.min(closestDist, LocationUtils.horzDistanceFast(loc, new Location(loc.lat, -115))); + System.out.println("Closest CEUS grid node to the -115 boundary: "+(int)closestDist+" km"); + +// ReturnPeriods[] rps = ReturnPeriods.values(); + ReturnPeriods[] rps = { ReturnPeriods.TWO_IN_50, ReturnPeriods.TEN_IN_50 }; + + EnumSet trts = EnumSet.of( + TectonicRegionType.ACTIVE_SHALLOW + , TectonicRegionType.STABLE_SHALLOW +// , TectonicRegionType.SUBDUCTION_INTERFACE +// , TectonicRegionType.SUBDUCTION_SLAB + ); + + int vs30 = 760; + + String nameMine = "OpenSHA"; + String nameTheirs = "NSHMP-Haz"; + String suffixMine = "opensha"; + String suffixTheirs = "ext"; + + File fssDir = new File("/home/kevin/OpenSHA/fss_inversions"); + File nshm23Dir = new File(fssDir, "2024_02_02-nshm23_branches-WUS_FM_v3/"); + + EnumSet bgOps = EnumSet.allOf(IncludeBackgroundOption.class); +// EnumSet bgOps = EnumSet.of(IncludeBackgroundOption.EXCLUDE); +// EnumSet bgOps = EnumSet.of(IncludeBackgroundOption.ONLY); +// File inputDir = new File(fssDir, "2026_07_30-nshm23-hazard_validation-WUS"); +// File inputDir = new File(fssDir, "2026_07_30-nshm23-hazard_validation-WUS-maxDist300"); +// File inputDir = new File(fssDir, "2026_07_30-nshm23-hazard_validation-WUS-maxDist300-nshmpIMLs"); +// File inputDir = new File(fssDir, "2026_07_31-nshm23-hazard_validation-WUS-origRakes-maxDist300-nshmpIMLs"); +// File inputDir = new File(fssDir, "2026_08_01-nshm23-hazard_validation-WUS-origNGAW2-maxDist300-nshmpIMLs"); + File inputDir = new File(fssDir, "2026_08_01-nshm23-hazard_validation-WUS-origRakes-origNGAW2-maxDist300-nshmpIMLs"); + File inputSolFile = new File(nshm23Dir, "results_WUS_FM_v3_branch_averaged_gridded_simplified_revised2026.zip"); + boolean rupMFDs = false; + + File compDirActiveSub = new File("/home/kevin/OpenSHA/nshm23/nshmp-haz-models/ext_hazard_calcs/" + + "conus_2023.R2-no_gmm_region-by_source-active_subduction-vs760-0p1-20260515-95ae7e82fbb85d"); +// + "conus_2023.R2-no_gmm_region-by_source-all-vs760-0p1-20260515-ad25787f499c13"); // hack for all, not just active + File compDirStable = new File("/home/kevin/OpenSHA/nshm23/nshmp-haz-models/ext_hazard_calcs/" + + "conus_2023.R2-no_gmm_region-by_source-stable-vs760-0p1-20260515-ea28700aef6c6f"); + File outputDir = new File(inputDir, "nshmp_haz_comparisons_"+imtDir); + + File modelDir = new File("/data/kevin/nshm23/nshmp-haz-models/nshm-conus-6.1.3"); +// File modelDir = new File("/data/kevin/nshm23/nshmp-haz-models/nshm-conus-6.2.0"); + + boolean doWrapperCalc = false; + + GriddedRegion mapReg = GriddedRegion.fromFeature(Feature.read(new File(inputDir, "gridded_region.geojson"))); + boolean plotTraces = false; + + Region zoomReg = null; + + Range curveXRange = new Range(1e-3, 1e1); + Range curveYRange = new Range(1e-6, 1e-0); +// Range curveXRange = new Range(1e-2, 1e1); +// Range curveYRange = new Range(1e-6, 1e-2); + + // the bay area paleo issue +// zoomReg = new Region(new Location(37.5, -122.5), new Location(38.5, -121.5)); + + // the rake-bin issue in NE CA +// curveXRange = new Range(1e-1, 1e1); +// curveYRange = new Range(1e-5, 2e-3); +// zoomReg = new Region(new Location(40, -122), new Location(41, -120)); + + // the dip issue near Santa Barbara +// curveXRange = new Range(1e-1, 1e1); +// curveYRange = new Range(1e-5, 2e-3); +// zoomReg = new Region(new Location(34, -121), new Location(35, -118)); + + // gridded degugging in Montana +// zoomReg = new Region(new Location(45, -110), new Location(49, -105)); + + // wider gridded degugging in NE corner +// zoomReg = new Region(new Location(40, -115), new Location(49, -105)); + + // Nevada-ish + zoomReg = new Region(new Location(35, -121), new Location(43, -113)); + + SourceFilterManager sourceFilters = new SourceFilterManager(SourceFilters.TRT_DIST_CUTOFFS); +// SourceFilterManager sourceFilters = new SourceFilterManager(SourceFilters.FIXED_DIST_CUTOFF); +// sourceFilters.getFilterInstance(FixedDistanceCutoffFilter.class).setMaxDistance(300d); + + Map gmmRefs = Map.of( + TectonicRegionType.ACTIVE_SHALLOW, AttenRelRef.USGS_NSHM23_ACTIVE, + TectonicRegionType.STABLE_SHALLOW, AttenRelRef.USGS_NSHM23_STABLE_R2); +// TectonicRegionType.ACTIVE_SHALLOW, AttenRelRef.NGAWest_2014_AVG_NOIDRISS); + Map gmms = new HashMap<>(); + Map wrapperGMMs = gmms; + for (TectonicRegionType trt : gmmRefs.keySet()) { + ScalarIMR gmm = gmmRefs.get(trt).get(); + gmm.setParamDefaults(); + gmm.getParameter(SigmaTruncTypeParam.NAME).setValue(SigmaTruncTypeParam.SIGMA_TRUNC_TYPE_1SIDED); + gmm.getParameter(SigmaTruncLevelParam.NAME).setValue(3d); + if (period == 0d) { + gmm.setIntensityMeasure(PGA_Param.NAME); + } else { + gmm.setIntensityMeasure(SA_Param.NAME); + SA_Param.setPeriodInSA_Param(gmm.getIntensityMeasure(), period); + } + gmms.put(trt, gmm); + } + +// NSHMP_GMM_Wrapper mixedForWrapperGMM = new NSHMP_GMM_Wrapper.WeightedCombination( +// Map.of(NshmpGmm.TOTAL_TREE_CONUS_ACTIVE_CRUST_2023, 2d/3d, +// NshmpGmm.TOTAL_TREE_CONUS_STABLE_CRUST_2023, 1d/3d), "Hack Mixed GMM", "HackMixed", false); +// mixedForWrapperGMM.setParamDefaults(); +// mixedForWrapperGMM.getParameter(SigmaTruncLevelParam.NAME).setValue(3d); +// if (period == 0d) { +// mixedForWrapperGMM.setIntensityMeasure(PGA_Param.NAME); +// } else { +// mixedForWrapperGMM.setIntensityMeasure(SA_Param.NAME); +// SA_Param.setPeriodInSA_Param(mixedForWrapperGMM.getIntensityMeasure(), period); +// } +// wrapperGMMs = Map.of(TectonicRegionType.ACTIVE_SHALLOW, gmms.get(TectonicRegionType.ACTIVE_SHALLOW), +// TectonicRegionType.STABLE_SHALLOW, mixedForWrapperGMM); + + File sourcesDirActiveSub = new File(compDirActiveSub, "vs30-"+vs30+"/"+imtDir+"/source"); + File sourcesDirStable = new File(compDirStable, "vs30-"+vs30+"/"+imtDir+"/source"); + boolean convertToProb = true; + + System.out.println("Output dir: "+outputDir.getAbsolutePath()); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + File resourcesDir = new File(outputDir, "resources"); + Preconditions.checkState(resourcesDir.exists() || resourcesDir.mkdir()); + List sites = SolHazardMapCalc.loadSites(mapReg, gmmRefs); + + Map myCurvesMap = new EnumMap<>(IncludeBackgroundOption.class); + for (IncludeBackgroundOption bgOp : bgOps) + myCurvesMap.put(bgOp, loadRegularCurves(inputDir, bgOp, mapReg, period)); + + Map extCurvesMap = new EnumMap<>(IncludeBackgroundOption.class); + boolean loadFault = bgOps.contains(IncludeBackgroundOption.INCLUDE) || bgOps.contains(IncludeBackgroundOption.EXCLUDE); + boolean loadGrid = bgOps.contains(IncludeBackgroundOption.INCLUDE) || bgOps.contains(IncludeBackgroundOption.ONLY); + + for (TectonicRegionType trt : trts) { + File sourceDir = trt == TectonicRegionType.STABLE_SHALLOW ? sourcesDirStable : sourcesDirActiveSub; + if (trt == TectonicRegionType.ACTIVE_SHALLOW || trt == TectonicRegionType.STABLE_SHALLOW) { + if (loadFault) { + DiscretizedFunc[] curves = loadExtCurves(new File(sourceDir, "FAULT/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.EXCLUDE); + if (trt == TectonicRegionType.STABLE_SHALLOW) { + // "fault cluster" is interface in the active_subduction dir, but crustal for stable + curves = loadExtCurves(new File(sourceDir, "FAULT_CLUSTER/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.EXCLUDE); + } + curves = loadExtCurves(new File(sourceDir, "FAULT_SYSTEM/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.EXCLUDE); + } + if (loadGrid) { + DiscretizedFunc[] curves = loadExtCurves(new File(sourceDir, "GRID/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.ONLY); + // TODO: is zone grid or fault? + curves = loadExtCurves(new File(sourceDir, "ZONE/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.ONLY); + } + } else if (trt == TectonicRegionType.SUBDUCTION_INTERFACE) { + if (loadFault) { + DiscretizedFunc[] curves = loadExtCurves(new File(sourceDir, "INTERFACE/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.EXCLUDE); + // "fault cluster" is interface in the active_subduction dir, but crustal for stable + curves = loadExtCurves(new File(sourceDir, "FAULT_CLUSTER/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.EXCLUDE); + } + } else if (trt == TectonicRegionType.SUBDUCTION_SLAB) { + if (loadGrid) { + DiscretizedFunc[] curves = loadExtCurves(new File(sourceDir, "SLAB/curves.csv"), mapReg); + addTo(extCurvesMap, curves, IncludeBackgroundOption.INCLUDE, IncludeBackgroundOption.ONLY); + } + } + } + + // convert to probabilities + if (convertToProb) { + for (IncludeBackgroundOption bgOp : List.copyOf(extCurvesMap.keySet())) + extCurvesMap.put(bgOp, ratesToProbs(extCurvesMap.get(bgOp))); + } + + FaultSystemSolution sol = null; + if (plotTraces || doWrapperCalc || zoomReg != null) + sol = FaultSystemSolution.load(inputSolFile); + GeographicMapMaker fullMapMaker = new GeographicMapMaker(mapReg); + GeographicMapMaker zoomMapMaker = null; + if (zoomReg != null) { + zoomMapMaker = new GeographicMapMaker(zoomReg); + zoomMapMaker.setFaultSections(sol.getRupSet().getFaultSectionDataList()); + zoomMapMaker.setSectOutlineChar(null); + } + if (plotTraces) { + fullMapMaker.setFaultSections(sol.getRupSet().getFaultSectionDataList()); + fullMapMaker.setSectOutlineChar(null); + } +// mapMaker.setDefaultPlotWidth(1000); + + BaseFaultSystemSolutionERF solERF = new BaseFaultSystemSolutionERF(); + if (doWrapperCalc) { + solERF.setSolution(sol); + solERF.setGriddedSeismicitySettings(solERF.getGriddedSeismicitySettings().forSupersamplingSettings(GridCellSupersamplingSettings.QUICK)); + if (sol.hasModule(RupMFDsModule.class)) + solERF.setParameter(UseRupMFDsParam.NAME, rupMFDs); + solERF.getTimeSpan().setDuration(1d); + } + + WrapperMatch[] wrapperMappings = null; + + Color transparent = new Color(255, 255, 255, 0); + + CPT hazCPT = GMT_CPT_Files.RAINBOW_UNIFORM.instance().rescale(-3, 1); + hazCPT.setLog10(true); + hazCPT.setNanColor(transparent); + +// CPT pDiffCPT = MethodsAndIngredientsHazChangeFigures.getCenterMaskedCPT(GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance(), 10d, 50d); + CPT pDiffCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-10d, 10d); + pDiffCPT.setNanColor(transparent); + + NshmpHazardModel model = null; + if (doWrapperCalc) + model = NshmpHazardModel.load(modelDir.toPath()); + + double diffScale; + if (period == 0d) + diffScale = 0.1; + else + diffScale = 0.05; + CPT diffCPT = GMT_CPT_Files.DIVERGING_BAM_UNIFORM.instance().reverse().rescale(-diffScale, diffScale); + diffCPT.setNanColor(transparent); + + List lines = new ArrayList<>(); + + lines.add("# Hazard Comparisons, "+nameMine+" vs "+nameTheirs); + lines.add(""); + + lines.add("This page compares "+nameMine+" and "+nameTheirs+" hazard maps."); + lines.add(""); + + IncludeBackgroundOption[] bgOrder = { + IncludeBackgroundOption.INCLUDE, + IncludeBackgroundOption.EXCLUDE, + IncludeBackgroundOption.ONLY + }; + + int tocIndex = lines.size(); + String topLink = "*[(top)](#table-of-contents)*"; + + for (IncludeBackgroundOption bgOp : bgOrder) { + if (!bgOps.contains(bgOp)) + continue; + DiscretizedFunc[] myCurves = myCurvesMap.get(bgOp); + DiscretizedFunc[] extCurves = extCurvesMap.get(bgOp); + + NshmErf wrapperERF = null; + if (doWrapperCalc) { + wrapperERF = new NshmErf(model, trts, bgOp); + wrapperERF.getTimeSpan().setDuration(1d); + wrapperERF.updateForecast(); + + solERF.setParameter(IncludeBackgroundParam.NAME, bgOp); + solERF.updateForecast(); + } + + String mapLabelAdd; + switch (bgOp) { + case INCLUDE: + lines.add("## Total hazard (fault+gridded)"); + mapLabelAdd = ""; + break; + case EXCLUDE: + lines.add("## On-fault hazard"); + mapLabelAdd = "On-fault "; + break; + case ONLY: + lines.add("## Gridded hazard"); + mapLabelAdd = "Gridded "; + break; + default: + throw new IllegalArgumentException("Unexpected value: " + bgOp); + } + lines.add(topLink); lines.add(""); + + for (ReturnPeriods rp : rps) { + GriddedGeoDataSet myMap = curvestoMap(myCurves, mapReg, rp); + GriddedGeoDataSet extMap = curvestoMap(extCurves, mapReg, rp); + + System.out.println("Doing "+bgOp+", "+rp); + + lines.add("### "+rp.label); + lines.add(topLink); lines.add(""); + + boolean[] zooms = zoomReg == null ? new boolean[] {false} : new boolean[] {false,true}; + + for (boolean zoom : zooms) { + String hazLabel = imtName+", "+rp.label; + String prefix = bgOp.name()+"_"+rp.name(); + + boolean curves = zoom || zooms.length == 1; + + GeographicMapMaker mapMaker = zoom ? zoomMapMaker : fullMapMaker; + Region plotReg = zoom ? zoomReg : mapReg; + if (zoom) { + prefix += "_zoom"; + + lines.add("#### Zoomed region"); + lines.add(topLink); lines.add(""); + } + + TableBuilder table = MarkdownUtils.tableBuilder(); + + table.addLine(nameMine, nameTheirs); + + table.initNewLine(); + + mapMaker.plotXYZData(myMap, hazCPT, mapLabelAdd+nameMine+", "+hazLabel+" (g)"); + mapMaker.plot(resourcesDir, prefix+"_"+suffixMine, " "); + table.addColumn("![Map]("+resourcesDir.getName()+"/"+prefix+"_"+suffixMine+".png)"); + mapMaker.plotXYZData(extMap, hazCPT, mapLabelAdd+nameTheirs+", "+hazLabel+" (g)"); + mapMaker.plot(resourcesDir, prefix+"_"+suffixTheirs, " "); + table.addColumn("![Map]("+resourcesDir.getName()+"/"+prefix+"_"+suffixTheirs+".png)"); + + table.finalizeLine(); + + table.addLine(MarkdownUtils.boldCentered("Ratio"), MarkdownUtils.boldCentered("Difference")); + + GriddedGeoDataSet pDiff = mapPDiff(myMap, extMap); + GriddedGeoDataSet diff = mapDiff(myMap, extMap); + + table.initNewLine(); + + mapMaker.plotXYZData(pDiff, pDiffCPT, mapLabelAdd+nameMine+" vs "+nameTheirs+", % Change, "+hazLabel); + mapMaker.plot(resourcesDir, prefix+"_pDiff", " "); + table.addColumn("![Map]("+resourcesDir.getName()+"/"+prefix+"_pDiff.png)"); + mapMaker.plotXYZData(diff, diffCPT, mapLabelAdd+nameMine+" - "+nameTheirs+", "+hazLabel+" (g)"); + mapMaker.plot(resourcesDir, prefix+"_diff", " "); + table.addColumn("![Map]("+resourcesDir.getName()+"/"+prefix+"_diff.png)"); + + table.finalizeLine(); + table.addLine(diffStr(pDiff, true, plotReg), diffStr(diff, false, plotReg)); + + lines.addAll(table.build()); + lines.add(""); + + if (curves) { + double maxDiff = Double.NEGATIVE_INFINITY; + double minDiff = Double.POSITIVE_INFINITY; + int maxDiffIndex = -1; + int minDiffIndex = -1; + for (int i=0; i maxDiff) { + maxDiff = v; + maxDiffIndex = i; + } + if (v < minDiff) { + minDiff = v; + minDiffIndex = i; + } + } + } + + table = MarkdownUtils.tableBuilder(); + + table.addLine("Min difference", "Max difference"); + + table.initNewLine(); + Site minSite = sites.get(minDiffIndex); + Site maxSite = sites.get(maxDiffIndex); + HazardCurveCalculator calc = new HazardCurveCalculator(sourceFilters); + for (boolean min : new boolean[] {true,false}) { + int index = min ? minDiffIndex : maxDiffIndex; + Preconditions.checkState(index >= 0); + DiscretizedFunc myCurve = myCurves[index]; + DiscretizedFunc extCurve = extCurves[index]; + Location loc = mapReg.getLocation(index); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + myCurve.setName(nameMine); + extCurve.setName(nameTheirs); + + funcs.add(extCurve); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Colors.tab_orange)); + + Site site = min ? minSite : maxSite; + + if (doWrapperCalc) { + DiscretizedFunc wrappedCurve = extCurve.deepClone(); + DiscretizedFunc logCurve = new ArbitrarilyDiscretizedFunc(); + for (int i=0; i param : site) + str += "

"+param.getName()+": "+param.getValue(); + table.addColumn(str); + } + table.finalizeLine(); + + if (doWrapperCalc && bgOp == IncludeBackgroundOption.EXCLUDE) { + // add distance hists + double maxDist = 50d; + double maxQuickDist = 60d; + int bins = 50; + + if (wrapperMappings == null) + wrapperMappings = WrapperRupSetRupMapper.map(sol, wrapperERF); + WrapperMatch[] myWrapperMappings = wrapperMappings; + + List minFSSRups = getRupIndexesWithinCutoff(sol, mapReg.getLocation(minDiffIndex), maxQuickDist); + List minWrapperSources = minFSSRups.stream().map( + rupIndex->myWrapperMappings[rupIndex].wrapperSource()).collect(Collectors.toList()); + List minWrapperRups = minFSSRups.stream().map( + rupIndex->myWrapperMappings[rupIndex].wrapperRup()).collect(Collectors.toList()); + List maxFSSRups = getRupIndexesWithinCutoff(sol, mapReg.getLocation(maxDiffIndex), maxQuickDist); + List maxWrapperSources = maxFSSRups.stream().map( + rupIndex->myWrapperMappings[rupIndex].wrapperSource()).collect(Collectors.toList()); + List maxWrapperRups = maxFSSRups.stream().map( + rupIndex->myWrapperMappings[rupIndex].wrapperRup()).collect(Collectors.toList()); + + int minRupIndex = -1; + int maxRupIndex = -1; + + System.out.println("Max rate source within "+(float)maxDist+" km"); + table.initNewLine(); + for (boolean min : new boolean[] {true,false}) { + Site site = min ? minSite : maxSite; + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + List fssIndexes = min ? minFSSRups : maxFSSRups; + List wrapperRups = min ? minWrapperRups : maxWrapperRups; + Preconditions.checkState(fssIndexes.size() == wrapperRups.size()); + + if (fssIndexes.isEmpty()) { + table.addColumn(""); + continue; + } + + // now find the rupture with the biggest change at our gm + int siteIndex = min ? minDiffIndex : maxDiffIndex; + double targetIM = curveVal(myCurves[siteIndex], rp); + + double maxDiffForRateDiff = 0d; + double maxRateDiff = 0d; + int maxDiffRupIndex = -1; + DiscretizedFunc maxDiffMyIMs = null; + DiscretizedFunc maxDiffTheirIMs = null; + ProbEqkRupture fssRup = null; + + for (int r=0; r maxRateDiff) { + maxRateDiff = rateDiff; + maxDiffMyIMs = myIMs; + maxDiffTheirIMs = theirIMs; + maxDiffRupIndex = rupIndex; + fssRup = myRup; + maxDiffForRateDiff = myDiff; + } + } + + if (min) + minRupIndex = maxDiffRupIndex; + else + maxRupIndex = maxDiffRupIndex; + + ProbEqkRupture wrapperRup = wrapperMappings[maxDiffRupIndex].wrapperRup(); + TectonicRegionType trt = wrapperMappings[maxDiffRupIndex].wrapperSource().getTectonicRegionType(); + ScalarIMR gmm = gmms.size() == 1 ? gmms.values().iterator().next() : gmms.get(trt); + String fssRupName = "M"+(float)fssRup.getMag()+", rake="+(float)fssRup.getAveRake() + +", P="+(float)fssRup.getProbability(); + String wrapperRupName = "M"+(float)wrapperRup.getMag()+", rake="+(float)wrapperRup.getAveRake() + +", P="+(float)wrapperRup.getProbability(); + + NSHMP_GMM_Wrapper wrapGMM = gmm instanceof NSHMP_GMM_Wrapper ? (NSHMP_GMM_Wrapper)gmm : null; + + if (min) + System.out.println("Min change rup for IM="+(float)targetIM+": "+maxDiffRupIndex); + else + System.out.println("Max change rup for IM="+(float)targetIM+": "+maxDiffRupIndex); + System.out.println("\tDiff: "+maxDiffForRateDiff); + System.out.println("\tRate: "+sol.getRateForRup(maxDiffRupIndex)); + System.out.println("\tRate-Diff: "+maxRateDiff); + System.out.println("\tFSS:\t"+fssRupName); + System.out.println("\t\tPOE:\t"+maxDiffMyIMs.getInterpolatedY_inLogXLogYDomain(targetIM)); + if (wrapGMM != null) { + wrapGMM.setEqkRupture(fssRup); + System.out.println("\t\tGmmInput:\t"+wrapGMM.getCurrentGmmInput()); + } + System.out.println("\tWrapper:\t"+wrapperRupName); + System.out.println("\t\tPOE:\t"+maxDiffTheirIMs.getInterpolatedY_inLogXLogYDomain(targetIM)); + if (wrapGMM != null) { + wrapGMM.setEqkRupture(wrapperRup); + System.out.println("\t\tGmmInput:\t"+wrapGMM.getCurrentGmmInput()); + } + + maxDiffMyIMs.setName(nameMine+" "+fssRupName); + funcs.add(maxDiffMyIMs); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Colors.tab_blue)); + + maxDiffTheirIMs.setName(nameTheirs+" "+wrapperRupName); + funcs.add(maxDiffTheirIMs); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Colors.tab_green)); + + if (wrapGMM != null) { + // extra tests + wrapGMM.setEqkRupture(fssRup); + NshmpGmmInput fssInput = wrapGMM.getCurrentGmmInput(); + wrapGMM.setEqkRupture(wrapperRup); + NshmpGmmInput wrapInput = wrapGMM.getCurrentGmmInput(); + + List updates = new ArrayList<>(); + List updateChars = new ArrayList<>(); + List updateNames = new ArrayList<>(); + + updates.add(NshmpGmmInput.builder().fromCopy(fssInput) + .rake(wrapInput.rake).build()); + updateNames.add("wrapper rake"); + updateChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 3f, Colors.tab_orange)); + + updates.add(NshmpGmmInput.builder().fromCopy(fssInput) + .rake(wrapInput.rake).dip(wrapInput.dip).build()); + updateNames.add("wrapper rake/dip"); + updateChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 3f, Colors.tab_purple)); + + updates.add(NshmpGmmInput.builder().fromCopy(fssInput) + .rake(wrapInput.rake).dip(wrapInput.dip).zHyp(wrapInput.zHyp).build()); + updateNames.add("wrapper rake/dip/zHyp"); + updateChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 3f, Colors.tab_olive)); + + for (int u=0; u= 0 && maxRupIndex >= 0) { + FaultSystemRupSet rupSet = sol.getRupSet(); + ClusterRuptures cRups = rupSet.requireModule(ClusterRuptures.class); + RupCartoonGenerator.plotRupture(resourcesDir, prefix+"_rup_min", cRups.get(minRupIndex), + "Rup "+minRupIndex+" M"+(float)rupSet.getMagForRup(minRupIndex) + +" rake="+(float)rupSet.getAveRakeForRup(minRupIndex) + +" dip="+(float)rupSet.getSurfaceForRupture(minRupIndex, 1d).getAveDip(), false, true); + RupCartoonGenerator.plotRupture(resourcesDir, prefix+"_rup_max", cRups.get(maxRupIndex), + "Rup "+maxRupIndex+" M"+(float)rupSet.getMagForRup(maxRupIndex) + +" rake="+(float)rupSet.getAveRakeForRup(maxRupIndex) + +" dip="+(float)rupSet.getSurfaceForRupture(maxRupIndex, 1d).getAveDip(), false, true); + + table.addLine("![Min rup]("+resourcesDir.getName()+"/"+prefix+"_rup_min.png)", + "![Max rup]("+resourcesDir.getName()+"/"+prefix+"_rup_max.png)"); + } + + // rake hist + table.initNewLine(); + for (boolean min : new boolean[] {true,false}) { + int index = min ? minDiffIndex : maxDiffIndex; + Preconditions.checkState(index >= 0); + Location loc = mapReg.getLocation(index); + List wrapperRups = min ? minWrapperRups : maxWrapperRups; + List fssIndexes = min ? minFSSRups : maxFSSRups; + List fssSources = fssIndexes.stream().map( + I->solERF.getSource(solERF.getSrcIndexForFltSysRup(I))).collect(Collectors.toList()); + + EvenlyDiscretizedFunc rakeHistFSS = new EvenlyDiscretizedFunc(-180d, 180d, 181); + EvenlyDiscretizedFunc rakeHistWrapper = new EvenlyDiscretizedFunc(-180d, 180d, 181); + + for (ProbEqkSource source : fssSources) + for (ProbEqkRupture rup : source) + rakeHistFSS.add(rakeHistFSS.getClosestXIndex(rup.getAveRake()), rup.getMeanAnnualRate(1d)); + for (ProbEqkRupture rup : wrapperRups) + rakeHistWrapper.add(rakeHistWrapper.getClosestXIndex(rup.getAveRake()), rup.getMeanAnnualRate(1d)); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + rakeHistWrapper.setName("Wrapper"); + funcs.add(rakeHistWrapper); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, ColorUtils.transparent(Colors.tab_green, 127))); + + rakeHistFSS.setName(nameMine); + funcs.add(rakeHistFSS); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, ColorUtils.transparent(Colors.tab_blue, 127))); + + PlotSpec plot = new PlotSpec(funcs, chars, " ", "Nearby rupture rake (degrees)", "Rate"); + plot.setLegendInset(RectangleAnchor.TOP_LEFT); + + HeadlessGraphPanel gp = PlotUtils.initScreenHeadless(); + + gp.drawGraphPanel(plot, false, false, new Range(-180, 180d), null); + + String histPrefix = prefix+"_hist_rake"; + if (min) + histPrefix += "_min"; + else + histPrefix += "_max"; + + PlotUtils.writePlots(resourcesDir, histPrefix, gp, 800, 800, true, true, false); + + table.addColumn("![Rake hist]("+resourcesDir.getName()+"/"+histPrefix+".png)"); + } + table.finalizeLine(); + + for (int d=0; d<3; d++) { + String distName; + HistogramFunction histFSS; + BiFunction distFunc; + if (d == 0) { + distName = "Rrup"; + histFSS = new HistogramFunction(0d, maxDist, bins); + distFunc = (S,L) -> S.getDistanceRup(L); + } else if (d == 1) { + distName = "Rjb"; + histFSS = new HistogramFunction(0d, maxDist, bins); + distFunc = (S,L) -> S.getDistanceJB(L); + } else { + distName = "RX"; + histFSS = new HistogramFunction(-maxDist, maxDist, bins); + distFunc = (S,L) -> S.getDistanceX(L); + } + + EvenlyDiscretizedFunc histWrapper = histFSS.deepClone(); + + table.initNewLine(); + for (boolean min : new boolean[] {true,false}) { + int index = min ? minDiffIndex : maxDiffIndex; + Preconditions.checkState(index >= 0); + Location loc = mapReg.getLocation(index); + List wrapperSources = min ? minWrapperSources : maxWrapperSources; + List fssIndexes = min ? minFSSRups : maxFSSRups; + List fssSources = fssIndexes.stream().map( + I->solERF.getSource(solERF.getSrcIndexForFltSysRup(I))).collect(Collectors.toList()); + + histFSS.scale(0d); + histWrapper.scale(0d); + + fillDistanceHist(fssSources, distFunc, histFSS, loc); + fillDistanceHist(wrapperSources, distFunc, histWrapper, loc); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + histWrapper.setName(null); + funcs.add(histWrapper); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, ColorUtils.transparent(Colors.tab_green, 127))); + + histFSS.setName(null); + funcs.add(histFSS); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, ColorUtils.transparent(Colors.tab_blue, 127))); + + EvenlyDiscretizedFunc cmlFSS = new EvenlyDiscretizedFunc(histFSS.getMinX()-0.5*histFSS.getDelta(), histFSS.size(), histFSS.getDelta()); + double sum = 0d; + for (int i=0; i csv = CSVFile.readFile(csvFile, true); + + double[] xVals = new double[csv.getNumCols()-2]; + for (int i=0; i curve.getMaxX()) + interpY[i] = 0d; + else + interpY[i] = curve.getInterpolatedY_inLogXDomain(x); + } + ret[n] = new LightFixedXFunc(xVals, interpY); + } + return ret; + } + + private static void addTo(Map map, DiscretizedFunc[] curves, + IncludeBackgroundOption... bgOps) { + for (IncludeBackgroundOption bgOp : bgOps) + map.put(bgOp, addTo(map.get(bgOp), curves)); + } + + private static DiscretizedFunc[] addTo(DiscretizedFunc[] current, DiscretizedFunc[]... allCurves) { +// System.out.println("addTo; current: "+(current == null ? "null" : "non-null")); +// System.out.println("allCurves.length: "+allCurves.length); +// for (int i=0; i 1) { + DiscretizedFunc[] comb = add(allCurves); + return add(current, comb); + } else { + Preconditions.checkState(allCurves.length == 1); + return add(current, allCurves[0]); + } + } + + private static DiscretizedFunc[] add(DiscretizedFunc[]... allCurves) { + DiscretizedFunc[] ret = new DiscretizedFunc[allCurves[0].length]; + + double[] xVals = new double[allCurves[0][0].size()]; + for (int i=0; i allConsidered = new ArrayList<>(); + List allConsideredAbs = new ArrayList<>(); + + for (int i=0; iavg="+df.format(avg)+"; avgAbs="+df.format(avgAbs) + +"

median="+df.format(median)+"; medianAbs="+df.format(medianAbs) + +"

"+numNan+" NaN; "+numInf+" inf"; + } + + private static List getSourcesWithinCutoff(AbstractERF erf, Location loc, double cutoff) { + Site site = new Site(loc); + return erf.getSourceList().parallelStream().filter(S->(float)S.getMinDistance(site) <= (float)cutoff).collect(Collectors.toList()); + } + + private static List getRupIndexesWithinCutoff(FaultSystemSolution sol, Location loc, double cutoff) { + List ret = new ArrayList<>(); + FaultSystemRupSet rupSet = sol.getRupSet(); + for (int rupIndex=0; rupIndex sources, BiFunction distFunc, + EvenlyDiscretizedFunc hist, Location loc) { + float min = (float)(hist.getMinX() < 0 ? hist.getMinX() - 0.5*hist.getDelta() : 0d); + float max = (float)(hist.getMaxX() + 0.5*hist.getDelta()); + sources.parallelStream().forEach((source)->{ + for (ProbEqkRupture rup : source) { + double dist = distFunc.apply(rup.getRuptureSurface(), loc); + if ((float)dist >= min && (float)dist <= max) { + int index = hist.getClosestXIndex(dist); + synchronized (hist) { + hist.add(index, rup.getMeanAnnualRate(1d)); + } + } + } + }); + } + + private static double curveVal(DiscretizedFunc curve, ReturnPeriods rp) { + if (curve == null) + return Double.NaN; + if (rp.oneYearProb > curve.getMaxY()) + return 0d; + if (rp.oneYearProb < curve.getMinY()) + // saturated + return curve.getMaxX(); + return curve.getFirstInterpolatedX_inLogXLogYDomain(rp.oneYearProb); +// return curve.getFirstInterpolatedX_inLogYDomain(rp.oneYearProb); + } + +} diff --git a/src/main/java/scratch/kevin/nshm23/hazardValidation/CorrRJBPlot.java b/src/main/java/scratch/kevin/nshm23/hazardValidation/CorrRJBPlot.java new file mode 100644 index 00000000..c686b8cc --- /dev/null +++ b/src/main/java/scratch/kevin/nshm23/hazardValidation/CorrRJBPlot.java @@ -0,0 +1,62 @@ +package scratch.kevin.nshm23.hazardValidation; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.jfree.chart.title.PaintScaleLegend; +import org.jfree.chart.ui.RectangleEdge; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.gui.plot.GraphPanel; +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.earthquake.rupForecastImpl.PointSourceNshm.DistanceCorrection2013; +import org.opensha.sha.util.TectonicRegionType; + +public class CorrRJBPlot { + + public static void main(String[] args) throws IOException { + File outputDir = new File("/tmp"); + + CPT magCPT = GMT_CPT_Files.SEQUENTIAL_BATLOW_UNIFORM.instance().rescale(6d, 8d); + + EvenlyDiscretizedFunc magRange = new EvenlyDiscretizedFunc(6.05, 19, 0.1); + EvenlyDiscretizedFunc distRange = new EvenlyDiscretizedFunc(0d, 100, 1d); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + DistanceCorrection2013 corr = new DistanceCorrection2013(); + TectonicRegionType trt = TectonicRegionType.ACTIVE_SHALLOW; + + for (int m=0; m myRups = gridList.getRuptures(trt, gridIndex); + ProbEqkSource mySource = gridList.getSource(trt, gridIndex, 1d, null, gridSettings); + Preconditions.checkState(myRups.size() == mySource.getNumRuptures()); + Site fakeSite = new Site(testLoc); + ProbEqkSource match = null; + for (ProbEqkSource source : wrapper) { + if (source.getTectonicRegionType() != trt) + continue; + if (source.getMinDistance(fakeSite) < 0.001) { + Preconditions.checkState(match == null, "Multiple matches"); + match = source; + } + } + + Preconditions.checkNotNull(match); + + System.out.println("We have "+myRups.size()+" ruptures"); + System.out.println("Wrapper has "+match.getNumRuptures()+" ruptures"); + + List unmapped = new ArrayList<>(match.getNumRuptures()); + for (int i=0; i matches = new ArrayList<>(); + GriddedRupture rup = myRups.get(g); + ProbEqkRupture myProbRup = mySource.getRupture(g); + double mag = rup.properties.magnitude; + double rake = rup.properties.rake; + for (int i=unmapped.size(); --i>=0;) { + int index = unmapped.get(i); + ProbEqkRupture probRup = match.getRupture(index); + if (Precision.equals(mag, probRup.getMag(), 0.001) && Precision.equals(rake, probRup.getAveRake(), 1)) { + matches.add(index); + unmapped.remove(i); + } + } + Collections.reverse(matches); + + PointSurface.DistanceCorrectable surf = (PointSurface.DistanceCorrectable) myProbRup.getRuptureSurface(); + + double rateSum = 0d; + System.out.println("Ours:\t"+rupStr(rup)); + for (int l=0; l<2; l++) { + Location loc = l == 0 ? testLoc : refLoc; + String locStr = l == 0 ? "Colocated" : (int)refDist+" km away"; + WeightedList dists = surf.getCorrectedDistances(loc); + for (int d=0; d= 0) + sectBitSets[s].set(node); + } + } + + for (int r=0; r= (float)minMags[m]) + for (int i = rupBits.nextSetBit(0); i >= 0; i = rupBits.nextSetBit(i + 1)) + fssXYZs[m].add(i, rate); + } + } + if (bgOp == IncludeBackgroundOption.INCLUDE || bgOp == IncludeBackgroundOption.ONLY) { + System.out.println("Calculating for FSS gridded"); + GridSourceList gridList = sol.requireModule(GridSourceList.class); + + for (int l=0; l= 0) { + for (GriddedRupture rup : gridList.getRuptures(trt, l)) { + for (int m=0; m= (float)minMags[m]) + fssXYZs[m].add(locIndex, rup.rate); + } + } + } + } + } + + // do NSHMP-haz + NshmErf erf = new NshmErf(model, Set.of(trt), IncludeBackgroundOption.INCLUDE); + erf.getTimeSpan().setDuration(1d); + erf.updateForecast(); + System.out.println("Calculating for NSHMP-haz"); + int numNSHMPSources = 0; + int numNSHMPRups = 0; + for (ProbEqkSource source : erf) { + NshmSource nshmSource = (NshmSource)source; + Object delegate = nshmSource.delegate(); + boolean gridLike = delegate instanceof NshmpGridSource; + if (!includeForBackgroundOption(gridLike, bgOp)) + continue; + int gridSourceIndex = -1; + if (gridLike) + gridSourceIndex = gridReg.indexForLocation(toOpenSHALocation(((NshmpGridSource)delegate).location(null))); + numNSHMPSources++; + for (ProbEqkRupture rup : source) { + numNSHMPRups++; + double rate = rup.getMeanAnnualRate(1d); + for (int m=0; m= (float)minMags[m]) { + if (gridLike) { + if (gridSourceIndex >= 0) + nhXYZs[m].add(gridSourceIndex, rate); + } else { + addFiniteRupRate(nhXYZs[m], rup.getRuptureSurface(), rate); + } + } + } + } + } + + System.out.println("NSHMP-Haz had "+numNSHMPSources+" matching sources with "+numNSHMPRups+" total ruptures"); + + System.out.println("Building maps"); + + GeographicMapMaker mapMaker = new GeographicMapMaker(reg); + mapMaker.setFaultSections(sol.getRupSet().getFaultSectionDataList()); + mapMaker.setSectOutlineChar(null); + Color transparent = new Color(255, 255, 255, 0); + + for (int m=0; m 0d) { + double logMax = Math.ceil(Math.log10(maxRate)); + CPT rateCPT = GMT_CPT_Files.RAINBOW_UNIFORM.instance().rescale(logMax - 6d, logMax); + rateCPT.setNanColor(transparent); + + mapMaker.plotXYZData(asLog10(fssXYZs[m]), rateCPT, "OpenSHA Rate, "+magLabel); + mapMaker.plot(outputDir, prefix+"_opensha", " "); + mapMaker.plotXYZData(asLog10(nhXYZs[m]), rateCPT, "NSHMP-Haz Rate, "+magLabel); + mapMaker.plot(outputDir, prefix+"_nshmp_haz", " "); + } + + double maxAbsDiff = maxAbs(diff); + if (maxAbsDiff > 0d) { + CPT diffCPT = GMT_CPT_Files.DIVERGING_BAM_UNIFORM.instance().reverse().rescale(-maxAbsDiff, maxAbsDiff); + diffCPT.setNanColor(transparent); + mapMaker.plotXYZData(diff, diffCPT, "OpenSHA - NSHMP-Haz Rate, "+magLabel); + mapMaker.plot(outputDir, prefix+"_diff", " "); + } + + CPT pDiffCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-100d, 100d); + pDiffCPT.setNanColor(transparent); + mapMaker.plotXYZData(pDiff, pDiffCPT, "OpenSHA vs NSHMP-Haz, % Change, "+magLabel); + mapMaker.plot(outputDir, prefix+"_pDiff", " "); + } + } + + private static boolean includeForBackgroundOption(boolean gridLike, IncludeBackgroundOption bgOp) { + switch (bgOp) { + case INCLUDE: + return true; + case ONLY: + return gridLike; + case EXCLUDE: + return !gridLike; + default: + throw new IllegalStateException("Unhandled background option: "+bgOp); + } + } + + private static Location toOpenSHALocation(org.opensha.nshmp.shaded.geo.NshmpLocation loc) { + return new Location(loc.latitude, loc.longitude, loc.depth); + } + + private static void addFiniteRupRate(GriddedGeoDataSet xyz, RuptureSurface surface, double rate) { + GriddedRegion gridReg = xyz.getRegion(); + BitSet bits = new BitSet(gridReg.getNodeCount()); + for (Location loc : surface.getEvenlyDiscritizedListOfLocsOnSurface()) { + int node = gridReg.indexForLocation(loc); + if (node >= 0) + bits.set(node); + } + for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i + 1)) + xyz.add(i, rate); + } + + private static String magLabel(double minMag) { + return minMag == 0d ? "m0" : "m"+(float)minMag; + } + + private static GriddedGeoDataSet diff(GriddedGeoDataSet xyz1, GriddedGeoDataSet xyz2) { + GriddedGeoDataSet ret = new GriddedGeoDataSet(xyz1.getRegion()); + for (int i=0; i 0d ? Math.log10(xyz.get(i)) : Double.NaN); + return xyz; + } + + private static double max(GriddedGeoDataSet xyz) { + double max = 0d; + for (int i=0; i csv = new CSVFile<>(true); + csv.addLine("Latitude", "Longitude", "OpenSHA Rate", "NSHMP-Haz Rate", "Difference", "Percent Difference"); + GriddedRegion gridReg = fssXYZ.getRegion(); + for (int i=0; i plotRegList = new ArrayList<>(); + List outlineChars = new ArrayList<>(); + for (Region plotReg : data.getRegions()) { + plotRegList.add(plotReg); + outlineChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, Color.BLACK)); + } + for (Region plotReg : data.getRegions()) { + plotRegList.add(plotReg); + outlineChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 2f, Color.WHITE)); + } + mapMaker.plotInsetRegions(plotRegList, outlineChars, null, 0d); + + GriddedRegion dataReg = new GriddedRegion(reg, 0.1, GriddedRegion.ANCHOR_0_0); + GriddedGeoDataSet xyz = new GriddedGeoDataSet(dataReg); + ArrayList values = data.getValues(dataReg.getNodeList()); + boolean anyGood = false; + for (int i=0; i 0d; + xyz.set(i, value); + } + } + if (!anyGood) + continue; + + mapMaker.plotXYZData(xyz, cpt, type); + + mapMaker.plot(outputDir, typePrefix+"_"+analReg.name()+"_opensha", "OpenSHA"); + + // load NSHMP-haz + GriddedGeoDataSet modelXYZ = new GriddedGeoDataSet(dataReg); + for (int i=0; i rups = new ArrayList<>(); + for (int sourceID=0; sourceID sects = GeoJSONFaultReader.readFaultSections(subSectsFile); - File outDir = new File(inDir, "slip_projection"); - Preconditions.checkState(outDir.exists() || outDir.mkdir()); - - CPT dipCPT = GMT_CPT_Files.SEQUENTIAL_LAJOLLA_UNIFORM.instance().reverse().rescale(0d, 60d); - double maxRatio = 1.5; - CPT ratioCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(0d, 2d).trim(1d, 2d).rescale(1d, maxRatio); - - GeographicMapMaker mapMaker = new GeographicMapMaker(sects); - mapMaker.setWriteGeoJSON(false); - mapMaker.setFillSurfaces(true); - - mapMaker.plotSectScalars(s->s.getAveDip(), dipCPT, "Dip (degrees)"); - mapMaker.plot(outDir, "dip", " "); - - // cos(dip) = horizontal / on-plane - // on-plane = horizontal / cos(dip) - mapMaker.plotSectScalars(s->1d/Math.cos(Math.toRadians(s.getAveDip())), - ratioCPT, "Projected / Horizontal Slip Rate Ratio (dead on)"); - mapMaker.plot(outDir, "slip_ratio_dead_on", " "); - } - -} diff --git a/src/main/java/scratch/kevin/nshm27/BathymetryConvert.java b/src/main/java/scratch/kevin/nshm27/BathymetryConvert.java new file mode 100644 index 00000000..629099f1 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/BathymetryConvert.java @@ -0,0 +1,78 @@ +package scratch.kevin.nshm27; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.opensha.commons.data.xyz.GriddedGeoDataSet; +import org.opensha.commons.geo.GriddedRegion; +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.LocationUtils; +import org.opensha.commons.gui.plot.GeographicMapMaker; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_GridSourceBuilder; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; + +import com.google.common.base.Preconditions; + +import net.mahdilamb.colormap.Colors; + +public class BathymetryConvert { + + public static void main(String[] args) throws IOException { + // data from https://www.ncei.noaa.gov/maps/grid-extract/ + // ETOPO 2022 layer (ice surface) + // converted from geotiff to xyz via gdal_translate -of XYZ exportImage gnmi_bathy.xyz + + NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.GNMI; + File inFile = new File("/home/kevin/Downloads/gnmi_bathy.xyz"); + +// NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.AMSAM; +// File inFile = new File("/home/kevin/Downloads/amsam_bathy.xyz"); + + GriddedRegion gridReg = NSHM27_GridSourceBuilder.initGridReg(seisReg); + GriddedGeoDataSet maxDists = new GriddedGeoDataSet(gridReg); + GriddedGeoDataSet depths = new GriddedGeoDataSet(gridReg); + for (int i=0; i= 0) { + Location gridLoc = gridReg.getLocation(index); + double dist = LocationUtils.cartesianDistanceSq(loc, gridLoc); + if (dist < maxDists.get(index)) { + maxDists.set(index, dist); + depths.set(index, depth); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + GriddedGeoDataSet.writeXYZFile(depths, new File("/tmp/"+seisReg.name()+"-depths.xyz")); + GeographicMapMaker mapMaker = new GeographicMapMaker(gridReg); + CPT cpt = GMT_CPT_Files.SEQUENTIAL_NAVIA_UNIFORM.instance().reverse().rescale(0d, 10d); + cpt.setNanColor(Colors.tab_orange); + mapMaker.plotXYZData(depths, cpt, "NOAA ETOPO (2022) bathymetric depth (km)"); + mapMaker.plot(new File("/tmp"), seisReg.name()+"_depths", " "); + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/BranchHalfBiasInvestigation.java b/src/main/java/scratch/kevin/nshm27/BranchHalfBiasInvestigation.java new file mode 100644 index 00000000..2d751e0d --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/BranchHalfBiasInvestigation.java @@ -0,0 +1,104 @@ +package scratch.kevin.nshm27; + +import java.io.File; +import java.io.IOException; + +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.TectonicRegionBranchTreeNode; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceCouplingDepthModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceObsSeisDMAdjustment; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue.CombinedSampledType; + +public class BranchHalfBiasInvestigation { + + public static void main(String[] args) throws IOException { +// File treeFile = new File("/home/kevin/OpenSHA/fss_inversions/2026_06_27-nshm27-AMSAM-3000samples-lhs_pairwise/logic_tree.json"); + File treeFile = new File("/home/kevin/OpenSHA/fss_inversions/2026_07_13-nshm27-AMSAM-5000samples-lhs_pairwise/logic_tree.json"); +// File treeFile = new File("/home/kevin/OpenSHA/fss_inversions/2026_07_11-nshm27-AMSAM-2000samples-lhs_pairwise/logic_tree.json"); + + LogicTree tree = LogicTree.read(treeFile); + LogicTree interfaceTree = null; + for (int l=0; l level = tree.getLevels().get(l); + if (level instanceof TectonicRegionBranchTreeNode.Level) { + interfaceTree = ((TectonicRegionBranchTreeNode.Level)level).getTree(); + break; + } + } + + int total = tree.size(); + int halfIndex = tree.size()/2; + int numHinged1 = 0; + int numHinged2 = 0; + double sumB1 = 0d; + int numB1 = 0; + double sumB2 = 0d; + int numB2 = 0; + + int numExtraploate1 = 0; + int numExtraploate2 = 0; + + int numTaperDouble1 = 0; + int numTaperNone1 = 0; + int numTaperDouble2 = 0; + int numTaperNone2 = 0; + + for (int i=0; i branch = interfaceTree.getBranch(i); + CombinedSampledType node = branch.requireValue(CombinedSampledType.class); + boolean first = i < halfIndex; + if (node.isHinged()) { + if (first) + numHinged1++; + else + numHinged2++; + } else { + double b = node.getB(null, null); + if (first) { + sumB1 += b; + numB1++; + } else { + sumB2 += b; + numB2++; + } + } + if (branch.hasValue(NSHM27_InterfaceObsSeisDMAdjustment.EXTRAPOLATE)) { + if (first) + numExtraploate1++; + else + numExtraploate2++; + } + if (branch.hasValue(NSHM27_InterfaceCouplingDepthModels.DOUBLE_TAPER)) { + if (first) + numTaperDouble1++; + else + numTaperDouble2++; + } + if (branch.hasValue(NSHM27_InterfaceCouplingDepthModels.NONE)) { + if (first) + numTaperNone1++; + else + numTaperNone2++; + } + } + + double avgB1 = sumB1 / (double)numB1; + double avgB2 = sumB2 / (double)numB2; + System.out.println("First half:"); + System.out.println("\t"+numHinged1+" hinged"); + System.out.println("\t"+avgB1+" average b"); + System.out.println("\t"+numExtraploate1+" extrapolate"); + System.out.println("\t"+numTaperDouble1+" taper-double"); + System.out.println("\t"+numTaperNone1+" taper-none"); + System.out.println("Second half:"); + System.out.println("\t"+numHinged2+" hinged"); + System.out.println("\t"+avgB2+" average b"); + System.out.println("\t"+numExtraploate2+" extrapolate"); + System.out.println("\t"+numTaperDouble2+" taper-double"); + System.out.println("\t"+numTaperNone2+" taper-none"); + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/DistSampleCountTests.java b/src/main/java/scratch/kevin/nshm27/DistSampleCountTests.java new file mode 100644 index 00000000..41949d84 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/DistSampleCountTests.java @@ -0,0 +1,159 @@ +package scratch.kevin.nshm27; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.apache.commons.statistics.distribution.TruncatedNormalDistribution; +import org.apache.commons.statistics.distribution.UniformContinuousDistribution; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.HistogramFunction; +import org.opensha.commons.data.function.XY_DataSet; +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.PlotSymbol; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.logicTree.LogicTreeLevel.ContinuousDistributionBinnedLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.ContinuousDistributionSampledLevel; +import org.opensha.commons.logicTree.LogicTreeNode.SimpleValuedNode; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; + +import com.google.common.collect.Range; + +import net.mahdilamb.colormap.Colors; + +public class DistSampleCountTests { + + public static void main(String[] args) throws IOException { +// ContinuousDistribution dist = TruncatedNormalDistribution.of(7.6, 0.134, 7.15, 8.05); + ContinuousDistribution dist = TruncatedNormalDistribution.of(8, 0.2, 7.45, 8.55); + int precisionScale = 1; + int bins = 3; + +//// ContinuousDistribution dist = UniformContinuousDistribution.of(0d, 1d); +//// ContinuousDistribution dist = UniformContinuousDistribution.of(0.5d, 1d); +// ContinuousDistribution dist = TruncatedNormalDistribution.of(0.75, 0.5, 0d, 1.5); +// int precisionScale = 2; + +// ContinuousDistribution dist = UniformContinuousDistribution.of(1000d, 1500d); +// int precisionScale = 2; + + int numSamples = 10000; + + ContinuousDistributionSampledLevel level = new ContinuousDistributionSampledLevel( + "Test level", "Level", dist, precisionScale, "Node ", "Node", "Node"); + + double[] samples = new double[numSamples]; + Random r = new Random(123456789l); + for (int i=0; i node : level.getNodes()) + track.addValue(node.getValue()); + + double delta = 1d/Math.pow(10, precisionScale); + + System.out.println("Values: "+track); +// HistogramFunction hist = HistogramFunction.getEncompassingHistogram(track.getMin(), track.getMax(), delta); + EvenlyDiscretizedFunc hist = new EvenlyDiscretizedFunc(track.getMin(), track.getMax(), 1 + (int)(track.getLength()/delta + 0.5)); + + for (SimpleValuedNode node : level.getNodes()) + hist.add(hist.getClosestXIndex(node.getValue()), 1d); + + hist.scale(1d/(numSamples*hist.getDelta())); + + EvenlyDiscretizedFunc pdfDensity = new EvenlyDiscretizedFunc(track.getMin()-0.5*delta, track.getMax()+0.5*delta, 1000); + + for (int i=0; i 0) + pdfDensity.set(i, density); + } + + EvenlyDiscretizedFunc pdfCoarseDensity = new EvenlyDiscretizedFunc(hist.getMinX(), hist.getMaxX(), hist.size()); + for (int i=0; i 0) + pdfCoarseDensity.set(i, density); + } + + double histSum = hist.calcSumOfY_Vals(); + for (int i=0; i funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + funcs.add(hist); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, Colors.tab_blue)); + + funcs.add(pdfDensity); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, Color.BLACK)); + + funcs.add(pdfCoarseDensity); + chars.add(new PlotCurveCharacterstics(PlotSymbol.FILLED_CIRCLE, 5f, Color.BLACK)); + + for (int i=0; i<=3; i++) { + double x = dist.inverseCumulativeProbability(i/3d); + double y = dist.density(x); + DefaultXY_DataSet third = new DefaultXY_DataSet(x, 0, x, y); + + funcs.add(third); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, Colors.tab_green)); + + third = new DefaultXY_DataSet(x, y); + + funcs.add(third); + chars.add(new PlotCurveCharacterstics(PlotSymbol.FILLED_CIRCLE, 5f, Colors.tab_green)); + } + + ContinuousDistributionBinnedLevel binned = bins > 0 ? level.toBinnedLevel(bins) : level.toBinnedLevel(); + List>> binNodes = binned.getNodes(); + for (int i=0; i> node = binNodes.get(i); + System.out.println("Bin node "+i+": "+node.getName()+" (wt="+(float)node.getNodeWeight()+")"); + if (i == binNodes.size()-1) + break; + double x = node.getValue().upperEndpoint(); + double y = dist.density(x); + DefaultXY_DataSet edge = new DefaultXY_DataSet(x, 0, x, y); + + funcs.add(edge); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 2f, Colors.tab_orange)); + + edge = new DefaultXY_DataSet(x, y); + + funcs.add(edge); + chars.add(new PlotCurveCharacterstics(PlotSymbol.FILLED_CIRCLE, 5f, Colors.tab_orange)); + } + + PlotSpec plot = new PlotSpec(funcs, chars, samples+" samples", "X", "Density"); + + HeadlessGraphPanel gp = PlotUtils.initScreenHeadless(); + + gp.drawGraphPanel(plot); + + PlotUtils.writePlots(new File("/tmp"), "dist_test", gp, 800, 650, true, false, false); + } + +} diff --git a/src/main/java/scratch/kevin/nshm26/DownDipInterfaceSubSectTests.java b/src/main/java/scratch/kevin/nshm27/DownDipInterfaceSubSectTests.java similarity index 99% rename from src/main/java/scratch/kevin/nshm26/DownDipInterfaceSubSectTests.java rename to src/main/java/scratch/kevin/nshm27/DownDipInterfaceSubSectTests.java index a0ade755..7b7e176e 100644 --- a/src/main/java/scratch/kevin/nshm26/DownDipInterfaceSubSectTests.java +++ b/src/main/java/scratch/kevin/nshm27/DownDipInterfaceSubSectTests.java @@ -1,4 +1,4 @@ -package scratch.kevin.nshm26; +package scratch.kevin.nshm27; import java.awt.Color; import java.io.BufferedReader; diff --git a/src/main/java/scratch/kevin/nshm26/DownDipRupSetBuildingTests.java b/src/main/java/scratch/kevin/nshm27/DownDipRupSetBuildingTests.java similarity index 97% rename from src/main/java/scratch/kevin/nshm26/DownDipRupSetBuildingTests.java rename to src/main/java/scratch/kevin/nshm27/DownDipRupSetBuildingTests.java index 62a691d8..79cf9d16 100644 --- a/src/main/java/scratch/kevin/nshm26/DownDipRupSetBuildingTests.java +++ b/src/main/java/scratch/kevin/nshm27/DownDipRupSetBuildingTests.java @@ -1,4 +1,4 @@ -package scratch.kevin.nshm26; +package scratch.kevin.nshm27; import java.awt.Color; import java.awt.image.BufferedImage; @@ -29,7 +29,7 @@ import org.opensha.sha.earthquake.faultSysSolution.ruptures.downDip.RectangularDownDipGrowingStrategy.NeighborOverlaps; import org.opensha.sha.earthquake.faultSysSolution.ruptures.util.GeoJSONFaultReader; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; -import org.opensha.sha.earthquake.rupForecastImpl.nshm26.logicTree.NSHM26_SubductionInterfaceFaultModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceFaultModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionScalingRelationships; import org.opensha.sha.faultSurface.FaultSection; import org.opensha.sha.faultSurface.GeoJSONFaultSection; @@ -48,10 +48,11 @@ public static void main(String[] args) throws IOException { // NSHM26_SubductionInterfaceFaultModels fm = NSHM26_SubductionInterfaceFaultModels.KERMADEC; // String prefix = "ker_slab2"; - NSHM26_SubductionInterfaceFaultModels fm = NSHM26_SubductionInterfaceFaultModels.MARIANA; + NSHM27_InterfaceFaultModels fm = NSHM27_InterfaceFaultModels.GNMI_V1; String prefix = "izu_slab2"; - Range minSupraRange = Range.closed(10d, 40d); + Range minSupraRange = Range.closed(20d, 40d); + double maxSubSeisAspectRatio = 4d; File inDir = new File(baseOutputDir, prefix); List sects = fm.buildSubSects(fm); @@ -112,7 +113,7 @@ public static void main(String[] args) throws IOException { Color participatingColor = overlapCPT.getMaxColor(); Color otherColor = overlapCPT.getMinColor(); - RectangularDownDipGrowingStrategy growingStrat = new RectangularDownDipGrowingStrategy(minSupraRange); + RectangularDownDipGrowingStrategy growingStrat = new RectangularDownDipGrowingStrategy(minSupraRange, maxSubSeisAspectRatio); RupSetScalingRelationship scale = PRVI25_SubductionScalingRelationships.LOGA_C4p0; HeadlessGraphPanel gp = PlotUtils.initScreenHeadless(); diff --git a/src/main/java/scratch/kevin/nshm27/ExampleLogicTreeSampleCSVs.java b/src/main/java/scratch/kevin/nshm27/ExampleLogicTreeSampleCSVs.java new file mode 100644 index 00000000..e5b60420 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/ExampleLogicTreeSampleCSVs.java @@ -0,0 +1,131 @@ +package scratch.kevin.nshm27; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeFigureWriter; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.LogicTreeNode.ValuedLogicTreeNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.sha.earthquake.faultSysSolution.logicTree.sectDistSampling.SectDistributionSampler.FixedFractileSampler; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.SectionSupraSeisBValues; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceFaultModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue.CombinedSampledType; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisRateModel.ClassificationDependentGR; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.util.TectonicRegionType; + +import scratch.kevin.nshm27.figures.LogicTreeFigure; + +public class ExampleLogicTreeSampleCSVs { + + public static void main(String[] args) throws IOException { + File outputDir = new File("/home/kevin/OpenSHA/nshm27/sampling/example_trees"); + NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.AMSAM; + String prefix = "nshm27_amsam_interface"; + + boolean inversion = true; + boolean gridded = false; + +// boolean inversion = false; +// boolean gridded = true; + +// boolean inversion = true; +// boolean gridded = true; + + int[] sampleCounts = { + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384 + }; + long seed = 123456l; + SamplingMethod method = SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE; + + if (inversion && gridded) + prefix += "_full"; + else if (inversion) + prefix += "_inversion_only"; + else if (gridded) + prefix += "_gridded_only"; + else + throw new IllegalStateException(); + + boolean common = gridded; + + List> levels = NSHM27_LogicTree.buildLevels( + seisReg, TectonicRegionType.SUBDUCTION_INTERFACE, + true, inversion, gridded, common); + + for (int s=0; s logicTree = LogicTree.buildSampled(levels, samples, seed, method, + NSHM27_InterfaceFaultModels.regionDefault(seisReg)); + + // remove the unnecessary fault model level (it's fixed) + logicTree = LogicTreeFigure.stripFaultModels(logicTree); + // remove the unnecessary overall model/regime level (it's fixed) + logicTree = LogicTreeFigure.stripModelLevel(logicTree); + + CSVFile csv = new CSVFile<>(true); + List header = new ArrayList<>(); + for (LogicTreeLevel level : logicTree.getLevels()) + header.add(level.getName()); + csv.addLine(header); + + for (LogicTreeBranch branch : logicTree) { + List line = new ArrayList<>(header.size()); + + for (LogicTreeNode node : branch) { + if (node instanceof NSHM27_InterfaceHingedBValue.CombinedSampledType combBSample) { + if (combBSample.isHinged()) + line.add(NSHM27_InterfaceHingedBValue.SHORT_NAME); + else + line.add((float)combBSample.getB(null, null)+""); + } else if (node instanceof ValuedLogicTreeNode valued) { + Object value = valued.getValue(); + if (value instanceof FixedFractileSampler fractiles) { + line.add((float)fractiles.getFixedFractile()+""); + } else if (value instanceof ClassificationDependentGR gr) { + line.add((float)gr.getSampleFractile()+""); + } else { +// if (!(value instanceof Number)) +// System.out.println("UNKNOWN value "+value+" of type "+value.getClass().getName() +// +" with node "+node.getShortName()+" of type "+node.getClass()); + line.add(value.toString()); + } + } else { + line.add(node.getShortName()); + } + } + + csv.addLine(line); + } + + csv.writeToFile(new File(outputDir, samplePrefix+".csv")); + + if (s == 0) { + LogicTreeFigureWriter ltFig = new LogicTreeFigureWriter(logicTree, false, true); + ltFig.write(outputDir, prefix, true, true); + } + System.out.println("========================="); + System.out.println(); + } + } + +} diff --git a/src/main/java/scratch/kevin/nshm26/GeoJSON3DExample.java b/src/main/java/scratch/kevin/nshm27/GeoJSON3DExample.java similarity index 98% rename from src/main/java/scratch/kevin/nshm26/GeoJSON3DExample.java rename to src/main/java/scratch/kevin/nshm27/GeoJSON3DExample.java index 478180ca..4e259853 100644 --- a/src/main/java/scratch/kevin/nshm26/GeoJSON3DExample.java +++ b/src/main/java/scratch/kevin/nshm27/GeoJSON3DExample.java @@ -1,4 +1,4 @@ -package scratch.kevin.nshm26; +package scratch.kevin.nshm27; import java.io.File; import java.io.IOException; diff --git a/src/main/java/scratch/kevin/nshm27/InterfaceSlipRatePercentiles.java b/src/main/java/scratch/kevin/nshm27/InterfaceSlipRatePercentiles.java new file mode 100644 index 00000000..324de539 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/InterfaceSlipRatePercentiles.java @@ -0,0 +1,83 @@ +package scratch.kevin.nshm27; + +import java.io.IOException; +import java.text.DecimalFormat; + +import org.apache.commons.math3.stat.StatUtils; +import org.opensha.sha.earthquake.faultSysSolution.logicTree.sectDistSampling.SectDistributionSampler.*; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceDeformationModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceFaultModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceDeformationModels.DeformationFront; + +public class InterfaceSlipRatePercentiles { + + public static void main(String[] args) throws IOException { + double[] fractiles = { + 0.00000001, + 0.0000001, + 0.000001, + 0.00001, + 0.0001, + 0.001, + 0.01, + 0.025, + 0.16, + 0.5, + 0.84, + 0.975, + 0.99, + 0.999, + 0.9999, + 0.99999, + 0.999999, + 0.9999999, + 0.99999999, + 1d, + 2d + }; + + DecimalFormat pDF = new DecimalFormat("0.#########%"); + DecimalFormat slipDF = new DecimalFormat("0.###"); + DecimalFormat groupedDF = new DecimalFormat("0"); + groupedDF.setGroupingSize(3); + groupedDF.setGroupingUsed(true); + + for (NSHM27_InterfaceFaultModels fm : NSHM27_InterfaceFaultModels.values()) { + DeformationFront df = NSHM27_InterfaceDeformationModels.getDeformationFront(fm); + System.out.println(fm.getName()); + + String[] labels = new String[fractiles.length]; + String[] results = new String[fractiles.length]; + int longestLabel = 0; + for (int f=0; f < fractiles.length; f++) { + double fractile = fractiles[f]; + String label; + FixedSampler sampler; + if (fractile == 2d) { + label = "Distribution-average"; + sampler = new AverageSampler(); + } else { + double rarity = Math.min(1d-fractile, fractile); + + label = pDF.format(fractile); + if (rarity < 0.1) + label += " (1 in "+groupedDF.format(1d/rarity)+")"; + sampler = new FixedFractileSampler(fractile); + } + + double[] slipRates = NSHM27_InterfaceDeformationModels.getCoupledSlipRates(df, sampler); + + longestLabel = Integer.max(longestLabel, label.length()); + labels[f] = label+":"; + results[f] = "mean="+slipDF.format(StatUtils.mean(slipRates)) + +"\trange=["+slipDF.format(StatUtils.min(slipRates))+", "+slipDF.format(StatUtils.max(slipRates))+"]"; + } + for (int f=0; f branch = NSHM27_LogicTree.buildDefault( +// NSHM26_SeismicityRegions.AMSAM, TectonicRegionType.SUBDUCTION_INTERFACE, false); + NSHM27_SeismicityRegions.GNMI, TectonicRegionType.SUBDUCTION_INTERFACE, false); + NSHM27_InterfaceFaultModels fm = branch.requireValue(NSHM27_InterfaceFaultModels.class); + NSHM27_InterfaceDeformationModels dm = branch.requireValue(NSHM27_InterfaceDeformationModels.class); + + NSHM27_SeismicityRegions reg = fm.getSeismicityRegion(); + File pdfBaseDir = new File("/home/kevin/OpenSHA/nshm26/data/spatial_seis_pdfs/"+reg.name().toLowerCase()+"/2026_03_09-v1_2D/INTERFACE"); + + System.out.println("Branch: "+branch+"; reg="+reg); + + NSHM27_SeisRateModelBranch rateModel = NSHM27_SeisRateModelBranch.PREFFERRED; + NSHM27_DeclusteringAlgorithms decluster = NSHM27_DeclusteringAlgorithms.AVERAGE; + NSHM27_SeisSmoothingAlgorithms smooth = NSHM27_SeisSmoothingAlgorithms.AVERAGE; + double cutoffHorzDist = 50d; + + List sects = dm.build(branch); + Location[] middles = new Location[sects.size()]; + for (int i=0; i transColors = new ArrayList<>(sects.size()); + for (int i=0; i mappings = assoc.getSectionFracsOnNode(i); + for (int s : mappings.keySet()) + impliedMoments[s] += moSum*mappings.get(s); + } + + double[] moFracts = new double[sects.size()]; + MinMaxAveTracker track = new MinMaxAveTracker(); + for (int i=0; i countMags = new HashMap<>(); + NSHM27_InterfaceMinSubSects[] minSects = NSHM27_InterfaceMinSubSects.values(); + for (NSHM27_InterfaceFaultModels fm : NSHM27_InterfaceFaultModels.values()) { + LogicTreeBranch branch = NSHM27_LogicTree.buildDefault( + fm.getSeismicityRegion(), TectonicRegionType.SUBDUCTION_INTERFACE, false); + branch.setValue(PRVI25_SubductionScalingRelationships.AVERAGE); + FaultSystemRupSet rupSet = factory.buildRuptureSet(branch, FaultSysTools.defaultNumThreads()); + + int[] counts = new int[minSects.length]; + double[] magSums = new double[minSects.length]; + + for (int r=0; r branch = NSHM27_LogicTree.buildDefault(reg, TectonicRegionType.SUBDUCTION_INTERFACE, false); + branch.setValue(scale); + FaultSystemRupSet rupSet = new NSHM27_InvConfigFactory().buildRuptureSet(branch, 16); + + DecimalFormat magDF = new DecimalFormat("0.00"); + + for (double lMax : lMaxs) { + BitSet rups = new BitSet(rupSet.getNumRuptures()); + for (int r=0; r regions = new ArrayList<>(); + List chars = new ArrayList<>(); + List colors = new ArrayList<>(); + + Color color = Colors.tab_blue; + + regions.add(NSHM27_SeismicityRegions.AMSAM.load()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Color.BLACK)); + colors.add(color); + + regions.add(region); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 3f, Color.BLACK)); + colors.add(color); + + regions.add(NSHM27_MapRegions.AMSAM.load()); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, Color.BLACK)); + colors.add(color); + + MinMaxAveTracker latTrack = new MinMaxAveTracker(); + MinMaxAveTracker lonTrack = new MinMaxAveTracker(); + for (Region reg : regions) { + latTrack.addValue(reg.getMinLat()); + latTrack.addValue(reg.getMaxLat()); + lonTrack.addValue(reg.getMinLon()); + lonTrack.addValue(reg.getMaxLon()); + } + List sects = NSHM27_PaperPaths.getInterfaceSolution(NSHM27_SeismicityRegions.AMSAM) + .getRupSet().getFaultSectionDataList(); + for (FaultSection sect : sects) { + for (Location loc : sect.getFaultTrace()) { + latTrack.addValue(loc.lat); + lonTrack.addValue(loc.lon); + } + } + + double minLat = Math.floor(latTrack.getMin()-0.5); + double maxLat = Math.ceil(latTrack.getMax()+0.5); + double minLon = Math.floor(lonTrack.getMin()-0.5); + double maxLon = Math.ceil(lonTrack.getMax()+0.5); + GeographicMapMaker mapMaker = new GeographicMapMaker( + new Region(new Location(minLat, minLon), new Location(maxLat, maxLon))); + + mapMaker.setFaultSections(sects); + + mapMaker.plotInsetRegions(regions, chars, colors, 0.3); + + mapMaker.plot(new File("/tmp"), "amsam_seismicity_regions", " "); + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/SamplerTest.java b/src/main/java/scratch/kevin/nshm27/SamplerTest.java new file mode 100644 index 00000000..0759b154 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/SamplerTest.java @@ -0,0 +1,136 @@ +package scratch.kevin.nshm27; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.rng.simple.RandomSource; +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.apache.commons.statistics.distribution.TruncatedNormalDistribution; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.data.Range; +import org.apache.commons.statistics.distribution.ContinuousDistribution.Sampler; +import org.apache.commons.statistics.distribution.NormalDistribution; +import org.opensha.commons.util.ColorUtils; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.HistogramFunction; +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.util.DataUtils.MinMaxAveTracker; + +import net.mahdilamb.colormap.Colors; + +public class SamplerTest { + + public static void main(String[] args) throws IOException { +// double mean = 1d; +// double sd = 0.1; +// double lower = 0.7; +// double upper = 1.3; + +// double mean = -1d; +// double sd = 0.1; +// double lower = -1.3; +// double upper = -0.7; + +// double mean = 1d; +// double sd = 0.1; +// double lower = 0.7; +// double upper = 1.3; + + double mean = 1d; + double sd = 0.1; + double lower = -0.1; + double upper = 1.3; + +// double mean = -1d; +// double sd = 0.1; +// double lower = -1d; +// double upper = -0.7; + +// double mean = -0.1d; +// double sd = 0.1; +// double lower = 0.01; +// double upper = 1d; + + int samples = 10000000; + + EvenlyDiscretizedFunc hist1 = HistogramFunction.getEncompassingHistogram(lower-0.1, upper+0.1, 0.01); + + ContinuousDistribution dist = TruncatedNormalDistribution.of(mean, sd, lower, upper); + + System.out.println("Reported dist params:"); + System.out.println("\tmean: "+dist.getMean()); + System.out.println("\tvar: "+dist.getVariance()); + System.out.println("\tsqrt(var): "+Math.sqrt(dist.getVariance())); + System.out.println("\tlower: "+dist.getSupportLowerBound()); + System.out.println("\tupper: "+dist.getSupportUpperBound()); + + Sampler sampler = dist.createSampler(RandomSource.XO_RO_SHI_RO_128_PP.create(123456l)); + for (int i=0; i 0) + pdfDensity.set(x, density); + } + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + hist1.setName("Current Rejection Sampler"); + funcs.add(hist1); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, Color.BLACK)); + + Color corrHistColor = Colors.tab_orange; + corrHistColor = ColorUtils.transparent(corrHistColor, 127); + hist2.setName("Corrected Rejection Sampler"); + funcs.add(hist2); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, corrHistColor)); + + pdfDensity.setName("PDF Density"); + funcs.add(pdfDensity); + chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 3f, Colors.tab_blue)); + + double maxY = 0d; + for (DiscretizedFunc func : funcs) + maxY = Math.max(maxY, func.getMaxY()); + + String title = "μ="+(float)mean+", σ="+(float)sd+", bounds=["+(float)lower+", "+(float)upper+"]"; + + PlotSpec plot = new PlotSpec(funcs, chars, title, "X", "Density"); + plot.setLegendInset(RectangleAnchor.TOP_LEFT); + HeadlessGraphPanel gp = PlotUtils.initScreenHeadless(); + + gp.setLegendFontSize(16); + + gp.drawGraphPanel(plot, false, false, new Range(hist1.getMinX(), hist1.getMaxX()), new Range(0d, maxY*1.2)); + + String prefix = "trunc_dist_"+(float)mean+"_"+(float)sd+"_"+(float)lower+"_"+(float)upper; + + PlotUtils.writePlots(new File("/tmp"), prefix, gp, 700, 450, true, false, false); + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/TreeBinCounts.java b/src/main/java/scratch/kevin/nshm27/TreeBinCounts.java new file mode 100644 index 00000000..e6713819 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/TreeBinCounts.java @@ -0,0 +1,85 @@ +package scratch.kevin.nshm27; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.TectonicRegionBranchTreeNode; +import org.opensha.commons.logicTree.LogicTreeLevel.BinnableLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.BinnedLevel; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +public class TreeBinCounts { + + public static void main(String[] args) throws IOException { + LogicTree tree = LogicTree.read(new File("/home/kevin/OpenSHA/nshm23/batch_inversions/" +// + "2026_03_23-nshm26-AMSAM-1000samples-gridded/logic_tree.json")); +// + "2026_03_25-nshm26-AMSAM-2000samples-gridded/logic_tree.json")); +// + "2026_03_27-nshm26-AMSAM-2000samples-gridded/logic_tree.json")); +// + "2026_03_27-nshm26-GNMI-2000samples-gridded/logic_tree.json")); + + "2026_04_02-nshm27-AMSAM-2000samples-lhs-gridded/logic_tree.json")); + + System.out.println("Stats for "+tree.size()+" branches"); + + for (int t=0; t level = null; + boolean binned = false; + Map nodeWeights = new LinkedHashMap<>(); + double sumWeight = 0d; + for (int i=0; i branch = trtLevel.getNodes().get(i).getValue(); + double weight = branch.getOrigBranchWeight(); + sumWeight += weight; + if (i == 0) { + level = branch.getLevel(l); + if (level instanceof BinnableLevel) { + level = ((BinnableLevel)level).toBinnedLevel(); + binned = true; + } + for (LogicTreeNode node : level.getNodes()) { + Preconditions.checkNotNull(node, "Null node for level %s: %s", l, level.getName()); + nodeWeights.put(node, 0d); + } + } + LogicTreeNode node = branch.getValue(l); + Preconditions.checkNotNull(node, "Null node for level %s: %s", l, level.getName()); + if (binned) { + LogicTreeNode oNode = node; + node = ((BinnedLevel)level).getBinUnchecked(node); + Preconditions.checkNotNull(node, "Null binned node for level %s branch %s: %s, value: %s [%s]", + l, i, level.getName(), oNode.getName(), + oNode instanceof LogicTreeNode.ValuedLogicTreeNode ? + ((LogicTreeNode.ValuedLogicTreeNode)oNode).getValue() : ""); + } + if (nodeWeights.containsKey(node)) + nodeWeights.put(node, nodeWeights.get(node) + weight); + else + nodeWeights.put(node, weight); + } + System.out.println(level.getName()); + for (LogicTreeNode node : nodeWeights.keySet()) { + double weight = nodeWeights.get(node); + double nodeWeight = node.getNodeWeight(null); + if (weight > 0d || nodeWeight > 0d) + System.out.println("\t"+node.getName()+":\t"+(float)weight + +"\t(nodeWeight="+(float)nodeWeight+")"); + } + } + } + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/UpdatedRandTreeSerialzationTests.java b/src/main/java/scratch/kevin/nshm27/UpdatedRandTreeSerialzationTests.java new file mode 100644 index 00000000..bb52a63f --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/UpdatedRandTreeSerialzationTests.java @@ -0,0 +1,152 @@ +package scratch.kevin.nshm27; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.apache.commons.rng.simple.RandomSource; +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.apache.commons.statistics.distribution.ContinuousDistribution.Sampler; +import org.apache.commons.statistics.distribution.TruncatedNormalDistribution; +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.LogicTreeNode.RandomlyGeneratedNode; +import org.opensha.commons.logicTree.LogicTreeNode.SimpleValuedNode; +import org.opensha.commons.logicTree.LogicTreeNode.ValuedLogicTreeNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; + +import com.google.common.base.Preconditions; + +public class UpdatedRandTreeSerialzationTests { + + public static void main(String[] args) throws IOException { + List> inTrees = new ArrayList<>(); + + inTrees.add(LogicTree.read(new File("/home/kevin/OpenSHA/nshm23/batch_inversions/2025_01_17-prvi25_crustal_branches-dmSample10x/logic_tree.json"))); + + double[] samples = new double[1000]; + Random r = new Random(12345l); + for (int i=0; i lastTree = inTrees.get(inTrees.size()-1); + for (int i=0; i tree = inTrees.get(t); + System.out.println("Processing tree "+t+" with "+tree.size()+" branches"); + + File treeOutFile = new File("/tmp/tree_out_"+t+".json"); + System.out.println("\tWriting tree to: "+treeOutFile.getAbsolutePath()); + tree.write(treeOutFile); + + File branchOutFile = new File("/tmp/branch_out_"+t+".json"); + System.out.println("\tWriting branch 0 to: "+branchOutFile.getAbsolutePath()); + tree.getBranch(0).writeToFile(branchOutFile); + + System.out.println("\tReading tree back in"); + LogicTree tree2 = LogicTree.read(treeOutFile); + + System.out.println("\tLevels:"); + for (LogicTreeLevel level : tree2.getLevels()) + System.out.println("\t\t"+level.getName()+" ("+level.getClass()+")"); + + System.out.println("\tReading branch 0 back in"); + LogicTreeBranch loadedBranch0 = LogicTreeBranch.read(branchOutFile); + for (int i=-1; i branch1, branch2; + if (i < 0) { + branch1 = tree.getBranch(0); + branch2 = loadedBranch0; + } else { + branch1 = tree.getBranch(i); + branch2 = tree2.getBranch(i); + } + List randGenNodes1 = branch1.getValues(RandomlyGeneratedNode.class); + List randGenNodes2 = branch2.getValues(RandomlyGeneratedNode.class); + if (randGenNodes1 == null) { + Preconditions.checkState(randGenNodes2 == null); + } else { + Preconditions.checkState(randGenNodes1.size() == randGenNodes2.size()); + for (int n=0; n valNodes1 = branch1.getValues(ValuedLogicTreeNode.class); + List valNodes2 = branch2.getValues(ValuedLogicTreeNode.class); + if (valNodes1 == null) { + Preconditions.checkState(valNodes2 == null); + } else { + Preconditions.checkState(valNodes1.size() == valNodes2.size(), + "Branch %s: Valued node list size mismatch: %s vs %s", i, valNodes1.size(), valNodes2.size()); + for (int n=0; n gen1 = valNodes1.get(n); + ValuedLogicTreeNode gen2 = valNodes2.get(n); + Preconditions.checkState(gen1.getValue().equals(gen2.getValue())); + Preconditions.checkState(gen1.equals(gen2)); + } + } + } + } + + } + + private static class TestValuedLevel extends LogicTreeLevel.RandomlySampledLevel { + + public TestValuedLevel() { + super("Test Valued Level", "TVL", "Random Node ", "RN", "RN"); + } + + @Override + public Class getValueType() { + return Double.class; + } + + @Override + protected void doBuild(double[] unitSamples, double weightEach) { + super.build(unitSamples, D->D, weightEach); + } + + } + + private static class TestDistLevel extends LogicTreeLevel.ContinuousDistributionSampledLevel { + + private TestDistLevel() { + this(null); + }; + + public TestDistLevel(ContinuousDistribution dist) { + super("Test Distribution Level", "TestDistLevel", dist, + "Distribution Sample ", "DistSample", "DistSample"); + } + + } + +} + diff --git a/src/main/java/scratch/kevin/nshm27/figures/BValDistFigure.java b/src/main/java/scratch/kevin/nshm27/figures/BValDistFigure.java new file mode 100644 index 00000000..93ec56fa --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/BValDistFigure.java @@ -0,0 +1,251 @@ +package scratch.kevin.nshm27.figures; + +import static scratch.kevin.nshm27.figures.NSHM27_PaperPaths.*; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.apache.commons.statistics.distribution.UniformContinuousDistribution; +import org.jfree.chart.plot.DatasetRenderingOrder; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.HistogramFunction; +import org.opensha.commons.data.function.XY_DataSet; +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.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeFigureWriter; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.util.modules.ModuleContainer; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.PureGR; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.SectionSupraSeisBValues; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.SectionSupraSeisBValues.DistributionSamplingLevel; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceObsSeisDMAdjustment; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisClassificationMethod; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisRateModel; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.util.TectonicRegionType; + +import net.mahdilamb.colormap.Colors; + +public class BValDistFigure { + + public static void main(String[] args) throws IOException { + System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", FaultSysTools.defaultNumThreads()+""); +// int numSamples = 100; +// int numSamples = 1000; +// int numSamples = 2000; +// int numSamples = 5000; +// int numSamples = 10000; + int numSamples = 50000; +// double binWidth = 0.025; + ModuleContainer.VERBOSE_DEFAULT = false; + double binWidth = 0.05; + Range bRange = new Range(-0.6, 1.6); + Range yRange = new Range(0, 1.4); + + Color hingedColor = Colors.tab_blue; + hingedColor = ColorUtils.transparent(hingedColor, 200); + Color hingedBelowOverlayColor = new Color(255, 255, 255, 160); + Color extrapColor = Colors.tab_green; + extrapColor = ColorUtils.transparent(extrapColor, 200); + Color combColor = Colors.tab_lightred; + + double extrapolateWeight = NSHM27_InterfaceObsSeisDMAdjustment.EXTRAPOLATE.getNodeWeight(); + double otherWeight = 1d-extrapolateWeight; + double hingeWeight = NSHM27_LogicTree.INTERFACE_B_HINGED_WEIGHT; + double distWeight = 1d - hingeWeight; + hingeWeight *= otherWeight; + distWeight *= otherWeight; + + NSHM27_LogicTree.INTERFACE_B_HINGED_WEIGHT = 1d; + + EvenlyDiscretizedFunc bValDiscr = HistogramFunction.getEncompassingHistogram(-1, 2, binWidth); + + NSHM27_InvConfigFactory factory = new NSHM27_InvConfigFactory(); + + for (NSHM27_SeismicityRegions seisReg : NSHM27_SeismicityRegions.values()) { + LogicTree tree = NSHM27_LogicTree.buildLogicTree(seisReg, + TectonicRegionType.SUBDUCTION_INTERFACE, numSamples, true, + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE); + tree.write(new File("/tmp/test_tree_"+seisReg.name()+".json")); + ContinuousDistribution dist = NSHM27_LogicTree.getInterfaceBDist(seisReg); + DistributionSamplingLevel distLevel = new DistributionSamplingLevel("Dist", "Dist", dist); + String distLabel = LogicTreeFigureWriter.getDistString(distLevel); + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + FaultSystemRupSet genericRS = factory.buildGenericRupSet(tree.getBranch(0), FaultSysTools.defaultNumThreads()); + + List> hingedBranches = new ArrayList<>(); + List> extrapolatedBranches = new ArrayList<>(); + for (LogicTreeBranch branch : tree) { + if (branch.hasValue(NSHM27_InterfaceObsSeisDMAdjustment.EXTRAPOLATE)) + extrapolatedBranches.add(branch); + else + hingedBranches.add(branch); + } + + // hinge samples + List> bFutures = new ArrayList<>(numSamples); + for (LogicTreeBranch branch : hingedBranches) { + bFutures.add(CompletableFuture.supplyAsync(()->{ + FaultSystemRupSet rs; + try { + rs = factory.updateRuptureSetForBranch(genericRS, branch); + } catch (IOException e) { + throw ExceptionUtils.asRuntimeException(e); + } + return NSHM27_InterfaceHingedBValue.calcRawInterfaceHingedBValue(rs, branch); + })); + } + + for (int i=0; i branch = hingedBranches.get(i); + try { + bFutures.get(i).get(); + } catch (Exception e) { + System.err.println("Failed on "+branch); + e.printStackTrace(); + System.err.flush(); + System.exit(1); + } + } + + EvenlyDiscretizedFunc hingedHist = new EvenlyDiscretizedFunc( + bValDiscr.getMinX(), bValDiscr.getMaxX(), bValDiscr.size()); + + double densityEach = hingeWeight/(bFutures.size()*hingedHist.getDelta()); + for (CompletableFuture future : bFutures) { + double b = future.join(); + int index = hingedHist.getClosestXIndex(b); + hingedHist.add(index, densityEach); + } + + for (LogicTreeBranch branch : hingedBranches) { + bFutures.add(CompletableFuture.supplyAsync(()->{ + FaultSystemRupSet rs; + try { + rs = factory.updateRuptureSetForBranch(genericRS, branch); + } catch (IOException e) { + throw ExceptionUtils.asRuntimeException(e); + } + return NSHM27_InterfaceHingedBValue.calcRawInterfaceHingedBValue(rs, branch); + })); + } + + EvenlyDiscretizedFunc extrapHist = new EvenlyDiscretizedFunc( + bValDiscr.getMinX(), bValDiscr.getMaxX(), bValDiscr.size()); + + densityEach = extrapolateWeight/(extrapolatedBranches.size()*hingedHist.getDelta()); + for (LogicTreeBranch branch : extrapolatedBranches) { + double b = ((PureGR)branch.requireValue(NSHM27_SeisRateModel.class).getRateRecord( + seisReg, branch.requireValue(NSHM27_SeisClassificationMethod.class), TectonicRegionType.SUBDUCTION_INTERFACE)).b; + int index = extrapHist.getClosestXIndex(b); + extrapHist.add(index, densityEach); + } + + EvenlyDiscretizedFunc totalHist = hingedHist.deepClone(); + + // The hinge calculation is truncated at b = 0. + int zeroBin = totalHist.getClosestXIndex(0d); + for (int i=0; i csvRateHeader = new ArrayList<>(); + List csvRIHeader = new ArrayList<>(); + csvRateHeader.add("Model Component"); + csvRIHeader.add("Model Component"); + for (double mag : csvMags) { + csvRateHeader.add("M>"+oDF.format(mag)+" rate"); + csvRIHeader.add("M>"+oDF.format(mag)+" RI"); + } + + for (NSHM27_SeismicityRegions seisReg : NSHM27_SeismicityRegions.values()) { + FaultSystemSolution sol = getSolution(seisReg); + GridSourceList gridList = sol.requireModule(GridSourceList.class); + + for (boolean mapRegion : new boolean[] {false,true}) { + Region reg; + if (mapRegion) + reg = NSHM27_MapRegions.valueOf(seisReg.name()).load(); + else + reg = seisReg.load(); + + IncrementalMagFreqDist fullObsMean = null; + EvenlyDiscretizedFunc fullObsMeanCml = null; + + for (boolean interfaceOnly : new boolean[] {false, true}) { + CSVFile rateCSV = null; + CSVFile riCSV = null; + if (!interfaceOnly) { + rateCSV = new CSVFile<>(true); + rateCSV.addLine(csvRateHeader); + riCSV = new CSVFile<>(true); + riCSV.addLine(csvRIHeader); + } + TectonicRegionType targetTRT = interfaceOnly ? TectonicRegionType.SUBDUCTION_INTERFACE : null; + List indvIncrFuncs = new ArrayList<>(); + List indvChars = new ArrayList<>(); + + SummedMagFreqDist gridSum = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + SummedMagFreqDist faultSum = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + + for (TectonicRegionType trt : TRTs) { + if (interfaceOnly && trt != TectonicRegionType.SUBDUCTION_INTERFACE) + continue; + Color gridColor = getColor(trt, IncludeBackgroundOption.ONLY); + Color faultColor = getColor(trt, IncludeBackgroundOption.EXCLUDE); + Color sumColor = getColor(trt, IncludeBackgroundOption.INCLUDE); + String trtName = NSHM27_RegionLoader.getNameForTRT(trt); + + IncrementalMagFreqDist gridMFD = loadGridded(gridList, trt, refMFD, reg); + IncrementalMagFreqDist faultMFD = loadFault(sol, trt, refMFD, reg); + + processCSVs(faultMFD, trtName+" (on-fault)", csvMags, rateCSV, riCSV); + processCSVs(gridMFD, trtName+" (gridded)", csvMags, rateCSV, riCSV); + + if (faultMFD != null) { + if (!interfaceOnly) { + SummedMagFreqDist sum = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + sum.addIncrementalMagFreqDist(gridMFD); + sum.addIncrementalMagFreqDist(faultMFD); + + sum.setName(trtName+" (combined)"); + indvIncrFuncs.add(sum); + indvChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 2f, sumColor)); + + processCSVs(sum, trtName+" (combined)", csvMags, rateCSV, riCSV); + } + + faultMFD.setName(trtName+" (on-fault)"); + indvIncrFuncs.add(faultMFD); + indvChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, faultColor)); + faultSum.addIncrementalMagFreqDist(faultMFD); + } + + gridMFD.setName(trtName+" (gridded)"); + indvIncrFuncs.add(gridMFD); + indvChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, gridColor)); + gridSum.addIncrementalMagFreqDist(gridMFD); + } + + List incrFuncs = new ArrayList<>(); + List cmlFuncs = new ArrayList<>(); + List chars = new ArrayList<>(); + + SummedMagFreqDist mfdSum = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + mfdSum.addIncrementalMagFreqDist(gridSum); + mfdSum.addIncrementalMagFreqDist(faultSum); + if (interfaceOnly) + mfdSum.setName("Total interface"); + else + mfdSum.setName("Total"); + incrFuncs.add(mfdSum); + cmlFuncs.add(mfdSum.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Color.BLACK)); + + processCSVs(mfdSum, "Total", csvMags, rateCSV, riCSV); + + // uncertainty for legend + IncrementalMagFreqDist emptyFunc = new IncrementalMagFreqDist(refMFD.getMinX(), refMFD.size(), refMFD.getDelta()); + UncertainBoundedIncrMagFreqDist emptyUnceratain = new UncertainBoundedIncrMagFreqDist(emptyFunc, emptyFunc, emptyFunc, null); + emptyUnceratain.setName(fractileLabel); + incrFuncs.add(emptyUnceratain); + cmlFuncs.add(emptyUnceratain); + chars.add(bounds68Char); + + // individual components + for (int i=0; i= 0); + IncrementalMagFreqDist[] incrFractiles = regMFDs.calcRegionalIncrementalFractiles(MFDType.SUM, regionIndex, fractiles); + UncertainBoundedIncrMagFreqDist incrExtrema = new UncertainBoundedIncrMagFreqDist(incrFractiles[3], incrFractiles[0], incrFractiles[6], null); + UncertainBoundedIncrMagFreqDist incr95 = new UncertainBoundedIncrMagFreqDist(incrFractiles[3], incrFractiles[1], incrFractiles[5], null); + UncertainBoundedIncrMagFreqDist incr68 = new UncertainBoundedIncrMagFreqDist(incrFractiles[3], incrFractiles[2], incrFractiles[4], null); + EvenlyDiscretizedFunc[] cmlFractiles = regMFDs.calcRegionalCumulativeFractiles(MFDType.SUM, regionIndex, fractiles); + UncertainArbDiscFunc cmlExtrema = new UncertainArbDiscFunc(cmlFractiles[3], cmlFractiles[0], cmlFractiles[6]); + UncertainArbDiscFunc cml95 = new UncertainArbDiscFunc(cmlFractiles[3], cmlFractiles[1], cmlFractiles[5]); + UncertainArbDiscFunc cml68 = new UncertainArbDiscFunc(cmlFractiles[3], cmlFractiles[2], cmlFractiles[4]); + + processCSVsWithCml(cmlFractiles[0], "Total (minimum)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[1], "Total (2.5 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[2], "Total (16 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[5], "Total (50 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[4], "Total (84 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[5], "Total (97.5 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(cmlFractiles[6], "Total (maximum)", csvMags, rateCSV, riCSV); + + processCSVsWithCml(obsCmlMean, "Observed", csvMags, rateCSV, riCSV); + processCSVsWithCml(obsCmlLow, "Observed (2.5 %-ile)", csvMags, rateCSV, riCSV); + processCSVsWithCml(obsCmlHigh, "Observed (97.5 %-ile)", csvMags, rateCSV, riCSV); + + incrExtrema.setName(null); + incrFuncs.add(incrExtrema); + cmlExtrema.setName(null); + cmlFuncs.add(cmlExtrema); + chars.add(extremaChar); + + incr95.setName(null); + incrFuncs.add(incr95); + cml95.setName(null); + cmlFuncs.add(cml95); + chars.add(bounds95Char); + + incr68.setName(null); + incrFuncs.add(incr68); + cml68.setName(null); + cmlFuncs.add(cml68); + chars.add(bounds68Char); + + RectangleAnchor anchor = RectangleAnchor.TOP_RIGHT; +// RectangleAnchor anchor = RectangleAnchor.BOTTOM_LEFT; + + String title = seisReg.getTitleCaseAcronym(); + if (mapRegion) + title += " Map Region"; + if (interfaceOnly) + title += " (interface)"; +// else +// title += " overall"; + + PlotSpec incrPlot = new PlotSpec(incrFuncs, chars, title, "Magnitude", "Incremental rate (1/yr)"); + incrPlot.setLegendInset(anchor); + + PlotSpec cmlPlot = new PlotSpec(cmlFuncs, chars, title, "Magnitude", "Cumulative rate (1/yr)"); + cmlPlot.setLegendInset(anchor); + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + + String prefix = seisReg.name(); + if (mapRegion) + prefix += "_map_region"; + if (interfaceOnly) + prefix += "_interface"; + + gp.drawGraphPanel(incrPlot, false, true, xRange, yRange); + +// PlotUtils.writePrintPlots(outputDir, prefix+"_incr_half", gp, halfWidth, halfHeight, 150, true, true, false); + PlotUtils.writePrintPlots(outputDir, prefix+"_incr", gp, fullWidth, fullHeight, 150, true, true, false); + + gp.drawGraphPanel(cmlPlot, false, true, xRange, yRange); + +// PlotUtils.writePrintPlots(outputDir, prefix+"_cml_half", gp, halfWidth, halfHeight, 150, true, true, false); + PlotUtils.writePrintPlots(outputDir, prefix+"_cml", gp, fullWidth, fullHeight, 150, true, true, false); + + if (!interfaceOnly) { + rateCSV.writeToFile(new File(outputDir, prefix+"_cml_rates.csv")); + riCSV.writeToFile(new File(outputDir, prefix+"_cml_ris.csv")); + } + } + } + } + } + + private static IncrementalMagFreqDist loadGridded(GridSourceList gridList, + TectonicRegionType trt, EvenlyDiscretizedFunc refMFD, Region reg) { + SummedMagFreqDist mfdSum = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + boolean regCheck = reg != null && !gridList.getGriddedRegion().equalsRegion(reg); + for (int l=0; l 0d) + return mfdSum; + return null; + } + + private static void processCSVs(IncrementalMagFreqDist mfd, String name, double[] mags, + CSVFile rateCSV, CSVFile riCSV) { + if (mfd == null || rateCSV == null) + return; + EvenlyDiscretizedFunc cml = mfd.getCumRateDistWithOffset(); + processCSVsWithCml(cml, name, mags, rateCSV, riCSV); + } + + private static void processCSVsWithCml(EvenlyDiscretizedFunc cmlMFD, String name, double[] mags, + CSVFile rateCSV, CSVFile riCSV) { + if (cmlMFD == null || rateCSV == null) + return; + List rateLine = new ArrayList<>(); + List riLine = new ArrayList<>(); + rateLine.add(name); + riLine.add(name); + for (double mag : mags) { + int index = cmlMFD.getClosestXIndex(mag); + double rate = cmlMFD.getY(index); + rateLine.add((float)rate+""); + double ri = 1d/rate; + if (ri > 10d) + riLine.add((int)Math.round(ri)+""); + else if (ri > 1d) + riLine.add(oDF.format(ri)); + else if (ri > 0.1) + riLine.add(twoDF.format(ri)); + else + riLine.add((float)ri+""); + } + rateCSV.addLine(rateLine); + riCSV.addLine(riLine); + } +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/CrustalNucleationAroundFaultZoom.java b/src/main/java/scratch/kevin/nshm27/figures/CrustalNucleationAroundFaultZoom.java new file mode 100644 index 00000000..5dd610cd --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/CrustalNucleationAroundFaultZoom.java @@ -0,0 +1,84 @@ +package scratch.kevin.nshm27.figures; + +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.List; + +import org.opensha.commons.data.xyz.GriddedGeoDataSet; +import org.opensha.commons.geo.GriddedRegion; +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.Region; +import org.opensha.commons.gui.plot.GeographicMapMaker; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.modules.FaultGridAssociations; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList; +import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList.GriddedRupture; +import org.opensha.sha.earthquake.faultSysSolution.reports.plots.NucleationRatePlot; +import org.opensha.sha.magdist.IncrementalMagFreqDist; +import org.opensha.sha.util.TectonicRegionType; + +public class CrustalNucleationAroundFaultZoom { + + public static void main(String[] args) throws IOException { + Region reg = new Region(new Location(13, 144), new Location(16, 146)); + FaultSystemSolution sol = FaultSystemSolution.load(new File( +// "/data/kevin/nshm23/batch_inversions/2026_03_27-nshm26-GNMI-2000samples-gridded/" + "/data/kevin/nshm23/batch_inversions/2026_07_13-nshm27-GNMI-5000samples-lhs_pairwise/" + + "results_GNMI_V1_ACTIVE_SHALLOW_branch_averaged.zip")); + File outputDir = new File("/tmp"); + GridSourceList gridList = sol.requireModule(GridSourceList.class); + + GriddedRegion gridReg = new GriddedRegion(reg, 0.1, GriddedRegion.ANCHOR_0_0); + + double[] minMags = {5d, 6d, 6.5, 7d, 7.5}; + GriddedGeoDataSet[] gridXYZs = new GriddedGeoDataSet[minMags.length]; + GriddedGeoDataSet[] totXYZs = new GriddedGeoDataSet[minMags.length]; + for (int m=0; m= minMags[m]) { + gridXYZs[m].add(l, rup.rate); + totXYZs[m].add(l, rup.rate); + } + } + } + } + + List solNuclMFDs = NucleationRatePlot.calcNuclMFDs(sol, TectonicRegionType.ACTIVE_SHALLOW); + for (int m=0; m"+magDF.format(minMags[m])+")"); + mapMaker.plot(outputDir, "nshm27_crustal_grid_nucl_zoom_m"+magDF.format(minMags[m]), " "); + mapMaker.plotXYZData(totXYZs[m], cpt, "Crustal total nucleation rate (M>"+magDF.format(minMags[m])+")"); + mapMaker.plot(outputDir, "nshm27_crustal_nucl_zoom_m"+magDF.format(minMags[m]), " "); + } + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/DMLowerLimitTests.java b/src/main/java/scratch/kevin/nshm27/figures/DMLowerLimitTests.java new file mode 100644 index 00000000..5a2e8e09 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/DMLowerLimitTests.java @@ -0,0 +1,135 @@ +package scratch.kevin.nshm27.figures; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.modules.ModuleContainer; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.faultSysSolution.inversion.Inversions; +import org.opensha.sha.earthquake.faultSysSolution.logicTree.sectDistSampling.SectDistributionSampler.FixedFractileSampler; +import org.opensha.sha.earthquake.faultSysSolution.modules.FaultGridAssociations; +import org.opensha.sha.earthquake.faultSysSolution.modules.SectSlipRates; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceDeformationModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.faultSurface.FaultSection; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; + +public class DMLowerLimitTests { + + public static void main(String[] args) throws IOException { + ModuleContainer.VERBOSE_DEFAULT = false; + NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.GNMI; + int numSamples = 50000; + NSHM27_LogicTree.INTERFACE_B_HINGED_WEIGHT = 1d; + LogicTree tree = NSHM27_LogicTree.buildLogicTree(seisReg, + TectonicRegionType.SUBDUCTION_INTERFACE, numSamples, true, + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE); + int fixedIndex = 27551; + double searchThreshold = 0d; + + NSHM27_InvConfigFactory factory = new NSHM27_InvConfigFactory(); + FaultSystemRupSet rs = factory.buildGenericRupSet(tree.getBranch(0), 16); + SectSlipRates slips1 = rs.requireModule(SectSlipRates.class); + FaultSystemRupSet genericRS = rs; + + double minDM = Double.POSITIVE_INFINITY; + LogicTreeBranch minDMBranch = null; + if (fixedIndex >= 0) { + LogicTreeBranch branch = tree.getBranch(fixedIndex); + minDM = ((FixedFractileSampler)branch.requireValue(NSHM27_InterfaceDeformationModels.class).getValue()).getFixedFractile(); + minDMBranch = branch; + } else { + for (LogicTreeBranch branch : tree) { + double fract = ((FixedFractileSampler)branch.requireValue(NSHM27_InterfaceDeformationModels.class).getValue()).getFixedFractile(); + if (fract < minDM) { + minDM = fract; + minDMBranch = branch; + } + } + } + System.out.println("Min DM fractile: "+minDM); + System.out.println("Branch: "+minDMBranch); + rs = factory.updateRuptureSetForBranch(rs, minDMBranch); + Preconditions.checkState(rs != genericRS); + SectSlipRates slips2 = rs.requireModule(SectSlipRates.class); + Preconditions.checkState(slips1 != slips2); + for (int s=0; s 0d) { + List> lowBranches = new ArrayList<>(); + for (LogicTreeBranch branch : tree) { + double fract = ((FixedFractileSampler)branch.requireValue(NSHM27_InterfaceDeformationModels.class).getValue()).getFixedFractile(); + if (fract < searchThreshold) + lowBranches.add(branch); + } + System.out.println("Now trying tree for "+lowBranches.size()+" low branches"); + List> bFutures = new ArrayList<>(lowBranches.size()); + for (LogicTreeBranch branch : lowBranches) { + bFutures.add(CompletableFuture.supplyAsync(()->{ + FaultSystemRupSet branchRS; + try { + branchRS = factory.updateRuptureSetForBranch(genericRS, branch); + } catch (IOException e) { + throw ExceptionUtils.asRuntimeException(e); + } + return NSHM27_InterfaceHingedBValue.calcRawInterfaceHingedBValue(branchRS, branch); + })); + } + + for (int i=0; i branch = lowBranches.get(i); + try { + bFutures.get(i).get(); + } catch (Exception e) { + System.err.println("Failed on "+branch); + e.printStackTrace(); + System.err.flush(); + System.exit(1); + } + } + System.out.println("All "+lowBranches.size()+" succeeded for searchThreshold="+(float)searchThreshold); + System.exit(0); + } + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/InterfaceLogicTreeMFDExploration.java b/src/main/java/scratch/kevin/nshm27/figures/InterfaceLogicTreeMFDExploration.java new file mode 100644 index 00000000..a5066f97 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/InterfaceLogicTreeMFDExploration.java @@ -0,0 +1,599 @@ +package scratch.kevin.nshm27.figures; + +import static scratch.kevin.nshm27.figures.NSHM27_PaperPaths.*; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; +import org.opensha.commons.data.WeightedList; +import org.opensha.commons.data.function.ArbDiscrEmpiricalDistFunc; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.LightFixedXFunc; +import org.opensha.commons.data.sampling.generator.LatinHypercubePointSetGenerator; +import org.opensha.commons.data.uncertainty.UncertainArbDiscFunc; +import org.opensha.commons.data.uncertainty.UncertainBoundedIncrMagFreqDist; +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.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.commons.util.modules.ModuleContainer; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; +import org.opensha.sha.earthquake.faultSysSolution.logicTree.sectDistSampling.SectDistributionSampler.FixedFractileSampler; +import org.opensha.sha.earthquake.faultSysSolution.modules.ClusterRuptures; +import org.opensha.sha.earthquake.faultSysSolution.modules.FaultGridAssociations; +import org.opensha.sha.earthquake.faultSysSolution.modules.SectSlipRates; +import org.opensha.sha.earthquake.faultSysSolution.ruptures.plausibility.impl.prob.RuptureProbabilityCalc.BinaryRuptureProbabilityCalc; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.faultSysSolution.util.MaxRuptureLengthBranchNode; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.PureGR; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.SectionSupraSeisBValues; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceCouplingDepthModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceDeformationModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceFaultModels; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceMinSubSects; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceObsSeisDMAdjustment; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisClassificationMethod; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisRateModel; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceHingedBValue.CombinedSampledType; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionScalingRelationships; +import org.opensha.sha.faultSurface.FaultSection; +import org.opensha.sha.magdist.GutenbergRichterMagFreqDist; +import org.opensha.sha.magdist.IncrementalMagFreqDist; +import org.opensha.sha.magdist.SummedMagFreqDist; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; + +import net.mahdilamb.colormap.Colors; + +public class InterfaceLogicTreeMFDExploration { + + public static void main(String[] args) throws IOException { + File outputDir = new File(NSHM27_PaperPaths.FIGURES_DIR, "interface_mfd_exploration"); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + ModuleContainer.VERBOSE_DEFAULT = false; + NSHM27_SeismicityRegions seisReg = NSHM27_SeismicityRegions.AMSAM; + + outputDir = new File(outputDir, seisReg.name()); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + + TectonicRegionType trt = TectonicRegionType.SUBDUCTION_INTERFACE; + + boolean includeObs = true; + boolean includeTotalObs = true; + + LogicTreeBranch branch = NSHM27_LogicTree.buildDefault(seisReg, trt, false); + LogicTreeBranch sampledBranch = NSHM27_LogicTree.buildDefault(seisReg, trt, true); +// int samples = 50; +// int samples = 500; +// int samples = 1000; + int samples = 10000; + +// boolean skipSampled = true; + boolean skipSampled = false; + + for (int l=0; l level = branch.getLevel(l); + System.out.println(l+". "+level.getName()); + System.out.println("\tClass:\t"+level.getClass()); + LogicTreeNode value = branch.getValue(l); + System.out.println("\tValue:\t"+value); + System.out.println("\tValue type:\t"+level.getType()); + System.out.println("\tNum nodes:\t"+level.getNodes().size()); + } + + System.out.println(branch); + + int[] levelIndexes = { + branch.getLevelTypeIndex(NSHM27_InterfaceCouplingDepthModels.class), + branch.getLevelTypeIndex(NSHM27_InterfaceDeformationModels.Aggregated.class), + branch.getLevelTypeIndex(PRVI25_SubductionScalingRelationships.class), + branch.getLevelTypeIndex(SectionSupraSeisBValues.class), + branch.getLevelTypeIndex(NSHM27_InterfaceObsSeisDMAdjustment.class), + branch.getLevelTypeIndex(NSHM27_InterfaceMinSubSects.class), + branch.getLevelTypeIndex(MaxRuptureLengthBranchNode.class), + }; + + double[] lhSamples = new LatinHypercubePointSetGenerator(new Random(12345l)).generate(1000, 1).getDimensionValues(0); + + WeightedList classificationChoices = new WeightedList<>(); + for (NSHM27_SeisClassificationMethod classification : NSHM27_SeisClassificationMethod.values()) + if (classification.getNodeWeight() > 0d) + classificationChoices.add(classification, classification.getNodeWeight()); + List classificationSamples = classificationChoices.sampleEvenly(samples, new Random(12345l)); + LogicTreeLevel rateLevel = sampledBranch.getLevel(sampledBranch.getLevelTypeIndex(NSHM27_SeisRateModel.class)); + ((RandomLevel)rateLevel).build(lhSamples); + List rateModelSamples = rateLevel.getNodes(); + + NSHM27_InvConfigFactory factory = new NSHM27_InvConfigFactory(); + FaultSystemRupSet rupSet = factory.buildRuptureSet(branch, FaultSysTools.defaultNumThreads()); + + EvenlyDiscretizedFunc refMFD = FaultSysTools.initEmptyMFD(5.01, 9.99); + + FaultGridAssociations assoc = rupSet.requireModule(FaultGridAssociations.class); + + IncrementalMagFreqDist defaultMFD = calculateMFD(factory, rupSet, branch, refMFD, assoc); + + double defaultMmax = 0d; + for (int m=0; m 0) + defaultMmax = defaultMFD.getX(m); + + CPT tab10CPT = GMT_CPT_Files.CATEGORICAL_TAB10_NOGRAY.instance(); + Color[] tab10 = new Color[tab10CPT.size()]; + for (int i=0; i avgStrings = new ArrayList<>(); + + IncrementalMagFreqDist obsMFD = null; + EvenlyDiscretizedFunc obsCmlMFD = null; + if (includeObs) { + NSHM27_SeisRateModel rateModel = branch.requireValue(NSHM27_SeisRateModel.class); + obsMFD = rateModel.build(seisReg, branch.requireValue(NSHM27_SeisClassificationMethod.class), trt, refMFD, defaultMmax); + obsMFD.setName("Observed (interface)"); + System.out.println("Observed rate M>5: "+obsMFD.getCumRate(obsMFD.getClosestXIndex(5.01))); + System.out.println("Observed rate M>6: "+obsMFD.getCumRate(obsMFD.getClosestXIndex(6.01))); + obsCmlMFD = obsMFD.getCumRateDistWithOffset(); + // this could be used to make it appear flat to Mmax, but it's not realistic and won't match the extrap branch +// IncrementalMagFreqDist obsTmp = obsMFD.deepClone(); +// obsTmp.scaleToIncrRate(0, obsCmlMFD.getY(0)); +// obsCmlMFD = obsTmp; + } + IncrementalMagFreqDist obsTotalMFD = null; + EvenlyDiscretizedFunc obsTotalCmlMFD = null; + if (includeTotalObs) { + NSHM27_SeisRateModel rateModel = branch.requireValue(NSHM27_SeisRateModel.class); + obsTotalMFD = rateModel.build(seisReg, branch.requireValue(NSHM27_SeisClassificationMethod.class), null, refMFD, defaultMmax); + obsTotalMFD.setName("Observed (total)"); + System.out.println("Observed total rate M>5: "+obsTotalMFD.getCumRate(obsTotalMFD.getClosestXIndex(5.01))); + System.out.println("Observed total rate M>6: "+obsTotalMFD.getCumRate(obsTotalMFD.getClosestXIndex(6.01))); + obsTotalCmlMFD = obsTotalMFD.getCumRateDistWithOffset(); + } + + for (int l : levelIndexes) { + Preconditions.checkState(l >= 0); + LogicTreeLevel level = branch.getLevel(l); + LogicTreeNode defaultValue = branch.getValue(l); + LogicTreeLevel sampledLevel = sampledBranch.getLevel(l); + System.out.println("Processing level "+l+". "+level.getName()); + List incrFuncs = new ArrayList<>(); + List cmlFuncs = new ArrayList<>(); + List chars = new ArrayList<>(); + + if (includeTotalObs) { + incrFuncs.add(obsTotalMFD); + cmlFuncs.add(obsTotalCmlMFD); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 3f, Color.GRAY)); + } + + if (includeObs) { + incrFuncs.add(obsMFD); + cmlFuncs.add(obsCmlMFD); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 3f, OBS_RATE_COLOR)); + } + + if (sampledLevel == level) { + System.out.println("\tNormal level"); + SummedMagFreqDist avgMFD = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + double sumWeight = 0d; + int index = 0; + String avgStr = level.getName()+" RIs:"; + for (LogicTreeNode node : level.getNodes()) { + double weight = node.getNodeWeight(branch); + if (weight > 0d) { + branch.setValue(node); + IncrementalMagFreqDist mfd = calculateMFD(factory, rupSet, branch, refMFD, assoc); + avgMFD.addIncrementalMagFreqDist(mfd, weight); + sumWeight += weight; + Color color = tab10[index++ % tab10.length]; + mfd.setName(node.getShortName()); + incrFuncs.add(mfd); + EvenlyDiscretizedFunc cml = mfd.getCumRateDistWithOffset(); + cmlFuncs.add(cml); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 4f, color)); + avgStr += "\n\t"+node.getShortName()+":\t"+(float)(1d/cml.getY(0)); + } + } + if ((float)sumWeight != 1f) + avgMFD.scale(1d/sumWeight); + avgMFD.setName("Weighted Average"); + incrFuncs.add(avgMFD); + EvenlyDiscretizedFunc cml = avgMFD.getCumRateDistWithOffset(); + cmlFuncs.add(avgMFD.getCumRateDistWithOffset()); + avgStr += "\n\tAverage:\t"+(float)(1d/cml.getY(0)); + avgStrings.add(avgStr); + chars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 4f, Color.DARK_GRAY)); + + branch.setValue(defaultValue); + } else { +// baselineMFD = defaultMFD.deepClone(); +// baselineMFD.setName(defaultValue.getName()); + System.out.println("\tSampled version: "+sampledLevel.getName()); + if (skipSampled) { + System.out.println("Skipping sampling this time"); + continue; + } + boolean doRateSamples = SectionSupraSeisBValues.class.isAssignableFrom(sampledLevel.getType()); + List> levels = new ArrayList<>(); + List values = new ArrayList<>(); + for (int i=0; i myBranch = new LogicTreeBranch<>(levels, values); + ((RandomLevel)sampledLevel).build(lhSamples); + Preconditions.checkState(sampledLevel.getNodes().size() == samples); + double weightEach = 1d/samples; + SummedMagFreqDist avgMFD = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + List> mfdFutures = new ArrayList<>(samples); + List sampledNodes = sampledLevel.getNodes(); + Preconditions.checkState(sampledNodes.size() == samples); + for (int n=0; n{ + LogicTreeBranch myBranch2 = myBranch.copy(); + myBranch2.setValue(classNode); + myBranch2.setValue(l, node); + if (doRateSamples) + myBranch2.setValue(rateNode); + try { + return calculateMFD(factory, rupSet, myBranch2, refMFD, assoc); + } catch (IOException e) { + e.printStackTrace(); + System.err.flush(); + System.exit(1); + return null; + } + })); + } + + ArbDiscrEmpiricalDistFunc[] incrPDFs = new ArbDiscrEmpiricalDistFunc[refMFD.size()]; + ArbDiscrEmpiricalDistFunc[] cmlPDFs = new ArbDiscrEmpiricalDistFunc[refMFD.size()]; + for (int i=0; i mfdFuture = mfdFutures.get(i); + IncrementalMagFreqDist mfd = mfdFuture.join(); + EvenlyDiscretizedFunc cml = mfd.getCumRateDistWithOffset(); + avgMFD.addIncrementalMagFreqDist(mfd, weightEach); + for (int m=0; m 0 || incrPDFs[m] != null) { + if (incrPDFs[m] == null) { + incrPDFs[m] = new ArbDiscrEmpiricalDistFunc(); + if (i > 0) { + // add weight for prior ones that were zero + incrPDFs[m].set(0d, weightEach*(i-1)); + } + } + incrPDFs[m].set(y, weightEach); + } + double cmlY = cml.getY(m); + if (cmlY > 0 || cmlPDFs[m] != null) { + if (cmlPDFs[m] == null) { + cmlPDFs[m] = new ArbDiscrEmpiricalDistFunc(); + if (i > 0) { + // add weight for prior ones that were zero + cmlPDFs[m].set(0d, weightEach*(i-1)); + } + } + cmlPDFs[m].set(cmlY, weightEach); + } + } + } + double[] fractiles = {0d, 0.025, 0.16, 0.5, 0.84, 0.975, 1d}; + String fractileNames = "p[0, 2.5, 16, 84, 97.5, 100]"; +// Color transColor = new Color(0, 0, 0, 60); + Color base = Colors.tab_blue; + IncrementalMagFreqDist[] incrFractiles = new IncrementalMagFreqDist[fractiles.length]; + EvenlyDiscretizedFunc[] cmlFractiles = new EvenlyDiscretizedFunc[fractiles.length]; + for (int f=0; f myBranch2 = myBranch.copy(); + myBranch2.setValue(l, new NSHM27_InterfaceDeformationModels("Lower", "Lower", "Lower", 0d, fixedMin)); + incrFractiles[0] = calculateMFD(factory, rupSet, myBranch2, refMFD, assoc); + cmlFractiles[0] = incrFractiles[0].getCumRateDistWithOffset(); + + FixedFractileSampler fixedMax = new FixedFractileSampler(1d); + myBranch2.setValue(l, new NSHM27_InterfaceDeformationModels("Upper", "Upper", "Upper", 0d, fixedMax)); + incrFractiles[6] = calculateMFD(factory, rupSet, myBranch2, refMFD, assoc); + cmlFractiles[6] = incrFractiles[6].getCumRateDistWithOffset(); + } + + UncertainBoundedIncrMagFreqDist incrExtrema = new UncertainBoundedIncrMagFreqDist( + incrMedian, incrFractiles[0], incrFractiles[6], null); + UncertainArbDiscFunc cmlExtrema = new UncertainArbDiscFunc(cmlMedian, cmlFractiles[0], cmlFractiles[6]); + incrExtrema.setName(null); + cmlExtrema.setName(null); + incrFuncs.add(incrExtrema); + cmlFuncs.add(cmlExtrema); + chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, ColorUtils.transparent(base, 50))); + + UncertainBoundedIncrMagFreqDist incr95 = new UncertainBoundedIncrMagFreqDist( + incrMedian, incrFractiles[1], incrFractiles[5], null); + UncertainArbDiscFunc cml95 = new UncertainArbDiscFunc(cmlMedian, cmlFractiles[1], cmlFractiles[5]); + incr95.setName(null); + cml95.setName(null); + incrFuncs.add(incr95); + cmlFuncs.add(cml95); + chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, ColorUtils.transparent(base, 70))); + + UncertainBoundedIncrMagFreqDist incr68 = new UncertainBoundedIncrMagFreqDist( + incrMedian, incrFractiles[2], incrFractiles[4], null); + UncertainArbDiscFunc cml68 = new UncertainArbDiscFunc(cmlMedian, cmlFractiles[2], cmlFractiles[4]); + incr68.setName(fractileNames); + cml68.setName(fractileNames); + incrFuncs.add(incr68); + cmlFuncs.add(cml68); + chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, ColorUtils.transparent(base, 100))); + + if (sampledLevel instanceof MaxRuptureLengthBranchNode.DistributionSamplingLevel) { + MaxRuptureLengthBranchNode.DistributionSamplingLevel distSampleLevel = + (MaxRuptureLengthBranchNode.DistributionSamplingLevel)sampledLevel; + MaxRuptureLengthBranchNode.FixedValueLevel fixedValueLevel = (MaxRuptureLengthBranchNode.FixedValueLevel)level; + ContinuousDistribution dist = distSampleLevel.getDistribution(); + double origFixedValue = fixedValueLevel.getValue(); + + fixedValueLevel.setValue(dist.getSupportLowerBound()); + branch.setValue(l, fixedValueLevel.getNodes().get(0)); + IncrementalMagFreqDist mfdLow = calculateMFD(factory, rupSet, branch, refMFD, assoc); + mfdLow.setName("Lmax="+(int)dist.getSupportLowerBound()+" km"); + incrFuncs.add(mfdLow); + cmlFuncs.add(mfdLow.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, Colors.tab_green)); + + IncrementalMagFreqDist baseline = defaultMFD.deepClone(); + baseline.setName("Lmax="+((MaxRuptureLengthBranchNode)defaultValue).getValue().intValue()+" km"); + incrFuncs.add(baseline); + cmlFuncs.add(baseline.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 4f, Color.BLACK)); + + fixedValueLevel.setValue(dist.getSupportUpperBound()); + branch.setValue(l, fixedValueLevel.getNodes().get(0)); + IncrementalMagFreqDist mfdHigh = calculateMFD(factory, rupSet, branch, refMFD, assoc); + mfdHigh.setName("Lmax="+(int)dist.getSupportUpperBound()+" km"); + incrFuncs.add(mfdHigh); + cmlFuncs.add(mfdHigh.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, Colors.tab_orange)); + + // again on top + baseline = baseline.deepClone(); + baseline.setName(null); + incrFuncs.add(baseline); + cmlFuncs.add(baseline.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 4f, Color.BLACK)); + + fixedValueLevel.setValue(origFixedValue); + branch.setValue(l, fixedValueLevel.getNodes().get(0)); + } else { + IncrementalMagFreqDist baseline = defaultMFD.deepClone(); + baseline.setName(defaultValue.getName()); + incrFuncs.add(baseline); + cmlFuncs.add(baseline.getCumRateDistWithOffset()); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 4f, Color.BLACK)); + } + + if (SectionSupraSeisBValues.class.isAssignableFrom(level.getType())) { + SummedMagFreqDist avgHingedMFD = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + SummedMagFreqDist avgSampledMFD = new SummedMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + double sumHingedWeight = 0d; + double sumSampledWeight = 0d; + for (int n=0; n origIncrs = new ArrayList<>(); + List nodes = level.getNodes(); + for (int i=0; i addFuncs = new ArrayList<>(); + List addChars = new ArrayList<>(); + CPT tab10light = GMT_CPT_Files.CATEGORICAL_TAB10_LIGHT_NOGRAY.instance(); + for (int i=0; i 0) + break; + for (int m=faultMminIndex+1; m branch, EvenlyDiscretizedFunc refMFD, FaultGridAssociations assoc) throws IOException { + System.out.println("Calculating MFD for: "+branch); + ClusterRuptures cRups = rupSet.requireModule(ClusterRuptures.class); + rupSet = factory.updateRuptureSetForBranch(rupSet, branch); + BinaryRuptureProbabilityCalc exclusionModel = NSHM27_InvConfigFactory.buildExclusionModel(rupSet, branch, cRups); + + BitSet includedRups = new BitSet(rupSet.getNumRuptures()); + for (int rupIndex=0; rupIndex 0d) { + GutenbergRichterMagFreqDist gr = new GutenbergRichterMagFreqDist(refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + gr.setAllButTotCumRate(mMin, mMax, moRate, b); + mfd.addIncrementalMagFreqDist(gr); + } + } + + return mfd; + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/InterfaceObsSeisAdjFigures.java b/src/main/java/scratch/kevin/nshm27/figures/InterfaceObsSeisAdjFigures.java new file mode 100644 index 00000000..3b3a65ce --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/InterfaceObsSeisAdjFigures.java @@ -0,0 +1,96 @@ +package scratch.kevin.nshm27.figures; + +import static scratch.kevin.nshm27.figures.NSHM27_PaperPaths.*; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.math3.stat.StatUtils; +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.gui.plot.GeographicMapMaker; +import org.opensha.commons.logicTree.LogicTreeBranch; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.DataUtils; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.commons.util.modules.ModuleContainer; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; +import org.opensha.sha.earthquake.faultSysSolution.modules.SectSlipRates; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.NSHM27_InvConfigFactory; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_InterfaceObsSeisDMAdjustment; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; + +public class InterfaceObsSeisAdjFigures { + + public static void main(String[] args) throws IOException { + ModuleContainer.VERBOSE_DEFAULT = false; + File outputDir = new File(FIGURES_DIR, "interface_obs_seis_adj"); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + + NSHM27_InvConfigFactory factory = new NSHM27_InvConfigFactory(); + + CPT redCPT = GMT_CPT_Files.SEQUENTIAL_LAJOLLA_UNIFORM.instance().reverse().rescale(0d, 1d); + + for (NSHM27_SeismicityRegions seisReg : NSHM27_SeismicityRegions.values()) { + LogicTreeBranch branch = NSHM27_LogicTree.buildDefault(seisReg, TectonicRegionType.SUBDUCTION_INTERFACE, false); + System.out.println("Default branch: "+branch); + + CSVFile csv = new CSVFile<>(true); + csv.addLine("Adjustment", "Overall Moment Reduction Factor", "Section-Averaged Reduction Factor", + "Maximum Reduction Factor", "Median Reduction Factor", "Average Slip Rate (mm/yr)", "Maximum Slip Rate (mm/yr)"); + + branch.setValue(NSHM27_InterfaceObsSeisDMAdjustment.NONE); + + FaultSystemRupSet rs = factory.buildRuptureSet(branch, FaultSysTools.defaultNumThreads()); + SectSlipRates fullSlips = rs.requireModule(SectSlipRates.class); + + GeographicMapMaker mapMaker = new GeographicMapMaker(rs.getFaultSectionDataList()); + + double fullMoment = fullSlips.calcTotalMomentRate(); + + for (NSHM27_InterfaceObsSeisDMAdjustment adj : NSHM27_InterfaceObsSeisDMAdjustment.values()) { + SectSlipRates slips; + if (adj == NSHM27_InterfaceObsSeisDMAdjustment.NONE) { + slips = fullSlips; + } else { + branch.setValue(adj); + rs = factory.buildRuptureSet(branch, FaultSysTools.defaultNumThreads()); + slips = rs.requireModule(SectSlipRates.class); + } + MinMaxAveTracker slipTrack = new MinMaxAveTracker(); + + double branchMoment = slips.calcTotalMomentRate(); + + double[] factors = new double[slips.size()]; + for (int s=0; s 0) { + magLabels[m] = "On-fault M>"+oDF.format(minMags[m]); + magPrefixes[m] = "m"+oDF.format(minMags[m]); + } else { + magLabels[m] = "On-fault"; + magPrefixes[m] = "supra"; + } + } + + double[] sltMinMags = {0d}; + String[] sltMagLabels = new String[minMags.length]; + String[] sltMagPrefixes = new String[minMags.length]; + for (int m=0; m 0) { + sltMagLabels[m] = "On-fault M>"+oDF.format(sltMinMags[m]); + sltMagPrefixes[m] = "m"+oDF.format(sltMinMags[m]); + } else { + sltMagLabels[m] = "On-fault"; + sltMagPrefixes[m] = "supra"; + } + } + + List fixedBatchNodes = List.of( + NSHM27_InterfaceDeformationModels.Aggregated.HIGH_COUPLING, + NSHM27_InterfaceDeformationModels.Aggregated.LOW_COUPLING, + NSHM27_InterfaceHingedBValue.HINGED_SINGLE_NODE, + NSHM27_InterfaceObsSeisDMAdjustment.EXTRAPOLATE, + NSHM27_InterfaceCouplingDepthModels.DEEP_TAPER, + NSHM27_InterfaceCouplingDepthModels.DOUBLE_TAPER, + NSHM27_InterfaceCouplingDepthModels.NONE); + List>> fixedBatchLevelClasses = List.of( + BinnedUniformSamplingLevel.class + ); + + for (NSHM27_SeismicityRegions seisReg : NSHM27_SeismicityRegions.values()) { + CPT cpt = GMT_CPT_Files.RAINBOW_UNIFORM.instance(); + if (seisReg == NSHM27_SeismicityRegions.AMSAM) + cpt = cpt.rescale(-4, -1); + else + cpt = cpt.rescale(-5, -2); + cpt.setLog10(true); + File dir = getSolDir(seisReg); + + File solFile = getSolFile(seisReg); + FaultSystemSolution baSol = FaultSystemSolution.load(solFile); + + List interfaceSects = new ArrayList<>(); + List interfaceIndexes = new ArrayList<>(); + for (FaultSection sect : baSol.getRupSet().getFaultSectionDataList()) { + if (sect.getTectonicRegionType() == TectonicRegionType.SUBDUCTION_INTERFACE) { + interfaceSects.add(sect); + interfaceIndexes.add(sect.getSectionId()); + } + } + int[] interfaceRemaps = interfaceIndexes.size() == baSol.getRupSet().getNumSections() ? null : Ints.toArray(interfaceIndexes); + + GeographicMapMaker mapMaker = new GeographicMapMaker(interfaceSects); + + String baPrefix = seisReg.name()+"_ba_"; + + for (int m=0; m analysisTree = getAnalysisLogicTree(seisReg); + + File sltFile = new File(dir, "results_nogrid.zip"); + SolutionLogicTree slt = SolutionLogicTree.load(sltFile); + LogicTree tree = slt.getLogicTree(); + Preconditions.checkState(tree.size() == analysisTree.size()); + + List batchNodesList = new ArrayList<>(); + List> batchNodesLevels = new ArrayList<>(); + for (LogicTreeNode node : fixedBatchNodes) { + LogicTreeLevel match = null; + for (LogicTreeLevel level : tree.getLevels()) { + if (level.isMember(node)) { + match = level; + break; + } + } + if (match == null) { + // check analysis tree + for (LogicTreeLevel level : analysisTree.getLevels()) { + if (level.isMember(node)) { + match = level; + break; + } + } + } + if (match != null) { + batchNodesList.add(node); + batchNodesLevels.add(match); + } + } + for (LogicTree theTree : List.of(tree, analysisTree)) { + for (LogicTreeLevel level : theTree.getLevels()) { + for (Class> clazz : fixedBatchLevelClasses) { + if (clazz.isAssignableFrom(level.getClass())) { + for (LogicTreeNode node : level.getNodes()) { + if (!batchNodesList.contains(node)) { + batchNodesList.add(node); + batchNodesLevels.add(level); + } + } + } + } + } + } + + LogicTreeNode[] batchNodes = new LogicTreeNode[batchNodesList.size()]; + for (int n=0; n level = batchNodesLevels.get(n); + System.out.println("Will average for node: "+level.getShortName()+" "+node.getFilePrefix()); + batchNodes[n] = node; + } + + double[][][] batchValues = new double[batchNodes.length][][]; + double[] batchWeightSums = new double[batchNodes.length]; + int[] batchCounts = new int[batchNodes.length]; + + CompletableFuture processFuture = null; + for (int b=0; b branch = tree.getBranch(b); + LogicTreeBranch analysisBranch = analysisTree.getBranch(b); + + System.out.println("Branch "+b+":\t"+analysisBranch); + + List matches = new ArrayList<>(); + for (LogicTreeNode node : batchNodes) + if (branch.hasValue(node) || analysisBranch.hasValue(node)) + matches.add(node.getFilePrefix()); + if (matches.isEmpty()) { + System.out.println("\tNo matches, skipping"); + continue; + } + System.out.println("\tMatches:\t"+matches); + + FaultSystemSolution sol = slt.forBranch(branch); + + if (processFuture != null) + processFuture.join(); + + double weight = tree.getBranchWeight(b); + + processFuture = CompletableFuture.runAsync(() -> { + int numSects = interfaceRemaps == null ? sol.getRupSet().getNumSections() : interfaceRemaps.length; + + double[][] magRates = new double[sltMinMags.length][]; + for (int m=0; m tree = NSHM27_LogicTree.buildLogicTree(seisReg, trt, samples, true, samplingMethod); + tree = stripFaultModels(tree); + + LogicTreeFigureWriter ltFig = new LogicTreeFigureWriter(tree, false, useLevelWeights); + ltFig.write(outputDir, seisReg.name()+"_"+trt.name(), true, true); + + boolean doSeparate = trt == TectonicRegionType.SUBDUCTION_INTERFACE + || (trt == TectonicRegionType.ACTIVE_SHALLOW && seisReg == NSHM27_SeismicityRegions.GNMI); + if (doSeparate) { + List> levels = NSHM27_LogicTree.buildLevels(seisReg, trt, useLevelWeights, true, false, false); + levels = stripFaultModels(levels); + tree = LogicTree.buildSampled(levels, samples, 123456l, NSHM27_InterfaceFaultModels.regionDefault(seisReg)); + + ltFig = new LogicTreeFigureWriter(tree, false, useLevelWeights); + ltFig.write(outputDir, seisReg.name()+"_"+trt.name()+"_inversion", true, true); + + // include common with gridded + levels = NSHM27_LogicTree.buildLevels(seisReg, trt, useLevelWeights, false, true, true); + levels = stripFaultModels(levels); + tree = LogicTree.buildSampled(levels, samples, 123456l); + + ltFig = new LogicTreeFigureWriter(tree, false, useLevelWeights); + ltFig.write(outputDir, seisReg.name()+"_"+trt.name()+"_gridded", true, true); + } + } + + LogicTree multiTree = NSHM27_LogicTree.buildMultiRegimeTree(seisReg, samples, true, samplingMethod); + LogicTreeFigureWriter ltFig = new LogicTreeFigureWriter(stripFaultModels(LogicTree.unrollTRTs(multiTree)), false, useLevelWeights); + ltFig.write(outputDir, seisReg.name()+"_combined", true, true); + } + } + + private static List> stripFaultModels(List> levels) { + List> ret = new ArrayList<>(); + + for (LogicTreeLevel level : levels) { + if (RupSetFaultModel.class.isAssignableFrom(level.getType())) + continue; + ret.add(level); + } + + return ret; + } + + public static LogicTree stripFaultModels(LogicTree tree) { + List> levels = stripFaultModels(tree.getLevels()); + return buildStrippedTree(tree, levels); + } + + private static List> stripModelLevel(List> levels) { + List> ret = new ArrayList<>(); + + for (LogicTreeLevel level : levels) { + if (NSHM27_ModelRegimeNode.class.isAssignableFrom(level.getType())) + continue; + ret.add(level); + } + + return ret; + } + + public static LogicTree stripModelLevel(LogicTree tree) { + List> levels = stripModelLevel(tree.getLevels()); + return buildStrippedTree(tree, levels); + } + + private static LogicTree buildStrippedTree(LogicTree tree, List> levels) { + List> branches = new ArrayList<>(tree.size()); + int[] levelIndexes = new int[levels.size()]; + Arrays.fill(levelIndexes, -1); + List> origLevels = tree.getLevels(); + for (int i=0; i level = levels.get(i); + for (int l=0; l origLevel = origLevels.get(l); + if (level == origLevel) { + Preconditions.checkState(levelIndexes[i] == -1); + levelIndexes[i] = l; + } + } + Preconditions.checkState(levelIndexes[i] >= 0); + } + for (LogicTreeBranch branch : tree) { + List values = new ArrayList<>(levels.size()); + for (int i=0; i modBranch = new LogicTreeBranch<>(levels, values); + modBranch.setOrigBranchWeight(branch.getOrigBranchWeight()); + branches.add(modBranch); + } + return LogicTree.fromExisting(levels, branches); + } + +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/NSHM27_PaperPaths.java b/src/main/java/scratch/kevin/nshm27/figures/NSHM27_PaperPaths.java new file mode 100644 index 00000000..05ab858a --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/NSHM27_PaperPaths.java @@ -0,0 +1,110 @@ +package scratch.kevin.nshm27.figures; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; + +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; +import org.opensha.sha.earthquake.param.IncludeBackgroundOption; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.util.TectonicRegionType; + +import net.mahdilamb.colormap.Colors; + +public class NSHM27_PaperPaths { + + public static final File PAPER_DIR =new File("/home/kevin/Documents/papers/2027_GNMI_AmSam_ERF/"); + public static final File FIGURES_DIR =new File(PAPER_DIR, "Figures"); + + public static final File INV_DIR = new File("/home/kevin/OpenSHA/fss_inversions/"); + + public static final String MODEL_DATE = "2026_07_13"; + + public static final File AMSAM_SOL_DIR = new File(INV_DIR, MODEL_DATE+"-nshm27-AMSAM-5000samples-lhs_pairwise"); + public static final File GNMI_SOL_DIR = new File(INV_DIR, MODEL_DATE+"-nshm27-GNMI-5000samples-lhs_pairwise"); + + public static File getSolDir(NSHM27_SeismicityRegions seisReg) { + return switch (seisReg) { + case AMSAM: + yield AMSAM_SOL_DIR; + case GNMI: + yield GNMI_SOL_DIR; + default: + throw new IllegalArgumentException("Unexpected value: " + seisReg); + }; + } + + public static File getSolFile(NSHM27_SeismicityRegions seisReg) { + return new File(getSolDir(seisReg), "results_branch_averaged.zip"); + } + + public static FaultSystemSolution getSolution(NSHM27_SeismicityRegions seisReg) throws IOException { + return FaultSystemSolution.load(getSolFile(seisReg)); + } + + public static File getInterfaceSolFile(NSHM27_SeismicityRegions seisReg) { + return new File(getSolDir(seisReg), "results_"+seisReg.name()+"_V1_SUBDUCTION_INTERFACE_branch_averaged.zip"); + } + + public static FaultSystemSolution getInterfaceSolution(NSHM27_SeismicityRegions seisReg) throws IOException { + return FaultSystemSolution.load(getInterfaceSolFile(seisReg)); + } + + public static LogicTree getLogicTree(NSHM27_SeismicityRegions seisReg) throws IOException { + File ltFile = new File(getSolDir(seisReg), "logic_tree.json"); + return LogicTree.read(ltFile); + } + + public static LogicTree getAnalysisLogicTree(NSHM27_SeismicityRegions seisReg) throws IOException { + File ltFile = new File(getSolDir(seisReg), "logic_tree_analysis.json"); + return LogicTree.read(ltFile); + } + + public static TectonicRegionType[] TRTs = { + TectonicRegionType.SUBDUCTION_INTERFACE, + TectonicRegionType.SUBDUCTION_SLAB, + TectonicRegionType.ACTIVE_SHALLOW, + }; + + public static Color getColor(TectonicRegionType trt, IncludeBackgroundOption bgType) { + return switch (trt) { + case ACTIVE_SHALLOW: + if (bgType == IncludeBackgroundOption.ONLY) + yield Colors.tab_lightblue; + else if (bgType == IncludeBackgroundOption.INCLUDE) + yield darker(Colors.tab_blue); + else + yield Colors.tab_blue; + case SUBDUCTION_INTERFACE: + if (bgType == IncludeBackgroundOption.ONLY) + yield Colors.tab_lightorange; + else if (bgType == IncludeBackgroundOption.INCLUDE) + yield darker(Colors.tab_orange); + else + yield Colors.tab_orange; + case SUBDUCTION_SLAB: + if (bgType == IncludeBackgroundOption.ONLY) + yield Colors.tab_lightgreen; + else if (bgType == IncludeBackgroundOption.INCLUDE) + yield darker(Colors.tab_green); + else + yield Colors.tab_green; + default: + throw new IllegalArgumentException("Unexpected value: " + trt); + }; + } + + public static Color OBS_RATE_COLOR = Colors.tab_brown.darker(); + + public static Color darker(Color color) { + return color.darker(); + } + + public static DecimalFormat oneDF = new DecimalFormat("0.0"); + public static DecimalFormat twoDF = new DecimalFormat("0.00"); + public static DecimalFormat oDF = new DecimalFormat("0.#"); + +} diff --git a/src/main/java/scratch/kevin/nshm27/figures/ObsUncertaintyBoundsFigure.java b/src/main/java/scratch/kevin/nshm27/figures/ObsUncertaintyBoundsFigure.java new file mode 100644 index 00000000..e5c8a038 --- /dev/null +++ b/src/main/java/scratch/kevin/nshm27/figures/ObsUncertaintyBoundsFigure.java @@ -0,0 +1,524 @@ +package scratch.kevin.nshm27.figures; + +import java.awt.Color; +import java.awt.Font; +import java.awt.geom.Point2D; +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.apache.commons.math3.stat.StatUtils; +import org.apache.commons.math3.util.Precision; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.chart.ui.TextAnchor; +import org.jfree.data.Range; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.HistogramFunction; +import org.opensha.commons.data.function.XY_DataSet; +import org.opensha.commons.data.xyz.EvenlyDiscrXYZ_DataSet; +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.PlotSymbol; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.gui.plot.jfreechart.xyzPlot.XYZPlotSpec; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateModel; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.Exact; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.PureGR; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateRecord; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateType; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisClassificationMethod; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisRateModelBranch; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_SeisRateModelSamples; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.magdist.GutenbergRichterMagFreqDist; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; + +import net.mahdilamb.colormap.Colors; + +import static scratch.kevin.nshm27.figures.NSHM27_PaperPaths.*; + +public class ObsUncertaintyBoundsFigure { + + public static void main(String[] args) throws IOException { + File outputDir = new File(FIGURES_DIR, "obs_mfd_bounds"); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + + boolean incremental = false; + EvenlyDiscretizedFunc refMFD = FaultSysTools.initEmptyMFD(3.05, 10.95); + + Color[] colors = { + Colors.tab_blue, + Colors.tab_orange, + Colors.tab_green + }; + + PlotLineType[] lineTypes = { + PlotLineType.DASHED, + PlotLineType.SOLID, + PlotLineType.DOTTED + }; + + PlotSymbol[] symbolTypes = { + PlotSymbol.FILLED_SQUARE, + PlotSymbol.FILLED_CIRCLE, + PlotSymbol.FILLED_INV_TRIANGLE + }; + + RateType[] types = { + RateType.M1, + RateType.M1_TO_MMAX, + RateType.EXACT + }; + + boolean includeWtMean = false; + + NSHM27_SeismicityRegions[] seisRegions = NSHM27_SeismicityRegions.values(); + TectonicRegionType[] trts = {TectonicRegionType.SUBDUCTION_INTERFACE, TectonicRegionType.SUBDUCTION_SLAB, TectonicRegionType.ACTIVE_SHALLOW}; + + double weightLow = NSHM27_SeisRateModelBranch.LOW.getNodeWeight(); + double weightPref = NSHM27_SeisRateModelBranch.PREFFERRED.getNodeWeight(); + double weightHigh = NSHM27_SeisRateModelBranch.HIGH.getNodeWeight(); + + for (NSHM27_SeismicityRegions seisReg : seisRegions) { + for (NSHM27_SeisClassificationMethod classification : NSHM27_SeisClassificationMethod.values()) { + for (TectonicRegionType trt : trts) { + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + String prefix = seisReg.name()+"_"+trt.name()+"_"+classification.name(); + String title = seisReg.getShortName()+" ("+NSHM27_RegionLoader.getNameForTRT(trt)+", "+classification.getShortName()+")"; + + DecimalFormat oDF = new DecimalFormat("0.#"); + + Double m1 = null; + Double mMax = null; + Map typeMagFuncs = new HashMap<>(); + EvenlyDiscretizedFunc overallMean = null; + SeismicityRateModel[] rateModels = new SeismicityRateModel[types.length]; + for (int t=0; t5: "+(float)weightAvg.getY(weightAvg.getClosestXIndex(5.01))); + System.out.println("\tM>6: "+(float)weightAvg.getY(weightAvg.getClosestXIndex(6.01))); + System.out.println("\tM>6 snapped: "+(float)weightAvg.getX(weightAvg.getClosestXIndex(6.01))); + System.out.println("\tM1="+m1.floatValue()); + System.out.println("\tMmax="+mMax.floatValue()); + } + + weightAvg.setName(typeName(type)+" Average"); + funcs.add(weightAvg); + chars.add(new PlotCurveCharacterstics(plt, 3f, Color.DARK_GRAY)); + } + } + + for (XY_DataSet func : funcs) { + if (func.getName() != null && func.getName().contains("M1")) + func.setName(func.getName().replace("M1", "M₁")); + if (func.getName() != null && func.getName().contains("Mmax")) + func.setName(func.getName().replace("Mmax", "Mₘₐₓ")); + } + + Range xRange = new Range(4d, 8d); + Range yRange = incremental ? new Range(1e-4, 1e2) : new Range(1e-3, 1e3); + + List anns = new ArrayList<>(); + Font annFont = new Font(Font.SANS_SERIF, Font.PLAIN, 22); + + DefaultXY_DataSet m1Line = new DefaultXY_DataSet(); + m1Line.set(m1, yRange.getLowerBound()); + m1Line.set(m1, yRange.getUpperBound()); + funcs.add(m1Line); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 2f, Color.DARK_GRAY)); + + DefaultXY_DataSet mMaxLine = new DefaultXY_DataSet(); + mMaxLine.set(mMax, yRange.getLowerBound()); + mMaxLine.set(mMax, yRange.getUpperBound()); + funcs.add(mMaxLine); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 2f, Color.DARK_GRAY)); + + XYTextAnnotation m1Ann = new XYTextAnnotation(" M₁=5", m1, yRange.getUpperBound()); + m1Ann.setFont(annFont); + m1Ann.setTextAnchor(TextAnchor.TOP_LEFT); + anns.add(m1Ann); + + XYTextAnnotation mMaxAnn = new XYTextAnnotation("Mₘₐₓ="+mMax.floatValue()+" ", mMax, yRange.getLowerBound()); + mMaxAnn.setFont(annFont); + mMaxAnn.setTextAnchor(TextAnchor.BOTTOM_RIGHT); + anns.add(mMaxAnn); + + PlotSpec plot = new PlotSpec(funcs, chars, title, "Magnitude", incremental ? "Incremental Rate (1/yr)" : "Cumulative Rate (1/yr)"); + plot.setLegendInset(true); + plot.setPlotAnnotations(anns); + + HeadlessGraphPanel gp = PlotUtils.initScreenHeadless(); + + gp.drawGraphPanel(plot, false, true, xRange, yRange); + + PlotUtils.writePlots(outputDir, prefix, gp, 700, 650, true, true, false); + + if (!incremental) { + List samples = new NSHM27_SeisRateModelSamples(seisReg, trt).loadOrigSamples(classification); + Collections.shuffle(samples, new Random(samples.size())); + +// int c = 200; +// int a = 127; +// int c = 150; +// int a = 80; + int c = 180; + int a = 60; + PlotCurveCharacterstics indvChar = new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, new Color(c, c, c, a)); + int maxNumRates = 1000; + int numRates = Integer.min(maxNumRates, samples.size()); + GutenbergRichterMagFreqDist[] rateMFDs = new GutenbergRichterMagFreqDist[samples.size()]; + for (int i=0; i(); + chars = new ArrayList<>(); + + linearHist.setName("Sampled Distribution"); + funcs.add(linearHist); + chars.add(new PlotCurveCharacterstics(PlotLineType.HISTOGRAM, 1f, Color.GRAY)); + + + DefaultXY_DataSet meanXY = new DefaultXY_DataSet(); + meanXY.set(meanValue, 0d); + meanXY.set(meanValue, maxY); + meanXY.setName("Mean"); + funcs.add(meanXY); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, Color.BLACK)); + + for (int t=0; t"+oDF.format(histMag)+" Rate", "Sample Count"); + plot.setLegendInset(true); + + gp.drawGraphPanel(plot, true, false, new Range(Math.pow(10, logMinRate), Math.pow(10, logMaxRate)), new Range(0d, maxY)); + + PlotUtils.writePlots(outputDir, prefix+"_hist_m"+oDF.format(histMag), gp, 700, 650, true, true, false); + } + + // write rate vs b + MinMaxAveTracker rateTrack = new MinMaxAveTracker(); + MinMaxAveTracker bTrack = new MinMaxAveTracker(); + double[] bValues = new double[samples.size()]; + double[] rates = new double[samples.size()]; + for (int s=0; s"+oDF.format(m1)+" Rate", "Fraction of "+samples.size()+" samples"); + xyzPlot.setLegendInset(RectangleAnchor.TOP_LEFT); + xyzPlot.setIncludeZlabelInLegend(false); + + double ratePlotMax = Math.min(rateVsB.getMaxY()-0.5*rateDelta, StatUtils.percentile(rates, 99.99)); + double ratePlotMin = Math.max(rateVsB.getMinY()+0.5*rateDelta, StatUtils.percentile(rates, 0.01)); + double bPlotMax = Math.min(rateVsB.getMaxX()-0.5*bDelta, StatUtils.percentile(bValues, 99.99)); + double bPlotMin = Math.max(rateVsB.getMinX()+0.5*bDelta, StatUtils.percentile(bValues, 0.01)); + + gp.drawGraphPanel(xyzPlot, false, false, new Range(bPlotMin, bPlotMax), new Range(ratePlotMin, ratePlotMax)); +// new Range(rateVsB.getMinX()-0.5*rateVsB.getGridSpacingX(), rateVsB.getMaxX()+0.5*rateVsB.getGridSpacingX()), +// new Range(rateVsB.getMinY()-0.5*rateVsB.getGridSpacingY(), rateVsB.getMaxY()+0.5*rateVsB.getGridSpacingY())); + + PlotUtils.writePrintPlots(outputDir, prefix+"_rate_vs_b", gp, + PlotUtils.DEFAULT_USABLE_PAGE_WIDTH*2d/3d, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH*2d/3d, + 150, true, true, false); + } + } + } + } + } + + private static String typeName(RateType type) { + String name = type.toString(); + return name.replace("Branches", "branches"); + } + + private static EvenlyDiscretizedFunc cmlMFD(RateRecord record, EvenlyDiscretizedFunc refMFD) { + if (record.type == RateType.EXACT) + return ((Exact)record).cumulativeDist; + Preconditions.checkState(record instanceof PureGR); + PureGR grRec = (PureGR)record; + // fake a cml GR + GutenbergRichterMagFreqDist grMFD = new GutenbergRichterMagFreqDist( + grRec.b, 1d, refMFD.getMinX(), refMFD.getMaxX(), refMFD.size()); + grMFD.scaleToIncrRate(grMFD.getX(grMFD.getClosestXIndex(grRec.M1+0.01)), grRec.rateAboveM1); + + EvenlyDiscretizedFunc cmlGR = new EvenlyDiscretizedFunc( + refMFD.getMinX()-0.5*refMFD.getDelta(), refMFD.size(), refMFD.getDelta()); + for (int i=0; i sects = fm.buildSubSects(fm); + + CPT dipCPT = GMT_CPT_Files.SEQUENTIAL_LAJOLLA_UNIFORM.instance().reverse().rescale(0d, 60d); + double maxRatio = 1.5; + CPT ratioCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(0d, 2d).trim(1d, 2d).rescale(1d, maxRatio); + + NSHM27_InterfaceDeformationModels.Aggregated dm = fm.getDefaultDeformationModel(); + + LogicTreeBranch branch = NSHM27_LogicTree.buildDefault(fm.getSeismicityRegion(), TectonicRegionType.SUBDUCTION_INTERFACE, false); + branch.setValue(NSHM27_InterfaceCouplingDepthModels.NONE); + +// double maxSlip = maxSlip(dm.apply(fm, branch, sects)); + CPT slipCPT = GMT_CPT_Files.SEQUENTIAL_BATLOW_UNIFORM.instance().rescale(0d, maxSlip); + + DeformationFront df = NSHM27_InterfaceDeformationModels.getDeformationFront(fm); + double moveOffset = 15d; // km + + LocationList dfTrace = df.trace(); + List regSects = new ArrayList<>(sects); + if (moveOffset > 0d) { + LocationList movedTrace = new LocationList(dfTrace.size()); + for (int i=0; is.getAveDip(), dipCPT, "Dip (degrees)"); + mapMaker.plot(outputDir, fm.name()+"_dip", " "); + + // cos(dip) = horizontal / on-plane + // on-plane = horizontal / cos(dip) + mapMaker.plotSectScalars(s->1d/Math.cos(Math.toRadians(s.getAveDip())), + ratioCPT, "Projected / Horizontal Slip Rate Ratio"); + mapMaker.plot(outputDir, fm.name()+"_slip_proj_ratio", " "); + + for (NSHM27_InterfaceCouplingDepthModels depthCoupling : NSHM27_InterfaceCouplingDepthModels.values()) { + branch.setValue(depthCoupling); + List dmSects = dm.apply(fm, branch, sects); + mapMaker.setFaultSections(dmSects); + mapMaker.plotSectScalars(s->s.getReducedAveSlipRate(), + slipCPT, "Slip deficit rate (mm/yr)"); + + List traces = new ArrayList<>(); + List traceChars = new ArrayList<>(); + + traces.add(dfTrace); + traceChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 15f, Color.BLACK)); +// traces.add(dfTrace); +// traceChars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 10f, Color.LIGHT_GRAY)); + int num = dfTrace.size(); + double[] slips = NSHM27_InterfaceDeformationModels.getCoupledSlipRates(df, dm.getSampler()); + for (int i=0; i lengthVals = new ArrayList<>(); + + double curLen = 0d; + for (int i=0; i 0) + curLen += LocationUtils.horzDistance(middle.get(i-1), middle.get(i)); + if (curLen >= nextMarker || i == numResample-1) { + Location loc; + double markerLen; + if (i > 0 && i < numResample-1) { + double overshoot = curLen - nextMarker; + double backAz = LocationUtils.azimuthRad(middle.get(i), middle.get(i-1)); + loc = LocationUtils.location(middle.get(i), backAz, overshoot); + markerLen = nextMarker; + } else { + loc = middle.get(i); + markerLen = curLen; + } + lengthLocs.add(loc); + lengthVals.add(markerLen); + + nextMarker += markerDelta; + } + } + + for (int i=0; i dmSects = odm.apply(fm, branch, sects); + + mapMaker.setFaultSections(dmSects); + mapMaker.plotSectScalars(s->s.getReducedAveSlipRate(), + slipCPT, "Slip deficit rate (mm/yr)"); + + mapMaker.plot(outputDir, fm.name()+"_"+odm.name()+"_slip_deficit_rate", + odm.getShortName()+" DM, Average Taper"); + } + } + + private static double maxSlip(List sects) { + double maxSlip = sects.stream().mapToDouble(S->S.getOrigAveSlipRate()).max().getAsDouble(); + double div10 = maxSlip / 10d; + if (div10 % 1 < 0.4) + return Math.floor(div10)*10d; + return Math.ceil(div10)*10d; + } + + private static Location middle(Location l1, Location l2) { + return new LocationAverager().add(l1, 1d).add(l2, 1d).getAverage(); + } + +} diff --git a/src/main/java/scratch/kevin/pointSources/DippingFaultTests.java b/src/main/java/scratch/kevin/pointSources/DippingFaultTests.java index 3898192d..5b9217cf 100644 --- a/src/main/java/scratch/kevin/pointSources/DippingFaultTests.java +++ b/src/main/java/scratch/kevin/pointSources/DippingFaultTests.java @@ -18,6 +18,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.Site; import org.opensha.commons.data.WeightedList; import org.opensha.commons.data.WeightedValue; @@ -566,7 +567,7 @@ public static void main(String[] args) throws IOException { name = "Finite"; // histColor = Colors.tab_lightorange; lineColor = Colors.tab_orange; - histColor = new Color(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue(), 127); + histColor = ColorUtils.transparent(lineColor, 127); scatterColorHW = Colors.tab_orange; scatterColorFW = Colors.tab_lightorange; scatterSymbol = PlotSymbol.BOLD_CROSS; @@ -576,7 +577,7 @@ public static void main(String[] args) throws IOException { name = "Point Sources"; // histColor = Colors.tab_lightblue; lineColor = Colors.tab_blue; - histColor = new Color(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue(), 127); + histColor = ColorUtils.transparent(lineColor, 127); scatterColorHW = Colors.tab_blue; scatterColorFW = Colors.tab_lightblue; scatterSymbol = PlotSymbol.BOLD_X; diff --git a/src/main/java/scratch/kevin/pointSources/InvCDF_RJBTableWriter.java b/src/main/java/scratch/kevin/pointSources/InvCDF_RJBTableWriter.java index 53913d2e..23a9ba28 100644 --- a/src/main/java/scratch/kevin/pointSources/InvCDF_RJBTableWriter.java +++ b/src/main/java/scratch/kevin/pointSources/InvCDF_RJBTableWriter.java @@ -24,6 +24,7 @@ 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.ColorUtils; import org.opensha.commons.util.cpt.CPT; import org.opensha.sha.earthquake.ProbEqkRupture; import org.opensha.sha.earthquake.ProbEqkSource; @@ -146,7 +147,7 @@ public static void main(String[] args) throws IOException { highlightFuncs.add(dist); highlightChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 5f, color)); } else { - color = new Color((255+color.getRed())/2, (255+color.getGreen())/2, (255+color.getBlue())/2); + color = ColorUtils.saturate(color, 1); funcs.add(dist); chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1.5f, color)); } diff --git a/src/main/java/scratch/kevin/pointSources/PointSourceBranchAveragedHazardScriptWriter.java b/src/main/java/scratch/kevin/pointSources/PointSourceBranchAveragedHazardScriptWriter.java index a2b8d9f7..6cea3bd7 100644 --- a/src/main/java/scratch/kevin/pointSources/PointSourceBranchAveragedHazardScriptWriter.java +++ b/src/main/java/scratch/kevin/pointSources/PointSourceBranchAveragedHazardScriptWriter.java @@ -394,7 +394,7 @@ else if (!supersampleQuick) System.out.println("Writing "+jobFile.getAbsolutePath()); - pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, queue); + pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/pointSources/paperFigs2026/PaperHazardScriptWriter.java b/src/main/java/scratch/kevin/pointSources/paperFigs2026/PaperHazardScriptWriter.java index 954f582a..3f7edb66 100644 --- a/src/main/java/scratch/kevin/pointSources/paperFigs2026/PaperHazardScriptWriter.java +++ b/src/main/java/scratch/kevin/pointSources/paperFigs2026/PaperHazardScriptWriter.java @@ -273,7 +273,7 @@ else if (gridReg.getNodeCount() > 5000) // System.out.println("\t\tWriting "+jobFile.getAbsolutePath()); - pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, queue); + pbsWrite.writeScript(jobFile, script, mins, myNodes, remoteTotalThreads, -1, queue); } } } diff --git a/src/main/java/scratch/kevin/pointSources/paperFigs2026/SpinningFaultExceedanceFigures.java b/src/main/java/scratch/kevin/pointSources/paperFigs2026/SpinningFaultExceedanceFigures.java index 6a58b6de..766a629e 100644 --- a/src/main/java/scratch/kevin/pointSources/paperFigs2026/SpinningFaultExceedanceFigures.java +++ b/src/main/java/scratch/kevin/pointSources/paperFigs2026/SpinningFaultExceedanceFigures.java @@ -49,6 +49,7 @@ import org.opensha.commons.gui.plot.PlotSpec; import org.opensha.commons.gui.plot.PlotSymbol; import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.DataUtils.MinMaxAveTracker; import org.opensha.commons.util.cpt.CPT; import org.opensha.sha.calc.RuptureExceedProbCalculator; @@ -94,7 +95,7 @@ private Sortables(String Label, Function function, Col label = Label; this.function = function; this.color = color; - this.transColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 80); + this.transColor = ColorUtils.transparent(color, 80); } }; @@ -348,7 +349,7 @@ public static void main(String[] args) throws IOException { func.setName("Centered individual"); funcs.add(func); // chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, Colors.tab_lightblue)); - chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1.5f, blend(Colors.tab_blue, 0.4, Colors.tab_lightblue, 0.6))); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1.5f, ColorUtils.blend(Colors.tab_blue, Colors.tab_lightblue, 0.6))); } // } else { // for (boolean hw : new boolean[] {true,false}) { @@ -1614,8 +1615,8 @@ public static void main(String[] args) throws IOException { } // spin the centered surfaces - Color centeredHWColor = overWhite(transColor(Colors.tab_blue, 80)); - Color centeredFWColor = overWhite(transColor(Colors.tab_lightblue, 80)); + Color centeredHWColor = ColorUtils.compositeOver(ColorUtils.transparent(Colors.tab_blue, 80), Color.WHITE); + Color centeredFWColor = ColorUtils.compositeOver(ColorUtils.transparent(Colors.tab_lightblue, 80), Color.WHITE); if (mech == FocalMech.STRIKE_SLIP) { // simple, no hw/fw DefaultXY_DataSet xyCircle = new DefaultXY_DataSet(); @@ -2043,7 +2044,7 @@ private static void addTransOutlineFuncs(List funcs, List funcs, List classpath = Lists.newArrayList(); classpath.add(new File("/home/scec-02/kmilner/hazMaps/svn/dist/OpenSHA_complete.jar")); - JavaShellScriptWriter javaWrite = new JavaShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, 7000, classpath); - USC_HPCC_ScriptWriter pbsWrite = new USC_HPCC_ScriptWriter("dodecacore"); + JavaShellScriptWriter javaWrite = new JavaShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, 7000, classpath); + USC_CARC_ScriptWriter pbsWrite = new USC_CARC_ScriptWriter("dodecacore"); int mins = 60; int nodes = 1; @@ -43,7 +43,7 @@ public static void main(String[] args) throws IOException { List script = javaWrite.buildScript(HazardBranchesPostProcess.class.getName(), cliargs); File pbsFile = new File(outDir, "assemble_"+name+".pbs"); - pbsWrite.writeScript(pbsFile, script, mins, nodes, ppn, queue); + pbsWrite.writeScript(pbsFile, script, mins, nodes, ppn, -1, queue); } } diff --git a/src/main/java/scratch/kevin/portfolioLEC/HazardMapLogicTreeInRegionsGen.java b/src/main/java/scratch/kevin/portfolioLEC/HazardMapLogicTreeInRegionsGen.java index 6f387307..426ec9d1 100644 --- a/src/main/java/scratch/kevin/portfolioLEC/HazardMapLogicTreeInRegionsGen.java +++ b/src/main/java/scratch/kevin/portfolioLEC/HazardMapLogicTreeInRegionsGen.java @@ -256,7 +256,7 @@ public static void main(String[] args) throws DocumentException, IOException { File pbsFile = new File(writeDir, prefix+".pbs"); USC_HPCC_ScriptWriter pbsWriter = new USC_HPCC_ScriptWriter(); - pbsWriter.writeScript(pbsFile, script, mins, nodes, ppn, queue); + pbsWriter.writeScript(pbsFile, script, mins, nodes, ppn, -1, queue); } } diff --git a/src/main/java/scratch/kevin/prvi25/AnegadaMFDTests.java b/src/main/java/scratch/kevin/prvi25/AnegadaMFDTests.java index 3e1bfe41..1a399d76 100644 --- a/src/main/java/scratch/kevin/prvi25/AnegadaMFDTests.java +++ b/src/main/java/scratch/kevin/prvi25/AnegadaMFDTests.java @@ -8,6 +8,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; import org.opensha.commons.gui.plot.HeadlessGraphPanel; @@ -138,7 +139,7 @@ public static void main(String[] args) throws IOException { if (type == MFDType.MAG_CORNER) { mfd.setName(null); funcs.add(mfd); - chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, new Color(color.getRed(), color.getGreen(), color.getBlue(), 127))); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, ColorUtils.transparent(color, 127))); mfdTable.put(b, seg, mfd); } IncrementalMagFreqDist weightedOverall = mfd.deepClone(); @@ -201,7 +202,7 @@ public static void main(String[] args) throws IOException { if (mfd == null) continue; funcs.add(mfd); - chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, new Color(color.getRed(), color.getGreen(), color.getBlue(), 127))); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, ColorUtils.transparent(color, 127))); weightSum += b.weight; mfd = mfd.deepClone(); @@ -228,7 +229,7 @@ public static void main(String[] args) throws IOException { mfd.setName("b="+(float)b.bValue); chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 3f, color)); } else { - chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, new Color(color.getRed(), color.getGreen(), color.getBlue(), 127))); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, ColorUtils.transparent(color, 127))); } funcs.add(mfd); } diff --git a/src/main/java/scratch/kevin/prvi25/BowinFaultAddTest.java b/src/main/java/scratch/kevin/prvi25/BowinFaultAddTest.java index 4f262e07..4baa4fd0 100644 --- a/src/main/java/scratch/kevin/prvi25/BowinFaultAddTest.java +++ b/src/main/java/scratch/kevin/prvi25/BowinFaultAddTest.java @@ -35,8 +35,9 @@ import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList; import org.opensha.sha.earthquake.faultSysSolution.modules.RupSetTectonicRegimes; import org.opensha.sha.earthquake.faultSysSolution.treeCombiners.SolutionLogicTreeCombinationProcessor; -import org.opensha.sha.earthquake.faultSysSolution.treeCombiners.SolutionLogicTreeCombinationProcessor.CombinedRupSetMappings; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.faultSysSolution.util.MergedSolutionCreator; +import org.opensha.sha.earthquake.faultSysSolution.util.MergedSolutionCreator.MergedRupSetMappings; import org.opensha.sha.earthquake.faultSysSolution.util.SolModuleStripper; import org.opensha.sha.earthquake.faultSysSolution.util.TrueMeanSolutionCreator; import org.opensha.sha.earthquake.param.IncludeBackgroundOption; @@ -251,12 +252,12 @@ public static void main(String[] args) throws IOException { FaultSystemSolution subductionSol = subductionBASols.get(combBranch.requireValue(PRVI25_SubductionFaultModels.class)); Preconditions.checkState(subductionSol.getRupSet().hasModule(RupSetTectonicRegimes.class), "Subduction solution doesn't have TRTs"); - FaultSystemSolution combined = SolutionLogicTreeCombinationProcessor.combineSols(solution, subductionSol, true); + FaultSystemSolution combined = MergedSolutionCreator.merge(solution, subductionSol); Preconditions.checkState(combined.getRupSet().hasModule(RupSetTectonicRegimes.class), "Combined solution doesn't have TRTs"); GridSourceList subductionGridded = subductionSol.requireModule(GridSourceList.class); - CombinedRupSetMappings mappings = combined.getRupSet().requireModule(CombinedRupSetMappings.class); - crustalGridded = GridSourceList.remapAssociations(crustalGridded, mappings.getInnerSectMappings()); - subductionGridded = GridSourceList.remapAssociations(subductionGridded, mappings.getOuterSectMappings()); + MergedRupSetMappings mappings = combined.getRupSet().requireModule(MergedRupSetMappings.class); + crustalGridded = GridSourceList.remapAssociations(crustalGridded, mappings.getSectMappingsOldToNew(0)); + subductionGridded = GridSourceList.remapAssociations(subductionGridded, mappings.getSectMappingsOldToNew(1)); combined.setGridSourceProvider(GridSourceList.combine(subductionGridded, crustalGridded)); creator.addSolution(combined, combBranch); @@ -317,7 +318,7 @@ public static void main(String[] args) throws IOException { System.out.println("Writing "+jobFile.getAbsolutePath()); - pbsWrite.writeScript(jobFile, script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(jobFile, script, mins, nodes, remoteTotalThreads, -1, queue); } } diff --git a/src/main/java/scratch/kevin/prvi25/CrustalSubductionTrueMeanCreator.java b/src/main/java/scratch/kevin/prvi25/CrustalSubductionTrueMeanCreator.java index 139a4044..3ff3102e 100644 --- a/src/main/java/scratch/kevin/prvi25/CrustalSubductionTrueMeanCreator.java +++ b/src/main/java/scratch/kevin/prvi25/CrustalSubductionTrueMeanCreator.java @@ -19,7 +19,8 @@ import org.opensha.sha.earthquake.faultSysSolution.modules.ProxyFaultSectionInstances; import org.opensha.sha.earthquake.faultSysSolution.modules.RupSetTectonicRegimes; import org.opensha.sha.earthquake.faultSysSolution.treeCombiners.SolutionLogicTreeCombinationProcessor; -import org.opensha.sha.earthquake.faultSysSolution.treeCombiners.SolutionLogicTreeCombinationProcessor.CombinedRupSetMappings; +import org.opensha.sha.earthquake.faultSysSolution.util.MergedSolutionCreator; +import org.opensha.sha.earthquake.faultSysSolution.util.MergedSolutionCreator.MergedRupSetMappings; import org.opensha.sha.earthquake.faultSysSolution.util.SolModuleStripper; import org.opensha.sha.earthquake.faultSysSolution.util.TrueMeanSolutionCreator; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.gridded.NSHM23_SingleRegionGridSourceProvider; @@ -123,14 +124,14 @@ public static void main(String[] args) throws IOException { FaultSystemSolution subductionSol = subductionBASols.get(branch.requireValue(PRVI25_SubductionFaultModels.class)); Preconditions.checkState(subductionSol.getRupSet().hasModule(RupSetTectonicRegimes.class), "Subduction solution doesn't have TRTs"); - FaultSystemSolution combined = SolutionLogicTreeCombinationProcessor.combineSols(crustalSol, subductionSol, true); + FaultSystemSolution combined = MergedSolutionCreator.merge(subductionSol, crustalSol); Preconditions.checkState(combined.getRupSet().hasModule(RupSetTectonicRegimes.class), "Combined solution doesn't have TRTs"); if (gridded) { GridSourceList crustalGridded = crustalSol.requireModule(GridSourceList.class); GridSourceList subductionGridded = subductionSol.requireModule(GridSourceList.class); - CombinedRupSetMappings mappings = combined.getRupSet().requireModule(CombinedRupSetMappings.class); - crustalGridded = GridSourceList.remapAssociations(crustalGridded, mappings.getInnerSectMappings()); - Map subductionMappings = new HashMap<>(mappings.getOuterSectMappings()); + MergedRupSetMappings mappings = combined.getRupSet().requireModule(MergedRupSetMappings.class); + crustalGridded = GridSourceList.remapAssociations(crustalGridded, mappings.getSectMappingsOldToNew(1)); + Map subductionMappings = new HashMap<>(mappings.getSectMappingsOldToNew(0)); // add slab IDs Preconditions.checkState(!subductionMappings.containsKey( PRVI25_GridSourceBuilder.CAR_SLAB_ASSOC_ID)); diff --git a/src/main/java/scratch/kevin/prvi25/GMMLogicTreeWriter.java b/src/main/java/scratch/kevin/prvi25/GMMLogicTreeWriter.java index f5dabd4d..d6354152 100644 --- a/src/main/java/scratch/kevin/prvi25/GMMLogicTreeWriter.java +++ b/src/main/java/scratch/kevin/prvi25/GMMLogicTreeWriter.java @@ -300,7 +300,7 @@ else if (bgOp == IncludeBackgroundOption.EXCLUDE) } argz += " "+MPJTaskCalculator.argumentBuilder().maxDispatch(100).threads(remoteTotalThreads).build(); List script = mpjWrite.buildScript(MPJ_LogicTreeHazardCalc.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, mapScriptName), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, mapScriptName), script, mins, nodes, remoteTotalThreads, -1, queue); // now write hazard curve script CSVFile csv = CSVFile.readStream(PRVI25_CrustalFaultModels.class.getResourceAsStream("/data/erf/prvi25/sites/prvi_sites.csv"), true); @@ -338,7 +338,7 @@ else if (bgOp == IncludeBackgroundOption.EXCLUDE) } argz += " "+MPJTaskCalculator.argumentBuilder().minDispatch(1).maxDispatch(10).threads(remoteTotalThreads).build(); script = mpjWrite.buildScript(MPJ_SiteLogicTreeHazardCurveCalc.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, siteScriptName), script, mins, nodes, remoteTotalThreads, queue); + pbsWrite.writeScript(new File(localDir, siteScriptName), script, mins, nodes, remoteTotalThreads, -1, queue); // combTree = LogicTree.read(new File(outputDir, "logic_tree.json")); // diff --git a/src/main/java/scratch/kevin/prvi25/GmmInputCacheBenchmark.java b/src/main/java/scratch/kevin/prvi25/GmmInputCacheBenchmark.java index 316a8d85..ebf007e6 100644 --- a/src/main/java/scratch/kevin/prvi25/GmmInputCacheBenchmark.java +++ b/src/main/java/scratch/kevin/prvi25/GmmInputCacheBenchmark.java @@ -17,6 +17,7 @@ import org.opensha.sha.calc.sourceFilters.SourceFilters; import org.opensha.sha.earthquake.faultSysSolution.hazard.mpj.AbstractSitewiseThreadedLogicTreeCalc; import org.opensha.sha.earthquake.faultSysSolution.modules.SolutionLogicTree; +import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysHazardCalcSettings; import org.opensha.sha.earthquake.param.IncludeBackgroundOption; import org.opensha.sha.earthquake.util.GriddedSeismicitySettings; import org.opensha.sha.imr.AttenRelRef; @@ -50,7 +51,7 @@ public static void main(String[] args) throws IOException { ExecutorService exec = Executors.newSingleThreadExecutor(); AbstractSitewiseThreadedLogicTreeCalc calc = new AbstractSitewiseThreadedLogicTreeCalc(exec, 1, slt, AttenRelRef.ASK_2014, periods, bgOp, GriddedSeismicitySettings.DEFAULT, - new SourceFilterManager(SourceFilters.TRT_DIST_CUTOFFS)) { + new SourceFilterManager(SourceFilters.TRT_DIST_CUTOFFS), FaultSysHazardCalcSettings.getXValManager()) { @Override public Site siteForIndex(int siteIndex, Map gmms) { diff --git a/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionPlotter.java b/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionPlotter.java index 20d3a2b6..bc22c9da 100644 --- a/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionPlotter.java +++ b/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionPlotter.java @@ -15,6 +15,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbDiscrEmpiricalDistFunc; import org.opensha.commons.data.function.DiscretizedFunc; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; @@ -82,8 +83,8 @@ public static void main(String[] args) throws IOException { int transAlpha = 60; Color randColor = Colors.tab_orange; Color threeBranchColor = Colors.tab_blue; - Color randAlphaColor = new Color(randColor.getRed(), randColor.getGreen(), randColor.getBlue(), transAlpha); - Color threeBranchAlphaColor = new Color(threeBranchColor.getRed(), threeBranchColor.getGreen(), threeBranchColor.getBlue(), transAlpha); + Color randAlphaColor = ColorUtils.transparent(randColor, transAlpha); + Color threeBranchAlphaColor = ColorUtils.transparent(threeBranchColor, transAlpha); Color indvColor = new Color(0, 0, 0, 20); PlotCurveCharacterstics indvChar = new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, indvColor); diff --git a/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionSolutionWriter.java b/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionSolutionWriter.java deleted file mode 100644 index e901b7eb..00000000 --- a/src/main/java/scratch/kevin/prvi25/GriddedRateDistributionSolutionWriter.java +++ /dev/null @@ -1,943 +0,0 @@ -package scratch.kevin.prvi25; - -import java.io.File; -import java.io.IOException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.function.Supplier; - -import org.opensha.commons.data.CSVFile; -import org.opensha.commons.geo.GriddedRegion; -import org.opensha.commons.geo.Region; -import org.opensha.commons.geo.json.Feature; -import org.opensha.commons.hpc.JavaShellScriptWriter; -import org.opensha.commons.hpc.mpj.FastMPJShellScriptWriter; -import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; -import org.opensha.commons.hpc.mpj.NoMPJSingleNodeShellScriptWriter; -import org.opensha.commons.hpc.pbs.BatchScriptWriter; -import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; -import org.opensha.commons.logicTree.Affects; -import org.opensha.commons.logicTree.BranchWeightProvider; -import org.opensha.commons.logicTree.DoesNotAffect; -import org.opensha.commons.logicTree.LogicTreeBranch; -import org.opensha.commons.logicTree.LogicTreeLevel; -import org.opensha.commons.logicTree.LogicTreeNode; -import org.opensha.commons.logicTree.LogicTreeLevel.FileBackedLevel; -import org.opensha.commons.logicTree.LogicTreeNode.FileBackedNode; -import org.opensha.commons.logicTree.LogicTreeNode.RandomlySampledNode; -import org.opensha.commons.util.DataUtils.MinMaxAveTracker; -import org.opensha.commons.util.io.archive.ArchiveOutput; -import org.opensha.sha.earthquake.faultSysSolution.FaultSystemRupSet; -import org.opensha.sha.earthquake.faultSysSolution.FaultSystemSolution; -import org.opensha.sha.earthquake.faultSysSolution.hazard.mpj.MPJ_LogicTreeHazardCalc; -import org.opensha.sha.earthquake.faultSysSolution.hazard.mpj.MPJ_SingleSolHazardCalc; -import org.opensha.sha.earthquake.faultSysSolution.modules.FaultCubeAssociations; -import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceList; -import org.opensha.sha.earthquake.faultSysSolution.modules.GridSourceProvider; -import org.opensha.sha.earthquake.faultSysSolution.modules.MFDGridSourceProvider; -import org.opensha.sha.earthquake.faultSysSolution.modules.SolutionLogicTree; -import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; -import org.opensha.sha.earthquake.faultSysSolution.util.SolLogicTreeSampler; -import org.opensha.sha.earthquake.param.IncludeBackgroundOption; -import org.opensha.sha.earthquake.rupForecastImpl.nshm23.gridded.NSHM23_SingleRegionGridSourceProvider; -import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_MaxMagOffFault; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.PRVI25_GridSourceBuilder; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.RateType; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalSeismicityRate; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_DeclusteringAlgorithms; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_LogicTree; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SeisSmoothingAlgorithms; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionCaribbeanSeismicityRate; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionMuertosSeismicityRate; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionScalingRelationships; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.util.PRVI25_RegionLoader; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.util.PRVI25_RegionLoader.PRVI25_SeismicityRegions; -import org.opensha.sha.imr.AttenRelRef; -import org.opensha.sha.magdist.GutenbergRichterMagFreqDist; -import org.opensha.sha.magdist.IncrementalMagFreqDist; - -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; - -import edu.usc.kmilner.mpj.taskDispatch.MPJTaskCalculator; - -public class GriddedRateDistributionSolutionWriter { - - public static void main(String[] args) throws IOException { - File ratesDir = new File("/home/kevin/OpenSHA/nshm23/prvi/rate_raw_data"); - File invsDir = new File("/home/kevin/OpenSHA/nshm23/batch_inversions/"); - FaultSystemSolution baSol = FaultSystemSolution.load(new File(invsDir, -// "2025_01_17-prvi25_subduction_branches/results_PRVI_SUB_FM_LARGE_branch_averaged.zip")); - "2025_01_17-prvi25_crustal_subduction_combined_branches/combined_branch_averaged_solution.zip")); - FaultSystemSolution subLargeSol = FaultSystemSolution.load(new File(invsDir, - "2025_01_17-prvi25_subduction_branches/results_PRVI_SUB_FM_LARGE_branch_averaged.zip")); - FaultSystemSolution crustalBASol = FaultSystemSolution.load(new File(invsDir, - "2025_01_17-prvi25_crustal_branches-dmSample10x/results_PRVI_CRUSTAL_FM_V1p1_branch_averaged_gridded.zip")); - -// File fullRandOutDir = new File(invsDir, "2025_05_13-prvi_gridded_variability-full_random"); - File fullRandOutDir = null; -// File threeBranchOutDir = new File(invsDir, "2025_05_13-prvi_gridded_variability-three_branch"); -// File threeBranchOutDir = null; - boolean threeBranchCorrelateMueAndCar = true; - File threeBranchOutDir = new File(invsDir, "2025_05_13-prvi_gridded_variability-three_branch-corr_mue_car"); - - Preconditions.checkState(fullRandOutDir == null || fullRandOutDir.exists() || fullRandOutDir.mkdir()); - Preconditions.checkState(threeBranchOutDir == null || threeBranchOutDir.exists() || threeBranchOutDir.mkdir()); - - List crustalPairs = loadRates(new File(ratesDir, "rbpairs-Crustal-Full-v3.csv")); - List carInterfacePairs = loadRates(new File(ratesDir, "rbpairs-CAR Interface-Full-v3.csv")); - List mueInterfacePairs = loadRates(new File(ratesDir, "rbpairs-MUE Interface-Full-v3.csv")); - List carSlabPairs = loadRates(new File(ratesDir, "rbpairs-CAR Intraslab-Full-v3.csv")); - List mueSlabPairs = loadRates(new File(ratesDir, "rbpairs-MUE Intraslab-Full-v3.csv")); - int numSamplesPer = 100; - int numTotalSamples = numSamplesPer*3*2*3*3*2; // times declustering and smoothing branches - Preconditions.checkState(numTotalSamples <= crustalPairs.size(), "Have %s samples but want %s sampling nodes", - crustalPairs.size(), numTotalSamples); - System.out.println(numTotalSamples+" total samples"); -// System.exit(0); - Random rand = new Random(numTotalSamples); - - List origDeclusterNodes = new ArrayList<>(); - LogicTreeLevel origDeclusterLevel = PRVI25_LogicTree.SEIS_DECLUSTER; - List crustalDeclusterNodes = new ArrayList<>(); - List interfaceDeclusterNodes = new ArrayList<>(); - for (PRVI25_DeclusteringAlgorithms node : origDeclusterLevel.getNodes()) { - if (node.getNodeWeight(null) == 0d) - continue; - origDeclusterNodes.add(node); - crustalDeclusterNodes.add(new FileBackedNode("Crustal "+node.getName(), node.getShortName(), - node.getNodeWeight(null), "Crustal"+node.getFilePrefix())); - interfaceDeclusterNodes.add(new FileBackedNode("Interface "+node.getName(), node.getShortName(), - node.getNodeWeight(null), "Interface"+node.getFilePrefix())); - } - FileBackedLevel crustalDeclusterLevel = new FileBackedLevel("Crustal "+origDeclusterLevel.getName(), - "Crustal"+origDeclusterLevel.getShortName(), crustalDeclusterNodes); - crustalDeclusterLevel.setAffected(origDeclusterLevel.getAffected(), origDeclusterLevel.getNotAffected(), false); - FileBackedLevel interfaceDeclusterLevel = new FileBackedLevel("Interface "+origDeclusterLevel.getName(), - "Interface"+origDeclusterLevel.getShortName(), interfaceDeclusterNodes); - interfaceDeclusterLevel.setAffected(origDeclusterLevel.getAffected(), origDeclusterLevel.getNotAffected(), false); - - List origSmoothingNodes = new ArrayList<>(); - LogicTreeLevel origSmoothingLevel = PRVI25_LogicTree.SEIS_SMOOTH; - List crustalSmoothingNodes = new ArrayList<>(); - List interfaceSmoothingNodes = new ArrayList<>(); - for (PRVI25_SeisSmoothingAlgorithms node : origSmoothingLevel.getNodes()) { - if (node.getNodeWeight(null) == 0d) - continue; - origSmoothingNodes.add(node); - crustalSmoothingNodes.add(new FileBackedNode("Crustal "+node.getName(), node.getShortName(), - node.getNodeWeight(null), "Crustal"+node.getFilePrefix())); - interfaceSmoothingNodes.add(new FileBackedNode("Interface "+node.getName(), node.getShortName(), - node.getNodeWeight(null), "Interface"+node.getFilePrefix())); - } - FileBackedLevel crustalSmoothingLevel = new FileBackedLevel("Crustal "+origSmoothingLevel.getName(), - "Crustal"+origSmoothingLevel.getShortName(), crustalSmoothingNodes); - crustalSmoothingLevel.setAffected(origSmoothingLevel.getAffected(), origSmoothingLevel.getNotAffected(), false); - FileBackedLevel interfaceSmoothingLevel = new FileBackedLevel("Interface "+origSmoothingLevel.getName(), - "Interface"+origSmoothingLevel.getShortName(), interfaceSmoothingNodes); - interfaceSmoothingLevel.setAffected(origSmoothingLevel.getAffected(), origSmoothingLevel.getNotAffected(), false); - - List> fullRandLevels = new ArrayList<>(); - fullRandLevels.add(crustalDeclusterLevel); - fullRandLevels.add(crustalSmoothingLevel); - fullRandLevels.add(PRVI25_LogicTree.MMAX_OFF); - CrustalRateSamplingLevel crustalSampler = new CrustalRateSamplingLevel(crustalPairs); - crustalSampler.buildNodes(rand, numTotalSamples); - fullRandLevels.add(crustalSampler); - fullRandLevels.add(interfaceDeclusterLevel); - fullRandLevels.add(interfaceSmoothingLevel); - fullRandLevels.add(PRVI25_LogicTree.SUB_SCALE); - CarSlabRateSamplingLevel carSampler = new CarSlabRateSamplingLevel(carSlabPairs, carInterfacePairs); - carSampler.buildNodes(rand, numTotalSamples); - MueRateSamplingLevel mueSampler = new MueRateSamplingLevel(mueSlabPairs, mueInterfacePairs); - mueSampler.buildNodes(rand, numTotalSamples); - fullRandLevels.add(carSampler); - fullRandLevels.add(mueSampler); - List> threeBranchLevels = new ArrayList<>(); - threeBranchLevels.add(crustalDeclusterLevel); - threeBranchLevels.add(crustalSmoothingLevel); - threeBranchLevels.add(PRVI25_LogicTree.MMAX_OFF); - threeBranchLevels.add(PRVI25_LogicTree.CRUSTAL_SEIS_RATE); - threeBranchLevels.add(interfaceDeclusterLevel); - threeBranchLevels.add(interfaceSmoothingLevel); - threeBranchLevels.add(PRVI25_LogicTree.SUB_SCALE); - threeBranchLevels.add(PRVI25_LogicTree.CAR_SEIS_RATE); - threeBranchLevels.add(PRVI25_LogicTree.MUE_SEIS_RATE); - - Region reg = PRVI25_RegionLoader.loadPRVI_Tight(); - GriddedRegion gridReg = new GriddedRegion(reg, 0.05, GriddedRegion.ANCHOR_0_0); - System.out.println("Region has "+gridReg.getNodeCount()+" nodes"); - SolutionLogicTree.FileBuilder threeBranchBuilder = null; - if (threeBranchOutDir != null) { - baSol.write(new File(threeBranchOutDir, "full_branch_averaged.zip")); - writeHazardScripts(threeBranchOutDir, gridReg); - threeBranchBuilder = new SolutionLogicTree.FileBuilder( -// new ArchiveOutput.AsynchronousZipFileOutput(new File(threeBranchOutDir, "results.zip"))); - new ArchiveOutput.ParallelZipFileOutput(new File(threeBranchOutDir, "results.zip"), 20)); - threeBranchBuilder.setSerializeGridded(true); - } - SolutionLogicTree.FileBuilder fullRandBuilder = null; - if (fullRandOutDir != null) { - baSol.write(new File(fullRandOutDir, "full_branch_averaged.zip")); - writeHazardScripts(fullRandOutDir, gridReg); - fullRandBuilder = new SolutionLogicTree.FileBuilder( -// new ArchiveOutput.AsynchronousZipFileOutput(new File(fullRandOutDir, "results.zip"))); - new ArchiveOutput.ParallelZipFileOutput(new File(fullRandOutDir, "results.zip"), 20)); - fullRandBuilder.setSerializeGridded(true); - } - - List crustalSamples = crustalSampler.getNodes(); - List carSamples = carSampler.getNodes(); - List mueSamples = mueSampler.getNodes(); - - IncrementalMagFreqDist refMFD = FaultSysTools.initEmptyMFD(PRVI25_GridSourceBuilder.OVERALL_MMIN, 8.6); - - baSol.setVerbose(false); - DecimalFormat pDF = new DecimalFormat("0.0%"); - - PRVI25_SubductionScalingRelationships scale = PRVI25_SubductionScalingRelationships.LOGA_C4p0; - List> levelsForInterface = new ArrayList<>(); - levelsForInterface.add(PRVI25_LogicTree.SUB_SCALE); - levelsForInterface.addAll(PRVI25_LogicTree.levelsSubductionGridded); - - double slabMmax = 7.95; // TODO: use branches - - int sampleIndex = 0; - int threeBranchWriteCount = 0; - int sampleWriteCount = 0; - for (int i1=0; i1> futures = new ArrayList<>(); - for (PRVI25_CrustalSeismicityRate crustalRate : PRVI25_CrustalSeismicityRate.values()) { - if (crustalRate.getNodeWeight(null) == 0d) - continue; - for (PRVI25_SubductionCaribbeanSeismicityRate carRate : PRVI25_SubductionCaribbeanSeismicityRate.values()) { - if (carRate.getNodeWeight(null) == 0d) - continue; - for (PRVI25_SubductionMuertosSeismicityRate mueRate : PRVI25_SubductionMuertosSeismicityRate.values()) { - if (mueRate.getNodeWeight(null) == 0d) - continue; - - if (threeBranchCorrelateMueAndCar && !carRate.getShortName().equals(mueRate.getShortName())) - continue; - - LogicTreeBranch branch = new LogicTreeBranch<>(threeBranchLevels); - branch.setValue(crustalDeclusterNode); - branch.setValue(crustalSmoothingNode); - branch.setValue(mmaxOff); - branch.setValue(crustalRate); - branch.setValue(interfaceDeclusterNode); - branch.setValue(interfaceSmoothingNode); - branch.setValue(carRate); - branch.setValue(mueRate); - branch.setValue(scale); - - if (threeBranchCorrelateMueAndCar) { - // need to correct the weight to remove the influence of the muertos - // rate branch - double curWeight = branch.getBranchWeight(); - // remove meurtos - curWeight /= mueRate.getNodeWeight(branch); - branch.setOrigBranchWeight(curWeight); - } - - LogicTreeBranch branchForCrustal = new LogicTreeBranch<>(PRVI25_LogicTree.levelsCrustalOffFault); - branchForCrustal.setValue(crustalOrigDeclusterNode); - branchForCrustal.setValue(crustalOrigSmoothingNode); - branchForCrustal.setValue(crustalRate); - branchForCrustal.setValue(mmaxOff); - - LogicTreeBranch branchForInterface = new LogicTreeBranch<>(levelsForInterface); - branchForInterface.setValue(interfaceOrigDeclusterNode); - branchForInterface.setValue(interfaceOrigSmoothingNode); - branchForInterface.setValue(mueRate); - branchForInterface.setValue(carRate); - branchForInterface.setValue(scale); - - futures.add(CompletableFuture.supplyAsync(new Supplier() { - - @Override - public GridResult get() { - try { - GridSourceList crustal = PRVI25_GridSourceBuilder.buildCrustalGridSourceProv(crustalBASol, branchForCrustal); - GridSourceList sub = PRVI25_GridSourceBuilder.buildCombinedSubductionGridSourceList(subLargeSol, branchForInterface); - GridSourceList comb = GridSourceList.combine(crustal, sub); - return new GridResult(comb, branch); - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - return null; - } - } - })); - } - } - } - - for (CompletableFuture future : futures) { - GridResult result = future.join(); - baSol.setGridSourceProvider(result.gridList); - threeBranchBuilder.solution(baSol, result.branch); - System.out.println("Writing 3-branch "+(threeBranchWriteCount++)); - } - } - - if (fullRandBuilder != null) { - System.out.println("Building "+numSamplesPer+" for "+crustalOrigDeclusterNode+", "+crustalOrigSmoothingNode - +", "+interfaceOrigDeclusterNode+", "+interfaceOrigSmoothingNode); - -// CompletableFuture prevFuture = null; - - Stopwatch totalWatch = Stopwatch.createStarted(); - Stopwatch ioWatch = Stopwatch.createUnstarted(); - List> futures = new ArrayList<>(); - for (int s=0; s branch = new LogicTreeBranch<>(fullRandLevels); - branch.setValue(crustalDeclusterNode); - branch.setValue(crustalSmoothingNode); - branch.setValue(crustalSample); - branch.setValue(mmaxOff); - branch.setValue(interfaceDeclusterNode); - branch.setValue(interfaceSmoothingNode); - branch.setValue(carSample); - branch.setValue(mueSample); - branch.setValue(scale); - - LogicTreeBranch branchForCrustal = new LogicTreeBranch<>(PRVI25_LogicTree.levelsCrustalOffFault); - branchForCrustal.setValue(crustalOrigDeclusterNode); - branchForCrustal.setValue(crustalOrigSmoothingNode); - branchForCrustal.setValue(mmaxOff); - - LogicTreeBranch branchForInterface = new LogicTreeBranch<>(levelsForInterface); - branchForInterface.setValue(interfaceOrigDeclusterNode); - branchForInterface.setValue(interfaceOrigSmoothingNode); - branchForInterface.setValue(scale); - - futures.add(CompletableFuture.supplyAsync(new Supplier() { - - @Override - public GridResult get() { - try { - GutenbergRichterMagFreqDist carSlabGR = buildGR(carSample.slabRate, carSample.slabB, - slabMmax, 5d, refMFD); - GutenbergRichterMagFreqDist mueSlabGR = buildGR(mueSample.slabRate, mueSample.slabB, - slabMmax, 5d, refMFD); - - GridSourceList carSlabList = PRVI25_GridSourceBuilder.buildSlabGridSourceList( - branchForInterface, PRVI25_SeismicityRegions.CAR_INTRASLAB, carSlabGR); - GridSourceList mueSlabList = PRVI25_GridSourceBuilder.buildSlabGridSourceList( - branchForInterface, PRVI25_SeismicityRegions.MUE_INTRASLAB, mueSlabGR); - - GridSourceList combSlabList = GridSourceList.combine(carSlabList, mueSlabList); - - Function carMFDBuilderFunc = new Function() { - - @Override - public IncrementalMagFreqDist apply(Double mmax) { - return buildGR(carSample.interfaceRate, carSample.interfaceB, - mmax, 5d, refMFD); - } - }; - Function mueMFDBuilderFunc = new Function() { - - @Override - public IncrementalMagFreqDist apply(Double mmax) { - return buildGR(mueSample.interfaceRate, mueSample.interfaceB, - mmax, 5d, refMFD); - } - }; - - GridSourceList carInterfaceList = PRVI25_GridSourceBuilder.buildInterfaceGridSourceList( - subLargeSol, branchForInterface, PRVI25_SeismicityRegions.CAR_INTERFACE, - scale.getMagAreaRelationship(), carMFDBuilderFunc); - GridSourceList mueInterfaceList = PRVI25_GridSourceBuilder.buildInterfaceGridSourceList( - subLargeSol, branchForInterface, PRVI25_SeismicityRegions.MUE_INTERFACE, - scale.getMagAreaRelationship(), mueMFDBuilderFunc); - - GridSourceList combInterfaceList = GridSourceList.combine(carInterfaceList, mueInterfaceList); - - GridSourceList combSubList = GridSourceList.combine(combSlabList, combInterfaceList); - - GutenbergRichterMagFreqDist crustalGR = buildGR(crustalSample.rate, crustalSample.b, - mmaxOff.getMaxMagOffFault(), 5d, refMFD); - NSHM23_SingleRegionGridSourceProvider crustalMFD = PRVI25_GridSourceBuilder.buildCrustalGridSourceProv( - crustalBASol, branchForCrustal, crustalBASol.getRupSet().requireModule(FaultCubeAssociations.class), crustalGR); - GridSourceList crustalList = crustalMFD.convertToGridSourceList(5d); - - GridSourceList combList = GridSourceList.combine(crustalList, combSubList); - return new GridResult(combList, branch); - } catch (IllegalStateException | IOException e) { - e.printStackTrace(); - System.exit(1); - return null; - } - } - })); - -// if (prevFuture != null) { -// ioWatch.start(); -// prevFuture.join(); -// ioWatch.stop(); -// } -// -// prevFuture = CompletableFuture.runAsync(new Runnable() { -// -// @Override -// public void run() { -// baSol.setGridSourceProvider(combList); -// try { -// fullRandBuilder.solution(baSol, branch); -// } catch (IOException e) { -// e.printStackTrace(); -// System.exit(1); -// } -// } -// }); - } -// prevFuture.join(); - - for (CompletableFuture future : futures) { - GridResult result = future.join(); - baSol.setGridSourceProvider(result.gridList); - fullRandBuilder.solution(baSol, result.branch); - System.out.println("Writing sampled "+(sampleWriteCount++)); - } - - totalWatch.stop(); - } - } - } - } - } - } - - if (fullRandBuilder != null) - fullRandBuilder.close(); - if (threeBranchBuilder != null) { - if (threeBranchCorrelateMueAndCar) - threeBranchBuilder.setWeightProv(new BranchWeightProvider.OriginalWeights()); - threeBranchBuilder.close(); - } - Preconditions.checkState(fullRandBuilder == null || sampleIndex == numTotalSamples, - "Only used %s samples but expected %s", sampleIndex, numTotalSamples); - } - - private static class GridResult { - public final GridSourceList gridList; - public final LogicTreeBranch branch; - - private GridResult(GridSourceList gridList, LogicTreeBranch branch) { - super(); - this.gridList = gridList; - this.branch = branch; - } - } - - private static GutenbergRichterMagFreqDist buildGR(double rateAboveM1, double b, double mMax, double m1, IncrementalMagFreqDist refMFD) { - GutenbergRichterMagFreqDist gr = new GutenbergRichterMagFreqDist(refMFD.getMinX(), refMFD.size(), refMFD.getDelta()); - // this sets shape, min/max - // subtract a tiny amount from mMax so that if it's exactly at a bin edge, e.g. 7.9, it rounds down, e.g. to 7.85 - gr.setAllButTotCumRate(refMFD.getX(0), refMFD.getX(refMFD.getClosestXIndex(mMax-0.001)), 1e16, b); - // this scales it to match - // similarly, add a tiny amount to M1 so that if it's exactly at a bin edge (which it should be as it's determined - // using cumulative binning), it rounds up to the incremental bin for that cumulative edge - gr.scaleToCumRate(refMFD.getClosestXIndex(m1+0.001), rateAboveM1); - return gr; - } - - public static List loadRates(File csvFile) throws IOException { - CSVFile csv = CSVFile.readFile(csvFile, false); - - boolean reading = false; - List ret = new ArrayList<>(); - - MinMaxAveTracker rateTrack = new MinMaxAveTracker(); - MinMaxAveTracker bTrack = new MinMaxAveTracker(); - for (int row=0; row fullBranch) { - return weight; - } - - @Override - public String getFilePrefix() { - return prefix; - } - - @Override - public String getShortName() { - return shortName; - } - - @Override - public String getName() { - return name; - } - - @Override - public long getSeed() { - return seed; - } - - @Override - public void init(String name, String shortName, String prefix, double weight, long seed) { - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - } - - } - - private static class CrustalRateSamplingLevel extends LogicTreeLevel.RandomlySampledLevel { - - private List samples; - private List randomizedSamples; - - private CrustalRateSamplingLevel() {} - - public CrustalRateSamplingLevel(List samples) { - this.samples = samples; - } - - @Override - public String getShortName() { - return "Crustal-Sampling"; - } - - @Override - public String getName() { - return "Crustal Rate/b Distribution Sampling"; - } - - @Override - public CrustalSamplingNode buildNodeInstance(int index, long seed, double weight) { - if (randomizedSamples == null) { - randomizedSamples = new ArrayList<>(samples); - Collections.shuffle(randomizedSamples, new Random(seed)); - } - double[] sample = randomizedSamples.get(index); - return new CrustalSamplingNode("Crustal Sample "+index, "Crustal-Sample"+index, "crustal_sample_"+index, weight, seed, - sample[0], sample[1]); - } - - @Override - public Class getType() { - return CrustalSamplingNode.class; - } - - } - - @DoesNotAffect(FaultSystemRupSet.SECTS_FILE_NAME) - @DoesNotAffect(FaultSystemRupSet.RUP_SECTS_FILE_NAME) - @DoesNotAffect(FaultSystemRupSet.RUP_PROPS_FILE_NAME) - @DoesNotAffect(FaultSystemSolution.RATES_FILE_NAME) - @DoesNotAffect(GridSourceProvider.ARCHIVE_GRID_REGION_FILE_NAME) - @DoesNotAffect(MFDGridSourceProvider.ARCHIVE_MECH_WEIGHT_FILE_NAME) - @DoesNotAffect(GridSourceList.ARCHIVE_GRID_LOCS_FILE_NAME) - @Affects(MFDGridSourceProvider.ARCHIVE_SUB_SEIS_FILE_NAME) - @Affects(MFDGridSourceProvider.ARCHIVE_UNASSOCIATED_FILE_NAME) - @Affects(GridSourceList.ARCHIVE_GRID_SOURCES_FILE_NAME) - private static class CarSlabSamplingNode implements RandomlySampledNode { - - private String name; - private String shortName; - private String prefix; - private double weight; - private long seed; - private double slabRate; - private double slabB; - private double interfaceRate; - private double interfaceB; - - - private CarSlabSamplingNode() { - - } - - private CarSlabSamplingNode(String name, String shortName, String prefix, double weight, long seed, - double slabRate, double slabB, double interfaceRate, double interfaceB) { - super(); - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - this.slabRate = slabRate; - this.slabB = slabB; - this.interfaceRate = interfaceRate; - this.interfaceB = interfaceB; - } - - @Override - public double getNodeWeight(LogicTreeBranch fullBranch) { - return weight; - } - - @Override - public String getFilePrefix() { - return prefix; - } - - @Override - public String getShortName() { - return shortName; - } - - @Override - public String getName() { - return name; - } - - @Override - public long getSeed() { - return seed; - } - - @Override - public void init(String name, String shortName, String prefix, double weight, long seed) { - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - } - - } - - private static class CarSlabRateSamplingLevel extends LogicTreeLevel.RandomlySampledLevel { - - private List slabSamples; - private List interfaceSamples; - private List randomizedIndexes; - - private CarSlabRateSamplingLevel() {} - - public CarSlabRateSamplingLevel(List slabSamples, List interfaceSamples) { - TotalRateComparator comp = new TotalRateComparator(8d); - Collections.sort(slabSamples, comp); - Collections.sort(interfaceSamples, comp); - this.slabSamples = slabSamples; - this.interfaceSamples = interfaceSamples; - } - - @Override - public String getShortName() { - return "CAR-Sampling"; - } - - @Override - public String getName() { - return "CAR Rate/b Distribution Sampling"; - } - - @Override - public CarSlabSamplingNode buildNodeInstance(int index, long seed, double weight) { - if (randomizedIndexes == null) { - randomizedIndexes = new ArrayList<>(slabSamples.size()); - for (int i=0; i getType() { - return CarSlabSamplingNode.class; - } - - } - - @DoesNotAffect(FaultSystemRupSet.SECTS_FILE_NAME) - @DoesNotAffect(FaultSystemRupSet.RUP_SECTS_FILE_NAME) - @DoesNotAffect(FaultSystemRupSet.RUP_PROPS_FILE_NAME) - @DoesNotAffect(FaultSystemSolution.RATES_FILE_NAME) - @DoesNotAffect(GridSourceProvider.ARCHIVE_GRID_REGION_FILE_NAME) - @DoesNotAffect(MFDGridSourceProvider.ARCHIVE_MECH_WEIGHT_FILE_NAME) - @DoesNotAffect(GridSourceList.ARCHIVE_GRID_LOCS_FILE_NAME) - @Affects(MFDGridSourceProvider.ARCHIVE_SUB_SEIS_FILE_NAME) - @Affects(MFDGridSourceProvider.ARCHIVE_UNASSOCIATED_FILE_NAME) - @Affects(GridSourceList.ARCHIVE_GRID_SOURCES_FILE_NAME) - private static class MueSamplingNode implements RandomlySampledNode { - - private String name; - private String shortName; - private String prefix; - private double weight; - private long seed; - private double slabRate; - private double slabB; - private double interfaceRate; - private double interfaceB; - - private MueSamplingNode() { - - } - - private MueSamplingNode(String name, String shortName, String prefix, double weight, long seed, - double slabRate, double slabB, double interfaceRate, double interfaceB) { - super(); - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - this.slabRate = slabRate; - this.slabB = slabB; - this.interfaceRate = interfaceRate; - this.interfaceB = interfaceB; - } - - @Override - public double getNodeWeight(LogicTreeBranch fullBranch) { - return weight; - } - - @Override - public String getFilePrefix() { - return prefix; - } - - @Override - public String getShortName() { - return shortName; - } - - @Override - public String getName() { - return name; - } - - @Override - public long getSeed() { - return seed; - } - - @Override - public void init(String name, String shortName, String prefix, double weight, long seed) { - this.name = name; - this.shortName = shortName; - this.prefix = prefix; - this.weight = weight; - this.seed = seed; - } - - } - - private static class MueRateSamplingLevel extends LogicTreeLevel.RandomlySampledLevel { - - private List slabSamples; - private List interfaceSamples; - private List randomizedIndexes; - - private MueRateSamplingLevel() {} - - public MueRateSamplingLevel(List slabSamples, List interfaceSamples) { - TotalRateComparator comp = new TotalRateComparator(8d); - Collections.sort(slabSamples, comp); - Collections.sort(interfaceSamples, comp); - this.slabSamples = slabSamples; - this.interfaceSamples = interfaceSamples; - } - - @Override - public String getShortName() { - return "MUE-Sampling"; - } - - @Override - public String getName() { - return "MUE Rate/b Distribution Sampling"; - } - - @Override - public MueSamplingNode buildNodeInstance(int index, long seed, double weight) { - if (randomizedIndexes == null) { - randomizedIndexes = new ArrayList<>(slabSamples.size()); - for (int i=0; i getType() { - return MueSamplingNode.class; - } - - } - - private static class TotalRateComparator implements Comparator { - - private double mmax; - - public TotalRateComparator(double mmax) { - this.mmax = mmax; - } - - @Override - public int compare(double[] o1, double[] o2) { - GutenbergRichterMagFreqDist mfd1 = new GutenbergRichterMagFreqDist(5d, mmax, 10); - mfd1.setAllButTotMoRate(mfd1.getMinX(), mfd1.getMaxX(), o1[0], o1[1]); - GutenbergRichterMagFreqDist mfd2 = new GutenbergRichterMagFreqDist(5d, mmax, 10); - mfd2.setAllButTotMoRate(mfd2.getMinX(), mfd2.getMaxX(), o2[0], o2[1]); - return Double.compare(mfd1.calcSumOfY_Vals(), mfd2.calcSumOfY_Vals()); - } - - } - - private static void writeHazardScripts(File outputDir, GriddedRegion gridReg) throws IOException { - String dirName = outputDir.getName(); - File localDir = outputDir; - - File remoteMainDir = new File("/project2/scec_608/kmilner/fss_inversions"); - int remoteTotalThreads = 20; - int remoteTotalMemGB = 50; - String queue = "scec"; - int nodes = 36; -// JavaShellScriptWriter mpjWrite = new MPJExpressShellScriptWriter( -// USC_CARC_ScriptWriter.JAVA_BIN, remoteTotalMemGB*1024, null, USC_CARC_ScriptWriter.MPJ_HOME); - JavaShellScriptWriter mpjWrite = new FastMPJShellScriptWriter( - USC_CARC_ScriptWriter.JAVA_BIN, remoteTotalMemGB*1024, null, USC_CARC_ScriptWriter.FMPJ_HOME); -// JavaShellScriptWriter mpjWrite = new NoMPJSingleNodeShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, -// remoteTotalMemGB*1024, null); nodes = 1; remoteInversionsPerBundle = 2; - BatchScriptWriter pbsWrite = new USC_CARC_ScriptWriter(); - - mpjWrite.setEnvVar("MAIN_DIR", remoteMainDir.getAbsolutePath()); - String mainDirPath = "$MAIN_DIR"; - mpjWrite.setEnvVar("DIR", mainDirPath+"/"+dirName); - String dirPath = "$DIR"; - - List classpath = new ArrayList<>(); - classpath.add(new File(dirPath+"/opensha-dev-all.jar")); - if (mpjWrite instanceof NoMPJSingleNodeShellScriptWriter) - classpath.add(new File("/project2/scec_608/kmilner/git/opensha/lib/mpj-0.38.jar")); - - mpjWrite.setClasspath(classpath); - if (mpjWrite instanceof MPJExpressShellScriptWriter) - ((MPJExpressShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); - else if (mpjWrite instanceof FastMPJShellScriptWriter) - ((FastMPJShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); - - File gridRegFile = new File(outputDir, "gridded_region.geojson"); - Feature.write(gridReg.toFeature(), gridRegFile); - - Double sigmaTrunc = 3d; - - for (IncludeBackgroundOption bgOp : IncludeBackgroundOption.values()) { - String mapScriptName = "batch_hazard_"+bgOp.name()+".slurm"; - String argz = "--input-file "+dirPath+"/results.zip"; - argz += " --output-dir "+dirPath+"/results"; - argz += " --output-file "+dirPath+"/results_hazard_"+bgOp.name()+".zip"; - argz += " --gridded-seis "+bgOp.name(); - if (bgOp != IncludeBackgroundOption.ONLY) - argz += " --external-fss "+dirPath+"/full_branch_averaged.zip"; - argz += " --quick-grid-calc"; - argz += " --region "+dirPath+"/"+gridRegFile.getName(); - argz += " --gmpe "+AttenRelRef.USGS_PRVI_ACTIVE.name(); - argz += " --gmpe "+AttenRelRef.USGS_PRVI_INTERFACE.name(); - argz += " --gmpe "+AttenRelRef.USGS_PRVI_SLAB.name(); - if (sigmaTrunc != null) - argz += " --gmm-sigma-trunc-one-sided "+sigmaTrunc.floatValue(); - argz += " "+MPJTaskCalculator.argumentBuilder().minDispatch(1).maxDispatch(100).threads(remoteTotalThreads).build(); - List script = mpjWrite.buildScript(MPJ_LogicTreeHazardCalc.class.getName(), argz); - pbsWrite.writeScript(new File(localDir, mapScriptName), script, 1440, nodes, remoteTotalThreads, queue); - } - } - -} diff --git a/src/main/java/scratch/kevin/prvi25/GriddedSeismicityMFDTests.java b/src/main/java/scratch/kevin/prvi25/GriddedSeismicityMFDTests.java index 62978fd0..f2977c8e 100644 --- a/src/main/java/scratch/kevin/prvi25/GriddedSeismicityMFDTests.java +++ b/src/main/java/scratch/kevin/prvi25/GriddedSeismicityMFDTests.java @@ -17,8 +17,8 @@ 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.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.Exact; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.Exact; import org.opensha.sha.magdist.GutenbergRichterMagFreqDist; import org.opensha.sha.magdist.IncrementalMagFreqDist; import org.opensha.sha.magdist.SummedMagFreqDist; diff --git a/src/main/java/scratch/kevin/prvi25/LogicTreeLineIntegralCalc.java b/src/main/java/scratch/kevin/prvi25/LogicTreeLineIntegralCalc.java index 8ddff7ca..64c858e5 100644 --- a/src/main/java/scratch/kevin/prvi25/LogicTreeLineIntegralCalc.java +++ b/src/main/java/scratch/kevin/prvi25/LogicTreeLineIntegralCalc.java @@ -14,6 +14,7 @@ import java.util.concurrent.Future; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.CSVFile; import org.opensha.commons.data.function.ArbDiscrEmpiricalDistFunc; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; @@ -223,7 +224,7 @@ public static PlotSpec writePlot(File outputDir, String prefix, List incrBounds95funcs = new ArrayList<>(); - List incrBounds68funcs = new ArrayList<>(); - List cmlBounds95funcs = new ArrayList<>(); - List cmlBounds68funcs = new ArrayList<>(); - List epochWeights = new ArrayList<>(); + WeightedList incrBounds95funcs = new WeightedList<>(); + WeightedList incrBounds68funcs = new WeightedList<>(); + WeightedList cmlBounds95funcs = new WeightedList<>(); + WeightedList cmlBounds68funcs = new WeightedList<>(); for (PRVI25_SeismicityRateEpoch epoch : PRVI25_SeismicityRateEpoch.values()) { double weight = epoch.getNodeWeight(null); @@ -602,17 +602,16 @@ else if (plot1900) UncertainArbDiscFunc cmlBounds95 = new UncertainArbDiscFunc(averageCml, cml2p5, cml97p5, UncertaintyBoundType.CONF_95); UncertainArbDiscFunc cmlBounds68 = new UncertainArbDiscFunc(averageCml, cml16, cml84, UncertaintyBoundType.CONF_68); - incrBounds95funcs.add(incrBounds95); - incrBounds68funcs.add(incrBounds68); - cmlBounds95funcs.add(cmlBounds95); - cmlBounds68funcs.add(cmlBounds68); - epochWeights.add(weight); + incrBounds95funcs.add(incrBounds95, weight); + incrBounds68funcs.add(incrBounds68, weight); + cmlBounds95funcs.add(cmlBounds95, weight); + cmlBounds68funcs.add(cmlBounds68, weight); } - UncertainBoundedIncrMagFreqDist incrBounds95 = PRVI25_SeismicityRateEpoch.averageUncert(incrBounds95funcs, epochWeights); - UncertainBoundedIncrMagFreqDist incrBounds68 = PRVI25_SeismicityRateEpoch.averageUncert(incrBounds68funcs, epochWeights); - UncertainArbDiscFunc cmlBounds95 = PRVI25_SeismicityRateEpoch.averageUncertCml(cmlBounds95funcs, epochWeights); - UncertainArbDiscFunc cmlBounds68 = PRVI25_SeismicityRateEpoch.averageUncertCml(cmlBounds68funcs, epochWeights); + UncertainBoundedIncrMagFreqDist incrBounds95 = SeismicityRateModel.averageUncert(incrBounds95funcs); + UncertainBoundedIncrMagFreqDist incrBounds68 = SeismicityRateModel.averageUncert(incrBounds68funcs); + UncertainArbDiscFunc cmlBounds95 = SeismicityRateModel.averageUncertCml(cmlBounds95funcs); + UncertainArbDiscFunc cmlBounds68 = SeismicityRateModel.averageUncertCml(cmlBounds68funcs); incrBounds95.setName("68% and 95% bounds"); myIncrFuncs.add(incrBounds95); diff --git a/src/main/java/scratch/kevin/prvi25/figures/DefModelSampleLineIntegralsPlot.java b/src/main/java/scratch/kevin/prvi25/figures/DefModelSampleLineIntegralsPlot.java index 9f545eb6..282313e5 100644 --- a/src/main/java/scratch/kevin/prvi25/figures/DefModelSampleLineIntegralsPlot.java +++ b/src/main/java/scratch/kevin/prvi25/figures/DefModelSampleLineIntegralsPlot.java @@ -10,6 +10,7 @@ import org.jfree.chart.ui.RectangleAnchor; import org.jfree.chart.ui.RectangleEdge; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbDiscrEmpiricalDistFunc; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DiscretizedFunc; @@ -159,7 +160,7 @@ else if (fractiles[f] == 1) // Color distColor = Colors.tab_red; Color distColor = Colors.tab_grey; Color origColor = Colors.tab_green; - Color transColor = new Color(distColor.getRed(), distColor.getGreen(), distColor.getBlue(), 60); + Color transColor = ColorUtils.transparent(distColor, 60); PlotCurveCharacterstics minMaxChar = new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, transColor); funcs.add(bounds); diff --git a/src/main/java/scratch/kevin/prvi25/figures/IndividualMFDPlots.java b/src/main/java/scratch/kevin/prvi25/figures/IndividualMFDPlots.java index 2531a86b..0e8b003b 100644 --- a/src/main/java/scratch/kevin/prvi25/figures/IndividualMFDPlots.java +++ b/src/main/java/scratch/kevin/prvi25/figures/IndividualMFDPlots.java @@ -18,6 +18,7 @@ import org.apache.commons.math3.util.Precision; import org.jfree.chart.ui.RectangleAnchor; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.WeightedList; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DiscretizedFunc; @@ -45,11 +46,11 @@ import org.opensha.sha.earthquake.faultSysSolution.modules.RegionsOfInterest; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSectionUtils; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateModel; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateType; import org.opensha.sha.earthquake.param.IncludeBackgroundOption; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_SegmentationModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.PRVI25_GridSourceBuilder; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.RateType; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateModel; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalSeismicityRate; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_DeclusteringAlgorithms; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SeisSmoothingAlgorithms; @@ -215,10 +216,9 @@ else if (trt == TectonicRegionType.SUBDUCTION_INTERFACE) else if (trt == TectonicRegionType.SUBDUCTION_INTERFACE) onFaultMean = CombinedMFDsPlot.calcFaultMFD(reg, sol, refMFD); - List obsList = new ArrayList<>(); - List obsCmlList = new ArrayList<>(); - List origObsList = r == 0 ? null : new ArrayList<>(); - List obsWeights = new ArrayList<>(); + WeightedList obsList = new WeightedList<>(); + WeightedList obsCmlList = new WeightedList<>(); + WeightedList origObsList = r == 0 ? null : new WeightedList<>(); for (PRVI25_SeismicityRateEpoch epoch : PRVI25_SeismicityRateEpoch.values()) { double weight = epoch.getNodeWeight(null); if (weight == 0d) @@ -227,23 +227,22 @@ else if (trt == TectonicRegionType.SUBDUCTION_INTERFACE) SeismicityRateModel cmlSeisModel = seisModelFunc.apply(epoch, RateType.EXACT); UncertainBoundedIncrMagFreqDist obs = seisModel.getBounded(refMFD, xRange.getUpperBound()+0.1); if (r == 0) { - obsList.add(obs); - obsCmlList.add(cmlSeisModel.getBoundedCml(refMFD, xRange.getUpperBound()+0.1)); + obsList.add(obs, weight); + obsCmlList.add(cmlSeisModel.getBoundedCml(refMFD, xRange.getUpperBound()+0.1), weight); // System.out.println("OBS cml for "+epoch+":\n"+obsCmlList.get(obsCmlList.size()-1)); } else { UncertainBoundedIncrMagFreqDist subsetObs = seisModel.getRemapped(reg, seisReg, PRVI25_DeclusteringAlgorithms.AVERAGE, PRVI25_SeisSmoothingAlgorithms.AVERAGE, refMFD, xRange.getUpperBound()+0.1); subsetObs.setName("Observed (subset), N5="+new DecimalFormat("0.0#").format(obs.getCumRate(obs.getClosestXIndex(5.01)))); - obsList.add(subsetObs); - origObsList.add(obs); + obsList.add(subsetObs, weight); + origObsList.add(obs, weight); obsCmlList.add(new UncertainArbDiscFunc( subsetObs.getCumRateDistWithOffset(), subsetObs.getLower().getCumRateDistWithOffset(), - subsetObs.getUpper().getCumRateDistWithOffset(), subsetObs.getBoundType())); + subsetObs.getUpper().getCumRateDistWithOffset(), subsetObs.getBoundType()), weight); } - obsWeights.add(weight); } - UncertainBoundedIncrMagFreqDist obs = PRVI25_SeismicityRateEpoch.averageUncert(obsList, obsWeights); - UncertainArbDiscFunc obsCml = PRVI25_SeismicityRateEpoch.averageUncertCml(obsCmlList, obsWeights); + UncertainBoundedIncrMagFreqDist obs = SeismicityRateModel.averageUncert(obsList); + UncertainArbDiscFunc obsCml = SeismicityRateModel.averageUncertCml(obsCmlList); IncrementalMagFreqDist gridded; UncertainBoundedIncrMagFreqDist[] griddedDists; if (trt == TectonicRegionType.ACTIVE_SHALLOW || trt == TectonicRegionType.SUBDUCTION_INTERFACE) { @@ -297,7 +296,7 @@ else if (trt == TectonicRegionType.SUBDUCTION_INTERFACE) texFW.write(LaTeXUtils.defineValueCommand(texPrefix+"ObsMFiveRI", LaTeXUtils.numberExpFormatFixedDecimal(1d/obsM5, 1), false)+"\n"); if (r > 0) { - UncertainBoundedIncrMagFreqDist origObs = PRVI25_SeismicityRateEpoch.averageUncert(origObsList, obsWeights); + UncertainBoundedIncrMagFreqDist origObs = SeismicityRateModel.averageUncert(origObsList); double origM5 = origObs.getCumRate(origObs.getClosestXIndex(5.01)); texFW.write(LaTeXUtils.defineValueCommand(texPrefix+"ObsMFivePercent", LaTeXUtils.numberAsPercent(100d*obsM5/origM5, 0), false)+"\n"); @@ -594,12 +593,12 @@ private static void plot(File outputDir, String prefix, Range xRange, UncertainBoundedIncrMagFreqDist[] totalDists, IncrementalMagFreqDist total, UncertainBoundedIncrMagFreqDist obs) throws IOException { Color onFaultColor = Colors.tab_red; - Color onFaultTransColor = new Color(onFaultColor.getRed(), onFaultColor.getGreen(), onFaultColor.getBlue(), 60); + Color onFaultTransColor = ColorUtils.transparent(onFaultColor, 60); Color obsColor = Colors.tab_green; Color griddedColor = Colors.tab_blue; - Color griddedTransColor = new Color(griddedColor.getRed(), griddedColor.getGreen(), griddedColor.getBlue(), 60); + Color griddedTransColor = ColorUtils.transparent(griddedColor, 60); Color totalColor = Colors.tab_purple; - Color totalTransColor = new Color(totalColor.getRed(), totalColor.getGreen(), totalColor.getBlue(), 60); + Color totalTransColor = ColorUtils.transparent(totalColor, 60); List funcs = new ArrayList<>(); List chars = new ArrayList<>(); @@ -854,8 +853,7 @@ private static IncrementalMagFreqDist sum(IncrementalMagFreqDist mfd1, Increment private static UncertainBoundedIncrMagFreqDist getMmaxAveragedSlab(EvenlyDiscretizedFunc refMFD, PRVI25_SeismicityRegions seisReg, boolean averageRate) throws IOException { - List slabMFDs = new ArrayList<>(); - List slabWeights = new ArrayList<>(); + WeightedList slabMFDs = new WeightedList<>(); for (PRVI25_SeismicityRateEpoch epoch : PRVI25_SeismicityRateEpoch.values()) { double epochWeight = epoch.getNodeWeight(null); if (epochWeight == 0d) @@ -885,11 +883,10 @@ private static UncertainBoundedIncrMagFreqDist getMmaxAveragedSlab(EvenlyDiscret } else { throw new IllegalStateException(); } - slabMFDs.add(siesModel.getBounded(refMFD, slabMmax.getIncrementalMmax())); - slabWeights.add(epochWeight*mMaxWeight); + slabMFDs.add(siesModel.getBounded(refMFD, slabMmax.getIncrementalMmax()), epochWeight*mMaxWeight); } } - return PRVI25_SeismicityRateEpoch.averageUncert(slabMFDs, slabWeights); + return SeismicityRateModel.averageUncert(slabMFDs); } static IncrementalMagFreqDist calcGriddedMFD(Region region, TectonicRegionType trt, diff --git a/src/main/java/scratch/kevin/prvi25/figures/LogicTreeFigureWriter.java b/src/main/java/scratch/kevin/prvi25/figures/LogicTreeFigureWriter.java index dbc49ce3..65e64af2 100644 --- a/src/main/java/scratch/kevin/prvi25/figures/LogicTreeFigureWriter.java +++ b/src/main/java/scratch/kevin/prvi25/figures/LogicTreeFigureWriter.java @@ -28,7 +28,7 @@ import org.opensha.commons.logicTree.LogicTree; import org.opensha.commons.logicTree.LogicTreeBranch; import org.opensha.commons.logicTree.LogicTreeLevel; -import org.opensha.commons.logicTree.LogicTreeLevel.RandomlySampledLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomlyGeneratedLevel; import org.opensha.commons.logicTree.LogicTreeNode; import org.opensha.commons.util.ExceptionUtils; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_MaxMagOffFault; @@ -128,7 +128,7 @@ public static void main(String[] args) throws IOException { for (LogicTreeNode node : branch) crustalFaultNodesUsed.add(node); for (LogicTreeLevel level : crustalFaultTree.getLevels()) { - if (level instanceof RandomlySampledLevel) { + if (level instanceof RandomlyGeneratedLevel) { int numRand = level.getNodes().size(); texFW.write(LaTeXUtils.defineValueCommand("CrustalFaultBranchesNumRand", LaTeXUtils.groupedIntNumber(numRand))+"\n"); } else { @@ -251,7 +251,7 @@ public LogicTreeFigureWriter(LogicTree tree, boolean includeSingleChoice, Map includedLevels.add(level); includedLevelChoices.add(uniqueChoices); maxLevelFontWidth = Integer.max(maxLevelFontWidth, new JPanel().getFontMetrics(levelFont).stringWidth(remapped(level.getName()))); - if (!(level instanceof RandomlySampledLevel)) { + if (!(level instanceof RandomlyGeneratedLevel)) { maxNodes = Integer.max(maxNodes, uniqueChoices.size()); for (LogicTreeNode node : uniqueChoices) { String name = remapped(node.getShortName()); @@ -316,7 +316,7 @@ protected void paintComponent(Graphics g) { int botLineY = y+lineHeight; int topChoiceY = botLineY + lineGap; int topWeightY = topChoiceY + choiceFontHeight; - if (level instanceof RandomlySampledLevel && nodes.size() > maxNodes && includedLevels.size() > 1) { + if (level instanceof RandomlyGeneratedLevel && nodes.size() > maxNodes && includedLevels.size() > 1) { // figure out how many branches we have without this HashSet uniquesWithout = new HashSet<>(); for (LogicTreeBranch branch : tree) { diff --git a/src/main/java/scratch/kevin/prvi25/figures/ObsUncertaintyBoundsFigure.java b/src/main/java/scratch/kevin/prvi25/figures/ObsUncertaintyBoundsFigure.java index 59b560f2..1d6f3de9 100644 --- a/src/main/java/scratch/kevin/prvi25/figures/ObsUncertaintyBoundsFigure.java +++ b/src/main/java/scratch/kevin/prvi25/figures/ObsUncertaintyBoundsFigure.java @@ -31,11 +31,11 @@ import org.opensha.commons.gui.plot.PlotUtils; import org.opensha.commons.util.DataUtils.MinMaxAveTracker; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.Exact; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.PureGR; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.RateRecord; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.RateType; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.Exact; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.PureGR; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateRecord; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateType; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalSeismicityRate; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SeismicityRateEpoch; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_SubductionCaribbeanSeismicityRate; @@ -46,7 +46,6 @@ import com.google.common.base.Preconditions; import net.mahdilamb.colormap.Colors; -import scratch.kevin.prvi25.GriddedRateDistributionSolutionWriter; import static scratch.kevin.prvi25.figures.PRVI_Paths.*; @@ -280,7 +279,7 @@ public static void main(String[] args) throws IOException { PlotUtils.writePlots(outputDir, prefix, gp, 700, 650, true, true, false); if (ref && refRatePairsFile != null && !incremental) { - List ratePairs = GriddedRateDistributionSolutionWriter.loadRates(refRatePairsFile); + List ratePairs = loadRates(refRatePairsFile); Collections.shuffle(ratePairs, new Random(ratePairs.size())); // int c = 200; @@ -428,6 +427,31 @@ public static void main(String[] args) throws IOException { } } + public static List loadRates(File csvFile) throws IOException { + CSVFile csv = CSVFile.readFile(csvFile, false); + + boolean reading = false; + List ret = new ArrayList<>(); + + MinMaxAveTracker rateTrack = new MinMaxAveTracker(); + MinMaxAveTracker bTrack = new MinMaxAveTracker(); + for (int row=0; row avgMFDs = new ArrayList<>(); - List> epochMFDs = new ArrayList<>(); + List> epochMFDs = new ArrayList<>(); PRVI25_SeismicityRegions[] regions = PRVI25_SeismicityRegions.values(); for (PRVI25_SeismicityRegions reg : regions) { @@ -105,9 +106,8 @@ public static void main(String[] args) throws IOException { throw new IllegalStateException("Unknown region: "+reg); } - List epochBounds = new ArrayList<>(); - List epochCmlBounds = new ArrayList<>(); - List epochWeights = new ArrayList<>(); + WeightedList epochBounds = new WeightedList<>(); + WeightedList epochCmlBounds = new WeightedList<>(); for (int e=0; e byEpoch = epochMFDs.get(r); + WeightedList byEpoch = epochMFDs.get(r); System.out.println(regions[r].getName()); for (double mag : regCmlMags) { @@ -312,7 +312,7 @@ public static void main(String[] args) throws IOException { System.out.println("\tM>"+(float)mag+" rate="+(float)rate+", ri="+(float)ri+" years"); if (mag == 5d) { for (int e=0; e> runDirs; + static { + runDirs = HashBasedTable.create(); + + /* + * MCS runs + */ + runDirs.put(SamplingMethod.MONTE_CARLO, 20000, List.of( + new File(PaperPaths.INVS_DIR, "2026_09_03-nshm27-AMSAM-20000samples-mcs-unique_seed"), // DONE recalc on frontera + new File(PaperPaths.INVS_DIR, "2026_09_05-nshm27-AMSAM-20000samples-mcs-unique_seed-2"), // DONE recalc on frontera + new File(PaperPaths.INVS_DIR, "2026_09_10-nshm27-AMSAM-20000samples-mcs-unique_seed-3"), // DONE recalc on frontera + new File(PaperPaths.INVS_DIR, "2026_09_10-nshm27-AMSAM-20000samples-mcs-unique_seed-4"), // DONE recalc on CARC + new File(PaperPaths.INVS_DIR, "2026_09_15-nshm27-AMSAM-20000samples-mcs-unique_seed-5"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_15-nshm27-AMSAM-20000samples-mcs-unique_seed-6"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-20000samples-mcs-unique_seed-7"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-20000samples-mcs-unique_seed-8"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-20000samples-mcs-unique_seed-9") // DONE on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-10"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-11"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-12"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-13"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-14"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-15"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-16"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-17"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-18"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-19"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-20000samples-mcs-unique_seed-20") // running on frontera + )); + + /* + * Sobol runs + */ + runDirs.put(SamplingMethod.OWEN_SCRAMBLED_SOBOL, 8192, List.of( + new File(PaperPaths.INVS_DIR, "2026_08_28-nshm27-AMSAM-8192samples-sobol_scrambled"), // DONE hazard recalc CARC + new File(PaperPaths.INVS_DIR, "2026_08_28-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed"), // DONE hazard recalc CARC +// new File(PaperPaths.INVS_DIR, "2026_08_29-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-2"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_08_29-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-3"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_09-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-4"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_09-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-5") // submitted hazard CARC + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-6"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-sobol_scrambled-unique_seed-7") // DONE on frontera + )); +// runDirs.put(SamplingMethod.OWEN_SCRAMBLED_SOBOL, 16384, List.of( +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-16384samples-sobol_scrambled"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed"), // running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-1"),// running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_17-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-2"),// running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_14-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-3"),// running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_14-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-4"),// running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_14-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-5"),// running on frontera +// new File(PaperPaths.INVS_DIR, "2026_09_14-nshm27-AMSAM-16384samples-sobol_scrambled-unique_seed-6") // running on frontera +// )); + + /* + * LHS runs + * TODO add more 4096? do 8192? + */ +// runDirs.put(SamplingMethod.LATIN_HYPERCUBE, 4096, List.of( // TODO these are ready for recalc, stage jar and submit hazard +// new File(PaperPaths.INVS_DIR, "2026_09_08-nshm27-AMSAM-4096samples-lhs"), // TODO: recalc hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_08-nshm27-AMSAM-4096samples-lhs-unique_seed"), // TODO: recalc hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_08-nshm27-AMSAM-4096samples-lhs-unique_seed-2"), // TODO: recalc hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_08-nshm27-AMSAM-4096samples-lhs-unique_seed-3") // TODO: recalc hazard CARC +// // TODO: configure/run 4 more +// )); +// runDirs.put(SamplingMethod.LATIN_HYPERCUBE, 8192, List.of( // TODO these are ready for recalc, stage jar and submit hazard +// // TODO: configure/run 8 +// )); + + /* + * Pairwise-LHS runs + */ + runDirs.put(SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE, 4096, List.of( +// new File(PaperPaths.INVS_DIR, "2026_08_28-nshm27-AMSAM-4096samples-lhs_pairwise"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_08_28-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_08_29-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-2"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_08_29-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-3"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_10-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-4"), // submitted hazard CARC +// new File(PaperPaths.INVS_DIR, "2026_09_10-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-5") // submitted hazard CARC + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-6"), // DONE on CARC + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-4096samples-lhs_pairwise-unique_seed-7") // DONE on CARC + )); + runDirs.put(SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE, 8192, List.of( + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-2"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-3"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-4"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-5"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-6"), // DONE on frontera + new File(PaperPaths.INVS_DIR, "2026_09_16-nshm27-AMSAM-8192samples-lhs_pairwise-unique_seed-7") // DONE on frontera + )); + } + + public static void main(String[] args) throws IOException { + Preconditions.checkState(MIN_SOBOL_PREFIX_SAMPLE_COUNT > 0 + && Integer.bitCount(MIN_SOBOL_PREFIX_SAMPLE_COUNT) == 1, + "MIN_SOBOL_PREFIX_SAMPLE_COUNT must be a positive power of two: %s", + MIN_SOBOL_PREFIX_SAMPLE_COUNT); + + File outputDir = new File(PaperPaths.FIGURES_DIR, "hazard_convergence"); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir(), + "Couldn't create output directory: %s", outputDir.getAbsolutePath()); + + ReturnPeriods rp = ReturnPeriods.TWO_IN_50; + + List sobolRuns = loadRunSpecs(SamplingMethod.OWEN_SCRAMBLED_SOBOL, + runDirs.row(SamplingMethod.OWEN_SCRAMBLED_SOBOL)); + List fullDesignRuns = new ArrayList<>(); + for (SamplingMethod method : runDirs.rowKeySet().stream().sorted().toList()) + if (method != SamplingMethod.MONTE_CARLO && method != SamplingMethod.OWEN_SCRAMBLED_SOBOL) + fullDesignRuns.addAll(loadRunSpecs(method, runDirs.row(method))); + List mcsRuns = loadRunSpecs(SamplingMethod.MONTE_CARLO, + runDirs.row(SamplingMethod.MONTE_CARLO)); + System.out.println("MCS reference has "+mcsRuns.stream().mapToInt(RunSpec::maxSamples).sum() + +" branches across "+mcsRuns.size()+" runs"); + + GriddedRegion gridReg = GriddedRegion.fromFeature( + Feature.read(new File(mcsRuns.get(0).directory, "gridded_region.geojson"))); + + double[] periods = { 0d, 1d }; + String[] periodNames = { "PGA", "1s SA" }; + String[] periodPrefixes = { "pga", "1s_sa" }; + for (int p=0; p loadRunSpecs(SamplingMethod method, + Map> runDirs) throws IOException { + List runs = new ArrayList<>(); + for (Map.Entry> entry : new TreeMap<>(runDirs).entrySet()) { + for (File dir : entry.getValue()) { + Preconditions.checkState(dir.isDirectory(), "Run directory doesn't exist: %s", dir.getAbsolutePath()); + LogicTree tree = LogicTree.read(new File(dir, "logic_tree_analysis.json")); + Preconditions.checkState(tree.size() == entry.getKey(), "Expected %s branches in %s, have %s", + entry.getKey(), dir.getName(), tree.size()); + Preconditions.checkState(tree.getSamplingMethod() == method, + "Expected %s tree, have %s: %s", method, tree.getSamplingMethod(), dir.getName()); + runs.add(new RunSpec(dir.getName(), dir, tree, method, + tree.getSamplingRandomSeed(), tree.size())); + } + } + return runs; + } + + private static List loadRunSpecs(SamplingMethod method, List runDirs) throws IOException { + List runs = new ArrayList<>(); + for (File dir : runDirs) { + Preconditions.checkState(dir.isDirectory(), "Run directory doesn't exist: %s", dir.getAbsolutePath()); + LogicTree tree = LogicTree.read(new File(dir, "logic_tree_analysis.json")); + Preconditions.checkState(tree.getSamplingMethod() == method, + "Expected %s tree, have %s: %s", method, tree.getSamplingMethod(), dir.getName()); + runs.add(new RunSpec(dir.getName(), dir, tree, method, + tree.getSamplingRandomSeed(), tree.size())); + } + return runs; + } + + private static void runSamplingConvergence(List sobolRuns, List fullDesignRuns, + List mcsRuns, + GriddedRegion gridReg, double period, String periodName, ReturnPeriods rp, File outputDir) throws IOException { + List sobolData = loadRunPeriodData(sobolRuns, gridReg, period, rp); + List fullDesignData = loadRunPeriodData(fullDesignRuns, gridReg, period, rp); + int[] sampleCounts = sobolData.stream().flatMap(data -> data.checkpoints().keySet().stream()) + .mapToInt(Integer::intValue).distinct().sorted().toArray(); + List mcsData = loadRunPeriodData(mcsRuns, gridReg, period, rp, sampleCounts); + List sobolConsensusData; + if (FIXED_SOBOL_CONSENSUS_SIZE == null) { + sobolConsensusData = sobolData; + System.out.println("Building Sobol consensus from all "+sobolData.size()+" runs"); + } else { + sobolConsensusData = sobolData.stream() + .filter(data -> data.run().maxSamples() == FIXED_SOBOL_CONSENSUS_SIZE) + .toList(); + Preconditions.checkState(!sobolConsensusData.isEmpty(), + "No %s-sample Sobol runs available for the fixed-size consensus", + FIXED_SOBOL_CONSENSUS_SIZE); + System.out.println("Building Sobol consensus from "+sobolConsensusData.size()+" independent " + +FIXED_SOBOL_CONSENSUS_SIZE+"-sample runs"); + } + + PooledHazardData pooledMCSData = buildPooledHazardData(mcsData, null, gridReg, rp, + MCS_REFERENCE_NAME, MCS_REFERENCE_NAME); + ReferenceStatistics mcsReference = pooledMCSData.reference(); + Map leaveOneOut = new LinkedHashMap<>(); + for (RunPeriodData data : sobolData) { + RunSpec excluded = sobolConsensusData.contains(data) ? data.run() : null; + leaveOneOut.put(data.run(), buildPooledHazardData(sobolConsensusData, excluded, gridReg, rp, + POOLED_SOBOL_REFERENCE_NAME, LOO_SOBOL_REFERENCE_NAME).reference()); + } + PooledHazardData pooledSobolData = buildPooledHazardData(sobolConsensusData, null, gridReg, rp, + POOLED_SOBOL_REFERENCE_NAME, LOO_SOBOL_REFERENCE_NAME); + ReferenceStatistics pooledSobol = pooledSobolData.reference(); + runMCSPoolBootstrap(mcsData, mcsReference, pooledSobol, MCS_POOL_BOOTSTRAP_REPLICATES, + MCS_POOL_BOOTSTRAP_SEED, outputDir); + + writePooledHazardFiles(new File(outputDir, "pooled_mcs"), pooledMCSData, gridReg, period, rp); + writePooledHazardFiles(new File(outputDir, "pooled_sobol"), pooledSobolData, gridReg, period, rp); + List poLHSPoolData = largestMethodRuns(fullDesignData, + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE); + if (!poLHSPoolData.isEmpty()) { + PooledHazardData pooledPOLHSData = buildPooledHazardData(poLHSPoolData, null, gridReg, rp, + POOLED_PO_LHS_REFERENCE_NAME, POOLED_PO_LHS_REFERENCE_NAME); + writePooledHazardFiles(new File(outputDir, "pooled_po_lhs"), + pooledPOLHSData, gridReg, period, rp); + } + + List comparisons = new ArrayList<>(); + for (RunPeriodData data : sobolData) { + ReferenceStatistics sobolReference = leaveOneOut.get(data.run()); + for (Map.Entry entry : data.checkpoints().entrySet()) { + appendComparisons(comparisons, data.run(), entry.getKey(), entry.getValue(), sobolReference, gridReg); + appendComparisons(comparisons, data.run(), entry.getKey(), entry.getValue(), mcsReference, gridReg); + } + } + // LHS and other full designs are evaluated at their generated sizes, without taking prefixes. + for (RunPeriodData data : fullDesignData) { + HazardStatistics statistics = data.checkpoints().get(data.run().maxSamples()); + appendComparisons(comparisons, data.run(), data.run().maxSamples(), + statistics, pooledSobol, gridReg); + appendComparisons(comparisons, data.run(), data.run().maxSamples(), + statistics, mcsReference, gridReg); + } + List mcsSpans = appendMCSSpanComparisons(comparisons, mcsData, sampleCounts, + pooledSobol, gridReg, rp); + writeReferenceComparisons(new File(outputDir, "reference_comparisons.csv"), comparisons); + writeReferenceComparisonSummary(new File(outputDir, "reference_comparison_summary.csv"), comparisons); + + List doublings = new ArrayList<>(); + for (RunPeriodData data : sobolData) { + for (Map.Entry entry : data.checkpoints().entrySet()) { + int lowerCount = entry.getKey(); + HazardStatistics upper = data.checkpoints().get(2*lowerCount); + if (upper == null) + continue; + for (ConvergenceMetric metric : ConvergenceMetric.values()) { + MapComparison comparison = compare(upper.values(metric), entry.getValue().values(metric)); + doublings.add(new DoublingComparison(data.run(), lowerCount, 2*lowerCount, + metric, comparison, gridReg.getLocation(comparison.maximumAbsoluteIndex()))); + } + } + } + writeDoublingComparisons(new File(outputDir, "paired_doubling_comparisons.csv"), doublings); + writeDoublingComparisonSummary(new File(outputDir, "paired_doubling_summary.csv"), doublings); + + List allData = new ArrayList<>(sobolData); + allData.addAll(fullDesignData); + allData.addAll(mcsData); + List realizations = new ArrayList<>(mcsSpans); + for (RunPeriodData data : allData) + data.checkpoints().forEach((count, statistics) -> realizations.add(new Realization(data.run(), count, statistics))); + List realizationPairs = buildRealizationPairComparisons(realizations, gridReg); + writeRealizationPairComparisons(new File(outputDir, "realization_pair_comparisons.csv"), realizationPairs); + writeRealizationPairComparisonSummary( + new File(outputDir, "realization_pair_summary.csv"), realizationPairs); + + HazardConvergencePlots.plotPeriod(outputDir, periodName); + } + + private static List largestMethodRuns(List allData, + SamplingMethod method) { + int largestSize = allData.stream() + .filter(data -> data.run().method() == method) + .mapToInt(data -> data.run().maxSamples()) + .max().orElse(-1); + if (largestSize < 0) + return List.of(); + return allData.stream() + .filter(data -> data.run().method() == method + && data.run().maxSamples() == largestSize) + .toList(); + } + + private static List loadRunPeriodData(List runs, + GriddedRegion gridReg, double period, ReturnPeriods rp, int... spanCounts) throws IOException { + if (runs.isEmpty()) + return List.of(); + int[] globalOffsets = new int[runs.size()]; + for (int i=1; i> futures = new ArrayList<>(runs.size()); + for (int i=0; i loadRunPeriodData( + run, gridReg, period, rp, spanCounts, globalOffset))); + } + List data = new ArrayList<>(runs.size()); + // Retrieve in input order so downstream CSV and plot ordering remains stable. + for (Future future : futures) { + try { + data.add(future.get()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while loading hazard runs", e); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException ioException) + throw ioException; + if (cause instanceof RuntimeException runtimeException) + throw runtimeException; + if (cause instanceof Error error) + throw error; + throw new IOException("Exception while loading hazard runs", cause); + } + } + return data; + } finally { + executor.shutdownNow(); + } + } + + private static RunPeriodData loadRunPeriodData(RunSpec run, GriddedRegion gridReg, + double period, ReturnPeriods rp, int[] spanCounts, int globalOffset) throws IOException { + System.out.println("\nLoading "+run.method().getShortName()+" run: "+run.id()); + ModelHazardMaps maps = loadMaps(new File(run.directory(), "results_hazard.zip"), + run.tree(), gridReg, period, rp); + double[][] branchMaps = copyValues(maps.individual()); + + double[] curveX = null; + double[][] curveSums = null; + Map checkpoints = new TreeMap<>(); + Map curveBoundaries = new TreeMap<>(); + try (BranchCurveLoader curveLoader = new BranchCurveLoader(run.directory())) { + for (int b=0; b= MIN_SOBOL_PREFIX_SAMPLE_COUNT && Integer.bitCount(count) == 1; + if (Arrays.stream(spanCounts).anyMatch(size -> (globalOffset+count) % size == 0)) + curveBoundaries.put(count, Arrays.stream(curveSums).map(double[]::clone).toArray(double[][]::new)); + if (fullRun || sobolCheckpoint) { + double[] curveMean = buildCurveMeanMap(curveSums, curveX, count, rp); + checkpoints.put(count, calcHazardStatistics(branchMaps, count, curveMean)); + System.out.println("\tBuilt "+count+"-sample checkpoint"); + } + } + } + Preconditions.checkState(checkpoints.containsKey(run.maxSamples())); + MapComparison archivedComparison = compare( + checkpoints.get(run.maxSamples()).values(ConvergenceMetric.MEAN_HAZARD), copyValues(maps.mean())); + System.out.println("\tCurve mean versus archived mean: "+archivedComparison); + return new RunPeriodData(run, branchMaps, curveX, curveSums, checkpoints, curveBoundaries); + } + + private static PooledHazardData buildPooledHazardData(List allRuns, + RunSpec excluded, GriddedRegion gridReg, ReturnPeriods rp, + String pooledName, String leaveOneOutName) { + int sampleCount = 0; + int curveSize = -1; + double[] curveX = null; + for (RunPeriodData data : allRuns) { + if (data.run().equals(excluded)) + continue; + sampleCount += data.run().maxSamples(); + if (curveX == null) { + curveX = data.curveX(); + curveSize = curveX.length; + } else { + Preconditions.checkState(curveSize == data.curveX().length); + for (int i=0; i 0); + double[][] curveSums = new double[gridReg.getNodeCount()][curveSize]; + double[][] branchMaps = new double[sampleCount][]; + int destBranch = 0; + for (RunPeriodData data : allRuns) { + if (data.run().equals(excluded)) + continue; + for (int n=0; n appendMCSSpanComparisons(List comparisons, + List runs, int[] sampleCounts, ReferenceStatistics sobolReference, + GriddedRegion gridReg, ReturnPeriods rp) { + List spans = new ArrayList<>(); + double[][] allMaps = runs.stream().flatMap(data -> Arrays.stream(data.branchMaps())) + .toArray(double[][]::new); + double[] curveX = runs.get(0).curveX(); + double[][] totalCurves = new double[gridReg.getNodeCount()][curveX.length]; + for (RunPeriodData data : runs) { + Preconditions.checkState(Arrays.equals(curveX, data.curveX()), "MCS curve grids differ"); + for (int n=0; n 1, "Too few MCS reference samples after exclusion"); + double[][] after = pooledCurvePrefix(runs, end, curveX.length); + double[][] spanCurves = new double[totalCurves.length][curveX.length]; + double[][] remainingCurves = new double[totalCurves.length][curveX.length]; + for (int n=0; n runs, int sampleCount, int curveSize) { + Preconditions.checkArgument(sampleCount > 0); + double[][] prefix = new double[runs.get(0).curveSums().length][curveSize]; + int remaining = sampleCount; + for (RunPeriodData data : runs) { + int runSamples = data.branchMaps().length; + double[][] addition; + if (remaining >= runSamples) { + addition = data.curveSums(); + remaining -= runSamples; + } else { + addition = Preconditions.checkNotNull(data.curveBoundaries().get(remaining), + "Missing pooled MCS curve boundary at local index %s", remaining); + remaining = 0; + } + for (int n=0; n= 0 && start < end && end <= rows.length); + double[][] remaining = new double[rows.length-(end-start)][]; + System.arraycopy(rows, 0, remaining, 0, start); + System.arraycopy(rows, end, remaining, start, rows.length-end); + return remaining; + } + + static double[] buildCurveMeanMap(double[][] curveSums, double[] curveX, + int sampleCount, ReturnPeriods rp) { + double[] map = new double[curveSums.length]; + double[] meanY = new double[curveX.length]; + for (int n=0; n curve.getMaxY()) + map[n] = 0d; + else if (rp.oneYearProb < curve.getMinY()) + map[n] = curve.getMaxX(); + else + map[n] = curve.getFirstInterpolatedX_inLogXLogYDomain(rp.oneYearProb); + } + return map; + } + + static HazardStatistics calcHazardStatistics(double[][] branchMaps, int sampleCount, + double[] curveMean) { + Preconditions.checkArgument(sampleCount > 1 && sampleCount <= branchMaps.length); + Preconditions.checkArgument(curveMean.length == branchMaps[0].length); + int numSites = curveMean.length; + double[] standardDeviation = new double[numSites]; + double[] iqr = new double[numSites]; + double[] central68 = new double[numSites]; + double[] central95 = new double[numSites]; + int workers = Math.min(numSites, Runtime.getRuntime().availableProcessors()); + // Partition sites rather than allocating a sample array for every parallel-stream element. + IntStream.range(0, workers).parallel().forEach(worker -> { + double[] values = new double[sampleCount]; + for (int n=worker; n -1e-12*sumSquares) + varianceNumerator = 0d; + Preconditions.checkState(varianceNumerator >= 0d, + "Negative variance numerator at site "+n+": "+varianceNumerator); + standardDeviation[n] = Math.sqrt(varianceNumerator/sampleCount); + Arrays.sort(values); + iqr[n] = empiricalFractile(values, 0.75)-empiricalFractile(values, 0.25); + central68[n] = empiricalFractile(values, 0.84)-empiricalFractile(values, 0.16); + central95[n] = empiricalFractile(values, 0.975)-empiricalFractile(values, 0.025); + } + }); + Map metricValues = new EnumMap<>(ConvergenceMetric.class); + metricValues.put(ConvergenceMetric.MEAN_HAZARD, curveMean); + metricValues.put(ConvergenceMetric.STANDARD_DEVIATION, standardDeviation); + metricValues.put(ConvergenceMetric.IQR, iqr); + metricValues.put(ConvergenceMetric.CENTRAL_68_RANGE, central68); + metricValues.put(ConvergenceMetric.CENTRAL_95_RANGE, central95); + return new HazardStatistics(metricValues); + } + + private static double empiricalFractile(double[] sortedValues, double fractile) { + Preconditions.checkArgument(sortedValues.length > 0 && fractile >= 0d && fractile <= 1d); + double previousValue = sortedValues[0]; + int index = 1; + while (index < sortedValues.length && (float)sortedValues[index] == (float)previousValue) + index++; + double previousCDF = (double)index/sortedValues.length; + if (fractile <= previousCDF) + return previousValue; + while (index < sortedValues.length) { + double value = sortedValues[index++]; + while (index < sortedValues.length && (float)sortedValues[index] == (float)value) + index++; + double cdf = (double)index/sortedValues.length; + if (fractile == cdf) + return value; + if (fractile < cdf) { + double relative = (fractile-previousCDF)/(cdf-previousCDF); + return previousValue + relative*(value-previousValue); + } + previousValue = value; + previousCDF = cdf; + } + return sortedValues[sortedValues.length-1]; + } + + private static void appendComparisons(List comparisons, RunSpec run, + int sampleCount, HazardStatistics statistics, ReferenceStatistics reference, GriddedRegion gridReg) { + appendComparisons(comparisons, run, sampleCount, statistics, reference, gridReg, 0); + } + + private static void appendComparisons(List comparisons, RunSpec run, + int sampleCount, HazardStatistics statistics, ReferenceStatistics reference, GriddedRegion gridReg, + int startIndex) { + for (ConvergenceMetric metric : ConvergenceMetric.values()) { + MapComparison comparison = compare(statistics.values(metric), reference.statistics().values(metric)); + comparisons.add(new ReferenceComparison(run, sampleCount, reference.name(), reference.sampleCount(), + metric, comparison, gridReg.getLocation(comparison.maximumAbsoluteIndex()), startIndex)); + } + } + + private static void writeReferenceComparisons(File file, List comparisons) + throws IOException { + CSVFile csv = new CSVFile<>(true); + csv.addLine("Run", "Sampling method", "Seed", "Maximum run size", "Sample count", + "Reference", "Reference sample count", + "Metric", "Spatial mean % change", "Spatial mean absolute % change", + "Spatial P95 absolute % change", "Maximum absolute % change", "Minimum % change", + "Maximum % change", "Worst longitude", "Worst latitude", "Start index", "End index (exclusive)"); + for (ReferenceComparison row : comparisons) { + MapComparison comparison = row.comparison(); + csv.addLine(row.run().id(), row.run().method().name(), row.run().seed()+"", + row.run().maxSamples()+"", row.sampleCount()+"", + row.referenceName(), row.referenceSampleCount()+"", row.metric().label, + comparison.meanPercentChange()+"", comparison.meanAbsolutePercentChange()+"", + comparison.p95AbsolutePercentChange()+"", comparison.maximumAbsolutePercentChange()+"", + comparison.minimumPercentChange()+"", comparison.maximumPercentChange()+"", + row.worstLocation().lon+"", row.worstLocation().lat+"", + row.startIndex()+"", (row.startIndex()+row.sampleCount())+""); + } + csv.writeToFile(file); + } + + private static void writeReferenceComparisonSummary(File file, List comparisons) + throws IOException { + Map> groups = new LinkedHashMap<>(); + for (ReferenceComparison comparison : comparisons) { + ReferenceComparisonGroup group = new ReferenceComparisonGroup(comparison.run().method(), + comparison.sampleCount(), + comparison.referenceName(), comparison.metric()); + groups.computeIfAbsent(group, key -> new ArrayList<>()).add(comparison); + } + CSVFile csv = new CSVFile<>(true); + csv.addLine("Sampling method", "Sample count", "Reference", "Metric", "Spatial summary", "Realizations", + "Mean", "Standard deviation", "Log standard deviation", "Minimum", "P2.5", "P16", "P50", "P84", + "P97.5", "Maximum"); + for (Map.Entry> entry : groups.entrySet()) { + ReferenceComparisonGroup group = entry.getKey(); + for (ConvergenceSummary summary : ConvergenceSummary.values()) { + double[] values = new double[entry.getValue().size()]; + for (int i=0; i comparisons) + throws IOException { + CSVFile csv = new CSVFile<>(true); + csv.addLine("Run", "Sampling method", "Seed", "Maximum run size", "Lower sample count", + "Upper sample count", "Metric", + "Spatial mean % change", "Spatial mean absolute % change", "Spatial P95 absolute % change", + "Maximum absolute % change", "Minimum % change", "Maximum % change", + "Worst longitude", "Worst latitude"); + for (DoublingComparison row : comparisons) { + MapComparison comparison = row.comparison(); + csv.addLine(row.run().id(), row.run().method().name(), row.run().seed()+"", + row.run().maxSamples()+"", row.lowerCount()+"", + row.upperCount()+"", row.metric().label, comparison.meanPercentChange()+"", + comparison.meanAbsolutePercentChange()+"", comparison.p95AbsolutePercentChange()+"", + comparison.maximumAbsolutePercentChange()+"", comparison.minimumPercentChange()+"", + comparison.maximumPercentChange()+"", row.worstLocation().lon+"", row.worstLocation().lat+""); + } + csv.writeToFile(file); + } + + private static void writeDoublingComparisonSummary(File file, List comparisons) + throws IOException { + Map> groups = new LinkedHashMap<>(); + for (DoublingComparison comparison : comparisons) { + DoublingComparisonGroup group = new DoublingComparisonGroup(comparison.run().method(), comparison.lowerCount(), + comparison.upperCount(), comparison.metric()); + groups.computeIfAbsent(group, key -> new ArrayList<>()).add(comparison); + } + CSVFile csv = new CSVFile<>(true); + csv.addLine("Sampling method", "Lower sample count", "Upper sample count", "Metric", + "Spatial summary", "Realizations", + "Mean", "Standard deviation", "Log standard deviation", "Minimum", "P2.5", "P16", "P50", "P84", + "P97.5", "Maximum"); + for (Map.Entry> entry : groups.entrySet()) { + DoublingComparisonGroup group = entry.getKey(); + for (ConvergenceSummary summary : ConvergenceSummary.values()) { + double[] values = new double[entry.getValue().size()]; + for (int i=0; i buildRealizationPairComparisons( + List allData, GriddedRegion gridReg) { + Map> groups = new LinkedHashMap<>(); + for (Realization data : allData) { + MethodCount group = new MethodCount(data.run().method(), data.sampleCount()); + groups.computeIfAbsent(group, unused -> new ArrayList<>()).add(data); + } + List comparisons = new ArrayList<>(); + for (Map.Entry> entry : groups.entrySet()) { + List data = entry.getValue(); + for (int i=0; i comparisons) throws IOException { + CSVFile csv = new CSVFile<>(true); + csv.addLine("Sampling method", "Sample count", "First run", "First seed", "Second run", "Second seed", + "Metric", "Spatial mean % change", "Spatial mean absolute % change", + "Spatial P95 absolute % change", "Maximum absolute % change", "Minimum % change", + "Maximum % change", "Worst longitude", "Worst latitude"); + for (RealizationPairComparison row : comparisons) { + MapComparison comparison = row.comparison(); + csv.addLine(row.method().name(), row.sampleCount()+"", row.first().id(), row.first().seed()+"", + row.second().id(), row.second().seed()+"", row.metric().label, + comparison.meanPercentChange()+"", comparison.meanAbsolutePercentChange()+"", + comparison.p95AbsolutePercentChange()+"", comparison.maximumAbsolutePercentChange()+"", + comparison.minimumPercentChange()+"", comparison.maximumPercentChange()+"", + row.worstLocation().lon+"", row.worstLocation().lat+""); + } + csv.writeToFile(file); + } + + private static void writeRealizationPairComparisonSummary(File file, + List comparisons) throws IOException { + Map> groups = new LinkedHashMap<>(); + for (RealizationPairComparison comparison : comparisons) { + RealizationPairComparisonGroup group = new RealizationPairComparisonGroup(comparison.method(), + comparison.sampleCount(), comparison.metric()); + groups.computeIfAbsent(group, unused -> new ArrayList<>()).add(comparison); + } + CSVFile csv = new CSVFile<>(true); + csv.addLine("Sampling method", "Sample count", "Metric", "Spatial summary", "Realization pairs", + "Mean", "Standard deviation", "Log standard deviation", "Minimum", "P2.5", "P16", "P50", "P84", + "P97.5", "Maximum"); + for (Map.Entry> entry : groups.entrySet()) { + RealizationPairComparisonGroup group = entry.getKey(); + for (ConvergenceSummary summary : ConvergenceSummary.values()) { + double[] values = new double[entry.getValue().size()]; + for (int i=0; i csv, List prefix, double[] values) { + List line = new ArrayList<>(prefix); + line.add(StatUtils.mean(values)+""); + line.add(standardDeviation(values)+""); + line.add(logStandardDeviation(values)+""); + line.add(StatUtils.min(values)+""); + line.add(percentile(values, 2.5)+""); + line.add(percentile(values, 16d)+""); + line.add(percentile(values, 50d)+""); + line.add(percentile(values, 84d)+""); + line.add(percentile(values, 97.5)+""); + line.add(StatUtils.max(values)+""); + csv.addLine(line); + } + + /** + * Bootstraps the complete IID MCS pool and compares each resampled pool with the fixed Sobol consensus. Branch + * indexes are sampled once per replicate and shared across sites, preserving the spatial dependence present in + * each branch. Mean hazard is omitted because its production value is derived from mean hazard curves rather than + * the arithmetic mean of branch maps. + */ + static void runMCSPoolBootstrap(List mcsData, ReferenceStatistics mcsReference, + ReferenceStatistics sobolReference, int numReplicates, long seed, File outputDir) throws IOException { + Preconditions.checkArgument(!mcsData.isEmpty()); + Preconditions.checkArgument(numReplicates > 1); + double[][] branchMaps = mcsData.stream().flatMap(data -> Arrays.stream(data.branchMaps())) + .toArray(double[][]::new); + Preconditions.checkState(branchMaps.length == mcsReference.sampleCount()); + System.out.println("\nBootstrapping pooled MCS uncertainty: "+branchMaps.length+" branches x " + +numReplicates+" replicates"); + + List metrics = Arrays.stream(ConvergenceMetric.values()) + .filter(metric -> metric != ConvergenceMetric.MEAN_HAZARD).toList(); + @SuppressWarnings("unchecked") + Map[] comparisons = new Map[numReplicates]; + IntStream.range(0, numReplicates).parallel().forEach(r -> { + long replicateSeed = RandomSeedUtils.uniqueSeedCombination(seed, branchMaps.length, r); + int[] counts = bootstrapCounts(branchMaps.length, branchMaps.length, replicateSeed); + HazardStatistics statistics = calcBootstrapHazardStatistics(branchMaps, counts, branchMaps.length); + Map replicateComparisons = new EnumMap<>(ConvergenceMetric.class); + for (ConvergenceMetric metric : metrics) + replicateComparisons.put(metric, + compare(statistics.values(metric), sobolReference.statistics().values(metric))); + comparisons[r] = replicateComparisons; + }); + + CSVFile replicateCSV = new CSVFile<>(true); + replicateCSV.addLine("Replicate", "MCS sample count", "Reference", "Reference sample count", "Metric", + "Spatial mean % change", + "Spatial mean absolute % change", "Spatial P95 absolute % change", "Maximum absolute % change", + "Minimum % change", "Maximum % change"); + CSVFile summaryCSV = new CSVFile<>(true); + summaryCSV.addLine("MCS sample count", "Reference", "Reference sample count", "Metric", "Spatial summary", + "Original pooled MCS comparison", + "Replicates", "Mean", "Standard deviation", "Log standard deviation", "Minimum", "P2.5", + "P16", "P50", "P84", "P97.5", "Maximum"); + for (ConvergenceMetric metric : metrics) { + MapComparison original = compare(mcsReference.statistics().values(metric), + sobolReference.statistics().values(metric)); + for (int r=0; r 0 && counts.length == branchMaps.length); + Preconditions.checkArgument(sampleCount > 1); + int countSum = Arrays.stream(counts).sum(); + Preconditions.checkArgument(countSum == sampleCount, + "Bootstrap counts sum to %s, expected %s", countSum, sampleCount); + int numSites = branchMaps[0].length; + double[] standardDeviation = new double[numSites]; + double[] iqr = new double[numSites]; + double[] central68 = new double[numSites]; + double[] central95 = new double[numSites]; + double[] values = new double[sampleCount]; + for (int n=0; n -1e-12*sumSquares) + varianceNumerator = 0d; + Preconditions.checkState(varianceNumerator >= 0d, + "Negative bootstrap variance numerator at site "+n+": "+varianceNumerator); + standardDeviation[n] = Math.sqrt(varianceNumerator/sampleCount); + Arrays.sort(values); + iqr[n] = empiricalFractile(values, 0.75)-empiricalFractile(values, 0.25); + central68[n] = empiricalFractile(values, 0.84)-empiricalFractile(values, 0.16); + central95[n] = empiricalFractile(values, 0.975)-empiricalFractile(values, 0.025); + } + Map metricValues = new EnumMap<>(ConvergenceMetric.class); + metricValues.put(ConvergenceMetric.STANDARD_DEVIATION, standardDeviation); + metricValues.put(ConvergenceMetric.IQR, iqr); + metricValues.put(ConvergenceMetric.CENTRAL_68_RANGE, central68); + metricValues.put(ConvergenceMetric.CENTRAL_95_RANGE, central95); + return new HazardStatistics(metricValues); + } + + /** + * Resamples the reference MCS branches with replacement. Smaller resample sizes describe the error expected from + * ordinary MCS at those sample counts; the full-size resample describes uncertainty in the reference itself. + * Results are deterministic for a given seed even though replicates are evaluated in parallel. + */ + static void runBootstrapTests(ModelHazardMaps reference, int[] sampleCounts, int numReplicates, long seed, + File outputDir, String outputPrefix) throws IOException { + Preconditions.checkArgument(numReplicates > 1); + Preconditions.checkArgument(sampleCounts.length > 0); + + double[][] branchValues = copyValues(reference.individual()); + StatisticMaps referenceStats = calcStatistics(branchValues, null, branchValues.length); + MapComparison archivedMeanComparison = compare(referenceStats.mean(), copyValues(reference.mean())); + System.out.println("Branch-map arithmetic mean versus archived curve-derived mean (expected to differ): " + +archivedMeanComparison); + + CSVFile replicateCSV = new CSVFile<>(true); + replicateCSV.addLine("Sample count", "Replicate", "Metric", "Spatial mean % change", + "Spatial mean absolute % change", "Minimum % change", "Maximum % change"); + CSVFile summaryCSV = new CSVFile<>(true); + summaryCSV.addLine("Sample count", "Metric", "Spatial summary", "Mean", "Standard deviation", + "Log standard deviation", "Minimum", "P2.5", "P16", "P50", "P84", "P97.5", "Maximum"); + CSVFile siteCSV = new CSVFile<>(true); + siteCSV.addLine("Sample count", "Metric", "Longitude", "Latitude", "Reference value", + "Mean % change", "Std. dev. % change", "P2.5", "P16", "P50", "P84", "P97.5"); + + for (int sampleCount : sampleCounts) { + Preconditions.checkArgument(sampleCount > 1); + System.out.println("\nBootstrapping "+sampleCount+" branches x "+numReplicates+" replicates"); + BootstrapReplicate[] replicates = new BootstrapReplicate[numReplicates]; + IntStream.range(0, numReplicates).parallel().forEach(r -> { + long replicateSeed = RandomSeedUtils.uniqueSeedCombination(seed, sampleCount, r); + int[] counts = bootstrapCounts(branchValues.length, sampleCount, replicateSeed); + StatisticMaps statistics = calcStatistics(branchValues, counts, sampleCount); + Map comparisons = new EnumMap<>(HazardMetric.class); + for (HazardMetric metric : HazardMetric.values()) + comparisons.put(metric, compare(metric.values(statistics), metric.values(referenceStats))); + replicates[r] = new BootstrapReplicate(statistics, comparisons); + }); + + appendReplicateCSVs(replicateCSV, summaryCSV, siteCSV, reference.mean(), referenceStats, + sampleCount, replicates); + for (HazardMetric metric : HazardMetric.values()) { + double[] meanAbs = new double[numReplicates]; + for (int r=0; r replicateCSV, CSVFile summaryCSV, + CSVFile siteCSV, GriddedGeoDataSet referenceMap, StatisticMaps referenceStats, + int sampleCount, BootstrapReplicate[] replicates) { + for (HazardMetric metric : HazardMetric.values()) { + for (int r=0; r csv, int sampleCount, String metric, + String quantity, double[] values) { + csv.addLine(sampleCount+"", metric, quantity, StatUtils.mean(values)+"", standardDeviation(values)+"", + logStandardDeviation(values)+"", + StatUtils.min(values)+"", + percentile(values, 2.5)+"", + percentile(values, 16d)+"", percentile(values, 50d)+"", percentile(values, 84d)+"", + percentile(values, 97.5)+"", StatUtils.max(values)+""); + } + + private static String formatDistribution(double[] values) { + return "median="+(float)percentile(values, 50d)+", 95%=["+(float)percentile(values, 2.5) + +", "+(float)percentile(values, 97.5)+"]"; + } + + private static double percentile(double[] values, double percentile) { + // StatUtils does not modify its input, which lets us reuse the per-replicate arrays for each percentile. + return StatUtils.percentile(values, percentile); + } + + static double standardDeviation(double[] values) { + return values.length < 2 ? Double.NaN : Math.sqrt(StatUtils.variance(values)); + } + + /** Sample standard deviation after a natural-log transform; undefined for nonpositive values or one observation. */ + static double logStandardDeviation(double[] values) { + if (values.length < 2) + return Double.NaN; + double[] logs = new double[values.length]; + for (int i=0; i 0d) || !Double.isFinite(values[i])) + return Double.NaN; + logs[i] = Math.log(values[i]); + } + return Math.sqrt(StatUtils.variance(logs)); + } + + private static int[] bootstrapCounts(int numBranches, int sampleCount, long seed) { + int[] counts = new int[numBranches]; + SplittableRandom random = new SplittableRandom(seed); + for (int i=0; i 0); + Preconditions.checkArgument(sampleCount > 1); + if (counts != null) + Preconditions.checkArgument(counts.length == branchValues.length); + int numSites = branchValues[0].length; + double[] sums = new double[numSites]; + double[] sumSquares = new double[numSites]; + for (int b=0; b -1e-12*sumSquares[n]) + varianceNumerator = 0d; + Preconditions.checkState(varianceNumerator >= 0d, + "Negative variance numerator at site "+n+": "+varianceNumerator); + double standardDeviation = Math.sqrt(varianceNumerator/sampleCount); + means[n] = mean; + standardDeviations[n] = standardDeviation; + coefficientsOfVariation[n] = standardDeviation/mean; + } + return new StatisticMaps(means, standardDeviations, coefficientsOfVariation); + } + + private static MapComparison compare(double[] testValues, double[] referenceValues) { + Preconditions.checkArgument(testValues.length == referenceValues.length); + double sum = 0d; + double sumAbsolute = 0d; + double min = Double.POSITIVE_INFINITY; + double max = Double.NEGATIVE_INFINITY; + double maxAbsolute = Double.NEGATIVE_INFINITY; + int maxAbsoluteIndex = -1; + double[] absoluteChanges = new double[testValues.length]; + for (int i=0; i maxAbsolute) { + maxAbsolute = absolute; + maxAbsoluteIndex = i; + } + } + Arrays.sort(absoluteChanges); + return new MapComparison(sum/testValues.length, sumAbsolute/testValues.length, + empiricalFractile(absoluteChanges, 0.95), maxAbsolute, maxAbsoluteIndex, min, max); + } + + private static double percentChange(double testValue, double referenceValue) { + Preconditions.checkState(Double.isFinite(testValue)); + Preconditions.checkState(Double.isFinite(referenceValue) && referenceValue > 0d, + "Reference values must be finite and positive: %s", referenceValue); + return 100d*(testValue/referenceValue - 1d); + } + + private static String mapFilePrefix(double period, ReturnPeriods rp) { + String perStr = period == 0d ? "pga" : (float)period+"s"; + return perStr+"_"+rp.name(); + } + + private static GriddedGeoDataSet readMap(GriddedRegion gridReg, InputStream is) throws IOException { + GriddedGeoDataSet xyz = new GriddedGeoDataSet(gridReg, false); + BufferedReader bRead = new BufferedReader(new InputStreamReader(is)); + String line = bRead.readLine(); + int index = 0; + while (line != null) { + line = line.trim(); + if (!line.startsWith("#")) { + StringTokenizer tok = new StringTokenizer(line); + double lon = Double.parseDouble(tok.nextToken()); + double lat = Double.parseDouble(tok.nextToken()); + double val = Double.parseDouble(tok.nextToken()); + Location loc = new Location(lat, lon); + Preconditions.checkState(LocationUtils.areSimilar(loc, gridReg.getLocation(index))); + xyz.set(index++, val); + } + line = bRead.readLine(); + } + Preconditions.checkState(index == gridReg.getNodeCount()); + bRead.close(); + return xyz; + } + + static ModelHazardMaps loadMaps(File hazardZip, LogicTree tree, GriddedRegion gridReg, + double period, ReturnPeriods rp) throws ZipException, IOException { + System.out.println("Loading maps from "+hazardZip.getAbsolutePath()); + try (ZipFile zip = new ZipFile(hazardZip)) { + String suffix = mapFilePrefix(period, rp)+".txt"; + String meanEntryName = "mean_map_"+suffix; + ZipEntry meanEntry = zip.getEntry(meanEntryName); + Preconditions.checkNotNull(meanEntry, "Entry doesn't exist in %s: %s", hazardZip.getAbsolutePath(), meanEntryName); + GriddedGeoDataSet meanMap = readMap(gridReg, zip.getInputStream(meanEntry)); + + GriddedGeoDataSet[] individual = new GriddedGeoDataSet[tree.size()]; + for (int i=0; i branch = tree.getBranch(i); + String mapName = branch.buildFileName()+"/map_"+suffix; + ZipEntry mapEntry = zip.getEntry(mapName); + Preconditions.checkNotNull(mapEntry, "Entry doesn't exist in %s: %s", hazardZip.getAbsolutePath(), mapName); + individual[i] = readMap(gridReg, zip.getInputStream(mapEntry)); + } + + System.out.println("\tLoaded mean & "+individual.length+" individual"); + + return new ModelHazardMaps(meanMap, individual); + } + } + + static DiscretizedFunc[] loadBranchCurves(File hazardResultsDir, LogicTreeBranch branch, + GriddedRegion gridReg, double period) throws IOException { + File runDir = branch.getBranchDirectory(hazardResultsDir, false); + File hazardDir = new File(runDir, "hazard_"+(float)gridReg.getSpacing()+"deg_grid_seis_INCLUDE"); + Preconditions.checkState(hazardDir.exists(), "Hazard directory doesn't exist: %s", hazardDir.getAbsolutePath()); + File hazardFile = new File(hazardDir, SolHazardMapCalc.getCSV_FileName("curves", period)); + if (!hazardFile.exists()) + hazardFile = new File(hazardDir, SolHazardMapCalc.getCSV_FileName("curves", period)+".gz"); + Preconditions.checkState(hazardFile.exists(), "Hazard curves file doesn't exist: %s", hazardFile.getAbsolutePath()); + // this will detect that it's gzipped + CSVFile csv = CSVFile.readFile(hazardFile, true); + return SolHazardMapCalc.loadCurvesCSV(csv, gridReg); + } + + static final class BranchCurveLoader implements AutoCloseable { + private final File hazardResultsDir; + private final File archiveFile; + private final ZipFile archive; + + BranchCurveLoader(File runDir) throws IOException { + hazardResultsDir = new File(runDir, "results"); + archiveFile = new File(runDir, "results_hazard_curves.zip"); + archive = archiveFile.isFile() ? new ZipFile(archiveFile) : null; + if (archive != null) + System.out.println("\tLoading branch curves from "+archiveFile.getAbsolutePath()); + } + + DiscretizedFunc[] load(LogicTreeBranch branch, GriddedRegion gridReg, + double period) throws IOException { + if (archive == null) + return loadBranchCurves(hazardResultsDir, branch, gridReg, period); + + String entryPrefix = branch.buildFileName()+"/" + +SolHazardMapCalc.getCSV_FileName("curves", period); + ZipEntry entry = archive.getEntry(entryPrefix+".gz"); + if (entry == null) + entry = archive.getEntry(entryPrefix); + Preconditions.checkNotNull(entry, "Hazard curves entry doesn't exist in %s: %s[.gz]", + archiveFile.getAbsolutePath(), entryPrefix); + InputStream raw = archive.getInputStream(entry); + try (InputStream in = entry.getName().endsWith(".gz") ? new GZIPInputStream(raw) : raw) { + CSVFile csv = CSVFile.readStream(in, true); + return SolHazardMapCalc.loadCurvesCSV(csv, gridReg); + } + } + + @Override + public void close() throws IOException { + if (archive != null) + archive.close(); + } + } + + private enum HazardMetric { + MEAN("Mean hazard") { + @Override double[] values(StatisticMaps maps) { return maps.mean(); } + }, + STANDARD_DEVIATION("SD of hazard") { + @Override double[] values(StatisticMaps maps) { return maps.standardDeviation(); } + }, + COEFFICIENT_OF_VARIATION("CV of hazard") { + @Override double[] values(StatisticMaps maps) { return maps.coefficientOfVariation(); } + }; + + final String label; + private HazardMetric(String label) { + this.label = label; + } + abstract double[] values(StatisticMaps maps); + } + + enum ConvergenceMetric { + MEAN_HAZARD("Mean hazard", "Mean"), + STANDARD_DEVIATION("SD of hazard", "SD"), + IQR("Interquartile range", "IQR"), + CENTRAL_68_RANGE("Central 68% range", "68%"), + CENTRAL_95_RANGE("Central 95% range", "95%"); + + final String label; + final String shortLabel; + private ConvergenceMetric(String label, String shortLabel) { + this.label = label; + this.shortLabel = shortLabel; + } + + static ConvergenceMetric fromLabel(String label) { + for (ConvergenceMetric metric : values()) + if (metric.label.equals(label)) + return metric; + throw new IllegalArgumentException("Unknown convergence metric: "+label); + } + } + + enum ConvergenceSummary { + MEAN_SIGNED("Spatial mean % change") { + @Override double value(MapComparison comparison) { return comparison.meanPercentChange(); } + }, + MEAN_ABSOLUTE("Spatial mean absolute % change") { + @Override double value(MapComparison comparison) { return comparison.meanAbsolutePercentChange(); } + }, + P95_ABSOLUTE("Spatial P95 absolute % change") { + @Override double value(MapComparison comparison) { return comparison.p95AbsolutePercentChange(); } + }, + MAXIMUM_ABSOLUTE("Maximum absolute % change") { + @Override double value(MapComparison comparison) { return comparison.maximumAbsolutePercentChange(); } + }; + + final String label; + private ConvergenceSummary(String label) { + this.label = label; + } + + static ConvergenceSummary fromLabel(String label) { + for (ConvergenceSummary summary : values()) + if (summary.label.equals(label)) + return summary; + throw new IllegalArgumentException("Unknown convergence summary: "+label); + } + + abstract double value(MapComparison comparison); + } + + private enum ComparisonQuantity { + MEAN("Spatial mean % change") { + @Override double value(MapComparison comparison) { return comparison.meanPercentChange(); } + }, + MEAN_ABSOLUTE("Spatial mean absolute % change") { + @Override double value(MapComparison comparison) { return comparison.meanAbsolutePercentChange(); } + }, + MINIMUM("Minimum % change") { + @Override double value(MapComparison comparison) { return comparison.minimumPercentChange(); } + }, + MAXIMUM("Maximum % change") { + @Override double value(MapComparison comparison) { return comparison.maximumPercentChange(); } + }; + + final String label; + private ComparisonQuantity(String label) { + this.label = label; + } + abstract double value(MapComparison comparison); + } + + record ModelHazardMaps(GriddedGeoDataSet mean, GriddedGeoDataSet[] individual) {} + + private record StatisticMaps(double[] mean, double[] standardDeviation, double[] coefficientOfVariation) {} + + record MapComparison(double meanPercentChange, double meanAbsolutePercentChange, + double p95AbsolutePercentChange, double maximumAbsolutePercentChange, int maximumAbsoluteIndex, + double minimumPercentChange, double maximumPercentChange) { + @Override + public String toString() { + return "mean="+(float)meanPercentChange+"%, abs="+(float)meanAbsolutePercentChange + +"%, p95abs="+(float)p95AbsolutePercentChange+"%, maxAbs=" + +(float)maximumAbsolutePercentChange+"%, range=["+(float)minimumPercentChange+"%, " + +(float)maximumPercentChange+"%]"; + } + } + + private record BootstrapReplicate(StatisticMaps statistics, Map comparisons) {} + + record RunSpec(String id, File directory, LogicTree tree, SamplingMethod method, + long seed, int maxSamples) {} + + record RunPeriodData(RunSpec run, double[][] branchMaps, double[] curveX, + double[][] curveSums, Map checkpoints, + Map curveBoundaries) {} + + record HazardStatistics(Map metricValues) { + double[] values(ConvergenceMetric metric) { + return Preconditions.checkNotNull(metricValues.get(metric)); + } + } + + record ReferenceStatistics(String name, String excludedRun, int sampleCount, + HazardStatistics statistics) {} + + private record PooledHazardData(ReferenceStatistics reference, double[] curveX, + double[][] curveSums, double[] meanMap) {} + + record ReferenceComparison(RunSpec run, int sampleCount, String referenceName, + int referenceSampleCount, ConvergenceMetric metric, MapComparison comparison, + Location worstLocation, int startIndex) {} + + private record ReferenceComparisonGroup(SamplingMethod method, int sampleCount, String referenceName, + ConvergenceMetric metric) {} + + private record DoublingComparison(RunSpec run, int lowerCount, int upperCount, + ConvergenceMetric metric, MapComparison comparison, Location worstLocation) {} + + private record DoublingComparisonGroup(SamplingMethod method, int lowerCount, int upperCount, + ConvergenceMetric metric) {} + + private record MethodCount(SamplingMethod method, int sampleCount) {} + + record Realization(RunSpec run, int sampleCount, HazardStatistics statistics) {} + + record RealizationPairComparison(SamplingMethod method, int sampleCount, + RunSpec first, RunSpec second, ConvergenceMetric metric, MapComparison comparison, + Location worstLocation) {} + + private record RealizationPairComparisonGroup(SamplingMethod method, int sampleCount, + ConvergenceMetric metric) {} + +} diff --git a/src/main/java/scratch/kevin/sampling/HazardConvergencePlots.java b/src/main/java/scratch/kevin/sampling/HazardConvergencePlots.java new file mode 100644 index 00000000..64367caf --- /dev/null +++ b/src/main/java/scratch/kevin/sampling/HazardConvergencePlots.java @@ -0,0 +1,526 @@ +package scratch.kevin.sampling; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; + +import org.apache.commons.math3.stat.StatUtils; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.XY_DataSet; +import org.opensha.commons.data.uncertainty.UncertainArbDiscFunc; +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.PlotSymbol; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.logicTree.sampling.SamplingMethod; + +import net.mahdilamb.colormap.Colors; +import scratch.kevin.sampling.HazardConvergenceCalcs.ConvergenceMetric; +import scratch.kevin.sampling.HazardConvergenceCalcs.ConvergenceSummary; + +/** Builds paper-oriented plots from the compact convergence summary CSV files. */ +public class HazardConvergencePlots { + + private static final Range Y_RANGE = new Range(5e-3, 2e1); + private static final Range SIGNED_Y_RANGE = new Range(-1d, 1d); + private static final String SOBOL_REFERENCE = HazardConvergenceCalcs.LOO_SOBOL_REFERENCE_NAME; + private static final String POOLED_SOBOL_REFERENCE = HazardConvergenceCalcs.POOLED_SOBOL_REFERENCE_NAME; + private static final String MCS_REFERENCE = HazardConvergenceCalcs.MCS_REFERENCE_NAME; + private static final SamplingMethod MCS = SamplingMethod.MONTE_CARLO; + private static final SamplingMethod SOBOL = SamplingMethod.OWEN_SCRAMBLED_SOBOL; + + private static final boolean INCLUDE_SIGNED_VARIABILITY_UNCERTAINTIES = true; + +// private static final ConvergenceMetric[] PLOT_METRICS = ConvergenceMetric.values(); + static final ConvergenceMetric[] PLOT_METRICS = { + ConvergenceMetric.MEAN_HAZARD, + ConvergenceMetric.STANDARD_DEVIATION, + ConvergenceMetric.CENTRAL_68_RANGE, + ConvergenceMetric.CENTRAL_95_RANGE + }; + + private static final Map METRIC_COLORS = Map.of( + ConvergenceMetric.MEAN_HAZARD, Colors.tab_blue, + ConvergenceMetric.STANDARD_DEVIATION, Colors.tab_orange, + ConvergenceMetric.CENTRAL_68_RANGE, Colors.tab_green, + ConvergenceMetric.CENTRAL_95_RANGE, Colors.tab_red, + ConvergenceMetric.IQR, Colors.tab_purple); + + private static final Map METRIC_SYMBOLS = Map.of( + ConvergenceMetric.MEAN_HAZARD, PlotSymbol.FILLED_CIRCLE, + ConvergenceMetric.STANDARD_DEVIATION, PlotSymbol.FILLED_INV_TRIANGLE, + ConvergenceMetric.CENTRAL_68_RANGE, PlotSymbol.FILLED_SQUARE, + ConvergenceMetric.CENTRAL_95_RANGE, PlotSymbol.FILLED_DIAMOND, + ConvergenceMetric.IQR, PlotSymbol.FILLED_TRIANGLE); + + static String getMethodName(SamplingMethod method) { + if (method == SamplingMethod.OWEN_SCRAMBLED_SOBOL) + return SamplingMethod.SOBOL.getShortName(); + return method.getShortName(); + } + + private static final Map METHOD_FILE_PREFIXES; + static { + Map prefixes = new HashMap<>(); + for (SamplingMethod method : SamplingMethod.values()) + prefixes.put(method, getMethodName(method).toLowerCase().replaceAll("-", "_").replace("'", "")); + METHOD_FILE_PREFIXES = prefixes; + } + + private static final boolean PLOT_INDV_MEANS = true; + + public static void main(String[] args) throws IOException { + File convergenceDir = new File(PaperPaths.FIGURES_DIR, "hazard_convergence"); + plotPeriod(new File(convergenceDir, "pga_two_in_50"), "PGA"); + plotPeriod(new File(convergenceDir, "1s_sa_two_in_50"), "1s SA"); + } + + static void plotPeriod(File outputDir, String periodName) throws IOException { + List references = loadReferenceSummaries( + new File(outputDir, "reference_comparisons.csv")); + List realizationPairs = loadRealizationPairSummaries( + new File(outputDir, "realization_pair_comparisons.csv")); + + for (SamplingMethod method : references.stream().map(ReferenceSummary::method).distinct().sorted().toList()) { + for (boolean sobolPool : new boolean[] {true, false}) { + plotReference(outputDir, references, method, sobolPool, ConvergenceSummary.MEAN_ABSOLUTE); + plotReference(outputDir, references, method, sobolPool, ConvergenceSummary.MEAN_SIGNED); +// // Retain the original Sobol convergence maximum plots as standalone figures. +// if (method == SOBOL) +// plotReference(outputDir, references, method, sobolPool, ConvergenceSummary.MAXIMUM_ABSOLUTE); + } + } + for (boolean sobolPool : new boolean[] {true, false}) { + plotMethodReference(outputDir, references, sobolPool, ConvergenceSummary.MEAN_ABSOLUTE, + "Absolute difference (%)"); + plotMethodReference(outputDir, references, sobolPool, ConvergenceSummary.MEAN_SIGNED, + "Signed bias (%)"); + } + plotRealizationPairs(outputDir, realizationPairs, ConvergenceSummary.MEAN_ABSOLUTE, + "Absolute difference (%)"); + } + + private static String referenceFor(SamplingMethod method, boolean sobolPool) { + return sobolPool ? (method == SOBOL ? SOBOL_REFERENCE : POOLED_SOBOL_REFERENCE) + : (method == MCS ? HazardConvergenceCalcs.LOO_MCS_REFERENCE_NAME : MCS_REFERENCE); + } + + private static boolean matchesReference(ReferenceSummary row, SamplingMethod method, boolean sobolPool) { + if (sobolPool && method == SOBOL) + // A fixed-size consensus only leaves out Sobol runs of that size; other sizes use the full pool. + return row.reference().equals(SOBOL_REFERENCE) || row.reference().equals(POOLED_SOBOL_REFERENCE); + return row.reference().equals(referenceFor(method, sobolPool)); + } + + private static boolean includeSummary(ConvergenceSummary actual, ConvergenceSummary requested) { + return actual == requested || requested == ConvergenceSummary.MEAN_ABSOLUTE + && actual == ConvergenceSummary.MAXIMUM_ABSOLUTE; + } + + private static void plotReference(File outputDir, List rows, + SamplingMethod method, boolean sobolPool, ConvergenceSummary summary) throws IOException { + List matching = rows.stream().filter(row -> row.method() == method + && matchesReference(row, method, sobolPool) + && includeSummary(row.spatialSummary(), summary)).toList(); + int[] counts = matching.stream().mapToInt(ReferenceSummary::sampleCount).distinct().sorted().toArray(); + if (counts.length < 2) + return; + String pool = sobolPool ? "pooled_sobol" : "pooled_mcs"; + String prefix = "convergence_"+METHOD_FILE_PREFIXES.get(method)+"_vs_" + +pool+"_"+summaryPrefix(summary); + String yLabel = summary == ConvergenceSummary.MEAN_SIGNED ? "Signed bias (%)" + : summary == ConvergenceSummary.MEAN_ABSOLUTE ? "Absolute difference (%)" + : "Maximum absolute difference (%)"; + writePlot(outputDir, prefix, getMethodName(method)+" vs "+(sobolPool ? "Sobol' pool" : "MCS pool"), + "Sample count", yLabel, counts, + Arrays.stream(counts).mapToObj(Integer::toString).toArray(String[]::new), matching, summary); + } + + static void plotMethodReference(File outputDir, List rows, + boolean sobolConsensus, ConvergenceSummary spatialSummary, String yLabel) throws IOException { + int[] counts = rows.stream().mapToInt(ReferenceSummary::sampleCount).distinct().sorted().toArray(); + for (int count : counts) + plotMethodReference(outputDir, rows, sobolConsensus, spatialSummary, yLabel, count); + } + + private static void plotMethodReference(File outputDir, List rows, + boolean sobolConsensus, ConvergenceSummary spatialSummary, String yLabel, int sampleCount) throws IOException { + List matching = new ArrayList<>(); + List labels = new ArrayList<>(); + for (SamplingMethod method : rows.stream().map(row -> row.method()).distinct().sorted().toList()) { + int index = labels.size(); + for (ReferenceSummary row : rows) { + if (row.method() == method && row.sampleCount() == sampleCount + && matchesReference(row, method, sobolConsensus) + && includeSummary(row.spatialSummary(), spatialSummary)) { + matching.add(new MethodSummary(index, row.metric(), row.spatialSummary(), row.realizations(), + row.mean(), row.standardDeviation(), row.minimum(), row.median(), row.maximum(), + row.logStandardDeviation(), row.individualValues())); + } + } + if (matching.stream().anyMatch(row -> row.count() == index)) + labels.add(getMethodName(method)); + } + if (matching.isEmpty()) + return; + String referencePrefix = sobolConsensus ? "pooled_sobol" : "pooled_mcs"; +// String title = sampleCount+" samples versus " +// +(sobolConsensus ? POOLED_SOBOL_REFERENCE : MCS_REFERENCE); + String title = sampleCount+" samples vs " + +(sobolConsensus ? "Sobol' pool" : "MCS pool"); + writePlot(outputDir, "method_comparison_"+sampleCount+"_"+referencePrefix+"_"+summaryPrefix(spatialSummary), + title, "Sampling method", yLabel, + IntStream.range(0, labels.size()).toArray(), labels.toArray(String[]::new), matching, spatialSummary); + } + + private static void plotRealizationPairs(File outputDir, List rows, + ConvergenceSummary spatialSummary, String yLabel) throws IOException { + int[] counts = rows.stream().mapToInt(RealizationPairSummary::sampleCount).distinct().sorted().toArray(); + for (int count : counts) + plotRealizationPairs(outputDir, rows, spatialSummary, yLabel, count); + } + + private static void plotRealizationPairs(File outputDir, List rows, + ConvergenceSummary spatialSummary, String yLabel, int sampleCount) throws IOException { + List matching = new ArrayList<>(); + List labels = new ArrayList<>(); + for (SamplingMethod method : rows.stream().map(row -> row.method()).distinct().sorted().toList()) { + int index = labels.size(); + for (RealizationPairSummary row : rows) { + if (row.method() == method && row.sampleCount() == sampleCount + && includeSummary(row.spatialSummary(), spatialSummary)) { + matching.add(new MethodSummary(index, row.metric(), row.spatialSummary(), row.realizationPairs(), + row.mean(), row.standardDeviation(), row.minimum(), row.median(), row.maximum(), + row.logStandardDeviation(), row.individualValues())); + } + } + if (matching.stream().anyMatch(row -> row.count() == index)) + labels.add(getMethodName(method)); + } + if (matching.isEmpty()) + return; + writePlot(outputDir, "method_comparison_"+sampleCount+"_realization_pairs_"+summaryPrefix(spatialSummary), + "Differences between "+sampleCount+"-sample realizations", "Sampling method", yLabel, + IntStream.range(0, labels.size()).toArray(), labels.toArray(String[]::new), matching, spatialSummary); + } + + private static void writePlot(File outputDir, String prefix, String title, String xLabel, String yLabel, + int[] counts, String[] countLabels, List rows, + ConvergenceSummary primary) throws IOException { + System.out.println("Building plot: "+title); + boolean signed = primary == ConvergenceSummary.MEAN_SIGNED; + Map> byMetric = new LinkedHashMap<>(); + for (ConvergenceMetric metric : PLOT_METRICS) { + List metricRows = rows.stream().filter(row -> row.metric().equals(metric) + && row.spatialSummary() == primary).toList(); + if (!metricRows.isEmpty()) + byMetric.put(metric, metricRows); + } + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + List maxFuncs = new ArrayList<>(); + List maxChars = new ArrayList<>(); + List medianFuncs = new ArrayList<>(); + List medianChars = new ArrayList<>(); + if (signed) { + ArbitrarilyDiscretizedFunc zero = new ArbitrarilyDiscretizedFunc(); + zero.set(-0.3d, 0d); + zero.set(counts.length-0.7d, 0d); + funcs.add(zero); + chars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 0.5f, Color.GRAY)); + } + for (Map.Entry> entry : byMetric.entrySet()) { + ArbitrarilyDiscretizedFunc median = new ArbitrarilyDiscretizedFunc(); + ArbitrarilyDiscretizedFunc lower = new ArbitrarilyDiscretizedFunc(); + ArbitrarilyDiscretizedFunc upper = new ArbitrarilyDiscretizedFunc(); + DefaultXY_DataSet indvMeans = entry.getKey() == ConvergenceMetric.MEAN_HAZARD && PLOT_INDV_MEANS ? new DefaultXY_DataSet() : null; + for (int i=0; i candidate.count() == count).toList()); + if (indvMeans != null) { + double[] values = row.individualValues(); + for (double value : values) + indvMeans.set((double)i, value); + + System.out.println("\t"+values.length+" mean values for "+title+", count="+count); + } + double center = signed ? row.mean() : row.median(); + median.set((double)i, center); + if (signed) { + double standardDeviation = row.standardDeviation(); + if (!Double.isFinite(standardDeviation)) + standardDeviation = 0d; + lower.set((double)i, center-standardDeviation); + upper.set((double)i, center+standardDeviation); + } else { + double logSD = row.logStandardDeviation(); + double factor = Double.isFinite(logSD) ? Math.exp(logSD) : 1d; + lower.set((double)i, row.median()/factor); + upper.set((double)i, row.median()*factor); + } + } + Color color = METRIC_COLORS.get(entry.getKey()); + PlotSymbol sym = METRIC_SYMBOLS.get(entry.getKey()); + PlotSymbol outlineSym = PlotSymbol.getOutlineSymbol(sym); + // Positive quantities use a shaded, median-centered multiplicative range defined by one standard + // deviation of the log-transformed values. For signed biases, retain that shading for mean hazard but + // draw the other mean +/- standard-deviation ranges as unobtrusive dotted bounds to avoid overlapping + // shaded regions. + if (!signed || entry.getKey() == ConvergenceMetric.MEAN_HAZARD) { + UncertainArbDiscFunc uncertainty = new UncertainArbDiscFunc(median, lower, upper); + funcs.add(uncertainty); + chars.add(new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, + ColorUtils.transparent(color, 70))); + } else if (INCLUDE_SIGNED_VARIABILITY_UNCERTAINTIES) { + funcs.add(lower); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 1f, + ColorUtils.transparent(color, 120))); + funcs.add(upper); + chars.add(new PlotCurveCharacterstics(PlotLineType.DOTTED, 1f, + ColorUtils.transparent(color, 120))); + } + if (indvMeans != null) { + medianFuncs.add(indvMeans); + medianChars.add(new PlotCurveCharacterstics(sym, 1.5f, color.darker().darker())); + } + if (outlineSym != null) { + // add slightly darker outline overlay + ArbitrarilyDiscretizedFunc clone = median.deepClone(); + clone.setName(null); + medianFuncs.add(clone); + medianChars.add(new PlotCurveCharacterstics(outlineSym, 5f, color.darker().darker())); + } + median.setName(entry.getKey().shortLabel); + medianFuncs.add(median); + if (primary == ConvergenceSummary.MEAN_ABSOLUTE) { + ArbitrarilyDiscretizedFunc worst = new ArbitrarilyDiscretizedFunc(); + for (int i=0; i row.metric() == entry.getKey() && row.count() == count + && row.spatialSummary() == ConvergenceSummary.MAXIMUM_ABSOLUTE) + .mapToDouble(SummaryRow::maximum).max() + .ifPresent(maximum -> worst.set((double)Arrays.binarySearch(counts, count), maximum)); + } + if (worst.size() > 0) { + maxFuncs.add(worst); // Unnamed, so it adds no legend entry. + maxChars.add(new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 0.5f, + PlotSymbol.getOutlineSymbol(sym), 3f, color)); + } + } + medianChars.add(new PlotCurveCharacterstics(PlotLineType.SOLID, 2f, sym, 5f, color)); + } + // Put every envelope in the dataset first so all median lines render above all shading. + funcs.addAll(maxFuncs); + chars.addAll(maxChars); + // add copies for names (then clear the names) + for (int i=0; i= 0 && index < labels.length && Math.abs(value-index) < 1e-6) + buffer.append(labels[index]); + return buffer; + } + @Override public StringBuffer format(long value, StringBuffer buffer, FieldPosition pos) { + return format((double)value, buffer, pos); + } + @Override public Number parse(String source, ParsePosition pos) { + pos.setErrorIndex(pos.getIndex()); + return null; + } + }; + } + + private static List loadReferenceSummaries(File file) throws IOException { + CSVFile csv = CSVFile.readFile(file, true); + Map> groups = new LinkedHashMap<>(); + for (int row=1; row rows = new ArrayList<>(); + for (Map.Entry> entry : groups.entrySet()) { + ReferenceGroup group = entry.getKey(); + double[] values = entry.getValue().stream().mapToDouble(Double::doubleValue).toArray(); + rows.add(new ReferenceSummary(group.method(), group.sampleCount(), group.reference(), group.metric(), + group.spatialSummary(), values.length, StatUtils.mean(values), + HazardConvergenceCalcs.standardDeviation(values), StatUtils.min(values), + StatUtils.percentile(values, 50d), StatUtils.max(values), + HazardConvergenceCalcs.logStandardDeviation(values), values)); + } + return rows; + } + + private static List loadRealizationPairSummaries(File file) throws IOException { + CSVFile csv = CSVFile.readFile(file, true); + Map> groups = new LinkedHashMap<>(); + for (int row=1; row rows = new ArrayList<>(); + for (Map.Entry> entry : groups.entrySet()) { + RealizationPairGroup group = entry.getKey(); + double[] values = entry.getValue().stream().mapToDouble(Double::doubleValue).toArray(); + rows.add(new RealizationPairSummary(group.method(), group.sampleCount(), group.metric(), + group.spatialSummary(), values.length, StatUtils.mean(values), + HazardConvergenceCalcs.standardDeviation(values), StatUtils.min(values), + StatUtils.percentile(values, 50d), StatUtils.max(values), + HazardConvergenceCalcs.logStandardDeviation(values), values)); + } + return rows; + } + + private static void addValue(Map> groups, K key, double value) { + groups.computeIfAbsent(key, unused -> new ArrayList<>()).add(value); + } + + static SummaryRow combineRows(List rows) { + if (rows.isEmpty()) + throw new IllegalArgumentException("Cannot combine an empty set of summary rows"); + SummaryRow first = rows.get(0); + int size = rows.stream().mapToInt(row -> row.individualValues().length).sum(); + double[] values = new double[size]; + int offset = 0; + for (SummaryRow row : rows) { + if (row.count() != first.count() || row.metric() != first.metric() + || row.spatialSummary() != first.spatialSummary()) + throw new IllegalArgumentException("Cannot combine summary rows for different plotted quantities"); + System.arraycopy(row.individualValues(), 0, values, offset, row.individualValues().length); + offset += row.individualValues().length; + } + return new CombinedSummary(first.count(), first.metric(), first.spatialSummary(), + StatUtils.mean(values), HazardConvergenceCalcs.standardDeviation(values), StatUtils.min(values), + StatUtils.percentile(values, 50d), StatUtils.max(values), + HazardConvergenceCalcs.logStandardDeviation(values), values); + } + + private static String summaryPrefix(ConvergenceSummary summary) { + return switch (summary) { + case MEAN_SIGNED -> "signed_bias"; + case MEAN_ABSOLUTE -> "mean_abs"; + case P95_ABSOLUTE -> "p95_abs"; + case MAXIMUM_ABSOLUTE -> "max_abs"; + }; + } + + interface SummaryRow { + int count(); + ConvergenceSummary spatialSummary(); + ConvergenceMetric metric(); + double mean(); + double standardDeviation(); + double minimum(); + double median(); + double maximum(); + double logStandardDeviation(); + double[] individualValues(); + } + + record ReferenceSummary(SamplingMethod method, int sampleCount, String reference, ConvergenceMetric metric, + ConvergenceSummary spatialSummary, + int realizations, double mean, double standardDeviation, double minimum, double median, double maximum, + double logStandardDeviation, double[] individualValues) implements SummaryRow { + @Override public int count() { return sampleCount; } + } + + private record MethodSummary(int methodIndex, ConvergenceMetric metric, + ConvergenceSummary spatialSummary, int realizations, + double mean, double standardDeviation, double minimum, double median, double maximum, + double logStandardDeviation, double[] individualValues) implements SummaryRow { + @Override public int count() { return methodIndex; } + } + + private record CombinedSummary(int count, ConvergenceMetric metric, + ConvergenceSummary spatialSummary, double mean, double standardDeviation, + double minimum, double median, double maximum, double logStandardDeviation, + double[] individualValues) implements SummaryRow {} + + + private record RealizationPairSummary(SamplingMethod method, int sampleCount, ConvergenceMetric metric, + ConvergenceSummary spatialSummary, int realizationPairs, + double mean, double standardDeviation, double minimum, double median, double maximum, + double logStandardDeviation, double[] individualValues) {} + + private record ReferenceGroup(SamplingMethod method, int sampleCount, String reference, + ConvergenceMetric metric, + ConvergenceSummary spatialSummary) {} + + private record RealizationPairGroup(SamplingMethod method, int sampleCount, + ConvergenceMetric metric, ConvergenceSummary spatialSummary) {} +} diff --git a/src/main/java/scratch/kevin/sampling/HazardMapPlots.java b/src/main/java/scratch/kevin/sampling/HazardMapPlots.java new file mode 100644 index 00000000..ec3ee72e --- /dev/null +++ b/src/main/java/scratch/kevin/sampling/HazardMapPlots.java @@ -0,0 +1,529 @@ +package scratch.kevin.sampling; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.ui.TextAnchor; +import org.jfree.data.Range; +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.data.function.DiscretizedFunc; +import org.opensha.commons.data.function.LightFixedXFunc; +import org.opensha.commons.data.xyz.GriddedGeoDataSet; +import org.opensha.commons.geo.GriddedRegion; +import org.opensha.commons.geo.Location; +import org.opensha.commons.geo.Region; +import org.opensha.commons.geo.json.Feature; +import org.opensha.commons.gui.plot.GeographicMapMaker; +import org.opensha.commons.gui.plot.HeadlessGraphPanel; +import org.opensha.commons.gui.plot.PlotSpec; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.logicTree.LogicTree; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.DataUtils.MinMaxAveTracker; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc; +import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc.ReturnPeriods; + +import com.google.common.base.Preconditions; + +import scratch.kevin.sampling.HazardConvergenceCalcs.ConvergenceMetric; +import scratch.kevin.sampling.HazardConvergenceCalcs.HazardStatistics; +import scratch.kevin.sampling.HazardConvergenceCalcs.ModelHazardMaps; + +public class HazardMapPlots { + + private static final ReturnPeriods RP = ReturnPeriods.TWO_IN_50; + + public static void main(String[] args) throws IOException { + File convergenceDir = new File(PaperPaths.FIGURES_DIR, "hazard_convergence"); + int[] sizes = { 512, 1024, 2048, 4096, 8192 }; + plotPeriod(new File(convergenceDir, "pga_two_in_50"), 0d, "PGA, "+RP.label, sizes); + plotPeriod(new File(convergenceDir, "1s_sa_two_in_50"), 1d, "1s SA, "+RP.label, sizes); + } + + private static void plotPeriod(File periodDir, double period, String perLabel, int... indvSizes) + throws IOException { + File mapDir = new File(periodDir, "hazard_maps"); + Preconditions.checkState(mapDir.exists() || mapDir.mkdir()); + + File firstMCSDir = HazardConvergenceCalcs.runDirs.row(SamplingMethod.MONTE_CARLO) + .values().iterator().next().get(0); + GriddedRegion gridReg = GriddedRegion.fromFeature( + Feature.read(new File(firstMCSDir, "gridded_region.geojson"))); + + List mcsPoolDirs = flatten(HazardConvergenceCalcs.runDirs.row(SamplingMethod.MONTE_CARLO)); + List sobolPoolDirs; + if (HazardConvergenceCalcs.FIXED_SOBOL_CONSENSUS_SIZE == null) { + sobolPoolDirs = flatten(HazardConvergenceCalcs.runDirs.row(SamplingMethod.OWEN_SCRAMBLED_SOBOL)); + } else { + sobolPoolDirs = Preconditions.checkNotNull(HazardConvergenceCalcs.runDirs.get( + SamplingMethod.OWEN_SCRAMBLED_SOBOL, + HazardConvergenceCalcs.FIXED_SOBOL_CONSENSUS_SIZE)); + } + + DecimalFormat groupedDF = new DecimalFormat("0"); + groupedDF.setGroupingSize(3); + groupedDF.setGroupingUsed(true); + + PooledHazardData mcsPool = loadPool(periodDir, "pooled_mcs", mcsPoolDirs, gridReg, period); + PooledHazardData sobolPool = loadPool(periodDir, "pooled_sobol", sobolPoolDirs, gridReg, period); + List poLHSPoolDirs = largestRuns(HazardConvergenceCalcs.runDirs.row( + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE)); + PooledHazardData poLHSPool = poLHSPoolDirs.isEmpty() ? null + : loadPool(periodDir, "pooled_po_lhs", poLHSPoolDirs, gridReg, period); + + plotMeanHazard(gridReg, sobolPool.data(), perLabel, mapDir, "pooled_sobol"); + plotMeanHazard(gridReg, mcsPool.data(), perLabel, mapDir, "pooled_mcs"); + plotComparisons(gridReg, sobolPool.data(), mcsPool.data(), perLabel, mapDir, "pooled_sobol_vs_mcs", + "Pooled Sobol' ("+nStr(sobolPool.data)+") vs MCS ("+nStr(mcsPool.data)+")"); + if (poLHSPool != null) { + plotMeanHazard(gridReg, poLHSPool.data(), perLabel, mapDir, "pooled_po_lhs"); + plotComparisons(gridReg, poLHSPool.data(), mcsPool.data(), perLabel, mapDir, + "pooled_po_lhs_vs_mcs", "Pooled Pairwise-Optimized LHS ("+nStr(poLHSPool.data) + +") vs MCS ("+nStr(mcsPool.data)+")"); + plotComparisons(gridReg, poLHSPool.data(), sobolPool.data(), perLabel, mapDir, + "pooled_po_lhs_vs_sobol", "Pooled Pairwise-Optimized LHS ("+nStr(poLHSPool.data) + +") vs Sobol' ("+nStr(sobolPool.data)+")"); + } + + // Plot the first realization available for each method and requested sample count. + Map fullSobolRunCache = new HashMap<>(); + for (int size : indvSizes) { + File sizeDir = new File(mapDir, size+"_samples"); + Preconditions.checkState(sizeDir.exists() || sizeDir.mkdir()); + for (SamplingMethod method : SamplingMethod.values()) { + HazardData data; + HazardData refMCS; + HazardData refSobol; + if (method == SamplingMethod.MONTE_CARLO) { + // MCS comparisons use the first span of the first run and remove that span from the MCS pool. + data = loadRunPrefix(firstMCSDir, size, gridReg, period, mcsPool); + refMCS = mcsPool.without(firstMCSDir, size, data.meanCurves(), gridReg); + refSobol = sobolPool.data(); + } else { + File runDir = selectIndividualRun(method, size, sobolPoolDirs); + if (runDir == null) + continue; + data = loadRunPrefix(runDir, size, gridReg, period, + method == SamplingMethod.OWEN_SCRAMBLED_SOBOL ? sobolPool : null); + refMCS = mcsPool.data(); + if (method == SamplingMethod.OWEN_SCRAMBLED_SOBOL && sobolPool.contains(runDir)) { + int fullRunSize = sobolPool.runSize(runDir); + HazardData fullRun = data; + if (size < fullRunSize) { + fullRun = fullSobolRunCache.get(runDir.getAbsoluteFile()); + if (fullRun == null) { + fullRun = loadRunPrefix(runDir, fullRunSize, gridReg, period, sobolPool); + fullSobolRunCache.put(runDir.getAbsoluteFile(), fullRun); + } + } + // Prefixes from one scramble are not independent of its suffix, so exclude the entire parent run. + refSobol = sobolPool.without(runDir, fullRunSize, fullRun.meanCurves(), gridReg); + } else { + refSobol = sobolPool.data(); + } + } + + String name = "Individual "+HazardConvergencePlots.getMethodName(method)+" ("+nStr(data)+")"; + + plotComparisons(gridReg, data, refMCS, perLabel, sizeDir, + method.name().toLowerCase()+"_vs_pooled_mcs", name+" vs pooled MCS ("+nStr(refMCS)+")"); + plotComparisons(gridReg, data, refSobol, perLabel, sizeDir, + method.name().toLowerCase()+"_vs_pooled_sobol", name+" vs pooled Sobol' ("+nStr(refSobol)+")"); + } + } + } + + private static File selectIndividualRun(SamplingMethod method, int sampleCount, + List sobolPoolDirs) { + List exactRuns = HazardConvergenceCalcs.runDirs.get(method, sampleCount); + if (exactRuns != null && !exactRuns.isEmpty()) + return exactRuns.get(0); + if (method != SamplingMethod.OWEN_SCRAMBLED_SOBOL) + return null; + + // Sobol sequences are nested: a larger realization supplies every shorter leading prefix. Prefer a parent + // already in the consensus pool so that the comparison can apply the same leave-one-out treatment as the + // convergence calculations. + Map> sobolRuns = HazardConvergenceCalcs.runDirs.row(method); + for (Map.Entry> entry : new TreeMap<>(sobolRuns).entrySet()) { + if (entry.getKey() < sampleCount) + continue; + for (File runDir : entry.getValue()) + if (sobolPoolDirs.contains(runDir)) + return runDir; + } + for (Map.Entry> entry : new TreeMap<>(sobolRuns).entrySet()) + if (entry.getKey() >= sampleCount && !entry.getValue().isEmpty()) + return entry.getValue().get(0); + return null; + } + + private static final DecimalFormat groupedDF = new DecimalFormat("0"); + static { + groupedDF.setGroupingSize(3); + groupedDF.setGroupingUsed(true); + } + + private static String nStr(HazardData data) { + return nStr(data.numBranches()); + } + + private static String nStr(int size) { + return "N="+groupedDF.format(size); + } + + private static List flatten(Map> dirsBySize) { + List dirs = new ArrayList<>(); + dirsBySize.entrySet().stream().sorted(Map.Entry.comparingByKey()) + .forEach(entry -> dirs.addAll(entry.getValue())); + return dirs; + } + + private static List largestRuns(Map> dirsBySize) { + return dirsBySize.entrySet().stream().max(Map.Entry.comparingByKey()) + .map(Map.Entry::getValue).orElse(List.of()); + } + + private static PooledHazardData loadPool(File periodDir, String poolName, List runDirs, + GriddedRegion gridReg, double period) throws IOException { + Preconditions.checkState(!runDirs.isEmpty(), "No runs available for %s", poolName); + DiscretizedFunc[] meanCurves = loadCurves( + new File(new File(periodDir, poolName), + SolHazardMapCalc.getCSV_FileName("mean_curves", period)+".gz"), gridReg); + List blocks = new ArrayList<>(); + for (File runDir : runDirs) { + LogicTree tree = LogicTree.read(new File(runDir, "logic_tree_analysis.json")); + ModelHazardMaps maps = HazardConvergenceCalcs.loadMaps( + new File(runDir, "results_hazard.zip"), tree, gridReg, period, RP); + blocks.add(new RunBlock(runDir.getAbsoluteFile(), HazardConvergenceCalcs.copyValues(maps.individual()))); + } + return new PooledHazardData(buildHazardData(meanCurves, concatenate(blocks), gridReg), blocks); + } + + private static HazardData loadRunPrefix(File runDir, int sampleCount, GriddedRegion gridReg, + double period, PooledHazardData cachedPool) throws IOException { + LogicTree tree = LogicTree.read(new File(runDir, "logic_tree_analysis.json")); + Preconditions.checkState(sampleCount <= tree.size(), "Requested %s of %s branches from %s", + sampleCount, tree.size(), runDir.getName()); + double[][] allBranchMaps = cachedPool == null ? null : cachedPool.branchMaps(runDir); + if (allBranchMaps == null) { + ModelHazardMaps maps = HazardConvergenceCalcs.loadMaps( + new File(runDir, "results_hazard.zip"), tree, gridReg, period, RP); + allBranchMaps = HazardConvergenceCalcs.copyValues(maps.individual()); + } + double[][] branchMaps = Arrays.copyOf(allBranchMaps, sampleCount); + DiscretizedFunc[] meanCurves = loadMeanCurves(runDir, tree, sampleCount, gridReg, period); + return buildHazardData(meanCurves, branchMaps, gridReg); + } + + private static DiscretizedFunc[] loadMeanCurves(File runDir, LogicTree tree, int sampleCount, + GriddedRegion gridReg, double period) throws IOException { + double[] xValues = null; + double[][] sums = null; + try (HazardConvergenceCalcs.BranchCurveLoader curveLoader = + new HazardConvergenceCalcs.BranchCurveLoader(runDir)) { + for (int b=0; b blocks) { + int size = blocks.stream().mapToInt(block -> block.branchMaps().length).sum(); + double[][] values = new double[size][]; + int index = 0; + for (RunBlock block : blocks) + for (double[] row : block.branchMaps()) + values[index++] = row; + return values; + } + + private static Region getMapReagion(GriddedRegion gridReg) { + if (!gridReg.isRectangular()) + return gridReg; + MinMaxAveTracker latTrack = new MinMaxAveTracker(); + MinMaxAveTracker lonTrack = new MinMaxAveTracker(); + for (Location loc : gridReg.getNodeList()) { + latTrack.addValue(loc.lat); + lonTrack.addValue(loc.lon); + } + double halfLat = gridReg.getLatSpacing()*0.5; + double halfLon = gridReg.getLonSpacing()*0.5; + return new Region(new Location(latTrack.getMin()-halfLat, lonTrack.getMin()-halfLon), + new Location(latTrack.getMax()+halfLat, lonTrack.getMax()+halfLon)); + } + + private static void plotMeanHazard(GriddedRegion gridReg, HazardData data, + String perLabel, File outputDir, String prefix) throws IOException { + GeographicMapMaker mapMaker = new GeographicMapMaker(getMapReagion(gridReg)); + CPT hazCPT = GMT_CPT_Files.RAINBOW_UNIFORM.instance().rescale(1e-2, 3d).asLog10(); + GriddedGeoDataSet map = SolHazardMapCalc.buildMap(data.meanCurves(), gridReg, RP); + mapMaker.plotXYZData(map, hazCPT, "Mean hazard, "+perLabel+" (g)"); + mapMaker.plot(outputDir, prefix, "", PlotUtils.DEFAULT_USABLE_PAGE_WIDTH/2d, 300); + } + + private static void plotComparisons(GriddedRegion gridReg, HazardData data, HazardData reference, + String perLabel, File outputDir, String prefix, String title) throws IOException { + Region region = getMapReagion(gridReg); + GeographicMapMaker mapMaker = new GeographicMapMaker(region); + CPT pDiffCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-5d, 5d); + pDiffCPT.setPreferredTickInterval(1d); + + DecimalFormat df = new DecimalFormat("0.00"); + Font statsFont = new Font(Font.SANS_SERIF, Font.PLAIN, 8); + Font metricFont = new Font(Font.SANS_SERIF, Font.BOLD, 10); +// Color bgPaint = new Color(255, 255, 255, 60); +// Color bgPaint = new Color(200, 200, 200, 120); + Color bgPaint = new Color(220, 220, 220, 200); + + List plots = new ArrayList<>(); + + for (ConvergenceMetric metric : HazardConvergencePlots.PLOT_METRICS) { + GriddedGeoDataSet xyz = asGeoDataSet(gridReg, data.statistics().values(metric)); + GriddedGeoDataSet refXYZ = asGeoDataSet(gridReg, reference.statistics().values(metric)); + GriddedGeoDataSet pDiff = pDiff(xyz, refXYZ); + mapMaker.plotXYZData(pDiff, pDiffCPT, perLabel+", % change"); + + mapMaker.clearAnnotations(); + + double mean = 0d; + double meanAbs = 0d; + double min=Double.MAX_VALUE; + double max=Double.MIN_VALUE; + for (int i=0; i yRanges = new ArrayList<>(plots.size()); + for (int i=0; i> rows = new ArrayList<>(); + List curRow = null; + for (int i=0; i(); + rows.add(curRow); + } + curRow.add(plots.get(i)); + } + List gps = new ArrayList<>(rows.size()); + for (List row : rows) { + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + gp.drawGraphPanel(row, false, false, List.of(xRange, xRange), List.of(yRange)); + gps.add(gp); + } + + PlotUtils.stitchPlotRows(outputDir, prefix, gps, false, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH, -1d, 300, true, true, true); + } +// List yRanges = new ArrayList<>(plots.size()); +// for (int i=0; i blocks) { + boolean contains(File runDir) { + return blocks.stream().anyMatch(block -> block.matches(runDir)); + } + + double[][] branchMaps(File runDir) { + return blocks.stream().filter(block -> block.matches(runDir)).findFirst() + .map(RunBlock::branchMaps).orElse(null); + } + + int runSize(File runDir) { + double[][] maps = branchMaps(runDir); + Preconditions.checkState(maps != null, "Run is not in pooled data: %s", runDir.getName()); + return maps.length; + } + + HazardData without(File runDir, int excludedCount, DiscretizedFunc[] excludedMean, + GriddedRegion gridReg) { + Preconditions.checkState(contains(runDir), "Run is not in pooled data: %s", runDir.getName()); + List retained = new ArrayList<>(); + for (RunBlock block : blocks) { + if (block.matches(runDir)) { + Preconditions.checkState(excludedCount <= block.branchMaps().length); + if (excludedCount < block.branchMaps().length) + retained.add(new RunBlock(block.directory(), + Arrays.copyOfRange(block.branchMaps(), excludedCount, block.branchMaps().length))); + } else { + retained.add(block); + } + } + int fullCount = data.branchMaps().length; + DiscretizedFunc[] meanCurves = subtractMeanCurves( + data.meanCurves(), fullCount, excludedMean, excludedCount); + return buildHazardData(meanCurves, concatenate(retained), gridReg); + } + } +} diff --git a/src/main/java/scratch/kevin/sampling/InitialSamplingTests.java b/src/main/java/scratch/kevin/sampling/InitialSamplingTests.java new file mode 100644 index 00000000..9e5ca1e7 --- /dev/null +++ b/src/main/java/scratch/kevin/sampling/InitialSamplingTests.java @@ -0,0 +1,204 @@ +package scratch.kevin.sampling; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.math3.stat.StatUtils; +import org.apache.commons.numbers.core.Precision; +import org.opensha.commons.data.sampling.ArrayPointSet; +import org.opensha.commons.data.sampling.CategoricalSamplingDimension; +import org.opensha.commons.data.sampling.ContinuousSamplingDimension; +import org.opensha.commons.data.sampling.DimensionedPointSet; +import org.opensha.commons.data.sampling.PermutedPointSet; +import org.opensha.commons.data.sampling.PointSet; +import org.opensha.commons.data.sampling.SamplingDimension; +import org.opensha.commons.data.sampling.generator.*; +import org.opensha.commons.data.sampling.optimization.PointSetHillClimber; +import org.opensha.commons.data.sampling.optimization.PointSetHillClimber.Result; +import org.opensha.commons.data.sampling.optimization.PointSetObjective; +import org.opensha.commons.data.sampling.scoring.ProjectionDiscrepancyScore; +import org.opensha.commons.data.sampling.scoring.ProjectionDiscrepancyScorer; + +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; + +public class InitialSamplingTests { + + public static void main(String[] args) { + int numSamples = powerOfTwo(12); +// int numSamples = 5000; +// int numDimensions = 10; + int numDimensions = 30; + int numCategorical = 5; + int maxCategoriesPerDimension = 5; + int numScoringDimensions = 3; + int numIterations = 100000; + + Random r = new Random(123456789l); // repeatable +// Random r = new Random(); // different each time + + List dimensions = buildDimensions(numDimensions, numCategorical, maxCategoriesPerDimension, r); + +// PointSetGenerator generator = new MonteCarloPointSetGenerator(r); +// PointSetGenerator generator = new LatinHypercubePointSetGenerator(r); +// PointSetGenerator generator = new SobolPointSetGenerator(); +// PointSetGenerator generator = new SobolPointSetGenerator(1); + PointSetGenerator generator = new OwenScrambledSobolPointSetGenerator(r); + + System.out.println("\nGenerating "+numSamples+" "+numDimensions+"-D samples with generator: "+generator); + + Stopwatch watch = Stopwatch.createStarted(); + PointSet samples = generator.generate(numSamples, numDimensions); + watch.stop(); + System.out.println("Done in "+timeStr(watch)); + int[] debugPoints = {0, 1, 2, 3, 4, numSamples-1}; + for (int debugPoint : debugPoints) { + System.out.print("Point "+debugPoint+":\t["); + for (int d=0; d 0) + System.out.print(", "); + System.out.print((float)samples.get(debugPoint, d)); + } + System.out.println("]"); + } + + ProjectionDiscrepancyScorer exactScorer = ProjectionDiscrepancyScorer.exact(16); + + System.out.println("\nScoring continuous case to order "+numScoringDimensions); + watch.reset().start(); + ProjectionDiscrepancyScore score = exactScorer.score(samples, numScoringDimensions); + watch.stop(); + System.out.println("Done in "+timeStr(watch)); + System.out.println("Continuous score:\t"+score); +// System.exit(0); + +// System.out.println("\nRe-scoring continuous case using quantized scorer"); +// ProjectionDiscrepancyScorer quantizedScorer = ProjectionDiscrepancyScorer.quantized(100); +// watch.reset().start(); +// ProjectionDiscrepancyScore quantizedScore = quantizedScorer.score(samples, numScoringDimensions); +// watch.stop(); +// System.out.println("Done in "+timeStr(watch)); +// System.out.println("Continuous score:\t"+quantizedScore); + + // now make some categorical + DimensionedPointSet dimensioned = new DimensionedPointSet(samples, dimensions); + System.out.println("\nScoring dimensioned set"); + watch.reset().start(); + ProjectionDiscrepancyScore dimensionedScore = exactScorer.score(dimensioned, numScoringDimensions); + watch.stop(); + System.out.println("Done in "+timeStr(watch)); + System.out.println("Dimensioned score:\t"+dimensionedScore); + + System.out.println("\nImproving pairwise with "+numIterations+" hill-climbing iterations"); + watch.reset().start(); + PermutedPointSet permuted = PermutedPointSet.independentDimensions(dimensioned); + PointSetObjective objective = ProjectionDiscrepancyScorer.quantized(100).objective(); + Result result = PointSetHillClimber.optimize(permuted, objective, numIterations, r); + watch.stop(); + System.out.println("Done in "+timeStr(watch)); + System.out.println("Optimization result:\t"+result); + + System.out.println("\nScoring optimized version"); + watch.reset().start(); + ProjectionDiscrepancyScore optimizedScore = exactScorer.score(permuted, numScoringDimensions); + watch.stop(); + System.out.println("Done in "+timeStr(watch)); + System.out.println("Optimized score:\t"+optimizedScore); + + // these tests can be uncommented if we need to check JVM or PointSet implementation performance again +// System.out.println("\nConverting optimized version to an ArrayPointSet"); +// watch.reset().start(); +// DimensionedPointSet materialized = new DimensionedPointSet(new ArrayPointSet(permuted), dimensions); +// watch.stop(); +// System.out.println("Done in "+timeStr(watch)); +// System.out.println("Optimized score:\t"+optimizedScore); +// +// System.out.println("\nRe-scoring ArrayPointSet view of optimized version"); +// watch.reset().start(); +// ProjectionDiscrepancyScore materializedScore = scorer.score(materialized, numScoringDimensions); +// watch.stop(); +// System.out.println("Done in "+timeStr(watch)); +// System.out.println("Optimized score:\t"+materializedScore); +// +// System.out.println("\nRe-scoring the initial continuos case (JVM test)"); +// watch.reset().start(); +// ProjectionDiscrepancyScore score2 = scorer.score(samples, numScoringDimensions); +// watch.stop(); +// System.out.println("Done in "+timeStr(watch)); +// System.out.println("Continuous re-score:\t"+score2); + } + + static List buildDimensions(int numDimensions, int numCategorical, int maxCategoriesPerDimension, Random r) { + System.out.println("Building categories"); + List dimensions = new ArrayList<>(numDimensions); + Preconditions.checkState(numCategorical <= numDimensions); + Preconditions.checkState(maxCategoriesPerDimension >= 2); + // fill with sequential initially + for (int i=0; i 2 ? 2 + r.nextInt(maxCategoriesPerDimension-2) : 2; + boolean even = r.nextBoolean(); + double[] weights = new double[numCategories]; + if (even) { + Arrays.fill(weights, 1d/numCategories); + } else { + for (int i=0; i 0.04999); + int removeIndex = r.nextInt(numCategories); + if (weights[removeIndex] > 0.0999) { + weights[removeIndex] -= 0.05d; + sum = StatUtils.sum(weights); + remainder = sum - 1d; + } + } + } + } + } + System.out.println("Replacing index "+index+" with categorical weights: "+Arrays.toString(weights)); + dimensions.set(index, CategoricalSamplingDimension.forWeights(weights)); + myNumCategorical++; + } + return dimensions; + } + + private static int powerOfTwo(int n) { + Preconditions.checkState(n <= 30); + return 1 << n; + } + + private static final DecimalFormat timeDF = new DecimalFormat("0.0"); + private static String timeStr(Stopwatch watch) { + double secs = watch.elapsed(TimeUnit.MILLISECONDS)/1000d; + if (secs < 90d) + return timeDF.format(secs)+" s"; + double mins = secs/60d; + if (mins < 90d) + return timeDF.format(mins)+" m"; + double hours = mins / 60d; + return timeDF.format(hours)+" h"; + } + +} diff --git a/src/main/java/scratch/kevin/sampling/PaperPaths.java b/src/main/java/scratch/kevin/sampling/PaperPaths.java new file mode 100644 index 00000000..20e263ef --- /dev/null +++ b/src/main/java/scratch/kevin/sampling/PaperPaths.java @@ -0,0 +1,12 @@ +package scratch.kevin.sampling; + +import java.io.File; + +public class PaperPaths { + + public static final File PAPER_DIR = new File("/home/kevin/Documents/papers/2026_epistemic_sampling/papers-2026-sampled-uncertainties"); + public static final File FIGURES_DIR = new File(PAPER_DIR, "Figures"); + + public static final File INVS_DIR = new File("/home/kevin/OpenSHA/fss_inversions"); + +} diff --git a/src/main/java/scratch/kevin/sampling/SamplingScoreFigures.java b/src/main/java/scratch/kevin/sampling/SamplingScoreFigures.java new file mode 100644 index 00000000..8b6572f0 --- /dev/null +++ b/src/main/java/scratch/kevin/sampling/SamplingScoreFigures.java @@ -0,0 +1,757 @@ +package scratch.kevin.sampling; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.io.IOException; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.IntToDoubleFunction; + +import org.apache.commons.math3.stat.StatUtils; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.DatasetRenderingOrder; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.data.Range; +import org.opensha.commons.data.CSVFile; +import org.opensha.commons.data.function.DefaultXY_DataSet; +import org.opensha.commons.data.function.EvenlyDiscretizedFunc; +import org.opensha.commons.data.function.XY_DataSet; +import org.opensha.commons.data.sampling.CategoricalSamplingDimension; +import org.opensha.commons.data.sampling.ContinuousSamplingDimension; +import org.opensha.commons.data.sampling.PointSet; +import org.opensha.commons.data.sampling.SamplingDimension; +import org.opensha.commons.data.sampling.scoring.CenteredDiscrepancy; +import org.opensha.commons.data.sampling.scoring.ProjectionDiscrepancyScore; +import org.opensha.commons.data.sampling.scoring.ProjectionDiscrepancyScorer; +import org.opensha.commons.data.sampling.scoring.ProjectionDiscrepancyScore.ProjectionResult; +import org.opensha.commons.data.uncertainty.UncertainArbDiscFunc; +import org.opensha.commons.data.xyz.EvenlyDiscrXYZ_DataSet; +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.PlotPreferences; +import org.opensha.commons.gui.plot.PlotSpec; +import org.opensha.commons.gui.plot.PlotSymbol; +import org.opensha.commons.gui.plot.PlotUtils; +import org.opensha.commons.gui.plot.jfreechart.xyzPlot.XYZPlotSpec; +import org.opensha.commons.logicTree.LogicTreeLevel; +import org.opensha.commons.logicTree.LogicTreeNode; +import org.opensha.commons.logicTree.sampling.LogicTreePointSetMapper; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; +import org.opensha.commons.util.RandomSeedUtils; +import org.opensha.commons.util.cpt.CPT; +import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.NSHM23_LogicTreeBranch; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_LogicTree; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.logicTree.NSHM27_ModelRegimeNode; +import org.opensha.sha.earthquake.rupForecastImpl.nshm27.util.NSHM27_RegionLoader.NSHM27_SeismicityRegions; +import org.opensha.sha.util.TectonicRegionType; + +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; + +import net.mahdilamb.colormap.Colors; + +public class SamplingScoreFigures { + + static List getDimsNSHM23() { + List> levels = new ArrayList<>(NSHM23_LogicTreeBranch.levelsCombined); + // remove the first fault model (fixed) level + levels.remove(0); + LogicTreePointSetMapper mapper = new LogicTreePointSetMapper<>(levels); + List dims = mapper.getSamplingDimensions(); + System.out.println("NSHM23 levels:"); + for (int l=0; l getDimsNSHM27_AmSam() { + List> levels = new ArrayList<>(); + levels.addAll(NSHM27_LogicTree.buildLevels(NSHM27_SeismicityRegions.AMSAM, TectonicRegionType.SUBDUCTION_INTERFACE, true, true, true, true)); + levels.addAll(NSHM27_LogicTree.buildLevels(NSHM27_SeismicityRegions.AMSAM, TectonicRegionType.SUBDUCTION_SLAB, true, true, true, false)); + levels.addAll(NSHM27_LogicTree.buildLevels(NSHM27_SeismicityRegions.AMSAM, TectonicRegionType.ACTIVE_SHALLOW, true, true, true, false)); + // remove the model/regime (fixed) level + for (int l=levels.size(); --l>=0;) + if (levels.get(l) instanceof NSHM27_ModelRegimeNode.Level) + levels.remove(l); + LogicTreePointSetMapper mapper = new LogicTreePointSetMapper<>(levels); + List dims = mapper.getSamplingDimensions(); + System.out.println("NSHM27 levels:"); + for (int l=0; l combPlotChars = Map.of( + SamplingMethod.MONTE_CARLO, + new PlotCurveCharacterstics(PlotLineType.DOTTED, 1f, Colors.tab_red), + SamplingMethod.LATIN_HYPERCUBE, + new PlotCurveCharacterstics(PlotLineType.DASHED, 1f, Colors.tab_green), + SamplingMethod.PAIRWISE_OPTIMIZED_LATIN_HYPERCUBE, + new PlotCurveCharacterstics(PlotLineType.SHORT_DASHED, 1f, Colors.tab_orange), + SamplingMethod.CENTERED_DISCREPANCY_OPTIMIZED_LATIN_HYPERCUBE, + new PlotCurveCharacterstics(PlotLineType.DOTTED_AND_DASHED, 1f, Colors.tab_purple), + SamplingMethod.OWEN_SCRAMBLED_SOBOL, + new PlotCurveCharacterstics(PlotLineType.SOLID, 1f, Colors.tab_blue)); +// int numPlotTrials = 10; + int numPlotTrials = 0; +// int numAvgTrials = 10; +// int numAvgTrials = 50; +// int numAvgTrials = 100; + int numAvgTrials = 200; +// int numAvgTrials = 500; + + System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "16"); + + boolean redoNormScores = false; + boolean redoCenteredDiscrepancies = false; + boolean replotIndvSamples = false; + + String treeName = null; + int numD = 10; +// int numD = 5; + List samplingDimensions = new ArrayList<>(); + for (int i=0; i samplingDimensions = getDimsNSHM23(); +// String samplingPrefix = "nshm23_"+samplingDimensions.size()+"d"; + +// String treeName = "NSHM27-AmSam"; +// List samplingDimensions = getDimsNSHM27_AmSam(); +// String samplingPrefix = "nshm27_amsam_"+samplingDimensions.size()+"d"; + + final int dimensions = samplingDimensions.size(); + int numContinuous = 0; + int numCategorical = 0; + for (SamplingDimension dim : samplingDimensions) { + if (dim instanceof CategoricalSamplingDimension) + numCategorical++; + else if (dim instanceof ContinuousSamplingDimension) + numContinuous++; + } + + if (treeName == null) + treeName = ""; + else + treeName += ": "; + if (dimensions == numContinuous) + treeName += dimensions+"D, all continuous"; + else if (dimensions == numCategorical) + treeName += dimensions+"D, all categorical"; + else + treeName += numContinuous+" continuous, "+numCategorical+" categorical"; + + System.out.println(treeName); + System.out.println(); + + File outputDir = new File(mainDir, samplingPrefix); + Preconditions.checkState(outputDir.exists() || outputDir.mkdir()); + + File scoresCSVFile = new File(outputDir, "combined_scores.csv"); + File centeredDiscrepancyCSVFile = new File(outputDir, "combined_centered_discrepancies.csv"); + + redoNormScores |= !scoresCSVFile.exists(); + redoCenteredDiscrepancies |= !centeredDiscrepancyCSVFile.exists(); + + ProjectionDiscrepancyScorer serialScorer = ProjectionDiscrepancyScorer.exact(1); +// ProjectionDiscrepancyScorer serialScorer = ProjectionDiscrepancyScorer.exact(4); + ProjectionDiscrepancyScorer parallelScorer = ProjectionDiscrepancyScorer.exact(16); + + Color[] orderColors = new Color[scoreOrders]; + Color[] oderLightColors = new Color[scoreOrders]; + CPT catCPT = GMT_CPT_Files.CATEGORICAL_TAB10_NOGRAY.instance(); + CPT catLightCPT = GMT_CPT_Files.CATEGORICAL_TAB10_LIGHT_NOGRAY.instance(); + for (int d=0; d1d+(scoreOrders-order)/2d; + + // this results in the following, and lower orders don't change as more are added: + // 1D: 3.375 + // 2D: 2.25 + // 3D: 1.5 + // 4D: 1.0 + // 5D: 0.6666667 + // 6D: 0.44444445 + IntToDoubleFunction orderThicknessFunc = (order)->Math.pow(1.5, 4-order); +// for (int order=1; order<=scoreOrders; order++) +// System.out.println(order+"D:\t"+(float)orderThicknessFunc.applyAsDouble(order)); +// System.exit(0); + + Range dimXRange = new Range(1d, dimensions); + Range logYRange = new Range(1e-4, 2e0); + Range equivYRange = new Range(1e2, sampleCounts[sampleCounts.length-1] > 3000 ? 1e8 : 1e7); + Range centeredYRange = new Range(1e-6, 1e-1); + + List>> methodScores = new ArrayList<>(); + List>> methodCenteredDiscrepancyScores = new ArrayList<>(); + for (int m=0; m()); + methodCenteredDiscrepancyScores.add(new ArrayList<>()); + } + + + if (!redoNormScores && !redoCenteredDiscrepancies) { + System.out.println("Replotting combined results only"); + } else { + Stopwatch totalWatch = Stopwatch.createStarted(); + for (int sampleCount : sampleCounts) { + Stopwatch sampleWatch = Stopwatch.createStarted(); + System.out.println("Doing "+sampleCount+" samples"); + File subDir = new File(outputDir, sampleCount+"_samples"); + Preconditions.checkState(subDir.exists() || subDir.mkdir()); + PointSet[] firstPointSets = new PointSet[methods.length]; + for (int m=0; m> sampleFutures = new LinkedList<>(); + + for (int i=0; imethod.prepare(sampleCount, samplingDimensions, seed))); + } + + List samples = new ArrayList<>(myTrials); + + while (!sampleFutures.isEmpty()) + samples.add(sampleFutures.removeFirst().join()); + + if (redoNormScores) { + // if we only have 1 trial, do that one in parallel + // if we have many, rely on across-trial parallelism instead + ProjectionDiscrepancyScorer scorer = myTrials == 1 ? parallelScorer : serialScorer; + + List> scoreFutures = new ArrayList<>(); + for (PointSet sample : samples) { + if (firstPointSets[m] == null) + firstPointSets[m] = sample; + scoreFutures.add(CompletableFuture.supplyAsync(()->scorer.score(sample, scoreOrders))); + } + + List scores = scoreFutures.stream().map(F->F.join()).toList(); + + methodScores.get(m).add(scores); + + if (method == SamplingMethod.OWEN_SCRAMBLED_SOBOL) { + // rebuild it to remove the row scrambling + firstPointSets[m] = method.createGenerator(baseRand.nextLong()).generate(sampleCount, dimensions); + } + + List funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + + double[][][] scores2D = new double[dimensions][dimensions][myTrials]; + for (int i=0; i shadedFuncs = new ArrayList<>(); + List shadedChars = new ArrayList<>(); + + for (int order=1; order<=scoreOrders; order++) { + double overallAverage = 0d; + double[][] dimScores = new double[dimensions][scores.size()]; + double[] dimAverages = new double[dimensions]; + + for (int s=0; s= 1); + dimScores[d][s] /= dimCounts[d]; + dimAverages[d] += dimScores[d][s]; + } + if (s < numPlotTrials) { + // plot it + EvenlyDiscretizedFunc dimFunc = new EvenlyDiscretizedFunc(1d, dimensions, 1d); + for (int d=0; d 1) { + EvenlyDiscretizedFunc upperDimFunc = new EvenlyDiscretizedFunc(1d, dimensions, 1d); + EvenlyDiscretizedFunc middleDimFunc = new EvenlyDiscretizedFunc(1d, dimensions, 1d); + EvenlyDiscretizedFunc lowerDimFunc = new EvenlyDiscretizedFunc(1d, dimensions, 1d); + for (int d=0; d 20 ? 2d : 1d; + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + + gp.drawGraphPanel(plot, false, true, dimXRange, logYRange); + PlotUtils.setXTick(gp, xTick); + + if (replotIndvSamples || !new File(subDir, "scores_"+prefix+".png").exists()) + PlotUtils.writePrintPlots(subDir, "scores_"+prefix, gp, + PlotUtils.DEFAULT_USABLE_PAGE_WIDTH/2d, 3d, 300, true, true, false); + + EvenlyDiscrXYZ_DataSet avgXYZ = new EvenlyDiscrXYZ_DataSet(dimensions, dimensions, 1d, 1d, 1d); + EvenlyDiscrXYZ_DataSet avgAbsXYZ = new EvenlyDiscrXYZ_DataSet(dimensions, dimensions, 1d, 1d, 1d); + CPT logRatioCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-1d, 1d); + logRatioCPT.setLog10(true); + CPT logAbsCPT = GMT_CPT_Files.DIVERGING_VIK_UNIFORM.instance().rescale(-1d, 1d).trim(0d, 1d); +// CPT logAbsCPT = logRatioCPT.trim(0d, 1d); + logAbsCPT.setLog10(true); + for (int i=0; i> scoreFutures = new ArrayList<>(); + for (PointSet sample : samples) { + scoreFutures.add(CompletableFuture.supplyAsync(()->{ + double score = CenteredDiscrepancy.score(sample); +// System.out.println("Score: "+(float)score); + return score; + })); + } + + List scores = scoreFutures.stream().map(F->F.join()).toList(); + + methodCenteredDiscrepancyScores.get(m).add(scores); + } + + methodWatch.stop(); + System.out.println("\tDONE in "+timeStr(methodWatch)); + } + + if (sampleCount <= 1024 && redoNormScores) { + // now plot 2D scatters + int[][] plotDims = { + {0, 1}, + {2, 3}, + {4, 5} + }; + for (int p=0; p= dimensions || dim2 >= dimensions) + continue; + + List plots = new ArrayList<>(); + Range range = new Range(0d, 1d); + List xRanges = new ArrayList<>(); + List yRanges = List.of(range); + List subtitles = new ArrayList<>(); + for (int m=0; m funcs = new ArrayList<>(); + List chars = new ArrayList<>(); + PointSet sample = firstPointSets[m]; + DefaultXY_DataSet xy = new DefaultXY_DataSet(); + for (int i=0; i 0) + prefix += "_"+dim1+"_"+dim2; + + if (replotIndvSamples || !new File(subDir, prefix+".png").exists()) + PlotUtils.writePrintPlots(subDir, prefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH, false, 300, true, true, false); + } + } + sampleWatch.stop(); + System.out.println("DONE with "+sampleCount+" in "+timeStr(sampleWatch)+"\n"); + } + + totalWatch.stop(); + System.out.println("DONE with all calculations in "+timeStr(totalWatch)); + } + + // now combined plots + String prefix = "combined_scores"; + + List scoreFuncs = new ArrayList<>(); + List scoreChars = new ArrayList<>(); + List equivCountFuncs = new ArrayList<>(); + List equivCountChars = new ArrayList<>(); + List centeredFuncs = new ArrayList<>(); + List centeredChars = new ArrayList<>(); + CSVFile scoresCSV = redoNormScores ? new CSVFile<>(true) : CSVFile.readFile(scoresCSVFile, true); + CSVFile centeredScoresCSV = redoCenteredDiscrepancies ? new CSVFile<>(true) : CSVFile.readFile(centeredDiscrepancyCSVFile, true); + if (redoNormScores) { + List header = new ArrayList<>(); + header.add(""); + for (int order=1; order<=scoreOrders; order++) + for (int s=0; s header = new ArrayList<>(); + header.add(""); + for (int s=0; s scoreLine = new ArrayList<>(); + scoreLine.add(method.getShortName()); + List centeredLine = new ArrayList<>(); + centeredLine.add(method.getShortName()); + + int colIndex = 1; + + for (int order=1; order<=scoreOrders; order++) { + EvenlyDiscretizedFunc scoreFunc = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); +// EvenlyDiscretizedFunc scoreLowerFunc = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); +// EvenlyDiscretizedFunc scoreUpperFunc = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); + EvenlyDiscretizedFunc equivFunc = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); + + for (int s=0; s scores = methodScores.get(m).get(s); + double sum = 0d; +// double min = Double.POSITIVE_INFINITY; +// double max = 0d; + for (ProjectionDiscrepancyScore score : scores) { + double orderScore = score.getOrderMeanScore(order); + sum += orderScore; +// min = Math.min(min, orderScore); +// max = Math.max(max, orderScore); + } + avg = sum / scores.size(); + } else { + avg = scoresCSV.getDouble(rowIndex, colIndex++); + } + scoreLine.add((float)avg+""); + + scoreFunc.set(s, avg); +// scoreLowerFunc.set(s, min); +// scoreUpperFunc.set(s, max); + double equivCount = (double)sampleCount / avg; + equivFunc.set(s, equivCount); + } + + if (order == 1) { + scoreFunc.setName(method.getShortName()); + equivFunc.setName(method.getShortName()); + } else if (method == SamplingMethod.MONTE_CARLO) { + // they all overlap, cleaner to just show 1D + continue; + } + + double thickness = orderThicknessFunc.applyAsDouble(order); + scoreFuncs.add(scoreFunc); + scoreChars.add(getForThickness(methodChar, thickness)); + +// UncertainArbDiscFunc rangeFunc = new UncertainArbDiscFunc(scoreFunc, scoreLowerFunc, scoreUpperFunc); +// rangeFunc.setName(null); +// scoreFuncs.add(0, rangeFunc); +// scoreChars.add(0, new PlotCurveCharacterstics(PlotLineType.SHADED_UNCERTAIN, 1f, methodTransColor)); + + equivCountFuncs.add(equivFunc); + equivCountChars.add(getForThickness(methodChar, thickness)); + } + + EvenlyDiscretizedFunc centeredFunc = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); + centeredFunc.setName(method.getShortName()); + for (int s=0; sd).average().getAsDouble(); + centeredLine.add((float)centered+""); + } else { + centered = centeredScoresCSV.getDouble(rowIndex, s+1); + } + centeredFunc.set(s, centered); + } + centeredFuncs.add(centeredFunc); + centeredChars.add(getForThickness(methodChar, 3f)); + + rowIndex++; + if (redoNormScores) + scoresCSV.addLine(scoreLine); + if (redoCenteredDiscrepancies) + centeredScoresCSV.addLine(centeredLine); + } + List orderTicknessFuncs = new ArrayList<>(); + List orderThicknessChars = new ArrayList<>(); + for (int order=1; order<=scoreOrders; order++) { + double thickness = orderThicknessFunc.applyAsDouble(order); + + XY_DataSet fakeXY = new DefaultXY_DataSet(-100d, 1d); + fakeXY.setName(order+"D"); + PlotCurveCharacterstics orderChar = new PlotCurveCharacterstics(PlotLineType.SOLID, (float)thickness, Color.GRAY); + orderTicknessFuncs.add(fakeXY); + orderThicknessChars.add(orderChar); + } + PlotSpec orderPlot = new PlotSpec(orderTicknessFuncs, orderThicknessChars, null, null, null); + + HeadlessGraphPanel gp = PlotUtils.initPrintHeadless(); + PlotPreferences prefs = gp.getPlotPrefs(); + prefs.setPlotLabelFontSize(10); + prefs.setLegendFontSize(7); + prefs.setLegendLineLength(6d); + prefs.getPlotPadding(); + prefs.setPlotPadding(new RectangleInsets(4, 0, 0, 12)); + + gp.drawGraphPanel(orderPlot, false, false); + LegendItemCollection orderLegendItems = gp.getPlot().getLegendItems(); + +// EvenlyDiscretizedFunc equivLinear = new EvenlyDiscretizedFunc(0d, sampleCounts.length, 1d); +// for (int s=0; s= 0 && index < sampleCounts.length + && Math.abs(value - index) < 1e-6) + buffer.append(sampleCounts[index]); + return buffer; + } + + @Override + public StringBuffer format(long value, StringBuffer buffer, FieldPosition pos) { + return format((double)value, buffer, pos); + } + + @Override + public Number parse(String source, ParsePosition pos) { + pos.setErrorIndex(pos.getIndex()); + return null; + } + }; + + PlotSpec plot = new PlotSpec(scoreFuncs, scoreChars, treeName, "Sample count", "Normalized projection score"); +// plot.setLegendInset(true); + plot.setLegendVisible(true); + + orderPlot.setLegendInset(RectangleAnchor.BOTTOM_LEFT); + plot.addPlotAnnotation(orderPlot.buildInsetLegend(orderLegendItems, prefs, false, true, categoricalXRange, logYRange)); + + gp.setRenderingOrder(DatasetRenderingOrder.REVERSE); + + gp.drawGraphPanel(plot, false, true, categoricalXRange, logYRange); + PlotUtils.setXTick(gp, 1); + ((NumberAxis)gp.getXAxis()).setNumberFormatOverride(categoryFormat); + + PlotUtils.writePrintPlots(outputDir, prefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH/2d, 4, 300, true, true, false); + if (redoNormScores) + scoresCSV.writeToFile(scoresCSVFile); + + plot = new PlotSpec(equivCountFuncs, equivCountChars, treeName, "Sample count", "Equivalent MCS count"); +// plot.setLegendInset(true); + plot.setLegendVisible(true); + + orderPlot.setLegendInset(RectangleAnchor.TOP_LEFT); + plot.addPlotAnnotation(orderPlot.buildInsetLegend(orderLegendItems, prefs, false, true, categoricalXRange, equivYRange)); + + gp.drawGraphPanel(plot, false, true, categoricalXRange, equivYRange); + PlotUtils.setXTick(gp, 1); + ((NumberAxis)gp.getXAxis()).setNumberFormatOverride(categoryFormat); + + prefix = "combined_equivs"; + PlotUtils.writePrintPlots(outputDir, prefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH/2d, 4, 300, true, true, false); + + // now centered + plot = new PlotSpec(centeredFuncs, centeredChars, treeName, "Sample count", "Squared centered discrepancy"); +// plot.setLegendInset(true); + plot.setLegendVisible(true); + + gp.drawGraphPanel(plot, false, true, categoricalXRange, centeredYRange); + PlotUtils.setXTick(gp, 1); + ((NumberAxis)gp.getXAxis()).setNumberFormatOverride(categoryFormat); + + prefix = "combined_centered_discrepancies"; + PlotUtils.writePrintPlots(outputDir, prefix, gp, PlotUtils.DEFAULT_USABLE_PAGE_WIDTH/2d, 4, 300, true, true, false); + + if (redoCenteredDiscrepancies) + centeredScoresCSV.writeToFile(centeredDiscrepancyCSVFile); + } + + private static PlotCurveCharacterstics getForThickness(PlotCurveCharacterstics pChar, double thickness) { + PlotCurveCharacterstics copy = (PlotCurveCharacterstics)pChar.clone(); + copy.setLineWidth((float)thickness); + return copy; + } + + private static final DecimalFormat timeDF = new DecimalFormat("0.0"); + private static String timeStr(Stopwatch watch) { + double secs = watch.elapsed(TimeUnit.MILLISECONDS)/1000d; + if (secs < 90d) + return timeDF.format(secs)+" s"; + double mins = secs/60d; + if (mins < 90d) + return timeDF.format(mins)+" m"; + double hours = mins / 60d; + return timeDF.format(hours)+" h"; + } + +} diff --git a/src/main/java/scratch/kevin/simulators/erf/HazardMapPBSGen.java b/src/main/java/scratch/kevin/simulators/erf/HazardMapPBSGen.java index 6fe5b425..f162beb4 100644 --- a/src/main/java/scratch/kevin/simulators/erf/HazardMapPBSGen.java +++ b/src/main/java/scratch/kevin/simulators/erf/HazardMapPBSGen.java @@ -20,7 +20,6 @@ import org.opensha.commons.hpc.JavaShellScriptWriter; import org.opensha.commons.hpc.mpj.FastMPJShellScriptWriter; import org.opensha.commons.hpc.pbs.BatchScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; import org.opensha.commons.util.XMLUtils; import org.opensha.sha.calc.hazardMap.components.AsciiFileCurveArchiver; import org.opensha.sha.calc.hazardMap.components.CalculationInputsXMLFile; @@ -58,8 +57,10 @@ public class HazardMapPBSGen { * @throws IOException */ public static void main(String[] args) throws IOException { - RunSites runSite = RunSites.HPCC; - BatchScriptWriter writer = new USC_HPCC_ScriptWriter(); +// RunSites runSite = RunSites.HPCC; +// BatchScriptWriter writer = new USC_HPCC_ScriptWriter(); + RunSites runSite = null; + BatchScriptWriter writer = null; int nodes = 30; int mins = 60 * 5; int heapMB = 9000; @@ -152,7 +153,7 @@ public static void main(String[] args) throws IOException { List script = mpj.buildScript(MPJHazardCurveDriver.class.getName(), cliArgs); - script = writer.buildScript(script, mins, nodes, 0, null); + script = writer.buildScript(script, mins, nodes, 0, -1, null); File pbsFile = new File(localRunDir, pbsName+".pbs"); JavaShellScriptWriter.writeScript(pbsFile, script); diff --git a/src/main/java/scratch/kevin/simulators/erf/TimeDepFSS_ERF_Simulator_ScriptGen.java b/src/main/java/scratch/kevin/simulators/erf/TimeDepFSS_ERF_Simulator_ScriptGen.java index 4bb87005..5c3e2ff8 100644 --- a/src/main/java/scratch/kevin/simulators/erf/TimeDepFSS_ERF_Simulator_ScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/erf/TimeDepFSS_ERF_Simulator_ScriptGen.java @@ -55,7 +55,7 @@ public static void main(String[] args) throws IOException { String scriptArgs = remoteOutputDir.getAbsolutePath()+" "+prefix+" "+trialsPerJob+" "+cov.name()+" "+duration; List script = writer.buildScript(TimeDepFSS_ERF_Simulator_Test.class.getName(), scriptArgs); - pbsWrite.writeScript(pbsFile, script, mins, 1, 8, null); + pbsWrite.writeScript(pbsFile, script, mins, 1, 8, -1, null); } } diff --git a/src/main/java/scratch/kevin/simulators/hazard/HazardMapCompareScriptGen.java b/src/main/java/scratch/kevin/simulators/hazard/HazardMapCompareScriptGen.java index 8f8fd9df..42f94c0b 100644 --- a/src/main/java/scratch/kevin/simulators/hazard/HazardMapCompareScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/hazard/HazardMapCompareScriptGen.java @@ -20,7 +20,7 @@ import org.opensha.commons.hpc.mpj.FastMPJShellScriptWriter.Device; import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; import org.opensha.commons.hpc.pbs.StampedeScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; +import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; import org.opensha.commons.param.Parameter; import org.opensha.commons.util.XMLUtils; import org.opensha.sha.calc.hazardMap.components.BinaryCurveArchiver; @@ -172,12 +172,12 @@ public static void main(String[] args) throws IOException, DocumentException { int nodes = 18; int ppn = 20; String queue = "scec_hiprio"; - File javaBin = USC_HPCC_ScriptWriter.JAVA_BIN; + File javaBin = USC_CARC_ScriptWriter.JAVA_BIN; File remoteMainDir = new File("/home/scec-02/kmilner/simulators/hazard"); JavaShellScriptWriter mpj = new MPJExpressShellScriptWriter(javaBin, 55*1024, null, - USC_HPCC_ScriptWriter.MPJ_HOME); + USC_CARC_ScriptWriter.MPJ_HOME); ((MPJExpressShellScriptWriter)mpj).setUseLaunchWrapper(true); - USC_HPCC_ScriptWriter writer = new USC_HPCC_ScriptWriter(); + USC_CARC_ScriptWriter writer = new USC_CARC_ScriptWriter(); // int mins = 24*60; // int nodes = 10; @@ -375,7 +375,7 @@ public static void main(String[] args) throws IOException, DocumentException { List script = mpj.buildScript(MPJHazardCurveDriver.class.getName(), cliArgs); - script = writer.buildScript(script, mins, nodes, ppn, queue); + script = writer.buildScript(script, mins, nodes, ppn, -1, queue); String jobName = localJobDir.getName(); if (!rsqsim) @@ -435,7 +435,7 @@ public static void main(String[] args) throws IOException, DocumentException { List script = mpj.buildScript(MPJHazardCurveDriver.class.getName(), cliArgs); - script = writer.buildScript(script, mins, nodes, ppn, queue); + script = writer.buildScript(script, mins, nodes, ppn, -1, queue); String jobName = localJobDir.getName()+"_"+getIMTLabel(imt, period); File pbsFile = new File(localJobDir, jobName+".pbs"); diff --git a/src/main/java/scratch/kevin/simulators/momRateVariation/UCERF3ComparisonScriptGen.java b/src/main/java/scratch/kevin/simulators/momRateVariation/UCERF3ComparisonScriptGen.java index 2822ead1..17c5eb33 100644 --- a/src/main/java/scratch/kevin/simulators/momRateVariation/UCERF3ComparisonScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/momRateVariation/UCERF3ComparisonScriptGen.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws IOException { List script = javaWrite.buildScript(UCERF3ComparisonCalc.class.getName(), argsStr); File outputFile = new File(localOutputDir, dirName+".pbs"); - pbsWrite.writeScript(outputFile, script, mins, 1, threadsPerBatch, queue); + pbsWrite.writeScript(outputFile, script, mins, 1, threadsPerBatch, -1, queue); } } diff --git a/src/main/java/scratch/kevin/simulators/plots/SlipLengthScalingPlot.java b/src/main/java/scratch/kevin/simulators/plots/SlipLengthScalingPlot.java index 101d8927..06752711 100644 --- a/src/main/java/scratch/kevin/simulators/plots/SlipLengthScalingPlot.java +++ b/src/main/java/scratch/kevin/simulators/plots/SlipLengthScalingPlot.java @@ -21,6 +21,7 @@ import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.data.Range; import org.jfree.chart.ui.TextAnchor; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DefaultXY_DataSet; import org.opensha.commons.data.function.DiscretizedFunc; @@ -503,12 +504,12 @@ private void plotExample() throws IOException { if (midSeis) { // make it a little transparent - fillColor = new Color(fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(), 160); + fillColor = ColorUtils.transparent(fillColor, 160); } else { // make it very transparent - fillColor = new Color(fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(), 80); + fillColor = ColorUtils.transparent(fillColor, 80); if (!slipped) - paint = new Color(paint.getRed(), paint.getGreen(), paint.getBlue(), 127); + paint = ColorUtils.transparent(paint, 127); } double[] polyElems = new double[verts.length*2]; diff --git a/src/main/java/scratch/kevin/simulators/plots/StationarityPlot.java b/src/main/java/scratch/kevin/simulators/plots/StationarityPlot.java index 0d85676c..ef130cc4 100644 --- a/src/main/java/scratch/kevin/simulators/plots/StationarityPlot.java +++ b/src/main/java/scratch/kevin/simulators/plots/StationarityPlot.java @@ -9,6 +9,7 @@ import org.jfree.chart.ui.RectangleEdge; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.function.ArbitrarilyDiscretizedFunc; import org.opensha.commons.data.function.DefaultXY_DataSet; import org.opensha.commons.data.function.EvenlyDiscretizedFunc; @@ -198,7 +199,7 @@ public void finalizePlot() throws IOException { straightLine.set(maxX, meanForMag); funcs.add(straightLine); chars.add(new PlotCurveCharacterstics(PlotLineType.DASHED, 2f, - new Color(c.getRed(), c.getGreen(), c.getBlue(), 100))); + ColorUtils.transparent(c, 100))); } String title = getCatalogName()+" Stationarity"; diff --git a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_CatalogSimScriptGen.java b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_CatalogSimScriptGen.java index 285b8671..ea34af4d 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_CatalogSimScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_CatalogSimScriptGen.java @@ -320,7 +320,7 @@ public static void main(String[] args) throws IOException { if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, "cat_bbp_parallel.slurm"), script); } diff --git a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_PartBSimScriptGen.java b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_PartBSimScriptGen.java index 23776d56..1122aedf 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_PartBSimScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_PartBSimScriptGen.java @@ -135,7 +135,7 @@ public static void main(String[] args) throws IOException { if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, "cat_bbp_partb.slurm"), script); } diff --git a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_RuptureScriptsGen.java b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_RuptureScriptsGen.java index 8f1dc4a7..60f1a499 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_RuptureScriptsGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/MPJ_BBP_RuptureScriptsGen.java @@ -14,7 +14,6 @@ import org.opensha.commons.hpc.pbs.BatchScriptWriter; import org.opensha.commons.hpc.pbs.StampedeScriptWriter; import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; import org.opensha.sha.simulators.RSQSimEvent; import org.opensha.sha.simulators.srf.RSQSimEventSlipTimeFunc; import org.opensha.sha.simulators.srf.RSQSimSRFGenerator; @@ -160,6 +159,7 @@ public static void main(String[] args) throws IOException { BatchScriptWriter pbsWrite; JavaShellScriptWriter mpjWrite; + int nodeMemBG; if (stampede) { threads = 96; queue = "skx-normal"; @@ -173,6 +173,7 @@ public static void main(String[] args) throws IOException { sharedScratchDir = null; pbsWrite = new StampedeScriptWriter(true); mpjWrite = new FastMPJShellScriptWriter(StampedeScriptWriter.JAVA_BIN, heapSizeMB, null, StampedeScriptWriter.FMPJ_HOME); + nodeMemBG = heapSizeMB / 1024 + 4; ((FastMPJShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); } else { // threads = 20; @@ -208,6 +209,7 @@ public static void main(String[] args) throws IOException { mpjWrite = new FastMPJShellScriptWriter( USC_CARC_ScriptWriter.JAVA_BIN, heapSizeMB, null, USC_CARC_ScriptWriter.FMPJ_HOME); ((FastMPJShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); + nodeMemBG = -1; } String dateStr = new SimpleDateFormat("yyyy_MM_dd").format(new Date()); @@ -312,7 +314,7 @@ else if (cs500Sites) if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, gpMins, nodes, threads, queue); + script = pbsWrite.buildScript(script, gpMins, nodes, threads, nodeMemBG, queue); pbsWrite.writeScript(new File(localJobDir, "gp_bbp_parallel.slurm"), script); } if (doShakeMap) { @@ -364,7 +366,7 @@ else if (cs500Sites) if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mapMins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mapMins, nodes, threads, nodeMemBG, queue); pbsWrite.writeScript(new File(localJobDir, "map_bbp_parallel.slurm"), script); } if (doGPShakeMaps) { @@ -431,7 +433,7 @@ else if (cs500Sites) if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mapMins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mapMins, nodes, threads, nodeMemBG, queue); pbsWrite.writeScript(new File(localJobDir, "map_bbp_parallel.slurm"), script); } } diff --git a/src/main/java/scratch/kevin/simulators/ruptures/azimuthal/AzimuthalScriptsGen.java b/src/main/java/scratch/kevin/simulators/ruptures/azimuthal/AzimuthalScriptsGen.java index 282f4935..980251a7 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/azimuthal/AzimuthalScriptsGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/azimuthal/AzimuthalScriptsGen.java @@ -13,7 +13,7 @@ import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; import org.opensha.commons.hpc.pbs.BatchScriptWriter; import org.opensha.commons.hpc.pbs.StampedeScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; +import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; import com.google.common.base.Preconditions; @@ -74,19 +74,19 @@ public static void main(String[] args) throws IOException { String queue = "scec"; int mins = 48*60; int heapSizeMB = 45*1024; - String bbpDataDir = USC_HPCC_ScriptWriter.NODE_TEMP_DIR; + String bbpDataDir = USC_CARC_ScriptWriter.NODE_TEMP_DIR; String nodeScratchDir = null; - String bbpCopyParentDir = USC_HPCC_ScriptWriter.SHARED_SCRATCH_DIR+"/kmilner"; - String nodeGFDir = USC_HPCC_ScriptWriter.NODE_TEMP_DIR+"/gfs"; + String bbpCopyParentDir = USC_CARC_ScriptWriter.SHARED_SCRATCH_DIR+"/kmilner"; + String nodeGFDir = USC_CARC_ScriptWriter.NODE_TEMP_DIR+"/gfs"; File bbpEnvFile = new File("/auto/scec-02/kmilner/bbp/bbp_env.sh"); // String sharedScratchDir = "${SCRATCHDIR}"; String sharedScratchDir = null; File remoteDir = new File("/auto/scec-02/kmilner/bbp/parallel"); - BatchScriptWriter pbsWrite = new USC_HPCC_ScriptWriter(); + BatchScriptWriter pbsWrite = new USC_CARC_ScriptWriter(); List classpath = new ArrayList<>(); classpath.add(new File(remoteDir, "opensha-dev-all.jar")); JavaShellScriptWriter mpjWrite = new MPJExpressShellScriptWriter( - USC_HPCC_ScriptWriter.JAVA_BIN, heapSizeMB, classpath, USC_HPCC_ScriptWriter.MPJ_HOME); + USC_CARC_ScriptWriter.JAVA_BIN, heapSizeMB, classpath, USC_CARC_ScriptWriter.MPJ_HOME); ((MPJExpressShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); // int threads = 48; @@ -189,7 +189,7 @@ public static void main(String[] args) throws IOException { if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); String scriptName = gp ? "gp_bbp_azimuthal.slurm" : "cat_bbp_azimuthal.slurm"; pbsWrite.writeScript(new File(localJobDir, scriptName), script); } diff --git a/src/main/java/scratch/kevin/simulators/ruptures/multifaultSeparate/MultifaultSeparatePageGen.java b/src/main/java/scratch/kevin/simulators/ruptures/multifaultSeparate/MultifaultSeparatePageGen.java index a86d93fa..a740e227 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/multifaultSeparate/MultifaultSeparatePageGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/multifaultSeparate/MultifaultSeparatePageGen.java @@ -16,6 +16,7 @@ import java.util.concurrent.Future; import org.jfree.data.Range; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.data.CSVFile; import org.opensha.commons.data.Site; import org.opensha.commons.data.function.DefaultXY_DataSet; @@ -516,7 +517,7 @@ private static void writeScatter(File outputDir, String prefix, double period, D String title = Double.isFinite(period) ? oDF.format(period)+"s SA" : "All Periods"; - color = new Color(color.getRed(), color.getGreen(), color.getBlue(), 80); + color = ColorUtils.transparent(color, 80); for (boolean log : new boolean[] {false, true}) { Range range; diff --git a/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityMagDistSimScriptGen.java b/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityMagDistSimScriptGen.java index d1d8c153..52b002a2 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityMagDistSimScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityMagDistSimScriptGen.java @@ -188,7 +188,7 @@ private static void writeScript(String catalogDirName, int skipYears, RuptureTyp if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, scriptFileName), script); } diff --git a/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityScenarioSimScriptGen.java b/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityScenarioSimScriptGen.java index e8e83b69..0ffeb346 100644 --- a/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityScenarioSimScriptGen.java +++ b/src/main/java/scratch/kevin/simulators/ruptures/rotation/MPJ_BBP_RotatedRupVariabilityScenarioSimScriptGen.java @@ -218,7 +218,7 @@ public static void main(String[] args) throws IOException { if (!addLines.isEmpty()) script.addAll(2, addLines); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); String scriptName = gp ? "gp_bbp_rotated.slurm" : "cat_bbp_rotated.slurm"; pbsWrite.writeScript(new File(localJobDir, scriptName), script); } diff --git a/src/main/java/scratch/kevin/simulators/synch/RecurrencePlotGen.java b/src/main/java/scratch/kevin/simulators/synch/RecurrencePlotGen.java index 62b7f9c7..3bf5b240 100644 --- a/src/main/java/scratch/kevin/simulators/synch/RecurrencePlotGen.java +++ b/src/main/java/scratch/kevin/simulators/synch/RecurrencePlotGen.java @@ -39,6 +39,7 @@ import org.opensha.commons.gui.plot.jfreechart.xyzPlot.XYZPlotSpec; import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; import org.opensha.commons.util.ComparablePairing; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.DataUtils.MinMaxAveTracker; import org.opensha.commons.util.FileUtils; import org.opensha.commons.util.cpt.CPT; @@ -306,8 +307,8 @@ private static CPT getHybridCPT(double threshold, double maxZ) throws IOExceptio // saturate for (CPTVal v : cpt) { - v.minColor = saturate(v.minColor); - v.maxColor = saturate(v.maxColor); + v.minColor = ColorUtils.saturate(v.minColor, 2); + v.maxColor = ColorUtils.saturate(v.maxColor, 2); } cpt.setAboveMaxColor(cpt.getMaxColor()); @@ -323,22 +324,6 @@ private static CPT getHybridCPT(double threshold, double maxZ) throws IOExceptio return cpt; } - private static Color saturate(Color c) { - int r = c.getRed(); - int g = c.getGreen(); - int b = c.getBlue(); - - int saturationSteps = 2; - - for (int i=0; i script = writer.buildScript(javaWrite.buildScript(className, argz), mins, nodes, ppn, queue); - writer.writeScript(outputFile, script, mins, nodes, ppn, queue); + List script = writer.buildScript(javaWrite.buildScript(className, argz), mins, nodes, ppn, -1, queue); + writer.writeScript(outputFile, script, mins, nodes, ppn, -1, queue); } } } diff --git a/src/main/java/scratch/kevin/ucerf3/BulkCompoundScriptWrite.java b/src/main/java/scratch/kevin/ucerf3/BulkCompoundScriptWrite.java index 67db5655..9693c436 100644 --- a/src/main/java/scratch/kevin/ucerf3/BulkCompoundScriptWrite.java +++ b/src/main/java/scratch/kevin/ucerf3/BulkCompoundScriptWrite.java @@ -8,7 +8,6 @@ import org.opensha.commons.hpc.mpj.FastMPJShellScriptWriter; import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; import org.opensha.commons.hpc.pbs.BatchScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; import com.google.common.collect.Lists; @@ -78,8 +77,8 @@ public static void main(String[] args) throws IOException { if (!writeDir.exists()) writeDir.mkdir(); - RunSites site = RunSites.HPCC; -// RunSites site = RunSites.STAMPEDE; +// RunSites site = RunSites.HPCC; + RunSites site = RunSites.STAMPEDE; int nodes = 30; // int bundleSize = 30; // TODO, must be >0 // int jobMins = 6*60; // TODO @@ -97,8 +96,8 @@ public static void main(String[] args) throws IOException { mpjWrite.setHeadless(true); BatchScriptWriter batchWrite = site.forBranch(null); - if (batchWrite instanceof USC_HPCC_ScriptWriter) - ((USC_HPCC_ScriptWriter)batchWrite).setNodesAddition(null); +// if (batchWrite instanceof USC_HPCC_ScriptWriter) +// ((USC_HPCC_ScriptWriter)batchWrite).setNodesAddition(null); for (U3LogicTreeBranchNode fm : fmBranches) { for (U3LogicTreeBranchNode dm : dmBranches) { @@ -124,7 +123,7 @@ public static void main(String[] args) throws IOException { String scriptName = remoteJobDir.getName()+".pbs"; - batchWrite.writeScript(new File(writeDir, scriptName), script, jobMins, nodes, site.getPPN(null), null); + batchWrite.writeScript(new File(writeDir, scriptName), script, jobMins, nodes, -1, site.getPPN(null), null); } } } diff --git a/src/main/java/scratch/kevin/ucerf3/GriddedSeisImportanceHazardMapCalc.java b/src/main/java/scratch/kevin/ucerf3/GriddedSeisImportanceHazardMapCalc.java index 18f05ef6..aefb1936 100644 --- a/src/main/java/scratch/kevin/ucerf3/GriddedSeisImportanceHazardMapCalc.java +++ b/src/main/java/scratch/kevin/ucerf3/GriddedSeisImportanceHazardMapCalc.java @@ -15,7 +15,7 @@ import org.opensha.commons.geo.Region; import org.opensha.commons.hpc.JavaShellScriptWriter; import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; +import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; import org.opensha.commons.util.XMLUtils; import org.opensha.sha.calc.hazardMap.components.BinaryCurveArchiver; import org.opensha.sha.calc.hazardMap.components.CalculationInputsXMLFile; @@ -157,14 +157,14 @@ public static void main(String[] args) throws IOException, DocumentException { xValsMap.put("curves", xValues); CalculationSettings calcSettings = new CalculationSettings(xValues, maxSourceDistance); - File javaBin = USC_HPCC_ScriptWriter.JAVA_BIN; + File javaBin = USC_CARC_ScriptWriter.JAVA_BIN; File jarFile = new File(remoteBaseDir, "opensha-dev-all.jar"); List classpath = Lists.newArrayList(); classpath.add(jarFile); MPJExpressShellScriptWriter mpj = new MPJExpressShellScriptWriter(javaBin, 60000, classpath, - USC_HPCC_ScriptWriter.MPJ_HOME); + USC_CARC_ScriptWriter.MPJ_HOME); mpj.setUseLaunchWrapper(true); List> imrMaps = Lists.newArrayList(); @@ -224,9 +224,9 @@ public static void main(String[] args) throws IOException, DocumentException { String cliArgs = "--max-dispatch 1000 "+remoteInputsFile.getAbsolutePath(); List script = mpj.buildScript(MPJHazardCurveDriver.class.getName(), cliArgs); - USC_HPCC_ScriptWriter writer = new USC_HPCC_ScriptWriter(); + USC_CARC_ScriptWriter writer = new USC_CARC_ScriptWriter(); - script = writer.buildScript(script, mins, nodes, ppn, queue); + script = writer.buildScript(script, mins, nodes, ppn, -1, queue); File pbsFile = new File(localSubDir, subDirName+".slurm"); JavaShellScriptWriter.writeScript(pbsFile, script); diff --git a/src/main/java/scratch/kevin/ucerf3/MPJ_UCERF3_ShakeMapPrecalcScriptGen.java b/src/main/java/scratch/kevin/ucerf3/MPJ_UCERF3_ShakeMapPrecalcScriptGen.java index b7288542..b78ad219 100644 --- a/src/main/java/scratch/kevin/ucerf3/MPJ_UCERF3_ShakeMapPrecalcScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/MPJ_UCERF3_ShakeMapPrecalcScriptGen.java @@ -156,7 +156,7 @@ public static void main(String[] args) throws IOException { List script = mpjWrite.buildScript(MPJ_UCERF3_ShakeMapPrecalc.class.getName(), argz); int mins = hours*60; - script = pbsWrite.buildScript(script, mins, nodes, ppn, queue); + script = pbsWrite.buildScript(script, mins, nodes, ppn, -1, queue); pbsWrite.writeScript(new File(localDir, jobName+".pbs"), script); } diff --git a/src/main/java/scratch/kevin/ucerf3/PureScratch.java b/src/main/java/scratch/kevin/ucerf3/PureScratch.java index a1a4917f..622e43b3 100644 --- a/src/main/java/scratch/kevin/ucerf3/PureScratch.java +++ b/src/main/java/scratch/kevin/ucerf3/PureScratch.java @@ -83,9 +83,9 @@ import org.opensha.commons.logicTree.LogicTree; import org.opensha.commons.logicTree.LogicTreeBranch; import org.opensha.commons.logicTree.LogicTreeLevel; -import org.opensha.commons.logicTree.LogicTreeLevel.RandomlySampledLevel; +import org.opensha.commons.logicTree.LogicTreeLevel.RandomlyGeneratedLevel; import org.opensha.commons.logicTree.LogicTreeNode; -import org.opensha.commons.logicTree.LogicTreeNode.RandomlySampledNode; +import org.opensha.commons.logicTree.LogicTreeNode.RandomlyGeneratedNode; import org.opensha.commons.mapping.PoliticalBoundariesData; import org.opensha.commons.mapping.gmt.elements.GMT_CPT_Files; import org.opensha.commons.param.Parameter; @@ -154,6 +154,8 @@ import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysHazardCalcSettings; import org.opensha.sha.earthquake.faultSysSolution.util.FaultSysTools; import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc.ReturnPeriods; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateModel; +import org.opensha.sha.earthquake.nshmp.seismicity.SeismicityRateFileLoader.RateType; import org.opensha.sha.earthquake.faultSysSolution.util.SubSectionBuilder; import org.opensha.sha.earthquake.observedEarthquake.ObsEqkRupList; import org.opensha.sha.earthquake.param.ApplyGardnerKnopoffAftershockFilterParam; @@ -179,8 +181,6 @@ import org.opensha.sha.earthquake.rupForecastImpl.nshm23.logicTree.random.BranchSamplingManager; import org.opensha.sha.earthquake.rupForecastImpl.nshm23.util.NSHM23_RegionLoader; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.PRVI25_GridSourceBuilder; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateFileLoader.RateType; -import org.opensha.sha.earthquake.rupForecastImpl.prvi25.gridded.SeismicityRateModel; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalDeformationModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalFaultModels; import org.opensha.sha.earthquake.rupForecastImpl.prvi25.logicTree.PRVI25_CrustalGMMs; @@ -712,10 +712,10 @@ private static void test263() throws IOException { System.out.println("\t\tAffected: "+level.getAffected()); System.out.println("\t\tNot affected: "+level.getNotAffected()); } - if (level instanceof RandomlySampledLevel) { + if (level instanceof RandomlyGeneratedLevel) { System.out.println("\tIt's a random level: "+level.getName()); - RandomlySampledLevel randLevel = (RandomlySampledLevel)level; - List nodes = randLevel.getNodes(); + RandomlyGeneratedLevel randLevel = (RandomlyGeneratedLevel)level; + List nodes = randLevel.getNodes(); System.out.println("\t\tNode count: "+nodes.size()); System.out.println("\t\tNode 0:\tseed="+nodes.get(0).getSeed()+"; weight="+nodes.get(0).getNodeWeight(null)); int lastIndex = nodes.size()-1; @@ -729,16 +729,16 @@ private static void test263() throws IOException { LogicTreeBranch branch = tree.getBranch(index); System.out.println("Branch "+index+": "+branch); for (LogicTreeNode val : branch) { - if (val instanceof RandomlySampledNode) { - RandomlySampledNode randNode = (RandomlySampledNode)val; + if (val instanceof RandomlyGeneratedNode) { + RandomlyGeneratedNode randNode = (RandomlyGeneratedNode)val; System.out.println("\t"+val.getName()+":\t"+randNode.getSeed()+"; weight="+(float)randNode.getNodeWeight(null)); } } } - RandomDefModSampleLevel level = new RandomDefModSampleLevel(); - level.buildNodes(new Random(), 10); + RandomDefModSampleLevel level = new RandomDefModSampleLevel("Name", "Short name"); +// level.build(new Random().nextLong(), 10); System.out.println("Test level: "+level.getName()); System.out.println("\tAffected: "+level.getAffected()); System.out.println("\tNot affected: "+level.getNotAffected()); @@ -2854,7 +2854,7 @@ private static void test325() throws IOException { File inFile = new File(dir, "logic_tree_full_gridded.json"); File outFile = new File(dir, "logic_tree_full_gridded_sampled_100k.json"); LogicTree tree = LogicTree.read(inFile); - tree = tree.sample(100000, true, new Random(tree.size()*100000l)); + tree = tree.sample(100000, true, tree.size()*100000l); tree.write(outFile); } diff --git a/src/main/java/scratch/kevin/ucerf3/eal/MPJ_UCERF3_EAL_CombinerScriptGen.java b/src/main/java/scratch/kevin/ucerf3/eal/MPJ_UCERF3_EAL_CombinerScriptGen.java index d9a9a34e..b6227a1b 100644 --- a/src/main/java/scratch/kevin/ucerf3/eal/MPJ_UCERF3_EAL_CombinerScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/eal/MPJ_UCERF3_EAL_CombinerScriptGen.java @@ -134,7 +134,7 @@ public static void main(String[] args) throws IOException { argz += " "+remoteJobDir.getAbsolutePath(); List script = mpjWrite.buildScript(MPJ_UCERF3_EAL_Combiner.class.getName(), argz); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, "eal_consolidate.slurm"), script); } diff --git a/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_ScriptGen.java b/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_ScriptGen.java index 2797a5ff..984fdcd2 100644 --- a/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_ScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_ScriptGen.java @@ -190,7 +190,7 @@ public static void main(String[] args) throws IOException { +remoteXML.getAbsolutePath()+" "+remoteOutput.getAbsolutePath(); File jobFile = new File(writeDir, name+".slurm"); - pbsWrite.writeScript(jobFile, javaWrite.buildScript(className, jobArgs), mins, nodes, ppn, queue); + pbsWrite.writeScript(jobFile, javaWrite.buildScript(className, jobArgs), mins, nodes, ppn, -1, queue); } } diff --git a/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_Validate_ScriptGen.java b/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_Validate_ScriptGen.java index e2f54800..ef75a674 100644 --- a/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_Validate_ScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/eal/UCERF3_EAL_Validate_ScriptGen.java @@ -136,7 +136,7 @@ public static void main(String[] args) throws IOException { +remoteXML.getAbsolutePath()+" "+remoteOutput.getAbsolutePath(); File jobFile = new File(writeDir, name+".pbs"); - pbsWrite.writeScript(jobFile, javaWrite.buildScript(className, jobArgs), mins, nodes, ppn, queue); + pbsWrite.writeScript(jobFile, javaWrite.buildScript(className, jobArgs), mins, nodes, ppn, -1, queue); } } } diff --git a/src/main/java/scratch/kevin/ucerf3/eal/spatialCorr/MPJ_SpatiallyCorrelatedLossCalcScriptGen.java b/src/main/java/scratch/kevin/ucerf3/eal/spatialCorr/MPJ_SpatiallyCorrelatedLossCalcScriptGen.java index 29e7fb99..622e329a 100644 --- a/src/main/java/scratch/kevin/ucerf3/eal/spatialCorr/MPJ_SpatiallyCorrelatedLossCalcScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/eal/spatialCorr/MPJ_SpatiallyCorrelatedLossCalcScriptGen.java @@ -89,7 +89,7 @@ public static void main(String[] args) throws IOException { argz += " "+remoteJobDir.getAbsolutePath(); List script = mpjWrite.buildScript(MPJ_SpatiallyCorrelatedLossCalc.class.getName(), argz); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(new File(localJobDir, "spatial_calc.slurm"), script); } diff --git a/src/main/java/scratch/kevin/ucerf3/etas/CacheSpeedScriptGen.java b/src/main/java/scratch/kevin/ucerf3/etas/CacheSpeedScriptGen.java deleted file mode 100644 index 2e3356f6..00000000 --- a/src/main/java/scratch/kevin/ucerf3/etas/CacheSpeedScriptGen.java +++ /dev/null @@ -1,40 +0,0 @@ -package scratch.kevin.ucerf3.etas; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -import org.opensha.commons.hpc.JavaShellScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; - -import com.google.common.collect.Lists; - -public class CacheSpeedScriptGen { - - public static void main(String[] args) throws IOException { - File localDir = new File("/home/kevin/OpenSHA/UCERF3/etas/cache_tests/soft_10Gjvm"); - File remoteDir = new File("/auto/scec-02/kmilner/ucerf3/etas_sim/cache_test/soft_10Gjvm"); - - double[] sizes = { 0d, 0.5d, 1d, 2d, 4d, 8d, 16d }; - int numRuns = 5; - - List classpath = Lists.newArrayList(); - classpath.add(new File(remoteDir, "OpenSHA_complete.jar")); - classpath.add(new File(remoteDir.getParentFile().getParentFile(), "commons-cli-1.2.jar")); - - JavaShellScriptWriter javaWrite = new JavaShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, 10*1024, classpath); - USC_HPCC_ScriptWriter pbsWrite = new USC_HPCC_ScriptWriter("dodecacore"); - - for (double size : sizes) { - for (int run=0; run script = javaWrite.buildScript(CacheSpeedTester.class.getName(), - remoteDir.getAbsolutePath()+" "+(float)size+" "+run); - script.add(script.size()-2, "cd "+remoteDir.getParentFile().getAbsolutePath()); - pbsWrite.writeScript(new File(localDir, jobName), script, 90, 1, 24, null); - } - } - } - -} diff --git a/src/main/java/scratch/kevin/ucerf3/etas/ETAS_CatalogEALCalculator.java b/src/main/java/scratch/kevin/ucerf3/etas/ETAS_CatalogEALCalculator.java index 75de3ba4..622fc7c1 100644 --- a/src/main/java/scratch/kevin/ucerf3/etas/ETAS_CatalogEALCalculator.java +++ b/src/main/java/scratch/kevin/ucerf3/etas/ETAS_CatalogEALCalculator.java @@ -39,6 +39,7 @@ import org.opensha.commons.gui.plot.PlotElement; import org.opensha.commons.gui.plot.PlotLineType; import org.opensha.commons.gui.plot.PlotSpec; +import org.opensha.commons.util.ColorUtils; import org.opensha.commons.util.DataUtils; import org.opensha.commons.util.DataUtils.MinMaxAveTracker; import org.opensha.commons.util.cpt.CPT; @@ -1175,7 +1176,7 @@ public static void writeLossExceed(File outputDir, String outputPrefix, List myElems = Lists.newArrayList(); List myChars = Lists.newArrayList(); - Color rangeColor = new Color((c.getRed()+255)/2, (c.getGreen()+255)/2, (c.getBlue()+255)/2); + Color rangeColor = ColorUtils.saturate(c, 1); if (hasConf) { // UncertainArbDiscDataset confRange = null; // try { diff --git a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_HazardMapCalcScriptGen.java b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_HazardMapCalcScriptGen.java index 6f441f0b..334c1ea9 100644 --- a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_HazardMapCalcScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_HazardMapCalcScriptGen.java @@ -16,7 +16,7 @@ import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; import org.opensha.commons.hpc.pbs.BatchScriptWriter; import org.opensha.commons.hpc.pbs.StampedeScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; +import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; import org.opensha.sha.imr.AttenRelRef; import org.opensha.sha.imr.AttenuationRelationship; @@ -193,14 +193,14 @@ public static void main(String[] args) throws IOException { boolean fmpj = nodes < 25; fmpj = false; if (fmpj) { - mpjWrite = new FastMPJShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, memGigs*1024, - null, USC_HPCC_ScriptWriter.FMPJ_HOME); + mpjWrite = new FastMPJShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, memGigs*1024, + null, USC_CARC_ScriptWriter.FMPJ_HOME); ((FastMPJShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); } else { - mpjWrite = new MPJExpressShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, memGigs*1024, - null, USC_HPCC_ScriptWriter.MPJ_HOME); + mpjWrite = new MPJExpressShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, memGigs*1024, + null, USC_CARC_ScriptWriter.MPJ_HOME); } - pbsWrite = new USC_HPCC_ScriptWriter(); + pbsWrite = new USC_CARC_ScriptWriter(); remoteMainDir = new File("/home/scec-02/kmilner/ucerf3/etas_hazard"); @@ -275,7 +275,7 @@ public static void main(String[] args) throws IOException { List script = mpjWrite.buildScript(MPJ_ETAS_HazardMapCalc.class.getName(), argz); int mins = hours*60; - script = pbsWrite.buildScript(script, mins, nodes, ppn, queue); + script = pbsWrite.buildScript(script, mins, nodes, ppn, -1, queue); String scriptName; if (stampede) { if (knl) diff --git a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorInternScriptGen.java b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorInternScriptGen.java index 51d59c9c..28b5a113 100644 --- a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorInternScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorInternScriptGen.java @@ -111,7 +111,7 @@ public static void main(String[] args) throws IOException { List script = mpjWrite.buildScript(MPJ_ETAS_Simulator.class.getName(), argz); - script = pbsWrite.buildScript(script, mins, nodes, ppn, queue); + script = pbsWrite.buildScript(script, mins, nodes, ppn, -1, queue); pbsWrite.writeScript(pbsFile, script); } } diff --git a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorScriptGen.java b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorScriptGen.java index 3b6e5c44..49666cdb 100644 --- a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_ETAS_SimulatorScriptGen.java @@ -15,7 +15,7 @@ import org.opensha.commons.hpc.mpj.MPJExpressShellScriptWriter; import org.opensha.commons.hpc.pbs.BatchScriptWriter; import org.opensha.commons.hpc.pbs.StampedeScriptWriter; -import org.opensha.commons.hpc.pbs.USC_HPCC_ScriptWriter; +import org.opensha.commons.hpc.pbs.USC_CARC_ScriptWriter; import scratch.UCERF3.erf.ETAS.ETAS_Simulator.TestScenario; import scratch.UCERF3.erf.ETAS.ETAS_CatalogIO; @@ -281,15 +281,15 @@ public static void main(String[] args) throws IOException { boolean fmpj = nodes < 25; fmpj = false; if (fmpj) { - mpjWrite = new FastMPJShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, memGigs*1024, - null, USC_HPCC_ScriptWriter.FMPJ_HOME); + mpjWrite = new FastMPJShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, memGigs*1024, + null, USC_CARC_ScriptWriter.FMPJ_HOME); ((FastMPJShellScriptWriter)mpjWrite).setUseLaunchWrapper(true); } else { - mpjWrite = new MPJExpressShellScriptWriter(USC_HPCC_ScriptWriter.JAVA_BIN, memGigs*1024, - null, USC_HPCC_ScriptWriter.MPJ_HOME); + mpjWrite = new MPJExpressShellScriptWriter(USC_CARC_ScriptWriter.JAVA_BIN, memGigs*1024, + null, USC_CARC_ScriptWriter.MPJ_HOME); } - pbsWrite = new USC_HPCC_ScriptWriter(); - ((USC_HPCC_ScriptWriter)pbsWrite).setSkipRootNode(hpcSkipRoot); + pbsWrite = new USC_CARC_ScriptWriter(); + ((USC_CARC_ScriptWriter)pbsWrite).setSkipRootNode(hpcSkipRoot); cacheDir = new File(remoteDir, "cache_fm3p1_ba"); } @@ -517,7 +517,7 @@ public static void main(String[] args) throws IOException { } } - script = pbsWrite.buildScript(script, mins, nodes, ppn, queue); + script = pbsWrite.buildScript(script, mins, nodes, ppn, -1, queue); pbsWrite.writeScript(pbsFile, script); if (writeConsolidate && !bundleConsolidate && stampede) { @@ -530,8 +530,8 @@ public static void main(String[] args) throws IOException { script.add(""); script.addAll(consolidationLines); - pbsWrite.writeScript(new File(localJobDir, "consolidate_dev.pbs"), script, 60, 1, 16, "development"); - pbsWrite.writeScript(new File(localJobDir, "consolidate_norm.pbs"), script, 60, 1, 16, "normal"); + pbsWrite.writeScript(new File(localJobDir, "consolidate_dev.pbs"), script, 60, 1, 16, -1, "development"); + pbsWrite.writeScript(new File(localJobDir, "consolidate_norm.pbs"), script, 60, 1, 16, -1, "normal"); } } } diff --git a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_GK_DesclusteringHazardCalcScriptGen.java b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_GK_DesclusteringHazardCalcScriptGen.java index 719661bb..6fe3e376 100644 --- a/src/main/java/scratch/kevin/ucerf3/etas/MPJ_GK_DesclusteringHazardCalcScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/etas/MPJ_GK_DesclusteringHazardCalcScriptGen.java @@ -56,7 +56,7 @@ public static void main(String[] args) throws IOException { List script = mpjWrite.buildScript(MPJ_GK_DesclusteringHazardCalc.class.getName(), argz); - script = pbsWrite.buildScript(script, mins, nodes, threads, queue); + script = pbsWrite.buildScript(script, mins, nodes, threads, -1, queue); pbsWrite.writeScript(pbsFile, script); } diff --git a/src/main/java/scratch/kevin/ucerf3/inversion/InversionEALInputGen.java b/src/main/java/scratch/kevin/ucerf3/inversion/InversionEALInputGen.java index 96f0799e..d78e2d6e 100644 --- a/src/main/java/scratch/kevin/ucerf3/inversion/InversionEALInputGen.java +++ b/src/main/java/scratch/kevin/ucerf3/inversion/InversionEALInputGen.java @@ -66,7 +66,7 @@ private static void writeRTGMJob(MPJExpressShellScriptWriter writer, File portfo List script = writer.buildScript(MPJ_AssetRTGM_Calc.class.getName(), args); USC_HPCC_ScriptWriter usc = new USC_HPCC_ScriptWriter(); - script = usc.buildScript(script, mins, nodes, 8, queue); + script = usc.buildScript(script, mins, nodes, 8, -1, queue); usc.writeScript(jobFile, script); } diff --git a/src/main/java/scratch/kevin/ucerf3/maps/MapScriptWriter.java b/src/main/java/scratch/kevin/ucerf3/maps/MapScriptWriter.java index e1f2290d..39268712 100644 --- a/src/main/java/scratch/kevin/ucerf3/maps/MapScriptWriter.java +++ b/src/main/java/scratch/kevin/ucerf3/maps/MapScriptWriter.java @@ -129,7 +129,7 @@ public static void main(String[] args) throws ZipException, IOException { scriptName = "maps_"+scriptName+".pbs"; - batchWrite.writeScript(new File(writeDir, scriptName), script, jobMins, nodes, site.getPPN(null), null); + batchWrite.writeScript(new File(writeDir, scriptName), script, jobMins, nodes, site.getPPN(null), -1, null); jobCount += branches.size(); batchCount++; diff --git a/src/main/java/scratch/kevin/ucerf3/maps/MultiSolComparisonMapScriptGen.java b/src/main/java/scratch/kevin/ucerf3/maps/MultiSolComparisonMapScriptGen.java index 3c601f9f..36646794 100644 --- a/src/main/java/scratch/kevin/ucerf3/maps/MultiSolComparisonMapScriptGen.java +++ b/src/main/java/scratch/kevin/ucerf3/maps/MultiSolComparisonMapScriptGen.java @@ -23,7 +23,8 @@ public class MultiSolComparisonMapScriptGen { public static void main(String[] args) throws IOException { File localMainDir = new File("/home/kevin/OpenSHA/UCERF3/biasi_downsample_tests"); - RunSites site = RunSites.HPCC; +// RunSites site = RunSites.HPCC; + RunSites site = null; File remoteMainDir = new File("/home/scec-02/kmilner/ucerf3/maps"); String runName = "biasi-downsample-pga"; @@ -84,7 +85,7 @@ public static void main(String[] args) throws IOException { List script = mpjWrite.buildScript(className, classArgs); - batchWrite.writeScript(pbsFile, script, jobMins, nodes, site.getPPN(null), null); + batchWrite.writeScript(pbsFile, script, jobMins, nodes, site.getPPN(null), -1, null); } } diff --git a/src/test/java/scratch/kevin/sampling/HazardConvergenceCalcsTest.java b/src/test/java/scratch/kevin/sampling/HazardConvergenceCalcsTest.java new file mode 100644 index 00000000..403f474d --- /dev/null +++ b/src/test/java/scratch/kevin/sampling/HazardConvergenceCalcsTest.java @@ -0,0 +1,103 @@ +package scratch.kevin.sampling; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.junit.Test; +import org.opensha.commons.geo.GriddedRegion; +import org.opensha.commons.geo.Location; +import org.opensha.commons.logicTree.sampling.SamplingMethod; +import org.opensha.sha.earthquake.faultSysSolution.util.SolHazardMapCalc.ReturnPeriods; + +import scratch.kevin.sampling.HazardConvergenceCalcs.*; + +public class HazardConvergenceCalcsTest { + @Test public void spanReferencesRetainRemaindersAndOtherRuns() { + GriddedRegion grid = new GriddedRegion(new Location(0, 0), new Location(0.1, 0.1), + 1d, new Location(0, 0)); + assertEquals(1, grid.getNodeCount()); + RunPeriodData first = run("first", 0, 7); + RunPeriodData second = run("second", 7, 5); + ReferenceStatistics sobol = new ReferenceStatistics(HazardConvergenceCalcs.POOLED_SOBOL_REFERENCE_NAME, + null, 7, HazardConvergenceCalcs.calcHazardStatistics(first.branchMaps(), 7, new double[] { 1 })); + List rows = new ArrayList<>(); + List spans = HazardConvergenceCalcs.appendMCSSpanComparisons(rows, List.of(first, second), new int[] {2, 4}, + sobol, grid, ReturnPeriods.TWO_IN_50); + assertEquals(9, spans.size()); + // C(6,2) at size 2 plus C(3,2) at size 4, each with five metrics. + assertEquals(90, HazardConvergenceCalcs.buildRealizationPairComparisons(spans, grid).size()); + // Six two-sample spans and three four-sample spans, each with two references and five metrics. + assertEquals(90, rows.size()); + for (ReferenceComparison row : rows) { + assertEquals(0, row.startIndex() % row.sampleCount()); + assertTrue(row.startIndex()+row.sampleCount() <= row.run().maxSamples()); + if (!row.referenceName().equals(HazardConvergenceCalcs.LOO_MCS_REFERENCE_NAME)) + continue; + assertEquals(12-row.sampleCount(), row.referenceSampleCount()); + int from = row.startIndex(); + int to = from+row.sampleCount(); + if (row.metric() == ConvergenceMetric.STANDARD_DEVIATION) { + double[] included = java.util.stream.IntStream.range(0, 12) + .filter(i -> i < from || i >= to).mapToDouble(i -> i+1).toArray(); + double mean = Arrays.stream(included).average().orElseThrow(); + double variance = Arrays.stream(included).map(v -> (v-mean)*(v-mean)).average().orElseThrow(); + double spanVariance = (row.sampleCount()*row.sampleCount()-1d)/12d; + assertEquals(100d*(Math.sqrt(spanVariance/variance)-1), row.comparison().meanPercentChange(), 1e-10); + } + if (row.metric() == ConvergenceMetric.MEAN_HAZARD) { + double spanScale = 0, remainingScale = 0; + for (int i=0; i<12; i++) { + if (i >= from && i < to) spanScale += i+1; + else remainingScale += i+1; + } + double test = HazardConvergenceCalcs.buildCurveMeanMap(curves(spanScale), first.curveX(), + row.sampleCount(), ReturnPeriods.TWO_IN_50)[0]; + double ref = HazardConvergenceCalcs.buildCurveMeanMap(curves(remainingScale), first.curveX(), + row.referenceSampleCount(), ReturnPeriods.TWO_IN_50)[0]; + assertEquals(100d*(test/ref-1), row.comparison().meanPercentChange(), 1e-10); + } + } + } + + private static RunPeriodData run(String name, int offset, int size) { + double[][] maps = new double[size][1]; + Map boundaries = new TreeMap<>(); + double sum = 0; + for (int i=0; i rows = new ArrayList<>(); + for (ConvergenceMetric metric : ConvergenceMetric.values()) { + for (int count : new int[] {512, 1024}) + rows.add(new ReferenceSummary(SamplingMethod.OWEN_SCRAMBLED_SOBOL, count, + HazardConvergenceCalcs.MCS_REFERENCE_NAME, metric, ConvergenceSummary.MEAN_ABSOLUTE, + 2, 0.2, 0.05, 0.1, 0.2, 0.3, 0.25, new double[] {0.15, 0.25})); + rows.add(new ReferenceSummary(SamplingMethod.MONTE_CARLO, 512, + HazardConvergenceCalcs.LOO_MCS_REFERENCE_NAME, metric, ConvergenceSummary.MEAN_ABSOLUTE, + 4, 0.3, 0.05, 0.2, 0.3, 0.4, 0.2, new double[] {0.2, 0.25, 0.35, 0.4})); + rows.add(new ReferenceSummary(SamplingMethod.LATIN_HYPERCUBE, 512, + HazardConvergenceCalcs.MCS_REFERENCE_NAME, metric, ConvergenceSummary.MEAN_ABSOLUTE, + 4, 0.2, 0.05, 0.1, 0.2, 0.3, 0.25, new double[] {0.1, 0.15, 0.25, 0.3})); + } + for (ReferenceSummary row : new ArrayList<>(rows)) + rows.add(new ReferenceSummary(row.method(), row.sampleCount(), row.reference(), row.metric(), + ConvergenceSummary.MAXIMUM_ABSOLUTE, row.realizations(), 1d, 0.25, 0.5, 1d, 5d, 0.2, + row.individualValues())); + for (ReferenceSummary row : new ArrayList<>(rows)) + if (row.spatialSummary() == ConvergenceSummary.MEAN_ABSOLUTE) + rows.add(new ReferenceSummary(row.method(), row.sampleCount(), row.reference(), row.metric(), + ConvergenceSummary.MEAN_SIGNED, row.realizations(), -0.1, 0.05, -0.2, -0.1, 0d, + Double.NaN, new double[] {-0.15, -0.05})); + HazardConvergencePlots.plotMethodReference(output.getRoot(), rows, false, + ConvergenceSummary.MEAN_ABSOLUTE, "Spatial mean absolute difference (%)"); + HazardConvergencePlots.plotMethodReference(output.getRoot(), rows, false, + ConvergenceSummary.MEAN_SIGNED, "Signed bias (%)"); + for (int count : new int[] {512, 1024}) { + assertTrue(new java.io.File(output.getRoot(), + "method_comparison_"+count+"_pooled_mcs_mean_abs.png").isFile()); + assertTrue(new java.io.File(output.getRoot(), + "method_comparison_"+count+"_pooled_mcs_signed_bias.png").isFile()); + } + } + + @Test public void combinesFullPoolAndLeaveOneOutRealizations() { + ReferenceSummary fullPool = new ReferenceSummary(SamplingMethod.OWEN_SCRAMBLED_SOBOL, 4096, + HazardConvergenceCalcs.POOLED_SOBOL_REFERENCE_NAME, ConvergenceMetric.MEAN_HAZARD, + ConvergenceSummary.MEAN_ABSOLUTE, 4, 2.5, 0d, 1d, 2.5, 4d, 0d, + new double[] {1d, 2d, 3d, 4d}); + ReferenceSummary leaveOneOut = new ReferenceSummary(SamplingMethod.OWEN_SCRAMBLED_SOBOL, 4096, + HazardConvergenceCalcs.LOO_SOBOL_REFERENCE_NAME, ConvergenceMetric.MEAN_HAZARD, + ConvergenceSummary.MEAN_ABSOLUTE, 5, 7d, 0d, 5d, 7d, 9d, 0d, + new double[] {5d, 6d, 7d, 8d, 9d}); + + SummaryRow combined = HazardConvergencePlots.combineRows(List.of(fullPool, leaveOneOut)); + assertArrayEquals(new double[] {1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d}, + combined.individualValues(), 0d); + assertEquals(5d, combined.mean(), 0d); + assertEquals(5d, combined.median(), 0d); + assertEquals(1d, combined.minimum(), 0d); + assertEquals(9d, combined.maximum(), 0d); + } +}