66import static gov .usgs .earthquake .nshmp .internal .Parsing .readEnum ;
77import static gov .usgs .earthquake .nshmp .internal .Parsing .readInt ;
88import static gov .usgs .earthquake .nshmp .internal .Parsing .readString ;
9+ import static gov .usgs .earthquake .nshmp .internal .Parsing .toMap ;
910import static gov .usgs .earthquake .nshmp .internal .SourceAttribute .DEPTH ;
1011import static gov .usgs .earthquake .nshmp .internal .SourceAttribute .DIP ;
1112import static gov .usgs .earthquake .nshmp .internal .SourceAttribute .ID ;
2122import java .io .InputStream ;
2223import java .util .ArrayList ;
2324import java .util .List ;
25+ import java .util .Map ;
2426import java .util .logging .Logger ;
2527
2628import javax .xml .parsers .SAXParser ;
3133import org .xml .sax .SAXParseException ;
3234import org .xml .sax .helpers .DefaultHandler ;
3335
36+ import com .google .common .collect .Lists ;
37+
38+ import gov .usgs .earthquake .nshmp .eq .Earthquakes ;
3439import gov .usgs .earthquake .nshmp .eq .fault .surface .RuptureScaling ;
3540import gov .usgs .earthquake .nshmp .eq .model .MfdHelper .GR_Data ;
3641import gov .usgs .earthquake .nshmp .eq .model .MfdHelper .SingleData ;
@@ -65,6 +70,11 @@ class InterfaceParser extends DefaultHandler {
6570
6671 private RuptureScaling rupScaling ;
6772
73+ // Data applying to all sourceSet
74+ private MagUncertainty unc = null ;
75+ private Map <String , String > epiAtts = null ;
76+ private Map <String , String > aleaAtts = null ;
77+
6878 // Default MFD data
6979 private boolean parsingDefaultMFDs = false ;
7080 private MfdHelper .Builder mfdHelperBuilder ;
@@ -83,10 +93,10 @@ static InterfaceParser create(SAXParser sax) {
8393 }
8494
8595 InterfaceSourceSet parse (
86- InputStream in ,
87- GmmSet gmmSet ,
96+ InputStream in ,
97+ GmmSet gmmSet ,
8898 ModelConfig config ) throws SAXException , IOException {
89-
99+
90100 checkState (!used , "This parser has expired" );
91101 this .gmmSet = gmmSet ;
92102 this .config = config ;
@@ -98,9 +108,9 @@ InterfaceSourceSet parse(
98108
99109 @ Override
100110 public void startElement (
101- String uri ,
102- String localName ,
103- String qName ,
111+ String uri ,
112+ String localName ,
113+ String qName ,
104114 Attributes atts ) throws SAXException {
105115
106116 SourceElement e = null ;
@@ -137,6 +147,14 @@ public void startElement(
137147 parsingDefaultMFDs = true ;
138148 break ;
139149
150+ case EPISTEMIC :
151+ epiAtts = toMap (atts );
152+ break ;
153+
154+ case ALEATORY :
155+ aleaAtts = toMap (atts );
156+ break ;
157+
140158 case SOURCE_PROPERTIES :
141159 rupScaling = readEnum (RUPTURE_SCALING , atts , RuptureScaling .class );
142160 log .fine ("Rup scaling: " + rupScaling );
@@ -201,8 +219,8 @@ public void startElement(
201219
202220 @ Override
203221 public void endElement (
204- String uri ,
205- String localName ,
222+ String uri ,
223+ String localName ,
206224 String qName ) throws SAXException {
207225
208226 SourceElement e = null ;
@@ -220,6 +238,15 @@ public void endElement(
220238 mfdHelper = mfdHelperBuilder .build ();
221239 break ;
222240
241+ case SETTINGS :
242+ // may not have mag uncertainty element so create the
243+ // uncertainty container upon leaving 'Settings'
244+ unc = MagUncertainty .create (epiAtts , aleaAtts );
245+ if (log .isLoggable (FINE )) {
246+ log .fine (unc .toString ());
247+ }
248+ break ;
249+
223250 case TRACE :
224251 readingTrace = false ;
225252 sourceBuilder .trace (LocationList .fromString (traceBuilder .toString ()));
@@ -282,24 +309,53 @@ private List<IncrementalMfd> buildMfds(Attributes atts) {
282309 private List <IncrementalMfd > buildGR (Attributes atts ) {
283310 List <IncrementalMfd > mfdList = new ArrayList <>();
284311 for (GR_Data grData : mfdHelper .grData (atts )) {
285- mfdList .add (buildGR (grData ));
312+ mfdList .addAll (buildGR (grData ));
286313 }
287314 return mfdList ;
288315 }
289316
290- private IncrementalMfd buildGR (GR_Data data ) {
317+ private List < IncrementalMfd > buildGR (GR_Data data ) {
291318
292319 int nMag = Mfds .magCount (data .mMin , data .mMax , data .dMag );
293320 checkState (nMag > 0 , "GR MFD with no mags" );
294321 double tmr = Mfds .totalMoRate (data .mMin , nMag , data .dMag , data .a , data .b );
322+ List <IncrementalMfd > mfds = Lists .newArrayList ();
323+
324+ if (unc .hasEpistemic ) {
325+ for (int i = 0 ; i < unc .epiCount ; i ++) {
326+ // update mMax and nMag
327+ double mMaxEpi = data .mMax + unc .epiDeltas [i ];
328+ int nMagEpi = Mfds .magCount (data .mMin , mMaxEpi , data .dMag );
329+ if (nMagEpi > 0 ) {
330+ double weightEpi = data .weight * unc .epiWeights [i ];
331+
332+ // epi branches preserve Mo between mMin and dMag(nMag-1),
333+ // not mMax to ensure that Mo is 'spent' on earthquakes
334+ // represented by the epi GR distribution with adj. mMax.
335+
336+ IncrementalMfd mfd = Mfds .newGutenbergRichterMoBalancedMFD (data .mMin ,
337+ data .dMag , nMagEpi , data .b , tmr * weightEpi );
338+ mfds .add (mfd );
339+ log .finer (" MFD type: GR [+epi -alea] " + epiBranch (i ));
340+ if (log .isLoggable (FINEST )) {
341+ log .finest (mfd .getMetadataString ());
342+ }
343+ } else {
344+ log .warning (" GR MFD epi branch with no mags [" + sourceBuilder .name + "]" );
295345
296- IncrementalMfd mfd = Mfds .newGutenbergRichterMoBalancedMFD (data .mMin , data .dMag , nMag ,
297- data .b , tmr * data .weight );
298- log .finer (" MFD type: GR" );
299- if (log .isLoggable (FINEST )) {
300- log .finest (mfd .getMetadataString ());
346+ }
347+ }
348+
349+ } else {
350+ IncrementalMfd mfd = Mfds .newGutenbergRichterMoBalancedMFD (data .mMin , data .dMag , nMag ,
351+ data .b , tmr * data .weight );
352+ mfds .add (mfd );
353+ log .finer (" MFD type: GR" );
354+ if (log .isLoggable (FINEST )) {
355+ log .finest (mfd .getMetadataString ());
356+ }
301357 }
302- return mfd ;
358+ return mfds ;
303359 }
304360
305361 /* Build SINGLE MFDs. */
@@ -311,7 +367,27 @@ private List<IncrementalMfd> buildSingle(Attributes atts) {
311367 return mfdList ;
312368 }
313369
370+ // only aleatory supported
314371 private IncrementalMfd buildSingle (SingleData data ) {
372+
373+ if (unc .hasAleatory ) {
374+ double tmr = data .rate * Earthquakes .magToMoment (data .m );
375+ if (!unc .moBalance ) {
376+ throw new RuntimeException ("moBalance must be 'true'" );
377+ }
378+ IncrementalMfd mfd = Mfds .newGaussianMoBalancedMFD (
379+ data .m ,
380+ unc .aleaSigma ,
381+ unc .aleaCount ,
382+ data .weight * tmr ,
383+ data .floats );
384+ log .finer (" MFD type: SINGLE [+alea]" );
385+ if (log .isLoggable (FINEST )) {
386+ log .finest (mfd .getMetadataString ());
387+ }
388+ return mfd ;
389+ }
390+
315391 IncrementalMfd mfd = Mfds .newSingleMFD (data .m , data .weight * data .rate , data .floats );
316392 log .finer (" MFD type: SINGLE" );
317393 if (log .isLoggable (FINEST )) {
@@ -320,4 +396,8 @@ private IncrementalMfd buildSingle(SingleData data) {
320396 return mfd ;
321397 }
322398
399+ private static String epiBranch (int i ) {
400+ return (i == 0 ) ? "(M-epi)" : (i == 2 ) ? "(M+epi)" : "(M)" ;
401+ }
402+
323403}
0 commit comments