def compute_prem_load(station_array, load_array, disk_radius, greensfunc, max_distance): # For a given station and a given set of loads, # Compute the loading on a PREM earth structure # Max distance is in degrees total_disp_x, total_disp_y, total_disp_v = [], [], []; for i in range(len(station_array.lon)): # for each station... # Take a set of rectangular loads and tile them into disk loads. CircleLoads = get_disks(load_array, disk_radius, max_distance, station_array.lon[i], station_array.lat[i]); print("Number of circles: %d" % len(CircleLoads.lon)); disk_sum_v, disk_sum_x, disk_sum_y = 0, 0, 0; for j in range(np.size(CircleLoads.lon)): dist_from_center = haversine.distance([CircleLoads.lat[j], CircleLoads.lon[j]], [station_array.lat[i], station_array.lon[i]]); # reported in km myindex = find_closest_greens(greensfunc.km, dist_from_center); # find the nearest answer in the Green's functions vdisp = greensfunc.vload[myindex]; # in m hdisp = greensfunc.hload[myindex]; # in m [xdisp, ydisp] = az_decompose(hdisp, (station_array.lat[i], station_array.lon[i]), ( CircleLoads.lat[j], CircleLoads.lon[j])); # Decompose radial into x and y components disk_sum_v = disk_sum_v + vdisp * CircleLoads.pressure[ j] * 1000 / 9.81; # THIS SHOULD BE DIVIDED BY 9.81! the PREM code already has it. Result in mm disk_sum_x = disk_sum_x + xdisp * CircleLoads.pressure[ j] * 1000 / 9.81; # THIS SHOULD BE DIVIDED BY 9.81! the PREM code already has it. Result in mm disk_sum_y = disk_sum_y + ydisp * CircleLoads.pressure[ j] * 1000 / 9.81; # THIS SHOULD BE DIVIDED BY 9.81! the PREM code already has it. Result in mm total_disp_x.append(disk_sum_x); total_disp_y.append(disk_sum_y); total_disp_v.append(disk_sum_v); return total_disp_x, total_disp_y, total_disp_v; # should exactly match length of input station_array fields.
def evaluate_gradients(point1, point2, ascending1, ascending2, descending1, descending2): mydistance = haversine.distance([point1[1], point1[0]], [point2[1], point2[0]]) print( "Gradient in ASCENDING track from point1 to point2: %f mm/yr in %f km " % (np.abs(ascending1 - ascending2), mydistance)) print("Equal to: %f mm/yr per 100 km \n" % (100 * np.abs(ascending1 - ascending2) / mydistance)) print( "Gradient in DESCENDING track from point1 to point2: %f mm/yr in %f km " % (np.abs(descending1 - descending2), mydistance)) print("Equal to: %f mm/yr per 100 km \n" % (100 * np.abs(descending1 - descending2) / mydistance)) return
def compute_circle(myVelfield, center, radius): close_stations = [] rad_distance = [] lon, lat = [], [] for station_vel in myVelfield: mydist = haversine.distance([center[1], center[0]], [station_vel.nlat, station_vel.elon]) if mydist <= radius: rad_distance.append(mydist) lon.append(station_vel.elon) lat.append(station_vel.nlat) close_stations.append(station_vel.name) print("Returning %d stations within %.3f km of %.4f, %.4f" % (len(close_stations), radius, center[0], center[1])) return close_stations, lon, lat, rad_distance
def get_disks(load_array, disk_radius, threshold_distance, sta_lon, sta_lat): # threshold_distance is in degrees circle_lons, circle_lats, circle_radius, circle_pressure = [], [], [], []; threshold_distance = threshold_distance * (np.pi / 180) * 6370; # converting to km (6370km = 1 radian). circle_area = np.pi * disk_radius * disk_radius; # Area = pi * r^2 square_side_length = np.sqrt(circle_area); # in same units as disk_radius for i in range(len(load_array.lon)): # for each rectangular load cell if abs(load_array.lat[i]) > 85: # ignoring the arctic and antarctic continue; dist_from_center = haversine.distance([load_array.lat[i], load_array.lon[i]], [sta_lat, sta_lon]); # reported in km if dist_from_center < threshold_distance: # if the load cell is less than a certain distance from the station, discretize it. center = [load_array.lon[i], load_array.lat[i]]; load_akm = load_array.east_width[i] * 111.0 * np.cos(center[1] * np.pi / 180); load_bkm = load_array.north_width[i] * 111.0; # The placement of each disk-shaped tile within the load n_tiles_x = int(np.floor(load_akm * 2 / square_side_length)); n_tiles_y = int(np.floor(load_bkm * 2 / square_side_length)); # n tiles fitting in x and y dim of rectangle x_array, y_array = [], []; x_nodes = np.linspace(center[0] - load_array.east_width[i], center[0] + load_array.east_width[i], n_tiles_x + 1, endpoint=True); y_nodes = np.linspace(center[1] - load_array.north_width[i], center[1] + load_array.north_width[i], n_tiles_y + 1, endpoint=True); for j in range(len(x_nodes) - 1): x_array.append((x_nodes[j] + x_nodes[j + 1]) * 0.5); # average of two nodes for j in range(len(y_nodes) - 1): y_array.append((y_nodes[j] + y_nodes[j + 1]) * 0.5); # average of two nodes [centerx, centery] = np.meshgrid(x_array, y_array); centerx = np.reshape(centerx, (np.size(centerx), 1)) centery = np.reshape(centery, (np.size(centery), 1)) # HERE WE RE-PACKAGE INTO CIRCULAR LOADS for j in range(np.size(centerx)): circle_lons.append(centerx[j]); circle_lats.append(centery[j]); circle_radius.append(disk_radius); circle_pressure.append(load_array.pressure[i]); CircleLoads = helper_functions.Load_Array(lon=circle_lons, lat=circle_lats, east_width=circle_radius, north_width=[], pressure=circle_pressure); return CircleLoads;
def create_los_rdr_geo_from_ground_ann_file(ann_file, x_axis, y_axis): # Make los.rdr.geo given .ann file from JPL website's UAVSAR interferograms and the ground-range sample points. # x-axis and y-axis are the x and y arrays where los vectors will be extracted on a corresponding grid. near_angle, far_angle, heading = jpl_uav_read_write.get_nearrange_farrange_heading_angles( ann_file) heading_cartesian = insar_vector_functions.bearing_to_cartesian(heading) # CCW from east print("Heading is %f degrees CW from north" % heading) print("Cartesian Heading is %f" % heading_cartesian) # Get the upper and lower left corners, so we can compute the length of the across-track extent in km ul_lon, ul_lat, ll_lon, ll_lat = jpl_uav_read_write.get_ground_range_left_corners( ann_file) cross_track_max = haversine.distance((ll_lat, ll_lon), (ul_lat, ul_lon)) # in km # Get the azimuth angle for the pixels looking up to the airplane # My own documentation says CCW from north, even though that's really strange. azimuth = heading_cartesian - 90 # 90 degrees to the right of the airplane heading # (for the look vector from ground to plane) azimuth = insar_vector_functions.cartesian_to_ccw_from_north(azimuth) # degrees CCW from North print("azimuth from ground to plane is:", azimuth) [X, Y] = np.meshgrid(x_axis, y_axis) (ny, nx) = np.shape(X) grid_az = azimuth * np.ones(np.shape(X)) grid_inc = np.zeros(np.shape(X)) print("Computing incidence angles for all pixels") for i in range(ny): for j in range(nx): xtp = cross_track_pos(X[i, j], Y[i, j], ll_lon, ll_lat, heading_cartesian) # THIS WILL HAVE TO CHANGE FOR ASCENDING AND DESCENDING inc = incidence_angle_trig(xtp, cross_track_max, near_angle, far_angle) grid_inc[i, j] = inc # Finally, write the 2 bands for los.rdr.geo isce_read_write.write_isce_unw(grid_inc, grid_az, nx, ny, "FLOAT", 'los.rdr.geo') return
def vert_adjust_by_reference_stations(names, coords, slope_obj): # How do we adjust the verticals for large-scale drought signatures? reference_station = 'P208' coord_box = [-123, -121, 39, 42] eq_coords = [-124.81, 40.53] radius = 250 max_radius = 350 reference_type = 'radius' # options = 'radius','box','station' new_slope_obj = [] background_slopes_before = [] background_slopes_after = [] for i in range(len(names)): if reference_type == 'station': if names[i] == reference_station: background_slopes_before.append(slope_obj[i][0]) background_slopes_after.append(slope_obj[i][1]) elif reference_type == 'box': if coord_box[0] < coords[i][0] < coord_box[1]: if coord_box[2] < coords[i][1] < coord_box[3]: background_slopes_before.append(slope_obj[i][0]) background_slopes_after.append(slope_obj[i][1]) elif reference_type == 'radius': mydistance = haversine.distance([coords[i][1], coords[i][0]], [eq_coords[1], eq_coords[0]]) if radius < mydistance < max_radius: background_slopes_before.append(slope_obj[i][0]) background_slopes_after.append(slope_obj[i][1]) vert_reference_before = np.nanmean(background_slopes_before) vert_reference_after = np.nanmean(background_slopes_after) print("Vert slope before: %f " % vert_reference_before) print("Vert slope after: %f " % vert_reference_after) for i in range(len(slope_obj)): new_slope_obj.append([ slope_obj[i][0] - vert_reference_before, slope_obj[i][1] - vert_reference_after, slope_obj[i][2] ]) return new_slope_obj
def cross_track_pos(target_lon, target_lat, nearrange_lon, nearrange_lat, heading_cartesian): # Given the heading of a plane and the coordinates of one near-range point # Get the cross-track position of point in a coordinate system centered # at (nearrange_lon, nearrange_lat) with given heading distance = haversine.distance((target_lat, target_lon), (nearrange_lat, nearrange_lon)) compass_bearing = haversine.calculate_initial_compass_bearing( (nearrange_lat, nearrange_lon), (target_lat, target_lon)) # this comes CW from north theta = insar_vector_functions.bearing_to_cartesian(compass_bearing) # angle of position vector, cartesian coords # heading_cartesian is the angle between the east unit vector and the flight direction x0 = distance * np.cos(np.deg2rad(theta)) y0 = distance * np.sin(np.deg2rad(theta)) # in the east-north coordinate systeem x_prime, y_prime = insar_vector_functions.rotate_vector_by_angle( x0, y0, heading_cartesian) return y_prime
def get_nearest_pixel_in_raster(raster_lon, raster_lat, target_lon, target_lat): """Take a raster (2d arrays with lat and lon) and find the grid location closest to the target location This could be optimized with a distance formula or walking algorithm in the future. """ dist = np.zeros(np.shape(raster_lon)); lon_shape = np.shape(raster_lon); for i in range(lon_shape[0]): for j in range(lon_shape[1]): mypt = [raster_lat[i][j], raster_lon[i][j]]; dist[i][j] = haversine.distance((target_lat, target_lon), mypt); minimum_distance = np.nanmin(dist); if minimum_distance < 0.25: # if we're inside the domain. idx = np.where(dist == np.nanmin(dist)); i_found = idx[0][0]; j_found = idx[1][0]; print(raster_lon[i_found][j_found], raster_lat[i_found][j_found]); else: i_found, j_found = np.nan, np.nan; # error codes return i_found, j_found, minimum_distance;
def latlon2xy_single(loni, lati, lon0, lat0): """ Convert lon/lat coordinate into cartesian x/y coordinate using reference point. :param loni: longitude of target point :type loni: float :param lati: latitude of target point :type lati: float :param lon0: longitude of reference point :type lon0: float :param lat0: latitude of reference point :type lat0: float :returns: x, y of target point, in km :rtype: float, float """ radius = haversine.distance([lat0, lon0], [lati, loni]) bearing = haversine.calculate_initial_compass_bearing((lat0, lon0), (lati, loni)) azimuth = 90 - bearing x = radius * np.cos(np.deg2rad(azimuth)) y = radius * np.sin(np.deg2rad(azimuth)) return x, y
def get_nearest_pixel_in_raster(raster_lon, raster_lat, target_lon, target_lat): """ A very general function Take a 2D raster of lons and lats and find the grid location closest to the target location """ dist = np.zeros(np.shape(raster_lon)) lon_shape = np.shape(raster_lon) for i in range(lon_shape[0]): for j in range(lon_shape[1]): mypt = [raster_lat[i][j], raster_lon[i][j]] dist[i][j] = haversine.distance((target_lat, target_lon), mypt) minimum_distance = np.nanmin(dist) if minimum_distance < 0.25: # if we're inside the domain. idx = np.where(dist == np.nanmin(dist)) i_found = idx[0][0] j_found = idx[1][0] print(raster_lon[i_found][j_found], raster_lat[i_found][j_found]) else: i_found, j_found = -1, -1 # error codes return i_found, j_found
def split_fault_trace(fault_trace, typical_spacing_km): """ Algorithm: Walk up the fault in chunks. If the chunk is smaller than typical_spacing_km, it becomes one segment. Otherwise we split the segment into something similar to typical_spacing_km. Returns: (starting lon, starting_lat, strike, length, ending_lon, ending_lat) for each fault trace segment """ all_fault_segments = []; for i in range(1, len(fault_trace[0])): start_point = (fault_trace[1][i-1], fault_trace[0][i-1]); end_point = (fault_trace[1][i], fault_trace[0][i]); segment_distance = haversine.distance(start_point, end_point); strike = haversine.calculate_initial_compass_bearing(start_point, end_point); if segment_distance < typical_spacing_km: # for the really small segments one_fault_segment = (fault_trace[0][i-1], fault_trace[1][i-1], strike, segment_distance, fault_trace[0][i], fault_trace[1][i]); all_fault_segments.append(one_fault_segment); else: # the segments greater than 2x the characteristic spacing num_subsegments = int(np.ceil(segment_distance / typical_spacing_km)); # making segments < typical_spacing counter = [x for x in range(0, num_subsegments+1)]; lon_difference = fault_trace[0][i] - fault_trace[0][i-1]; lon_step = lon_difference / num_subsegments; lon_subarray = [fault_trace[0][i-1] + lon_step*x for x in counter]; # for x subsegments, we have x+1 elements in lon_subarray lat_difference = fault_trace[1][i] - fault_trace[1][i-1]; lat_step = lat_difference / num_subsegments; lat_subarray = [fault_trace[1][i-1] + lat_step*x for x in counter]; for j in range(1, len(lon_subarray)): one_fault_segment = (lon_subarray[j-1], lat_subarray[j-1], strike, segment_distance/num_subsegments, lon_subarray[j], lat_subarray[j]); all_fault_segments.append(one_fault_segment); print("Meshed fault trace of %d segments into %d segments " % (len(fault_trace[0]), len(all_fault_segments))); return all_fault_segments;