def test_generate_fault_source_model_complex(self): ''' Tests the function to turn fault model into mtkSimpleFault or mtkComplexFault ''' self.fault = mtkActiveFault('001', 'A Fault', self.complex_fault, [(5.0, 1.0)], 0., None, aseismic=0., msr_sigma=[(0.0, 1.0)], neotectonic_fault=None, scale_rel=[(WC1994(), 1.0)], aspect_ratio=1.0, shear_modulus=[(30., 1.0)], disp_length_ratio=[(1.25E-5, 1.0)]) # Define simple placeholder MFD rec_models = [ IncrementalMFD(5.0, 0.1, 1.0 * np.ones(10)), IncrementalMFD(5.0, 0.1, 2.0 * np.ones(10)) ] self.fault.mfd = (rec_models, [0.5, 0.5], [WC1994(), WC1994()]) # Run model source_model, weights = self.fault.generate_fault_source_model() self.assertEqual(len(source_model), 2) self.assertTrue(isinstance(source_model[0], mtkComplexFaultSource)) for iloc, model in enumerate(source_model): self.assertEqual(model.id, '001') self.assertTrue(isinstance(model.mfd, EvenlyDiscretizedMFD)) np.testing.assert_array_almost_equal(model.mfd.occurrence_rates, rec_models[iloc].occur_rates) self.assertAlmostEqual(weights[iloc], 0.5)
def collapse_branches(self, mmin, bin_width, mmax): ''' Collapse the logic tree branches into a single IncrementalMFD :param float mmin: Minimum magnitude of reference mfd :param float bin_width: Bin width of reference mfd :param float mmax: Maximum magnitude of reference mfd :returns: :class: openquake.hmtk.models.IncrementalMFD ''' master_mags = np.arange(mmin, mmax + (bin_width / 2.), bin_width) master_rates = np.zeros(len(master_mags), dtype=float) for model in self.mfd_models: id0 = np.logical_and( master_mags >= np.min(model.magnitudes) - 1E-9, master_mags <= np.max(model.magnitudes) + 1E-9) # Use interpolation in log10-y values yvals = np.log10(model.recurrence.occur_rates) interp_y = np.interp(master_mags[id0], model.magnitudes, yvals) master_rates[id0] = master_rates[id0] + (model.weight * 10. ** interp_y) return IncrementalMFD(mmin, bin_width, master_rates)
def get_recurrence(self, config): ''' Calculates the recurrence model for the given settings as an instance of the openquake.hmtk.models.IncrementalMFD :param dict config: Configuration settings of the magnitude frequency distribution. ''' model = MFD_MAP[config['Model_Name']]() model.setUp(config) model.get_mmax(config, self.msr, self.rake, self.area) model.mmax = model.mmax + (self.msr_sigma * model.mmax_sigma) # As the Anderson & Luco arbitrary model requires the input of the # displacement to length ratio if 'AndersonLucoAreaMmax' in config['Model_Name']: if not self.disp_length_ratio: # If not defined then default to 1.25E-5 self.disp_length_ratio = 1.25E-5 min_mag, bin_width, occur_rates = model.get_mfd( self.slip, self.area, self.shear_modulus, self.disp_length_ratio) else: min_mag, bin_width, occur_rates = model.get_mfd(self.slip, self.area, self.shear_modulus) self.recurrence = IncrementalMFD(min_mag, bin_width, occur_rates) self.magnitudes = min_mag + np.cumsum( bin_width * np.ones(len(occur_rates), dtype=float)) - bin_width self.max_mag = np.max(self.magnitudes)
def _build_mock_recurrence_branches(self): ''' Given the mock branches return information necessary to define a collapse model ''' # Build test data mags = COLLAPSE_DATA[0, :-1] weights = COLLAPSE_DATA[1:-1, -1] rates = COLLAPSE_DATA[1:-1:, :-1] expected_rate = COLLAPSE_DATA[-1, :-1] test_fault = mtkActiveFault('001', 'A Fault', self.simple_fault, [(5.0, 1.0)], 0., None) test_fault.mfd_models = [] for (iloc, weight) in enumerate(weights): idx = rates[iloc, :] > 0 model = RecurrenceBranch(None, None, None, None, None, weight=weight) model.recurrence = IncrementalMFD(np.min(rates[iloc, idx]), 0.1, rates[iloc, idx]) model.magnitudes = mags[idx] test_fault.mfd_models.append(model) return test_fault, expected_rate, np.min(mags), np.max(mags), weights
def generate_recurrence_models( self, collapse=False, bin_width=0.1, config=None, rendered_msr=None): ''' Iterates over the lists of values defining epistemic uncertainty in the parameters and calculates the corresponding recurrence model At present epistemic uncertainty is supported for: 1) slip rate, 2) magnitude scaling relation, 3) shear modulus, 4) displacement to length ratio) and 5) recurrence model. :param list config: List of MFD model configurations :param bool collapse: Boolean flag indicating whether to collapse the logic tree branches :param float bin_width: If collapsing the logic tree branches the reference mfd must be defined. The minimum and maximum magnitudes are updated from the model, but the bin width must be specified here :param list/dict config: Configuration (or sets of configurations) of the recurrence calculations :param rendered_msr: If collapsing the logic tree branches a resulting magnitude scaling relation must be defined as instance of :class: openquake.hazardlib.scalerel.base.BaseASR ''' if collapse and not rendered_msr: raise ValueError('Collapsing logic tree branches requires input ' 'of a single msr for rendering sources') # Generate a set of tuples with corresponding weights if config is not None: self.generate_config_set(config) if not isinstance(self.config, list): raise ValueError('MFD configuration missing or incorrectly ' 'formatted') # Generate the branching index branch_index, _number_branches = self._generate_branching_index() mmin = np.inf mmax = -np.inf for idx in branch_index: tuple_list = [] # Get slip tuple_list.append(self.slip[idx[0]]) # Get msr tuple_list.append(self.msr[idx[1]]) # Get shear modulus tuple_list.append(self.shear_modulus[idx[2]]) # Get displacement length ratio tuple_list.append(self.disp_length_ratio[idx[3]]) # Get msr sigma tuple_list.append(self.msr_sigma[idx[4]]) # Get config tuple_list.append(self.config[idx[5]]) # Calculate branch weight as product of tuple weights branch_weight = np.prod(np.array([val[1] for val in tuple_list])) # Instantiate recurrence model model = RecurrenceBranch(self.area, tuple_list[0][0], tuple_list[1][0], self.rake, tuple_list[2][0], tuple_list[3][0], tuple_list[4][0], weight=branch_weight) model.get_recurrence(tuple_list[5][0]) self.mfd_models.append(model) # Update the total minimum and maximum magnitudes for the fault if model.recurrence.min_mag < mmin: mmin = model.recurrence.min_mag if np.max(model.magnitudes) > mmax: mmax = np.max(model.magnitudes) if collapse: self.mfd = ([self.collapse_branches(mmin, bin_width, mmax)], [1.0], [rendered_msr]) else: mfd_mods = [] mfd_wgts = [] mfd_msr = [] for model in self.mfd_models: mfd_mods.append(IncrementalMFD(model.recurrence.min_mag, model.recurrence.bin_width, model.recurrence.occur_rates)) mfd_wgts.append(model.weight) mfd_msr.append(model.msr) self.mfd = (mfd_mods, mfd_wgts, mfd_msr)