construct_mesh#
- emg3d.meshes.construct_mesh(frequency, properties, center, domain=None, vector=None, seasurface=None, **kwargs)[source]#
Return a TensorMesh for given input parameters.
Designing an appropriate grid is the most time-consuming part of any 3D modelling:
Cell sizes should be small enough to represent changes in the model as well as to minimize interpolation errors in the fields.
The computational domain has to be big enough to avoid effects from the boundary condition.
The total number of cells should be small to speed up computation.
These are in itself contradictory requirements, and they additionally depend all on the subsurface properties, the frequency under consideration, and the survey type.
This function is a helper routine to construct an appropriate grid. However, there is no guarantee that it is the best or even a good grid. (For this a solid grid-convergence test would be needed.) The constructed grid is frequency- and property-dependent. Some details are explained in other functions:
The minimum cell width \(\Delta_\text{min}\) is a function of
frequency
,properties[0]
,min_width_pps
, andmin_width_limits
, see Equation (36). (However, a providedvector
will overrule it.)The skin depth \(\delta\) is a function of
frequency
andproperties
, see Equation (34).The wavelength \(\lambda\) is a function of
frequency
andproperties
, see Equation (35).
The relation of the survey domain, computational domain, and buffer zone is shown in Figure 18 for a x-z-section; the y-direction behaves the same as the x-direction (the figures are only visible in the web version of the API docs on https://emg3d.emsig.xyz).
The buffer zone around the survey domain is by default one wavelength. This means that the signal has to travel two wavelengths to get from the end of the survey domain to the end of the computational domain and back. This approach is quite conservative and on the safe side. You can reduce the buffer thickness if you know what you are doing. There are three parameters which influence the thickness of the buffer for a given frequency:
properties
, which is used to calculate the skin depth and the wavelength,lambda_factor
(default is 1) which sets how many times the wavelength is the thickness of the buffer (relative factor), andmax_buffer
, which is an absolute maximum for the buffer thickness. A graphical illustration is given in Figure 19.- Parameters:
- frequencyfloat
Frequency (Hz) to calculate the skin depth; both the minimum cell width and the extent of the buffer zone, and therefore of the computational domain, are a function of skin depth.
- properties{float, array_like}
Properties to calculate the skin depths, which in turn are used to calculate the minimum cell width (usually at source location) and the extent of the buffer around the survey domain. The properties can be either resistivities, conductivities, or the logarithm (natural or base 10) thereof. By default it assumes resistivities, but it can be changed with the parameter
mapping
.Five formats are recognized for properties: it can either be a float or a list of 2, 3, 4, or 7 floats. Depending on the format these properties are used to calculate the following parameters:
p
: min_width and buffer in all directions;[p1, p2]
:p1
: min_width,p2
: buffer in all directions;
[p1, p2, p3]
:p1
: min_width,p2
: buffer in negative z-direction,p3
: buffer in all other directions;
[p1, p2, p3, p4]
:p1
: min_width,p2
: buffer in horizontal directions,p3
;p4
: buffer in negative; positive z-direction.
[p1, p2, p3, p4, p5, p6, p7]
:p1
: min_width,p2
;p3
: buffer in negative; positive x-direction,p4
;p5
: buffer in negative; positive y-direction,p6
;p7
: buffer in negative; positive z-direction.
- centerarray_like
Center coordinates (x, y, z). The mesh is centered around this point, which means that it is the location of the smallest cell. Usually this is the source location. Note that from v1.9.0 the default will change: until then, the center is assumed to be at the edge; from v1.9.0 onwards, it is assumed to be at the cell center. It can be changed via the parameter
center_on_edge
.- domain{tuple, list, dict, None}, optional
Contains the survey-domain limits. This domain should include all source and receiver positions as well as any important feature of the model. Format:
([xmin, xmax], [ymin, ymax], [zmin, zmax])
or{'x': [xmin, xmax], 'y': [ymin, ymax], 'z': [zmin, zmax]}
.It can be None, or individual lists can be None (e.g.,
(None, None, [zmin, zmax])
), in which case you have to provide either the correspondingdistance
or avector
, from which the domain is then calculated. If only one list is provided it is applied to all dimensions.- distance{tuple, list, dict, None}, optional
An alternative to
domain
: Instead of defining the domain in absolute values, they are defined here as distance from the center. Format:([xl, xr], [yl, yr], [zd, zu])
or{'x': [xl, xr], 'y': [yl, yr], 'z': [zd, zu]}
. From this the domain is given as([cx-xl, cx+xr], [cy-yl, cy+yr], [cz-zd, cz+zu])
, wherecenter=(cx, cy, cz)
.- vector{tuple, ndarray, dict, None}, optional
Contains vectors of mesh-edges that should be used. Format:
(xvector, yvector, zvector)
or{'x': xvector, 'y': yvector, 'z': zvector}
.If also
domain
ordistance
is defined, the following happens:There must be at least two cells within the domain, otherwise
vector
is set to None.Where the
vector
is outside the domain, it will be trimmed to it.Where the
vector
is smaller than the domain, it will be extended following the normal rules. The last cell-width in each direction will be taken as starting cell width, together with the domain stretching factor.
It can be None, or individual ndarrays can be None (e.g.,
(xvector, yvector, None)
), in which case you have to provide adomain
ordistance
. If only one ndarray is provided it is applied to all dimensions.- center_on_edge{tuple, bool, dict, None}, optional
Contains booleans defining if center is at the edge or at the cell center. Format:
None
,bool
,(xbool, ybool, zbool)
or{'x': xbool, 'y': ybool, 'z': zbool}
.Only relevant if no vector is provided in given direction.
- seasurfacefloat, default: None
Air-sea interface, has to be above the center. This has only to be set in the marine case, when the mesh in z-direction is sought for (and the seasurface is not contained in
vector
). If set, it will try to ensure that at the sea surface is an actual boundary.If the seasurface lies higher than the survey domain it will increase the survey domain to include the seasurface.
If the seasurface is too close to the center it will most likely fail to find a good grid. It will still create the grid, raising a warning that the seasurface is not at an actual boundary.
- stretching{tuple, list, dict}, default: [1.0, 1.5]
Maximum stretching factors in the form of
[max Ds, max Dc]
: the first value is the maximum stretching for the survey domain (default is 1.0), the second value is the maximum stretching for the buffer zone (default is 1.5). If a list is provided the same is used for all three dimension. Alternatively a tuple of three lists can be provided,(x, y, z)
or{'x': x, 'y': y, 'z': z}
. Note that the first value has no influence on dimensions where avector
is provided.- min_width_limits{float, list, tuple, dict, None}, default: None
Limits on cell width; passed through to
cell_width
aslimits
. A tuple of three or a dict withx;y;z
can be provided for direction dependent values. Note that this value has no influence on dimensions where avector
is provided.- min_width_pps{float, tuple, dict}, default: 3.0
Points per skin depth; passed through to
cell_width
aspps
. A tuple of three or a dict withx;y;z
can be provided for direction dependent values. Note that this value has no influence on dimensions where avector
is provided.- lambda_factorfloat, default: 1.0
The buffer is set to one wavelength, starting at the survey domain (or at the center if
lambda_from_center=True
). This can be regarded as quite conservative (but safe). The parameterlambda_factor
can be used to reduce (or increase) this factor.- max_bufferfloat, default: 100_000
Maximum thickness of the buffer zone around the survey domain. If
lambda_from_center=True
, this is the maximum distance from the center to the end of the computational domain.- lambda_from_centerbool, default: False
Flag how to compute the extent of the computational mesh as a function of wavelength:
False (default): The distance from the edge of the survey domain to the edge of the computational domain is one wavelength.
True: The distance from the center to the edge of the computational domain and back to the end of the survey domain is two wavelengths.
- mapping{str, Map}, default: ‘Resistivity’
Defines what type the input
property_{x;y;z}
-values correspond to. By default, they represent resistivities (Ohm.m). The implemented mappings are:'Resistivity'
; ρ (Ω m);'Conductivity'
; σ (S/m);'LgResistivity'
; log_10(ρ);'LgConductivity'
; log_10(σ);'LnResistivity'
; log_e(ρ);'LnConductivity'
; log_e(σ).
- cell_numbersarray_like, optional
List of possible numbers of cells. See
good_mg_cell_nr
. Default isgood_mg_cell_nr(1024, 5, 3)
, which corresponds to numbers 16, 24, 32, 40, 48, 64, 80, 96, 128, 160, 192, 256, 320, 384, 512, 640, 768, 1024.- verbint, default: 0
If 1 verbose, if 0 silent. The info is added either way to the returned mesh as
mesh.construct_mesh_info
.
- Returns:
- gridTensorMesh
Resulting mesh, a
emg3d.meshes.TensorMesh
instance.