def clip_modem_model(model_fn, clip): """ Read in ModEM model and clip to a smaller box """ m_obj = modem.Model() m_obj.read_model_file(model_fn) ### --> need to convert model coordinates into lat and lon utm_center = gis_tools.project_point_ll2utm(model_center[1], model_center[0]) lat = np.zeros_like(m_obj.grid_north[clip:-(clip + 1)]) lon = np.zeros_like(m_obj.grid_east[clip:-(clip + 1)]) depth = m_obj.grid_z[:-1] / 1000.0 for ii, north in enumerate(m_obj.grid_north[clip:-(clip + 1)]): m_lat, m_lon = gis_tools.project_point_utm2ll(utm_center[0], utm_center[1] + north, utm_center[2]) lat[ii] = m_lat for ii, east in enumerate(m_obj.grid_east[clip:-(clip + 1)]): m_lat, m_lon = gis_tools.project_point_utm2ll(utm_center[0] + east, utm_center[1], utm_center[2]) lon[ii] = m_lon res = np.log10(m_obj.res_model[clip:-clip, clip:-clip, :]) return lat, lon, depth, res
def test_project_point_utm2ll(self): new_lat, new_lon = project_point_utm2ll(self.easting, self.northing, self.zone) print(new_lat, new_lon) self.assertTrue(np.isclose(self.lat, new_lat)) self.assertTrue(np.isclose(self.lon, new_lon)) # testing with epsg new_lat, new_lon = project_point_utm2ll(self.easting, self.northing, utm_zone=self.zone, epsg=self.to_epsg) print(new_lat, new_lon) self.assertTrue(np.isclose(self.lat, new_lat)) self.assertTrue(np.isclose(self.lon, new_lon))
def center_point(self): """ calculate the center point from the given station locations Returns ------------- **center_location** : np.ndarray structured array of length 1 dtype includes (east, north, zone, lat, lon) """ dtype = [('lat', np.float), ('lon', np.float), ('east', np.float), ('north', np.float), ('elev', np.float), ('zone', 'S4')] center_location = np.recarray(1, dtype=dtype) # AK - using the mean here but in get_relative_locations used (max + min)/2, why??? # center_point = np.array([self.east.mean(), self.north.mean()]) # # #translate the stations so they are relative to 0,0 # east_center = (self.rel_east.max()-np.abs(self.rel_east.min()))/2 # north_center = (self.rel_north.max()-np.abs(self.rel_north.min()))/2 # # center_point[0] -= east_center # center_point[1] -= north_center # # # calculate center point in lat, lon, easting, northing # center_location['east'] = center_point[0] # center_location['north'] = center_point[1] center_point = np.array([ self.east.max() + self.east.min(), self.north.max() + self.north.min() ]) / 2. center_location['east'] = center_point[0] center_location['north'] = center_point[1] center_location['zone'] = self.utm_zone[0] center_ll = gis_tools.project_point_utm2ll(float(center_point[0]), float(center_point[1]), self.utm_zone[0], epsg=self.model_epsg) center_location['lat'] = center_ll[0] center_location['lon'] = center_ll[1] # BM: Because we are now writing center_point.elev to ModEm # data file, we need to provide it. # The center point elevation is the highest point of the # model. Before topography is applied, this is the highest # station. After it's applied, it's the highest point # point of the surface model (this will be set by calling # Data.project_stations_on_topography). center_location['elev'] = self.elev.max() return center_location
def center_point(self): """ calculate the center point from the given station locations Returns ------------- **center_location** : np.ndarray structured array of length 1 dtype includes (east, north, zone, lat, lon) """ center_location = np.recarray(1, dtype=self.dtype) # AK - using the mean here but in get_relative_locations used (max + min)/2, why??? # center_point = np.array([self.east.mean(), self.north.mean()]) # # #translate the stations so they are relative to 0,0 # east_center = (self.rel_east.max()-np.abs(self.rel_east.min()))/2 # north_center = (self.rel_north.max()-np.abs(self.rel_north.min()))/2 # # center_point[0] -= east_center # center_point[1] -= north_center # # # calculate center point in lat, lon, easting, northing # center_location['east'] = center_point[0] # center_location['north'] = center_point[1] center_point = np.array([ self.east.max() + self.east.min(), self.north.max() + self.north.min() ]) / 2. center_location['east'] = center_point[0] center_location['north'] = center_point[1] center_location['zone'] = self.utm_zone[0] center_ll = gis_tools.project_point_utm2ll(float(center_point[0]), float(center_point[1]), self.utm_zone[0], epsg=self.model_epsg) center_location['lat'] = center_ll[0] center_location['lon'] = center_ll[1] return center_location
def get_profile_specs(o2d_data, site_easts, site_norths): """ Get specifications for the MARE2D profile line from Occam2D profile. Parameters ---------- m2d_profile : mtpy.modeling.occam2d.Data Occam2D data object that has been initialised with EDI data. site_easts : np.ndarray 1D array of floats of length n. Easting coordinates for the station locations. site_norths : np.ndarray 1D array of floats of length n. Northing coordinates for the station locations. Returns ------- tuple(float, ..., int, str) x0, y0: start of profile line. x1, y1: end of profile line. mare_origin_x, mare_origin_y: Origin of the Mare2D profile, which is the middle of the line. epsg: epsg code of the profile origin utm_zone: utm code of the profile origin (of form e.g. '54K S') """ m, c1 = o2d_data.profile_line # Find start of profile # Assume that the start of the profile always has minimum eastings x0 = site_easts.min() y0 = m * x0 + c1 # Find end of the profile # Assume y1 as the maximum northing x1 = site_easts.max() y1 = m * x1 + c1 # Mare2D origin (middle of profile line) mare_origin_x = (site_easts.min() + site_easts.max()) / 2 mare_origin_y = (site_norths.min() + site_norths.max()) / 2 # UTM zone of Mare2D profile epsg = o2d_data.model_epsg projected_origin = gis_tools.project_point_utm2ll(mare_origin_x, mare_origin_y, None, epsg=epsg) utm_zone = gis_tools.get_utm_zone(projected_origin[0], projected_origin[1])[2] return (x0, y0, x1, y1, mare_origin_x, mare_origin_y, epsg, utm_zone)
def get_model_lower_left_coord(self, model_fn=None, model_center=None, pad_east=0, pad_north=0): """ Find the models lower left hand corner in (lon, lat) decimal degrees """ if model_fn is not None: self.model_fn = model_fn if self.model_fn is None: raise IOError('Need to input a ModEM model file name to read in') self.pad_east = pad_east self.pad_north = pad_north model_obj = modem.Model() model_obj.model_fn = self.model_fn model_obj.read_model_file() if model_center: center_zone, center_east, center_north = gis_tools.project_point_ll2utm( model_center[1], model_center[0]) lower_left_east = center_east+model_obj.grid_center[1]+\ model_obj.nodes_east[0:pad_east].sum()-\ model_obj.nodes_east[pad_east]/2 lower_left_north = center_north+model_obj.grid_center[1]+\ model_obj.nodes_north[0:pad_north].sum()+\ model_obj.nodes_north[pad_north]/2 ll_lat, ll_lon = gis_tools.project_point_utm2ll( lower_left_north, lower_left_east, center_zone) print 'Lower Left Coordinates should be ({0:.5f}, {1:.5f})'.format( ll_lon, ll_lat) return (ll_lon, ll_lat) else: raise IOError('Need to input model center (lon, lat)')
model_center = (45.654713, -118.547148) model_center_ne = gis_tools.project_point_ll2utm( model_center[0], model_center[1], epsg=26911 ) m_obj = modem.Model() m_obj.read_model_file(mfn) # need to make a lat and lon list lat = np.zeros(m_obj.nodes_north.size) lon = np.zeros(m_obj.nodes_east.size) for ii, north in enumerate(model_center_ne[0] - m_obj.grid_north[:-1]): lat_00, lon_00 = gis_tools.project_point_utm2ll( north, model_center_ne[1], model_center_ne[2] ) lat[ii] = lat_00 for ii, east in enumerate(model_center_ne[1] - m_obj.grid_east[:-1]): lat_00, lon_00 = gis_tools.project_point_utm2ll( model_center_ne[0], east, model_center_ne[2] ) lon[ii] = lon_00 # nc_obj = netCDF4.Dataset(m_obj.model_fn[:-4]+'.nc', 'w', format='NETCDF4') nc_obj = netCDF4.Dataset( r"c:\Users\jpeacock\OneDrive - DOI\Geothermal\Umatilla\modem_inv\inv_09\um_z05_c025_086.nc", "w", format="NETCDF4", )
dtype=dtypes) except pd._libs.parsers.ParserError: df = pd.read_csv(txt_fn, skiprows=1, delimiter=r"\s+", usecols=(0, 1, 2, 3, 4), names=cols, dtype=dtypes) for col in cols: df_dict[col] += df[col].to_list() geometry = [] stations = {'ID': [], 'elev': [], 'lat': [], 'lon': []} for index in range(len(df_dict['station'])): lon, lat = gis_tools.project_point_utm2ll(df_dict['easting'][index], df_dict['northing'][index], df_dict['zone'][index], datum='NAD83') geometry.append(Point(lon, lat)) stations['ID'].append(df_dict['station'][index]) stations['elev'].append(df_dict['elevation'][index]) stations['lat'].append(lat) stations['lon'].append(lon) gdf = gpd.GeoDataFrame(stations, crs=crs, geometry=geometry) gdf.to_file(r"c:\Users\jpeacock\OneDrive - DOI\EDI_FILES\wannamaker.kml", driver='kml') gdf.to_file(r"c:\Users\jpeacock\OneDrive - DOI\EDI_FILES\wannamaker.shp", driver='ESRI Shapefile')
spacing_east = 1000. spacing_north = 1000. east_arr = np.arange(ll_utm['easting_min'], ll_utm['easting_max'] + spacing_east, spacing_east) north_arr = np.arange(ll_utm['northing_min'], ll_utm['northing_max'] + spacing_east, spacing_east) kml_fn = r"c:\Users\jpeacock\Documents\Geothermal\Umatilla\um_phase_02_mt_stations_{0:.0f}m.kml".format( spacing_east) kml_obj = skml.Kml() count = 200 for ii, east in enumerate(east_arr): print '-' * 30 for jj, north in enumerate(north_arr): print east, north lat_ii, lon_jj = gis_tools.project_point_utm2ll( east, north, ll_utm['zone']) kml_obj.newpoint(name='um{0:03}'.format(count), coords=[(lon_jj, lat_ii)]) count += 1 kml_obj.save(kml_fn) print 'Number of stations: {0}'.format(count + 1)
data_epsg = 26911 model_center = (35.488658, -115.494148) dfn = r"c:\Users\jpeacock\Documents\MountainPass\modem_inv\inv_07\mp_modem_data_z03_topo_edit.dat" if dfn is not None: d_obj = modem.Data() d_obj.read_data_file(dfn) # ============================================================================= # Load in file # ============================================================================= a = np.loadtxt(fn, skiprows=3, dtype=np.float, delimiter=None).T ### compute the lower left hand corner of the raster lower_left = gis_tools.project_point_utm2ll(a[1].min(), a[0].min(), utm_zone) lower_left = (a[1].min(), a[0].min()) east, north, zone = gis_tools.project_points_ll2utm(a[1], a[0], datum='NAD27') ### make equally spaced points on regular grid x_new = np.linspace(east.min(), east.max(), num=(east.max() - east.min()) / d) y_new = np.linspace(north.min(), north.max(), num=(north.max() - north.min()) / d) xg, yg = np.meshgrid(x_new, y_new) ### interpolate the data onto a regular grid basement = interpolate.griddata((east, north), -1 * a[2], (xg, yg),
# ============================================================================= # Read in model file # ============================================================================= m_obj = modem.Model() m_obj.read_model_file(model_fn) ### --> need to convert model coordinates into lat and lon utm_center = gis_tools.project_point_ll2utm(model_center[1], model_center[0]) lat = np.zeros_like(m_obj.grid_north[clip:-(clip + 1)]) lon = np.zeros_like(m_obj.grid_east[clip:-(clip + 1)]) depth = m_obj.grid_z[:-1] / 1000. for ii, north in enumerate(m_obj.grid_north[clip:-(clip + 1)]): m_lat, m_lon = gis_tools.project_point_utm2ll(utm_center[0], utm_center[1] + north, utm_center[2]) lat[ii] = m_lat for ii, east in enumerate(m_obj.grid_east[clip:-(clip + 1)]): m_lat, m_lon = gis_tools.project_point_utm2ll(utm_center[0] + east, utm_center[1], utm_center[2]) lon[ii] = m_lon # ============================================================================= # Create NetCDF4 dataset compliant with IRIS format # ============================================================================= dataset = netcdf.Dataset(save_fn, 'w', format='NETCDF4') dataset.title = "Electrical Resistivity Model" dataset.id = "iMUSH_MT_2018" dataset.summary = "Crustal resistivity model of Mount St. Helens and surrounding \n"+\ "area estimated from magnetotelluric data part of the iMUSH project. \n"+\
def interpolate_elevation_to_grid(grid_east, grid_north, epsg=None, utm_zone=None, surfacefile=None, surface=None, method='linear', fast=True): """ project a surface to the model grid and add resulting elevation data to a dictionary called surface_dict. Assumes the surface is in lat/long coordinates (wgs84) The 'fast' method extracts a subset of the elevation data that falls within the mesh-bounds and interpolates them onto mesh nodes. This approach significantly speeds up (~ x5) the interpolation procedure. **returns** nothing returned, but surface data are added to surface_dict under the key given by surfacename. **inputs** choose to provide either surface_file (path to file) or surface (tuple). If both are provided then surface tuple takes priority. surface elevations are positive up, and relative to sea level. surface file format is: ncols 3601 nrows 3601 xllcorner -119.00013888889 (longitude of lower left) yllcorner 36.999861111111 (latitude of lower left) cellsize 0.00027777777777778 NODATA_value -9999 elevation data W --> E N | V S Alternatively, provide a tuple with: (lon,lat,elevation) where elevation is a 2D array (shape (ny,nx)) containing elevation points (order S -> N, W -> E) and lon, lat are either 1D arrays containing list of longitudes and latitudes (in the case of a regular grid) or 2D arrays with same shape as elevation array containing longitude and latitude of each point. other inputs: surfacename = name of surface for putting into dictionary surface_epsg = epsg number of input surface, default is 4326 for lat/lon(wgs84) method = interpolation method. Default is 'nearest', if model grid is dense compared to surface points then choose 'linear' or 'cubic' """ # read the surface data in from ascii if surface not provided if surface is None: surface = mtfh.read_surface_ascii(surfacefile) x, y, elev = surface # if lat/lon provided as a 1D list, convert to a 2d grid of points if len(x.shape) == 1: x, y = np.meshgrid(x, y) if len(grid_east.shape) == 1: grid_east, grid_north = np.meshgrid(grid_east, grid_north) if (fast): buffer = 1 # use a buffer of 1 degree around mesh-bounds mlatmin, mlonmin = gis_tools.project_point_utm2ll(grid_east.min(), grid_north.min(), epsg=epsg, utm_zone=utm_zone) mlatmax, mlonmax = gis_tools.project_point_utm2ll(grid_east.max(), grid_north.max(), epsg=epsg, utm_zone=utm_zone) subsetIndices = (x >= mlonmin-buffer) & \ (x <= mlonmax+buffer) & \ (y >= mlatmin-buffer) & \ (y <= mlatmax+buffer) x = x[subsetIndices] y = y[subsetIndices] elev = elev[subsetIndices] # end if xs, ys, utm_zone = gis_tools.project_points_ll2utm(y, x, epsg=epsg, utm_zone=utm_zone) # elevation in model grid # first, get lat,lon points of surface grid points = np.vstack([arr.flatten() for arr in [xs, ys]]).T # corresponding surface elevation points values = elev.flatten() # xi, the model grid points to interpolate to xi = np.vstack([arr.flatten() for arr in [grid_east, grid_north]]).T # elevation on the centre of the grid nodes elev_mg = spi.griddata(points, values, xi, method=method).reshape(grid_north.shape) return elev_mg
def interpolate_elevation_to_grid(grid_east, grid_north, epsg=None, utm_zone=None, surfacefile=None, surface=None, method='linear', fast=True): """ # Note: this documentation is outdated and seems to be copied from # model.interpolate_elevation2. It needs to be updated. This # funciton does not update a dictionary but returns an array of # elevation data. project a surface to the model grid and add resulting elevation data to a dictionary called surface_dict. Assumes the surface is in lat/long coordinates (wgs84) The 'fast' method extracts a subset of the elevation data that falls within the mesh-bounds and interpolates them onto mesh nodes. This approach significantly speeds up (~ x5) the interpolation procedure. **returns** nothing returned, but surface data are added to surface_dict under the key given by surfacename. **inputs** choose to provide either surface_file (path to file) or surface (tuple). If both are provided then surface tuple takes priority. surface elevations are positive up, and relative to sea level. surface file format is: ncols 3601 nrows 3601 xllcorner -119.00013888889 (longitude of lower left) yllcorner 36.999861111111 (latitude of lower left) cellsize 0.00027777777777778 NODATA_value -9999 elevation data W --> E N | V S Alternatively, provide a tuple with: (lon,lat,elevation) where elevation is a 2D array (shape (ny,nx)) containing elevation points (order S -> N, W -> E) and lon, lat are either 1D arrays containing list of longitudes and latitudes (in the case of a regular grid) or 2D arrays with same shape as elevation array containing longitude and latitude of each point. other inputs: surfacename = name of surface for putting into dictionary surface_epsg = epsg number of input surface, default is 4326 for lat/lon(wgs84) method = interpolation method. Default is 'nearest', if model grid is dense compared to surface points then choose 'linear' or 'cubic' """ # read the surface data in from ascii if surface not provided if surfacefile: lon, lat, elev = mtfh.read_surface_ascii(surfacefile) elif surface: lon, lat, elev = surface else: raise ValueError("'surfacefile' or 'surface' must be provided") # if lat/lon provided as a 1D list, convert to a 2d grid of points if len(lon.shape) == 1: # BM: There seems to be an issue using dense grids (X and Y # become arrays of (N, N)), and get flattened to 1D array # of N^2 in point projection below. # Interpolation then can't be performed because # there's a dimension mismatch between lon/lat and elev. # This issue doesn't happen when using 'fast' method below, so # when not using fast, get a sparse grid instead. if fast: lon, lat = np.meshgrid(lon, lat) else: lon, lat = np.meshgrid(lon, lat, sparse=True) lat = lat.T if len(grid_east.shape) == 1: grid_east, grid_north = np.meshgrid(grid_east, grid_north) if (fast): buffer = 1 # use a buffer of 1 degree around mesh-bounds mlatmin, mlonmin = gis_tools.project_point_utm2ll(grid_east.min(), grid_north.min(), epsg=epsg, utm_zone=utm_zone) mlatmax, mlonmax = gis_tools.project_point_utm2ll(grid_east.max(), grid_north.max(), epsg=epsg, utm_zone=utm_zone) subsetIndices = (lon >= mlonmin - buffer) & \ (lon <= mlonmax + buffer) & \ (lat >= mlatmin - buffer) & \ (lat <= mlatmax + buffer) lon = lon[subsetIndices] lat = lat[subsetIndices] elev = elev[subsetIndices] # end if projected_points = gis_tools.project_point_ll2utm(lat, lon, epsg=epsg, utm_zone=utm_zone) # elevation in model grid # first, get lat,lon points of surface grid points = np.vstack([ arr.flatten() for arr in [projected_points.easting, projected_points.northing] ]).T # corresponding surface elevation points values = elev.flatten() # xi, the model grid points to interpolate to xi = np.vstack([arr.flatten() for arr in [grid_east, grid_north]]).T # elevation on the centre of the grid nodes elev_mg = spi.griddata(points, values, xi, method=method).reshape(grid_north.shape) return elev_mg
delimiter=r"\s+", usecols=(0, 1, 2, 3, 4), names=cols, dtype=dtypes, ) for col in cols: df_dict[col] += df[col].to_list() geometry = [] stations = {"ID": [], "elev": [], "lat": [], "lon": []} for index in range(len(df_dict["station"])): lon, lat = gis_tools.project_point_utm2ll( df_dict["easting"][index], df_dict["northing"][index], df_dict["zone"][index], datum="NAD83", ) geometry.append(Point(lon, lat)) stations["ID"].append(df_dict["station"][index]) stations["elev"].append(df_dict["elevation"][index]) stations["lat"].append(lat) stations["lon"].append(lon) gdf = gpd.GeoDataFrame(stations, crs=crs, geometry=geometry) gdf.to_file(r"c:\Users\jpeacock\OneDrive - DOI\EDI_FILES\wannamaker.kml", driver="kml") gdf.to_file( r"c:\Users\jpeacock\OneDrive - DOI\EDI_FILES\wannamaker.shp", driver="ESRI Shapefile", )