def write_intxt(input_object, output_file, label=None): ofile = open(output_file, 'w'); if label: ofile.write(label); ofile.write("# General: poissons_ratio friction_coef lon_min lon_max lon_zero lat_min lat_max lat_zero\n"); ofile.write("# Source_Patch: strike rake dip length_km width_km lon lat depth_km slip_m\n"); ofile.write("# Receiver: strike rake dip length_km width_km lon lat depth_km\n\n"); ofile.write("General: %f %f %f %f %f %f %f %f \n" % (input_object.PR1, input_object.FRIC, input_object.minlon, input_object.maxlon, input_object.zerolon, input_object.minlat, input_object.maxlat, input_object.zerolat) ); for src in input_object.source_object: if not src.potency: # write a finite source L = fault_vector_functions.get_strike_length(src.xstart, src.xfinish, src.ystart, src.yfinish); # in km W = fault_vector_functions.get_downdip_width(src.top, src.bottom, src.dipangle); # in km fault_lon, fault_lat = fault_vector_functions.xy2lonlat(src.xstart, src.ystart, src.zerolon, src.zerolat); slip = fault_vector_functions.get_vector_magnitude([src.rtlat, src.reverse]); # in m ofile.write("Source_Patch: %f %f %f %f %f %f %f %f %f\n" % (src.strike, src.rake, src.dipangle, L, W, fault_lon, fault_lat, src.top, slip)); if src.potency: # write a focal mechanism source continue; # still working on this. for rec in input_object.receiver_object: L = fault_vector_functions.get_strike_length(rec.xstart, rec.xfinish, rec.ystart, rec.yfinish); # in km W = fault_vector_functions.get_downdip_width(rec.top, rec.bottom, rec.dipangle); # in km fault_lon, fault_lat = fault_vector_functions.xy2lonlat(rec.xstart, rec.ystart, rec.zerolon, rec.zerolat); ofile.write("Receiver: %f %f %f %f %f %f %f %f \n" % (rec.strike, rec.rake, rec.dipangle, L, W, fault_lon, fault_lat, rec.top) ); ofile.close(); print("Writing file %s " % output_file); return;
def write_stress_results_slippy_format(faults_list, shear, normal, coulomb, outfile): """ :param faults_list: a list of fault dictionaries :param outfile: name of output file. :param shear: list of shear stress change on each element, kpa :param normal: list of normal stress, kpa :param coulomb: list of coulomb stress, kpa Caveat: This is ALMOST slippy format. You will lose the fault segment number, and we add the rake column. """ print("Writing file %s " % outfile) ofile = open(outfile, 'w') ofile.write( "# lon[degrees] lat[degrees] depth[m] strike[degrees] dip[degrees] rake[degrees] length[m] width[m] " "shear[KPa] normal[KPa] coulomb[KPa]\n") for i, item in enumerate(faults_list): x_center, y_center = fault_vector_functions.add_vector_to_point( 0, 0, item["length"] / 2, item["strike"]) center_lon, center_lat = fault_vector_functions.xy2lonlat( x_center, y_center, item["lon"], item["lat"]) ofile.write("%f %f %f " % (center_lon, center_lat, item["depth"] * -1000)) ofile.write( "%f %f %f %f %f %f %f %f \n" % (item["strike"], item["dip"], item["rake"], item["length"] * 1000, item["width"] * 1000, shear[i], normal[i], coulomb[i])) ofile.close() return
def write_slippy_distribution(faults_list, outfile): """ :param faults_list: a list of fault dictionaries :param outfile: name of output file. Caveat: can only do one fault segment right now. That part of the read/write cycle is lossy. """ print("Writing file %s " % outfile) ofile = open(outfile, 'w') ofile.write( "# lon[degrees] lat[degrees] depth[m] strike[degrees] dip[degrees] length[m] width[m] left-lateral[m] " "thrust[m] tensile[m] segment_num\n") for item in faults_list: x_center, y_center = fault_vector_functions.add_vector_to_point( 0, 0, item["length"] / 2, item["strike"]) center_lon, center_lat = fault_vector_functions.xy2lonlat( x_center, y_center, item["lon"], item["lat"]) rtlat_slip, dip_slip = fault_vector_functions.get_rtlat_dip_slip( item["slip"], item["rake"]) tensile_slip = 0 ofile.write("%f %f %f " % (center_lon, center_lat, item["depth"] * -1000)) ofile.write( "%f %f %f %f %f %f %f 0 \n" % (item["strike"], item["dip"], item["length"] * 1000, item["width"] * 1000, -1 * rtlat_slip, dip_slip, tensile_slip)) ofile.close() return
def get_receiver_profile(line): """ Create a horizontal profile based on the provided params. 'Receiver_Horizontal_Profile: depth strike dip rake centerlon centerlat length_km width_km inc_km' """ [depth, strike, dip, rake, centerlon, centerlat, length, width, inc] = [float(i) for i in line.split()[1:10]]; startlon = fault_vector_functions.xy2lonlat(-length, 0, centerlon, centerlat)[0]; endlon = fault_vector_functions.xy2lonlat(length, 0, centerlon, centerlat)[0]; startlat = fault_vector_functions.xy2lonlat(0, -width, centerlon, centerlat)[1]; endlat = fault_vector_functions.xy2lonlat(0, width, centerlon, centerlat)[1]; lonpts = np.arange(startlon, endlon, inc/111.00); latpts = np.arange(startlat, endlat, inc/111.00); X, Y = np.meshgrid(lonpts, latpts); lon1d = np.reshape(X, (np.size(X),)); lat1d = np.reshape(Y, (np.size(X),)); horiz_profile = cc.Receiver_Horiz_Profile(depth_km=depth, strike=strike, dip=dip, rake=rake, centerlon=centerlon, centerlat=centerlat, lon1d=lon1d, lat1d=lat1d, shape=np.shape(X)); return horiz_profile;
def get_updip_corners_lon_lat(fault_dict_object): """ Return the lon/lat of 2 shallow corners of a fault_dict_object """ [source] = fault_dict_to_coulomb_fault([fault_dict_object]) [_, _, x_updip, y_updip] = conversion_math.get_fault_four_corners(source) lons, lats = fault_vector_functions.xy2lonlat(x_updip, y_updip, source.zerolon, source.zerolat) return lons, lats
def get_four_corners_lon_lat(fault_dict_object): """ Return the lon/lat of all 4 corners of a fault_dict_object """ [source] = fault_dict_to_coulomb_fault([fault_dict_object]) [x_total, y_total, _, _] = conversion_math.get_fault_four_corners(source) lons, lats = fault_vector_functions.xy2lonlat(x_total, y_total, source.zerolon, source.zerolat) return lons, lats
def annotate_figure_with_sources(fig, inputs, params, fmscale="0.3c", dotstyle="s0.3c"): """ Draw each source in inputs.source_object, a list of sources Inputs and Params provide additional information about the calcuation. dotstyle is for source dots fmscale is for focal mechanism size """ # Draw dots for EQ sources eq_lon, eq_lat = [], [] for source in inputs.source_object: source_lon, source_lat = fault_vector_functions.xy2lonlat( source.xstart, source.ystart, inputs.zerolon, inputs.zerolat) eq_lon.append(source_lon) eq_lat.append(source_lat) fig.plot(eq_lon, eq_lat, style=dotstyle, color="purple", pen="thin,black") for source in inputs.source_object: [x_total, y_total, _, _] = conversion_math.get_fault_four_corners(source) lons, lats = fault_vector_functions.xy2lonlat(x_total, y_total, inputs.zerolon, inputs.zerolat) if not source.potency: # in case of area sources, outline the fault patches fig.plot(x=lons, y=lats, pen="thick,black") else: # in case of point sources, draw focal mechanisms mag = io_intxt.get_mag_from_dc_potency(source.potency, params.mu, source.rake) focal_mechanism = dict(strike=source.strike, dip=source.dipangle, rake=source.rake, magnitude=mag) fig.meca(focal_mechanism, scale=fmscale, longitude=lons[0], latitude=lats[0], depth=source.top) return fig
def read_slippy_distribution(infile, desired_segment=-1): """ Read a file from the Slippy inversion outputs (lon[degrees] lat[degrees] depth[m] strike[degrees] dip[degrees] length[m] width[m] left-lateral[m] thrust[m] tensile[m] segment_num) into a list of fault dictionaries. Lon/lat usually refer to the center top of the fault, so it must convert the lon/lat to the top left corner. :param infile: name of input slip distribution file :type infile: string :param desired_segment: starting at 0, which fault segment do we want to return? default of -1 means all. :type desired_segment: int :returns: list of fault dictionaries :rtype: list """ print("Reading slippy distribution %s " % infile) fault_list = [] [ lon, lat, depth, strike, dip, length, width, ll_slip, thrust_slip, _, num ] = np.loadtxt(infile, skiprows=1, unpack=True, dtype={ "names": ('lon', 'lat', 'depth', 'strike', 'dip', 'length', 'width', 'ss', 'ds', 'tensile', 'num'), "formats": (float, float, float, float, float, float, float, float, float, float, float) }) for i in range(len(lon)): if desired_segment == -1 or desired_segment == num[i]: one_fault = { "strike": strike[i], "dip": dip[i], "length": length[i] / 1000, "width": width[i] / 1000, "depth": -depth[i] / 1000 } center_lon = lon[i] center_lat = lat[i] x_start, y_start = fault_vector_functions.add_vector_to_point( 0, 0, one_fault["length"] / 2, one_fault["strike"] - 180) # in km corner_lon, corner_lat = fault_vector_functions.xy2lonlat( x_start, y_start, center_lon, center_lat) one_fault["lon"] = corner_lon one_fault["lat"] = corner_lat one_fault["rake"] = fault_vector_functions.get_rake( rtlat_strike_slip=-ll_slip[i], dip_slip=thrust_slip[i]) one_fault["slip"] = fault_vector_functions.get_total_slip( ll_slip[i], thrust_slip[i]) one_fault["tensile"] = 0 fault_list.append(one_fault) return fault_list
def write_synthetic_grid_full_results(x, y, x2d, y2d, zerolon, zerolat, u, v, w, outdir): ofile = open(outdir + 'disps_model_grid.txt', 'w') ofile.write("# Format: x y lon lat udisp vdisp wdisp (m) \n") for i in np.arange(0, len(y)): for j in np.arange(0, len(x)): loni, lati = fault_vector_functions.xy2lonlat( x2d[i][j], y2d[i][j], zerolon, zerolat) ofile.write( "%f %f %f %f %f %f %f\n" % (x2d[i][j], y2d[i][j], loni, lati, u[i][j], v[i][j], w[i][j])) ofile.close() return
def read_stress_slippy_format(infile): """ Read stress results from CFS calculation :param infile: text file in full-stress format :returns: fault_list (internal dictionary format). shear, normal, and coulomb are matching lists in KPa """ print("Reading file %s " % infile) fault_list = [] [ lon, lat, depth, strike, dip, rake, length, width, shear, normal, coulomb ] = np.loadtxt(infile, skiprows=1, unpack=True, dtype={ "names": ('lon', 'lat', 'depth', 'strike', 'dip', 'rake', 'length', 'width', 'shear', 'normal', 'coulomb'), "formats": (float, float, float, float, float, float, float, float, float, float, float, float) }) for i in range(len(lon)): one_fault = { "strike": strike[i], "dip": dip[i], "length": length[i] / 1000, "width": width[i] / 1000, "depth": -depth[i] / 1000 } center_lon = lon[i] center_lat = lat[i] x_start, y_start = fault_vector_functions.add_vector_to_point( 0, 0, one_fault["length"] / 2, one_fault["strike"] - 180) # in km corner_lon, corner_lat = fault_vector_functions.xy2lonlat( x_start, y_start, center_lon, center_lat) one_fault["lon"] = corner_lon one_fault["lat"] = corner_lat one_fault["rake"] = rake[i] one_fault["slip"] = 0 one_fault["tensile"] = 0 fault_list.append(one_fault) return fault_list, shear, normal, coulomb
def write_synthetic_grid_triplets(x, y, x2d, y2d, zerolon, zerolat, u, v, w, outdir): """ Write lists of lon/lat/def for each component of deformation in synthetic grid Used for GMT plots """ ofile_w = open(outdir + 'xyz_model.txt', 'w') ofile_u = open(outdir + 'xyu_model.txt', 'w') ofile_v = open(outdir + 'xyv_model.txt', 'w') for i in np.arange(0, len(y)): for j in np.arange(0, len(x)): loni, lati = fault_vector_functions.xy2lonlat( x2d[i][j], y2d[i][j], zerolon, zerolat) ofile_w.write("%f %f %f\n" % (loni, lati, w[i][j])) ofile_u.write("%f %f %f\n" % (loni, lati, u[i][j])) ofile_v.write("%f %f %f\n" % (loni, lati, v[i][j])) ofile_w.close() ofile_u.close() ofile_v.close() return
def write_faults_json(faults_list, outfile): """ Writes faults to json as receivers with zero slip position is lon/lat/depth in meters (negative means below surface) :param faults_list: list of fault dictionaries :type faults_list: list :param outfile: name of output json file :type outfile: string """ output = {} for k, fault in enumerate(faults_list): # Convert the fault (which has top left corner) into a fault with top center coordinate label = "fault" + str(k) newfault = {} corner_lon = fault["lon"] corner_lat = fault["lat"] x_center, y_center = fault_vector_functions.add_vector_to_point( 0, 0, fault["length"] / 2, fault["strike"]) center_lon, center_lat = fault_vector_functions.xy2lonlat( x_center, y_center, corner_lon, corner_lat) newfault["strike"] = fault["strike"] newfault["dip"] = fault["dip"] newfault["length"] = fault["length"] * 1000 newfault["width"] = fault["width"] * 1000 newfault["basis1"] = [1, 0, 0] newfault["basis2"] = None newfault["Nlength"] = 1 newfault["Nwidth"] = 1 newfault["penalty"] = 1 newfault["position"] = [ center_lon, center_lat, -fault["depth"] * 1000 ] output[label] = newfault with open(outfile, 'w') as ofile: json.dump(output, ofile, indent=4) return
def read_faults_json(infile): """ Read all faults from a json file (just geometry; no slip or rake) into a list of fault dictionaries. It has to convert from fault center to fault corner. Faults read from JSON have zero slip. :param infile: name of input json file :type infile: string :returns: list of fault dictionaries :rtype: list """ fault_list = [] config_file = open(infile, 'r') config = json.load(config_file) for key in config.keys(): one_fault = { "strike": config[key]["strike"], "dip": config[key]["dip"], "length": config[key]["length"] / 1000.0, "width": config[key]["width"] / 1000.0 } center_lon = config[key]["position"][0] center_lat = config[key]["position"][1] x_start, y_start = fault_vector_functions.add_vector_to_point( 0, 0, one_fault["length"] / 2, one_fault["strike"] - 180) # in km corner_lon, corner_lat = fault_vector_functions.xy2lonlat( x_start, y_start, center_lon, center_lat) # one_fault["lon"] = corner_lon one_fault["lat"] = corner_lat one_fault["depth"] = -config[key]["position"][2] / 1000 one_fault["rake"] = 0 one_fault["slip"] = 0 one_fault["tensile"] = 0 fault_list.append(one_fault) config_file.close() return fault_list
def coulomb_fault_to_fault_dict(source_object): """Convert a list of fault objects from Elastic_stresses_py into a list of internal dictionary objects""" fault_dict_list = [] for src in source_object: if src.potency: print( "ERROR! Cannot convert a point source into a rectangular source. Skipping..." ) continue one_fault = { "strike": src.strike, "dip": src.dipangle, "depth": src.top, "rake": fault_vector_functions.get_rake(rtlat_strike_slip=src.rtlat, dip_slip=src.reverse), "slip": fault_vector_functions.get_total_slip(src.rtlat, src.reverse), "tensile": src.tensile, "length": fault_vector_functions.get_strike_length(src.xstart, src.xfinish, src.ystart, src.yfinish), "width": fault_vector_functions.get_downdip_width(src.top, src.bottom, src.dipangle) } lon, lat = fault_vector_functions.xy2lonlat(src.xstart, src.ystart, src.zerolon, src.zerolat) one_fault["lon"] = lon one_fault["lat"] = lat fault_dict_list.append(one_fault) return fault_dict_list
def read_srcmod_distribution(infile): """ Let's assume that the lon/lat/depth given in the SRCMOD .fsp file is for the top center of the fault patch. This function doesn't have a unit test yet. :param infile: name of input slip distribution file, defined to be the '.fsp' file :type infile: string :returns: list of fault dictionaries :rtype: list """ print("Reading SRCMOD distribution %s " % infile) fault_list = [] overall_strike, overall_dip, total_len_km, nx, total_width_km, nz = 0, 90, 10, 10, 10, 10 # defaults. ifile = open(infile, 'r') for line in ifile: temp = line.split() if len(temp) > 3: if temp[0] == '%' and temp[1] == 'Mech': overall_strike = float(temp[5]) overall_dip = float(temp[8]) if temp[0] == '%' and temp[1] == 'Size': total_len_km = float(temp[5]) total_width_km = float(temp[9]) if temp[0] == '%' and temp[3] == 'Nx': nx = int(temp[5]) nz = int(temp[8]) if temp[0] != '%': lon_top_center = float(temp[1]) lat_top_center = float(temp[0]) depth_top_center = float(temp[4]) depth_top, _ = fault_vector_functions.get_top_bottom_from_center( depth_top_center, total_width_km / nz, overall_dip) slip_m = float(temp[5]) rake = float(temp[6]) one_fault = { "strike": overall_strike, "dip": overall_dip, "length": total_len_km / nx, "width": total_width_km / nz, "depth": depth_top_center, "rake": rake, "slip": slip_m, "tensile": 0 } x_start, y_start = fault_vector_functions.add_vector_to_point( 0, 0, one_fault["length"] / 2, one_fault["strike"] - 180) # in km _downdip_width_proj = one_fault["width"] * np.cos( np.deg2rad(overall_dip)) # x_start, y_start = fault_vector_functions.add_vector_to_point(x_start, y_start, downdip_width_proj/2, # one_fault["strike"] - 90); # ^^ offset the fault location for center. Optional/unknown. corner_lon, corner_lat = fault_vector_functions.xy2lonlat( x_start, y_start, lon_top_center, lat_top_center) one_fault["lon"] = corner_lon one_fault["lat"] = corner_lat fault_list.append(one_fault) ifile.close() print(" -->Returning %d fault segments" % len(fault_list)) return fault_list
def map_stress_plot(params, inputs, out_object, stress_component): """ Using PyGMT Filling in fault patches with colors corresponding to their stress changes """ if stress_component == 'shear': plotting_stress = out_object.receiver_shear label = 'Shear' elif stress_component == 'normal': plotting_stress = out_object.receiver_normal label = 'Normal' else: plotting_stress = out_object.receiver_coulomb # The default option label = 'Coulomb' if not out_object.receiver_object: return # Make stress bounds for color map. vmin, vmax = -1, 1 [cmap_opts, cbar_opts] = utilities.define_colorbar_series(plotting_stress, vmin=vmin, vmax=vmax) # Make cpt pygmt.makecpt(cmap="jet", series=str(cmap_opts[0]) + "/" + str(cmap_opts[1]) + "/" + str(cmap_opts[2]), output="mycpt.cpt", background=True) # Make Map region = [inputs.minlon, inputs.maxlon, inputs.minlat, inputs.maxlat] proj = "M7i" fig = pygmt.Figure() title = "+t\"" + stress_component + " stress\"" # must put escaped quotations around the title. fig.basemap(region=region, projection=proj, frame=title) fig.coast(shorelines="1.0p,black", region=region, borders="1", projection=proj, frame="1.0") # the boundary. fig.coast(region=region, projection=proj, borders='2', shorelines='0.5p,black', water='white', map_scale="g-125.5/39.6+c1.5+w50") fig = annotate_figure_with_sources(fig, inputs, params) # Draw each receiver, with associated data for i in range(len(out_object.receiver_object)): rec = out_object.receiver_object[i] [x_total, y_total, _, _] = conversion_math.get_fault_four_corners(rec) lons, lats = fault_vector_functions.xy2lonlat(x_total, y_total, inputs.zerolon, inputs.zerolat) fig.plot(x=lons, y=lats, zvalue=str(plotting_stress[i]), pen="thick,black", color="+z", cmap="mycpt.cpt") # color = stress # Colorbar annotation fig.coast(shorelines="1.0p,black", region=region, projection=proj) # the boundary. fig.colorbar(position="jBr+w3.5i/0.2i+o2.5c/1.5c+h", cmap="mycpt.cpt", shading="0.8", truncate=str(cbar_opts[0]) + "/" + str(cbar_opts[1]), frame=["x" + str(0.2), "y+L\"KPa\""]) # Annotate with aftershock locations fig = annotate_figure_with_aftershocks(fig, aftershocks_file=params.aftershocks, style='c0.02c') fig.savefig(params.outdir + label + '_map.png') return