[cig-commits] [commit] master: Merged upstream, small edits to pyvq (16f4e7d)
cig_noreply at geodynamics.org
cig_noreply at geodynamics.org
Wed Jan 28 22:37:37 PST 2015
Repository : https://github.com/geodynamics/vq
On branch : master
Link : https://github.com/geodynamics/vq/compare/4a71dae87966b80bfee7c194773543359a343617...941b3d7e55983967dea392d12aeac9ce3998ca30
>---------------------------------------------------------------
commit 16f4e7d8bb091c20d2c5a99394ea7496b05f9482
Merge: 6c3ca73 a77e012
Author: kwschultz <kwschultz at ucdavis.edu>
Date: Wed Dec 10 12:28:27 2014 -0800
Merged upstream, small edits to pyvq
>---------------------------------------------------------------
16f4e7d8bb091c20d2c5a99394ea7496b05f9482
config.h.in | 1 +
examples/CMakeLists.txt | 73 ++++++++++++++++++++--
examples/{example_params.d => example_params.prm} | 0
examples/{example_params.d => greens_generate.prm} | 3 +-
examples/{example_params.d => greens_input.prm} | 4 +-
examples/pyvq.py | 2 +-
examples/setup_params.sh | 3 +-
examples/sum_greens.py | 32 ++++++++++
quakelib/cmake/FindPythonModule.cmake | 25 ++++++++
src/core/Simulation.cpp | 6 +-
src/io/EventOutput.cpp | 5 --
src/io/GreensFileOutput.cpp | 5 ++
src/io/HDF5Data.cpp | 27 ++------
src/misc/GreensFunctions.cpp | 2 +
src/simulation/UpdateBlockStress.cpp | 32 ++++++++--
15 files changed, 176 insertions(+), 44 deletions(-)
diff --cc examples/pyvq.py
index 103302d,0000000..237c4f4
mode 100755,000000..100755
--- a/examples/pyvq.py
+++ b/examples/pyvq.py
@@@ -1,367 -1,0 +1,367 @@@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import math
+import sys
+import argparse
+import quakelib
+
+scipy_available = True
+try:
+ import scipy.stats
+except ImportError:
+ scipy_available = False
+
+matplotlib_available = True
+try:
+ import matplotlib.pyplot as plt
+except ImportError:
+ matplotlib_available = False
+
+numpy_available = True
+try:
+ import numpy as np
+except ImportError:
+ numpy_available = False
+
+class MagFilter:
+ def __init__(self, min_mag=None, max_mag=None):
+ self._min_mag = min_mag if min_mag is not None else -float("inf")
+ self._max_mag = max_mag if max_mag is not None else float("inf")
+
+ def test_event(self, event):
+ return (event.getMagnitude() >= self._min_mag and event.getMagnitude() <= self._max_mag)
+
+ def plot_str(self):
+ label_str = ""
+# TODO: change to <= character
+ if self._min_mag != -float("inf"): label_str += str(self._min_mag)+"<"
+ if self._max_mag != float("inf"): label_str += "M<"+str(self._max_mag)
+ return label_str
+
+class YearFilter:
+ def __init__(self, min_year=None, max_year=None):
+ self._min_year = min_year if min_year is not None else -float("inf")
+ self._max_year = max_year if max_year is not None else float("inf")
+
+ def test_event(self, event):
+ return (event.getEventYear() >= self._min_year and event.getEventYear() <= self._max_year)
+
+ def plot_str(self):
+ label_str = ""
+# TODO: change to <= character
+ if self._min_year != -float("inf"): label_str += str(self._min_year)+"<"
+ if self._max_year != float("inf"): label_str += "year<"+str(self._max_year)
+ return label_str
+
+class EventNumFilter:
+ def __init__(self, min_event_num=None, max_event_num=None):
+ self._min_event_num = min_event_num if min_event_num is not None else -sys.maxint
+ self._max_event_num = max_event_num if max_event_num is not None else sys.maxint
+
+ def test_event(self, event):
+ return (event.getEventNumber() >= self._min_event_num and event.getEventNumber() <= self._max_event_num)
+
+ def plot_str(self):
+ label_str = ""
+# TODO: change to <= character
+ if self._min_event_num != -sys.maxint: label_str += str(self._min_event_num)+"<"
+ if self._max_event_num != sys.maxint: label_str += "event num<"+str(self._max_event_num)
+ return label_str
+
+class SectionFilter:
+ def __init__(self, model, section_list):
+ self._section_list = section_list
+ self._elem_to_section_map = {elem_num: model.element(elem_num).section_id() for elem_num in range(model.num_elements())}
+
+ def test_event(self, event):
+ event_elements = event.getInvolvedElements()
+ for elem_num in event_elements:
+ elem_section = self._elem_to_section_map[elem_num]
+ if not elem_section in self._section_list: return True
+
+ return False
+
+ def plot_str(self):
+ return "my_string"
+
+class Events:
+ def __init__(self, event_file, event_file_type, sweep_file = None):
+ self._events = quakelib.ModelEventSet()
+ if event_file_type == "hdf5":
+ self._events.read_file_hdf5(event_file)
+ elif event_file_type == "text" and sweep_file != None:
+ self._events.read_file_ascii(event_file, sweep_file)
+ else:
+ sys.exit("event_file_type must be hdf5 or text. If text, a sweep_file is required.")
+
+ self._filtered_events = range(len(self._events))
+ self._plot_str = ""
+
+ def plot_str(self):
+ return self._plot_str
+
+ def set_filters(self, filter_list):
+ self._filtered_events = [evnum for evnum in range(len(self._events))]
+ self._plot_str = ""
+ for cur_filter in filter_list:
+ new_filtered_events = [evnum for evnum in self._filtered_events if cur_filter.test_event(self._events[evnum])]
+ self._filtered_events = new_filtered_events
+ self._plot_str += cur_filter.plot_str()
+ if len(self._filtered_events) == 0:
+ raise "No events matching filters found!"
+
+ def interevent_times(self):
+ event_times = [self._events[evnum].getEventYear() for evnum in self._filtered_events]
+ return [event_times[i+1]-event_times[i] for i in xrange(len(event_times)-1)]
+
+ def event_years(self):
+ return [self._events[evnum].getEventYear() for evnum in self._filtered_events]
+
+ def event_rupture_areas(self):
+ return [self._events[evnum].calcEventRuptureArea() for evnum in self._filtered_events]
+
+ def event_magnitudes(self):
+ return [self._events[evnum].getMagnitude() for evnum in self._filtered_events]
+
+ def event_mean_slip(self):
+ return [self._events[evnum].calcMeanSlip() for evnum in self._filtered_events]
+
+class BasePlotter:
+ def create_plot(self, plot_type, log_y, x_data, y_data, plot_title, x_label, y_label):
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ ax.set_xlabel(x_label)
+ ax.set_ylabel(y_label)
+ ax.set_title(plot_title)
+ if log_y:
+ ax.set_yscale('log')
+ if plot_type == "scatter":
+ ax.scatter(x_data, y_data)
+ elif plot_type == "line":
+ ax.plot(x_data, y_data)
+ plt.show()
+
+class MagnitudeRuptureAreaPlot(BasePlotter):
+ def plot(self, events):
+ ra_list = events.event_rupture_areas()
+ mag_list = events.event_magnitudes()
+ ra_renorm_list = [quakelib.Conversion().sqm2sqkm(ra) for ra in ra_list]
+ self.create_plot("scatter", True, mag_list, ra_renorm_list, events.plot_str(), "Magnitude", "Rupture Area (square km)")
+
+class MagnitudeMeanSlipPlot(BasePlotter):
+ def plot(self, events):
+ slip_list = events.event_mean_slip()
+ mag_list = events.event_magnitudes()
+ self.create_plot("scatter", True, mag_list, slip_list, events.plot_str(), "Magnitude", "Mean Slip (meters)")
+
+class FrequencyMagnitudePlot(BasePlotter):
+ def plot(self, events):
+ mag_list = events.event_magnitudes()
+ min_mag = min(mag_list)
+ max_mag = max(mag_list)
+ mag_width = (max_mag - min_mag)/99
+ mag_vals = [min_mag+i*mag_width for i in range(100)]
+ mag_counts = [0]*100
+ for mag in mag_list:
+ mag_counts[int((mag-min_mag)/mag_width)] += 1
+ mag_counts.reverse()
+ for i in range(len(mag_counts)-1):
+ mag_counts[i+1] += mag_counts[i]
+ mag_counts.reverse()
+ mag_norm = [m/float(len(mag_list)) for m in mag_counts]
+ self.create_plot("scatter", True, mag_vals, mag_norm, events.plot_str(), "Magnitude", "Frequency")
+ #print(mag_norm)
+
+class StressHistoryPlot(BasePlotter):
+ def plot(self, stress_set, elements):
+ stress_histories = {}
+ for element in elements:
+ stress_histories[element] = []
+ for stress_state in stress_set:
+ if stress_state.getSweepNum() == 0:
+ stresses = stress_state.stresses()
+ for stress in stresses:
+ if stress._element_id in elements:
+ stress_histories[element].append(stress._shear_stress)
+ for element in elements:
+ print(stress_histories[element])
+ #self.create_plot("scatter", True, mag_vals, mag_norm, events.plot_str(), "Shear Stress", "Year")
+
+
+class ProbabilityPlot(BasePlotter):
+ def plot_p_of_t(self, events):
+ # Cumulative probability P(t) as a function of interevent time t
+ intervals = np.array(events.interevent_times())
+ prob = {}
+ prob['x'] = np.sort(intervals)
+ prob['y'] = np.arange(float(intervals.size))/float(intervals.size)
+ self.create_plot("line", False, prob['x'], prob['y'], events.plot_str(), "P(t)","t [years]")
+
+ def plot_conditional_fixed_dt(self, events, fixed_dt=30.0):
+ # P(t0 + dt, t0) vs. t0 for fixed dt
+ intervals = np.array(events.interevent_times())
+ prob_dt = {'x':[],'y':[]}
+ t0_to_eval = np.arange(0.0,int(intervals.max())+.01,1.0)
+ for t0 in t0_to_eval:
+ int_t0_dt = intervals[np.where( intervals > t0+fixed_dt)]
+ int_t0 = intervals[np.where( intervals > t0)]
+ if int_t0.size != 0:
+ prob_dt['x'].append(t0)
+ prob_dt['y'].append(1.0 - float(int_t0_dt.size)/float(int_t0.size))
+ self.create_plot("line", False, prob_dt['x'], prob_dt['y'], events.plot_str(), "P(t0 + dt, t0)","t0 [years]")
+ """
+ def plot_p_of_t_multi(self, events):
+ # Cumulative conditional probability P(t,t0) as a function of
+ # interevent time t, computed for multiple t0
+ intervals = np.array(events.interevent_times())
+ conditional = {}
+ t0_to_eval = np.arange(0.0,int(intervals.max())+.01,1.0)
+ for t0 in t0_to_eval:
+ int_t0_dt = intervals[np.where( intervals > t0+fixed_dt)]
+ self.create_plot("line", False, prob['x'], prob['y'], events.plot_str(), "P(t)","t [years]")
+ """
+
+class Distributions:
+ def weibull(X, beta, tau):
+ # Return the Weibull distribution for the parameters given,
+ # for the x point or for the array of x values given.
+ if len(X) == 1:
+ return 1-np.exp( -(X/float(tau))**beta)
+ else:
+ return np.array([1-np.exp( -(X/float(tau))**beta) for x in X])
+
+ def cond_weibull(X, t0, beta, tau):
+ # Return the conditional Weibull distribution at a single point
+ # or for an array of points.
+ if len(X) == 1:
+ return 1-np.exp( (t0/float(tau))**beta - (X/float(tau))**beta)
+ else:
+ return np.array([1-np.exp( (t0/float(tau))**beta - (x/float(tau))**beta) for x in X])
+
+if __name__ == "__main__":
+ # Specify arguments
+ parser = argparse.ArgumentParser(description="PyVQ.")
+
+ # Event/model file arguments
+ parser.add_argument('--event_file', required=True,
+ help="Name of event file to analyze.")
+ parser.add_argument('--event_file_type', required=True,
+ help="Event file type, either hdf5 or text.")
+ parser.add_argument('--sweep_file', required=False,
+ help="Name of sweep file to analyze.")
+ parser.add_argument('--model_file', required=False,
+ help="Name of model (geometry) file to use in analysis.")
+ parser.add_argument('--stress_index_file', required=False,
+ help="Name of stress index file to use in analysis.")
+ parser.add_argument('--stress_file', required=False,
+ help="Name of stress file to use in analysis.")
+
+ # Event filtering arguments
+ parser.add_argument('--min_magnitude', type=float, required=False,
+ help="Minimum magnitude of events to process.")
+ parser.add_argument('--max_magnitude', type=float, required=False,
+ help="Maximum magnitude of events to process.")
+ parser.add_argument('--min_year', type=float, required=False,
+ help="Minimum year of events to process.")
+ parser.add_argument('--max_year', type=float, required=False,
+ help="Maximum year of events to process.")
+ parser.add_argument('--min_event_num', type=float, required=False,
+ help="Minimum event number of events to process.")
+ parser.add_argument('--max_event_num', type=float, required=False,
+ help="Maximum event number of events to process.")
+ parser.add_argument('--use_sections', type=int, nargs='+', required=False,
+ help="List of model sections to use (all sections used if unspecified).")
+
+ # Event plotting arguments
+ parser.add_argument('--plot_freq_mag', required=False,
+ help="Generate frequency magnitude plot.")
+ parser.add_argument('--plot_mag_rupt_area', required=False,
+ help="Generate magnitude vs rupture area plot.")
+ parser.add_argument('--plot_mag_mean_slip', required=False,
+ help="Generate magnitude vs mean slip plot.")
+ parser.add_argument('--plot_prob_vs_t', required=False,
+ help="Generate earthquake recurrence probability at time t plot, --use_sections required.")
+ parser.add_argument('--plot_prob_vs_t_fixed_dt', required=False,
+ help="Generate earthquake recurrence probability at time t + dt vs t plot, --use_sections required.")
+
+ # Stress plotting arguments
+ parser.add_argument('--stress_elements', type=int, nargs='+', required=False,
+ help="List of elements to plot stress history for.")
+
+ # Validation/testing arguments
+ parser.add_argument('--validate_slip_sum', required=False,
+ help="Ensure the sum of mean slip for all events is within 1 percent of the specified value.")
+ parser.add_argument('--validate_mean_interevent', required=False,
+ help="Ensure the mean interevent time for all events is within 2 percent of the specified value.")
+
+ args = parser.parse_args()
+
+ # Read the event and sweeps files
+ if args.event_file_type == "hdf5":
+ events = Events(args.event_file, args.event_file_type)
+ else:
+ events = Events(args.event_file, args.event_file_type, sweep_file = args.sweep_file)
+
+ # Read the geometry model if specified
+ if args.model_file:
+ model = quakelib.ModelWorld()
+ model.read_file_ascii(args.model_file)
+ else:
+ model = None
+
+ # Read the stress files if specified
+ if args.stress_index_file and args.stress_file:
+ stress_set = quakelib.ModelStressSet()
+ stress_set.read_file_ascii(args.stress_index_file, args.stress_file)
+ else:
+ stress_set = None
+
+ # Set up filters
+ event_filters = []
+ if args.min_magnitude or args.max_magnitude:
+ event_filters.append(MagFilter(min_mag=args.min_magnitude, max_mag=args.max_magnitude))
+
+ if args.min_year or args.max_year:
+ event_filters.append(YearFilter(min_mag=args.min_year, max_mag=args.max_year))
+
+ if args.min_event_num or args.max_event_num:
+ event_filters.append(EventNumFilter(min_mag=args.min_event_num, max_mag=args.max_event_num))
+
+ if args.use_sections:
+ event_filters.append(SectionFilter(model, args.use_sections))
+
+ events.set_filters(event_filters)
+
+ # Generate plots
+ if args.plot_freq_mag:
+ FrequencyMagnitudePlot().plot(events)
+ if args.plot_mag_rupt_area:
+ MagnitudeRuptureAreaPlot().plot(events)
+ if args.plot_mag_mean_slip:
+ MagnitudeMeanSlipPlot().plot(events)
+ if args.plot_p_of_t:
+ ProbabilityPlot().plot_p_of_t(events)
+ if args.plot_prob_vs_t_fixed_dt:
- ProbabilityPlot().plot_conditional_fixed_dt(events)
++ ProbabilityPlot().plot_conditional_fixed_dt(events)`
+
+ # Generate stress plots
+ if args.stress_elements:
+ # TODO: check that stress_set is valid
+ StressHistoryPlot().plot(stress_set, args.stress_elements)
+
+ # Validate data if requested
+ err = False
+ if args.validate_slip_sum:
+ mean_slip = sum(events.event_mean_slip())
+ if abs(mean_slip-args.validate_slip_sum)/args.validate_slip_sum > 0.01: err = True
+ print("Calculated mean slip:", mean_slip, "vs. expected:", args.validate_slip_sum)
+
+ if args.validate_mean_interevent:
+ ie_times = events.interevent_times()
+ mean_ie = sum(ie_times)/len(ie_times)
+ if abs(mean_ie-args.mean_interevent)/args.mean_interevent > 0.02: err = True
+ print("Calculated mean interevent:", mean_interevent, "vs. expected:", args.mean_interevent)
+
+ if err: exit(1)
More information about the CIG-COMMITS
mailing list