def test_check_mesh(): # Bad class name. grid = meshes.BaseMesh(h=[2, 2, 2], origin=(0, 0, 0)) grid.__class__.__name__ = 'Test' with pytest.raises(TypeError, match="Mesh must be a TensorMesh."): meshes.check_mesh(grid) # Wrong dimension. if discretize is None: grid = meshes.TensorMesh(h=[2, 2, 2], origin=(0, 0, 0)) grid.origin = (0, 0) else: grid = meshes.TensorMesh(h=[2, 2], origin=(0, 0)) with pytest.raises(TypeError, match="Mesh must be a 3D mesh."): meshes.check_mesh(grid) # Bad cell number. grid = meshes.TensorMesh(h=[[2, ], [2, ], [2, 2]], origin=(0, 0, 0)) with pytest.warns(UserWarning, match='ptimal for MG solver. Good numbers'): meshes.check_mesh(grid) # A good one, nothing should happen. hx = np.ones(16)*20 grid = meshes.TensorMesh(h=[hx, hx, hx], origin=(0, 0, 0)) meshes.check_mesh(grid)
def to_dict(self, copy=False): """Store the necessary information of the Field in a dict. Parameters ---------- copy : bool, default: False If True, returns a deep copy of the dict. Returns ------- out : dict Dictionary containing all information to re-create the Field. """ out = { '__class__': self.__class__.__name__, # v ensure emg3d-TensorMesh 'grid': meshes.TensorMesh(self.grid.h, self.grid.origin).to_dict(), 'data': self._field, 'frequency': self._frequency, 'electric': self.electric, } if copy: return deepcopy(out) else: return out
def _dict_serialize(inp): """Serialize emg3d-classes and other objects in inp-dict. Returns a serialized dictionary <out> of <inp>, where all members of `emg3d.utils._KNOWN_CLASSES` are serialized with their respective `to_dict()` methods. Any other (non-emg3d) object can be added too, as long as it knows how to serialize itself. There are some limitations: 1. Key names are converted to strings. 2. None values are converted to 'NoneType'. 3. TensorMesh instances from discretize will be stored as if they would be simpler emg3d.TensorMesh instances. Parameters ---------- inp : dict Input dictionary to serialize. Returns ------- out : dict Serialized <inp>-dict. """ # Initiate output dictionary. out = {} # Loop over items. for key, value in inp.items(): # Serialize known classes. if isinstance(value, tuple(utils._KNOWN_CLASSES.values())): # Workaround for discretize.TensorMesh (store as emg3d.TensorMesh) if hasattr(value, 'face_areas'): value = meshes.TensorMesh(value.h, value.origin) # Serialize. value = value.to_dict() # If value is a dict we use recursion if isinstance(value, dict): value = _dict_serialize(value) # Limitation 1: None -> 'NoneType' elif value is None: value = 'NoneType' # Store value # Limitation 2: Cast keys -> str(key) out[str(key)] = value return out
def to_dict(self, copy=False): """Store the necessary information in a dict for serialization. Parameters ---------- copy : bool, default: False If True, returns a deep copy of the dict. Returns ------- out : dict Dictionary containing all information to re-create the Model. """ out = { '__class__': self.__class__.__name__, # v ensure emg3d-TensorMesh 'grid': meshes.TensorMesh(self.grid.h, self.grid.origin).to_dict(), **{prop: getattr(self, prop) for prop in self._properties}, 'mapping': self.map.name, } if copy: return deepcopy(out) else: return out
def test_TensorMesh_repr(self): # Create some dummy data grid = meshes.TensorMesh( [np.ones(2), np.ones(2), np.ones(2)], np.zeros(3)) # Check representation of TensorMesh. if discretize is None: assert 'TensorMesh: 2 x 2 x 2 (8)' in grid.__repr__() assert not hasattr(grid, '_repr_html_') else: assert 'TensorMesh: 8 cells' in grid.__repr__() assert hasattr(grid, '_repr_html_')
def test_TensorMesh(self): # Load mesh created with discretize.TensorMesh. grid = REGRES['grid'] grid['h'] = [grid.pop('hx'), grid.pop('hy'), grid.pop('hz')] mesh = meshes.BaseMesh(grid['h'], origin=grid['origin']) # Use this grid instance to create emg3d equivalent. emg3dgrid = meshes.TensorMesh(grid['h'], origin=grid['origin']) # Ensure they are the same. for key, value in grid.items(): if key == 'h': for i in range(3): assert_allclose(value[i], getattr(emg3dgrid, key)[i]) else: assert_allclose(value, getattr(emg3dgrid, key)) # Copy cgrid = emg3dgrid.copy() assert_allclose(cgrid.cell_volumes, emg3dgrid.cell_volumes) dgrid = emg3dgrid.to_dict() cdgrid = meshes.TensorMesh.from_dict(dgrid.copy()) assert_allclose(cdgrid.cell_volumes, emg3dgrid.cell_volumes) del dgrid['hx'] with pytest.raises(KeyError, match="'hx'"): meshes.TensorMesh.from_dict(dgrid) # Check __eq__. assert emg3dgrid == cgrid newgrid = meshes.TensorMesh( [np.ones(3), np.ones(3), np.ones(3)], np.zeros(3)) assert emg3dgrid != newgrid assert 'TensorMesh: 40 x 30 x 1 (1,200)' in mesh.__repr__() assert not hasattr(mesh, '_repr_html_') assert mesh.cell_volumes.sum() > 69046392
class TestEstimateGriddingOpts(): if xarray is not None: # Create a simple survey sources = emg3d.surveys.txrx_coordinates_to_dict( emg3d.TxElectricDipole, (0, [1000, 3000, 5000], -950, 0, 0)) receivers = emg3d.surveys.txrx_coordinates_to_dict( emg3d.RxElectricPoint, (np.arange(11)*500, 2000, -1000, 0, 0)) frequencies = (0.1, 10.0) survey = emg3d.Survey( sources, receivers, frequencies, noise_floor=1e-15, relative_error=0.05) # Create a simple grid and model grid = meshes.TensorMesh( [np.ones(32)*250, np.ones(16)*500, np.ones(16)*500], np.array([-1250, -1250, -2250])) model = emg3d.Model(grid, 0.1, np.ones(grid.shape_cells)*10) model.property_y[5, 8, 3] = 100000 # Cell at source center def test_empty_dict(self): gdict = meshes.estimate_gridding_opts({}, self.model, self.survey) assert gdict['frequency'] == 1.0 assert gdict['mapping'] == self.model.map.name assert_allclose(gdict['center'], (0, 3000, -950)) assert_allclose(gdict['domain']['x'], (-500, 5500)) assert_allclose(gdict['domain']['y'], (600, 5400)) assert_allclose(gdict['domain']['z'], (-3651, -651)) assert_allclose(gdict['properties'], [100000, 10, 10, 10, 10, 10, 10]) def test_mapping_vector(self): gridding_opts = { 'mapping': "LgConductivity", 'vector': 'xZ', } gdict = meshes.estimate_gridding_opts( gridding_opts, self.model, self.survey) assert_allclose( gdict['properties'], np.log10(1/np.array([100000, 10, 10, 10, 10, 10, 10])), atol=1e-15) assert_allclose(gdict['vector']['x'], self.grid.nodes_x) assert gdict['vector']['y'] is None assert_allclose(gdict['vector']['z'], self.grid.nodes_z) def test_vector_domain_distance(self): gridding_opts = { 'vector': 'Z', 'domain': (None, [-1000, 1000], None), 'distance': [[5, 10], None, None], } gdict = meshes.estimate_gridding_opts( gridding_opts, self.model, self.survey) assert gdict['vector']['x'] == gdict['vector']['y'] is None assert_allclose(gdict['vector']['z'], self.model.grid.nodes_z) assert gdict['domain']['x'] is None assert gdict['domain']['y'] == [-1000, 1000] assert gdict['domain']['z'] == [self.model.grid.nodes_z[0], self.model.grid.nodes_z[-1]] assert gdict['distance']['x'] == [5, 10] assert gdict['distance']['y'] == gdict['distance']['z'] is None # As dict gridding_opts = { 'vector': 'Z', 'domain': {'x': None, 'y': [-1000, 1000], 'z': None}, 'distance': {'x': [5, 10], 'y': None, 'z': None}, } gdict = meshes.estimate_gridding_opts( gridding_opts, self.model, self.survey) assert gdict['vector']['x'] == gdict['vector']['y'] is None assert_allclose(gdict['vector']['z'], self.model.grid.nodes_z) assert gdict['domain']['x'] is None assert gdict['domain']['y'] == [-1000, 1000] assert gdict['domain']['z'] == [self.model.grid.nodes_z[0], self.model.grid.nodes_z[-1]] assert gdict['distance']['x'] == [5, 10] assert gdict['distance']['y'] == gdict['distance']['z'] is None def test_pass_along(self): gridding_opts = { 'vector': {'x': None, 'y': 1, 'z': None}, 'stretching': [1.2, 1.3], 'seasurface': -500, 'cell_numbers': [10, 20, 30], 'lambda_factor': 0.8, 'max_buffer': 10000, 'min_width_limits': ([20, 40], [20, 40], [20, 40]), 'min_width_pps': 4, 'verb': -1, } gdict = meshes.estimate_gridding_opts( gridding_opts.copy(), self.model, self.survey) # Check that all parameters passed unchanged. gdict2 = {k: gdict[k] for k, _ in gridding_opts.items()} # Except the tuple, which should be a dict now gridding_opts['min_width_limits'] = { 'x': gridding_opts['min_width_limits'][0], 'y': gridding_opts['min_width_limits'][1], 'z': gridding_opts['min_width_limits'][2] } assert helpers.compare_dicts(gdict2, gridding_opts) def test_factor(self): sources = emg3d.TxElectricDipole((0, 3000, -950, 0, 0)) receivers = emg3d.RxElectricPoint((0, 3000, -1000, 0, 0)) # Adjusted x-domain. survey = emg3d.Survey( self.sources, receivers, self.frequencies, noise_floor=1e-15, relative_error=0.05) gdict = meshes.estimate_gridding_opts({}, self.model, survey) assert_allclose(gdict['domain']['x'], (-800, 800)) # Adjusted x-domain. survey = emg3d.Survey( sources, self.receivers, self.frequencies, noise_floor=1e-15, relative_error=0.05) gdict = meshes.estimate_gridding_opts({}, self.model, survey) assert_allclose(gdict['domain']['y'], (1500, 3500)) def test_error(self): with pytest.raises(TypeError, match='Unexpected gridding_opts'): _ = meshes.estimate_gridding_opts( {'what': True}, self.model, self.survey)
def expand_grid_model(model, expand, interface): """Expand model and grid according to provided parameters. Expand the grid and corresponding model in positive z-direction from the edge of the grid to the interface with property ``expand[0]``, and a 100 m thick layer above the interface with property ``expand[1]``. The provided properties are taken as isotropic (as is the case in water and air); ``mu_r`` and ``epsilon_r`` are expanded with ones, if necessary. The ``interface`` is usually the sea-surface, and ``expand`` is therefore ``[property_sea, property_air]``. Parameters ---------- model : Model The model; a :class:`emg3d.models.Model` instance. expand : list The two properties below and above the interface: ``[below_interface, above_interface]``. interface : float Interface between the two properties in ``expand``. Returns ------- exp_grid : TensorMesh Expanded grid; a :class:`emg3d.meshes.TensorMesh` instance. exp_model : Model The expanded model; a :class:`emg3d.models.Model` instance. """ grid = model.grid def extend_property(prop, add_values, nadd): """Expand property `model.prop`, IF it is not None.""" if getattr(model, prop) is None: prop_ext = None else: prop_ext = np.zeros((grid.shape_cells[0], grid.shape_cells[1], grid.shape_cells[2] + nadd)) prop_ext[:, :, :-nadd] = getattr(model, prop) if nadd == 2: prop_ext[:, :, -2] = add_values[0] prop_ext[:, :, -1] = add_values[1] return prop_ext # Initiate. nzadd = 0 hz_ext = grid.h[2] # Fill-up property_below. if grid.nodes_z[-1] < interface - 0.05: # At least 5 cm. hz_ext = np.r_[hz_ext, interface - grid.nodes_z[-1]] nzadd += 1 # Add 100 m of property_above. if grid.nodes_z[-1] <= interface + 0.001: # +1mm hz_ext = np.r_[hz_ext, 100] nzadd += 1 if nzadd > 0: # Extend properties. property_x = extend_property('property_x', expand, nzadd) property_y = extend_property('property_y', expand, nzadd) property_z = extend_property('property_z', expand, nzadd) mu_r = extend_property('mu_r', [1, 1], nzadd) epsilon_r = extend_property('epsilon_r', [1, 1], nzadd) # Create extended grid and model. grid = meshes.TensorMesh([grid.h[0], grid.h[1], hz_ext], origin=grid.origin) model = Model(grid, property_x, property_y, property_z, mu_r, epsilon_r, mapping=model.map.name) return model