Releases: emsig/emg3d
Meshing: improve vector
-
Meshes: Non-backwards compatible changes in
construct_mesh
(origin_and_widths
;estimate_gridding_options
) when providing
vector
's (implemented non-backwards compatible as the old rules were not
intuitive nor logic; previous meshes can still be obtained, mostly, by
setting the parameters carefully).- Priority-order changed to
domain > distance > vector
(before it was
domain > vector > distance
). - A provided
vector
is new trimmed to the corresponding domain if it is
larger than a also provided domain (fromdomain
ordistance
);
trimmed at the first point where
vector <= domain[0]
,vector >= domain[1]
. - A
vector
can new also be smaller than the defined domain, and the
domain is then filled according to the normal rules; the last cell of
vector
in each direction is taken as starting width for the expansion.
- Priority-order changed to
-
Bugfixes and maintenance:
- Removed functions and modules that were deprecated in v1.2.1.
- Fixed kwargs-error when adding
add_noise
explicitly to
Simulation.compute()
. - Python 3.10 added to tests; Python 3.7 tests reduced to minimum.
Bugfix CLI-select
CLI: Add remove_empty
to parameter file; set to False
by default (pre-v1.3.1 behaviour, and therefore backwards compatible).
Select: remove empty pairs
-
Survey.select
removes now empty source-receiver-frequency pairs. If you
want the old behaviour setremove_empty=False
. -
Maintenance: Added a cron to GHA; 20th of every month at 14:14.
File-based computations
-
electrodes
:- New source
TxMagneticPoint
(requiresdiscretize
; mainly used as
adjoint source for magnetic receivers; does not work in the presence of
magnetic permeabilities in the vicinity of the source). - Both receivers (
Rx{Electric;Magnetic}Point
) can now produce their
proper adjoint (thanks to @sgkang!).
- New source
-
Changes in Simulation and parallel execution.
- Parallel computation is not sharing the simulation any longer.
- Parallel computation can new be done both file-based or all in memory.
The new possibility for file-based computation should make it possible
to compute responses for any amount of source-frequency pairs. See
parameterfile_dir
in the Simulation class (or corresponding parameter
in the CLI parameter file). get_model
andget_hfield
are now done on the fly, they are not
stored in a dict;simulation._dict_model
and
simulation._dict_hfield
do not exist any longer.- New methods
jvec
(sensitivity times a vector) andjtvec
(sensitivity transpose times a vector). These methods are currently
experimental; documentation and examples are lacking behind.
-
Various small things:
- Models and Fields return itself (not a copy) when the grid provided to
interpolate_to_grid
is the same as the current one.
- Models and Fields return itself (not a copy) when the grid provided to
Remove optimize & bug fix
-
io
: Adjustment so that hdf5 tracks the order of dicts. -
simulations
:-
Adjust printing: correct simulation results for adjusted solver printing
levels; default solver verbosity is new 1;log
can now be
overwritten insolver_opts
(mainly for debugging). -
Functions moved out of
simulations
:expand_grid_model
moved to
models
andestimate_gridding_options
tomeshes
. The
availability of these functions throughsimulations
will be removed in
v1.4.0.
-
-
optimize
: the module is deprecated and will be removed in v1.4.0. The two
functionsoptimize.{misfit;gradient}
are embedded directly in
Simulation.{misfit;gradient}
.
White noise
-
CLI:
- New parameters
save
andload
to save and load an entire simulation.
In the parameter file, they are under[files]
; on the command line,
they are available as--save
and--load
; they are followed by the
filename including its path and suffix. (In turn, the parameter
store_simulation
was removed.)
- New parameters
-
simulations.Simulation
:- Warns if the gradient is called, but
receiver_interpolation
is not
'linear'
. - Slightly changed the added noise in
compute(observed=True)
: It uses new
thesurvey.add_noise
attribute. There is new a flag to set if noise
should be added or not (add_noise
), and if the amplitudes should be
chopped or not (min_amplitude
). Also note that the added noise is new
white noise with constant amplitude and random phase.
- Warns if the gradient is called, but
-
surveys
:-
New function
random_noise
, which can be used to create random noise in
different ways. The default noise is white noise, hence constant amplitude
with random phase. (This is different to before, where random Gaussian
noise was added separately to the real and imaginary part.) For the random
noise it requires new at least NumPy 1.17.0. -
New attribute
Survey.add_noise
, which uses under the hood above
function. -
A
Survey
can new be instantiated without receivers by setting
receivers
toNone
. This is useful if one is only interested in
forward modelling the entire fields. In this case, the related data object
and the noise floor and relative error have no meaning. Also, in
conjunction with a Simulation, the misfit and the gradient will be zero.
-
-
Various:
- All emg3d-warnings (not solver warnings) are now set to
'always'
, and
corresponding print statements were removed. - Simplified (unified)
_edge_curl_factor
(private fct).
- All emg3d-warnings (not solver warnings) are now set to
Adjoint-fix for electric receivers
This release contains, besides the usual small bugfixes, typos, and small
improvements, an important fix for optimize.gradient
. Keep in mind that
while the forward modelling is regarded as stable, the optimize
module is
still work in progress.
The fixes with regard to optimize.gradient
ensure that the gradient is
indeed using the proper adjoint to back-propagate the field. This is currently
only given for electric receivers, not yet for magnetic receivers. These
improvement happened mainly thanks to the help of Seogi (@sgkang).
The changes in more detail:
-
fields
:get_receiver
has a new keywordmethod
, which can be'cubic'
or
'linear'
; default is the former, which is the same behaviour as before.
However, if you want to compute the gradient, you should set it to
'linear'
in your Simulation parameters. Otherwise the adjoint-state
gradient will not exactly be the adjoint state.get_source_field
returns new the real-valued, frequency-independent
source vector iffrequency=None
.get_source_field
uses the adjoint of trilinear interpolation for point
sources (new). For dipoles and wires it the source is distributed onto the
cells as fraction of the source length (as before).
-
electrodes
: Re-introduced the point source asTxElectricPoint
. -
simulations.Simulation
:- New keyword
receiver_interpolation
, which corresponds to themethod
inget_receiver
(see above). Cubic is more precise. However, if you are
interested in the gradient, you need to choose linear interpolation at the
moment, as the point source is the adjoint of linear interpolation. To be
the proper adjoint for the gradient the receiver has to be interpolated
linearly too. - If
gridding
is'same'
or'input'
, it checks now if the provided
grid is a sensible grid for emg3d; if not, it throws a warning.
- New keyword
-
meshes
: New functioncheck_grid
to verify if a given grid is good for
emg3d. -
optimize.gradient
: Changed order when going from computational grid to
inversion grid. Changing the grids at the field stage (cubic interpolation)
seems to be better than changing at the cell-averaged stage::New: field_comp -> field_inv -> cells_inv Old: field_comp -> cells_comp -> cells_inv
-
cli
: Uses now by default linear receiver interpolation if the
gradient
is wanted (new), otherwise it uses cubic interpolation (as
before). The new keywordreceiver_interpolation
of the simulation can be
set in the parameter file, which overwrites the described default behaviour.
Stable API
Here it is, three months of hard labour lead to v1.0.0!
There are many changes, and they are listed below for each module.
Your existing code will break, and I apologize for it. Please do not hesitate
to get in touch if you have troubles updating your code.
API: With version 1.0 the API becomes stable and you can expect that your
code will work fine for the duration of emg3d v1.x
.
- Removed all deprecated features.
- Reduced top namespace to principal functions;
get_receiver
is not in the
top namespace any longer. It is advised to use directly the field method:
field.get_receiver
. - Moved emsig.github.io to emsig.xyz and emsig.readthedocs.io to
emg3d.emsig.xyz. - Changed principal repo branch from
master
tomain
.
Detailed changes by module
CLI
- Because frequencies are now dicts as well in a Survey they have to be named
by their key instead of their value when selecting data in the parameter
file. - Entire configuration is now added to the log file.
Core
restrict_weights
: New signature.
Electrodes
- New module containing all sources and receivers. Currently implemented are
TxElectricDipole
,TxMagneticDipole
,TxElectricWire
,
RxElectricPoint
, andRxMagneticPoint
. - New class
TxElectricWire
for an arbitrary electric wire. - Receivers can be defined in absolute coordinates, or in coordinates relative
to source position if they move with the source. Latter makes only sense
within a Survey/Simulation. dip
is new calledelevation
to make it clear that it is the angle
positive upwards (anticlockwise from the horizontal plane).- Bugfix of the loop area for a magnetic dipole (the area was previously wrong
except for dipoles of length of 1). - Zero source strength does no longer mean "normalized", it means zero
strength (hence no source). - Besides the sources and receivers it contains utilities how to move
electrodes in the coordinate system (e.g.,rotation
).
Fields
-
fields.Field
:- Is not a subclassed ndarray any longer; with all its advantages and
disadvantages. E.g., operations onField
are not possible any longer
and have to be carried out onField.field
. However, it should be easier
to maintain and expand in the future. - New signature.
- Knows new its
grid
. As a consequence, all functions that required
previously thegrid
and thefield
require new only thefield
;
e.g.,emg3d.fields.get_receiver
. - Has no property
ensure_pec
any longer, it is ensured directly in
solver.prolongation
. - Has new the methods
interpolate_to_grid
andget_receiver
.
- Is not a subclassed ndarray any longer; with all its advantages and
-
Renamed parameters in all functions:
src
tosource
;freq
tofrequency
;rec
toreceiver
.
-
Removed functions and classes:
SourceField
; it is just a regularField
now;get_receiver
(the name still exists, but it is now what was before
fields.get_receiver_response
).
-
Renamed functions and classes (both do not take a
grid
any longer):get_h_field
toget_magnetic_field
;fields.get_receiver_response
tofields.get_receiver
.
I/O
Model
,Field
,Survey
, andSimulation
instances saved with an
older version of emg3d will not be able to de-serialize with version 1.0. You
have to update those files, see this gist:
https://gist.github.com/prisae/8345c3798e35f1c73efef617ac495538
Maps
-
Changed function and class names:
_Map
toBaseMap
;grid2grid
tointerpolate
(new signature);edges2cellaverages
tointerp_edges_to_vol_averages
(new signature);volume_average
tointerp_volume_average
(new signature);interp3d
tointerp_spline_3d
(new signature).
-
maps.interpolate
:- Can now be used to interpolate values living on a grid to another grid or
to points defined either by a tuple or by an ndarray. - The implemented interpolation methods are 'nearest' (new), 'linear',
'cubic', and 'volume'. Volume averaging ('volume') only works for
grid-to-grid interpolations, not for grid-to-points interpolations. - Does not accept entire fields any longer. Entire fields can be mapped with
their ownfield.interpolate_to_grid
method.
- Can now be used to interpolate values living on a grid to another grid or
-
Maps cannot be (de-)serialized any longer (
{to;from_dict}
); simply store
its name, which can be provided tomodels.Model
. -
Function
rotation
should be used for anything involving angles to use
the defined coordinate system consistently.
Meshes
-
Changed function and class names:
_TensorMesh
toBaseMesh
;min_cell_width
tocell_width
.get_origin_widths
toorigin_and_widths
(has new finer loops to fine
grid sizes than before).
-
meshes.BaseMesh
:- Reduced to the attributes
origin
,h
,shape_{cells;nodes}
,
n_{cells;edges;faces}
,n_{edges;faces}_{x;y;z}
,
{nodes;cell_centers}_{x;y;z}
,shape_{edges;faces}_{x;y;z}
, and
cell_volumes
. These are the only required attributes foremg3d
.
- Reduced to the attributes
-
meshes.construct_mesh
:domain
,vector
,distance
,
stretching
,min_width_limits
, andmin_width_pps
can now also
be provided as a dict containing the three keys'{x;y;z}'
. -
meshes.skin_depth
takes newmu_r
instead ofmu
. -
good_mg_cell_nr
:max_prime
is newmax_lowest
, as it could also
be, e.g., 9, which is not a prime.
Models
-
models.Model
:-
Knows new its
grid
. As a consequence, all the functions that used to
require thegrid
and themodel
require new only themodel
;
e.g.,emg3d.solver.solve
oremg3d.fields.get_magnetic_field
. -
If
property_y
orproperty_z
are not set they return nowNone
,
notproperty_x
. -
If a float is provided for a property it is new expanded to the shape of
the model, and not kept as a float. -
Has to be initiated with all desired properties; it cannot be changed
afterwards. E.g., if it was initiated without electric permittivity, it
cannot be added afterwards. However, it can be initiated with dummy values
and adjusted later. -
Renamed
interpolate2grid
tointerpolate_to_grid
.
-
-
models.VolumeModel
: Does not take agrid
any longer.
Simulations
-
Simulation
:- Works new for electric and magnetic dipole sources as well as electric wire
sources; electric and magnetic point receivers. - Works now as well for surveys that contain receivers which are positioned
relatively to the source. - New signature: no
grid
any longer,name
is new an optional keyword
parameter, new optional keyword parameterinfo
. - Method
get_sfield
is removed.
- Works new for electric and magnetic dipole sources as well as electric wire
-
expand_grid_model
andestimate_gridding_opts
have new signatures and
do not take agrid
any longer.
Solver
-
solver.solve
:-
New signature: no
grid
any longer;efield
andcycle
are moved
to keyword arguments. -
The defaults for
sslsolver
,semicoarsening
, andlinerelaxation
is newTrue
(before it wasFalse
). This is not necessarily the
fastest setting, but generally the most robust setting. -
New keyword parameter
plain
, which is by defaultFalse
. If it is
set toTrue
it uses plain multigrid, hencesslsolver=False
,
semicoarsening=False
, andlinerelaxation=False
, unless these
parameters were set to anything different thanTrue
. -
Some verbosity levels changed (for consistency reasons throughout emg3d).
The new levels are [old levels in brackets]:- -1: Nothing [0]
- 0: Warnings [1]
- 1: One-liner at the end [2]
- 2: One-liner (dynamically updated) [-1]
- 3: Runtime and information about the method [same]
- 4: Additional information for each MG-cycle [same]
- 5: Everything (slower due to additional error computations) [same]
Level three updates now dynamically, just as level 2.
-
-
solve_source()
: New function, a shortcut forsolve()
. It takes a
source
and afrequency
instead of asfield
, gets thesfield
internally, and forwards everything tosolver.solve
. -
multigrid
,krylov
,smoothing
,restriction
,prolongation
,
residual
,RegularGridProlongator
: New signature, mainly not taking a
grid
any longer.
Surveys
-
Survey
:frequencies
is new a dict just likesources
andreceivers
.sources
andreceivers
must be tuples or dicts; lists are no longer
permitted. For this, the modulesurveys
has new convenience functions
txrx_coordinates_to_dict
andtxrx_lists_to_dict
.- Has no attribute
observed
any longer; access it just like any other
data throughSurvey.data.observed
. rec_coords
andsrc_coords
attributes changed to the methods
receiver_coordinates
andsource_coordinates
.
receiver_coordinates
takes an optional source key.
For relatively located receivers, it returns by default all positions of
this receiver for all source position. If a source-key is provided it only
returns the receiver position for this source. This does not affect
absolutely positioned receivers.- Has no attribute
rec_types
any longer. name
is new optional.- New optional keywords
date
andinfo
. noise_floor
andrelative_error
are new stored as data array if they
are not floats.- The keyword
fixed
has been dropped. To simulate fixed surveys define
the receivers with a relative offs...
Magnetics in Simulation
-
Simulation
:- Sources and receivers can now be magnetic, also for the adjoint-state
gradient (unit loops, not yet arbitrarily loops).
- Sources and receivers can now be magnetic, also for the adjoint-state
-
fields.get_source_field
:- The
msrc
argument introduced in v0.16.0 is renamed toelectric
, and
has the opposite meaning. If True, the source is electric, if False, the
source is magnetic. This was made to streamline the meaning with the
meaning given insurveys.Dipole
. The old parametermsrc
is
deprecated and will be removed. Warning, ifmsrc
was provided as
positional argument instead of as keyword argument it will now be taken as
electric
, with the opposite meaning (backwards incompatible). - The magnetic source was corrected and has the opposite sign now (factor -1;
backwards incompatible).
- The
-
Bug fixes:
- Simulation: Stop overwriting synthetic data if provided in the survey to a
simulation. - CLI: Removed configuration info from output data; caused problems when
storing to h5. This has to be resolved with properly addressing the io
stuff. Currently only stores the data selection to output data.
- Simulation: Stop overwriting synthetic data if provided in the survey to a
Verbosity & Logging
-
Solve
has a new keywordlog
, which enables to log the solver messages
in the returned info dictionary instead of printing them to screen. This is
utilized in the CLI and in theSimulation
class to log the solver info. -
Survey
has a new attributeselect
, which returns a reduced survey
containing the selected sources, receivers, and frequencies. -
CLI:
- Configuration info is added to output data.
- Checks now first if all required files and directories exist, and exits
gracefully otherwise informing the user. (The default thrown Python errors
would be good enough; but user of the CLI interface might not be familiar
with Python, so it is better to throw a very simple, clear message.) - Log is more verbose with regards to solver (rel. error, time, nr of it.).
-
Dipole
throws new an error instead of a warning if it received an unknown
keyword. -
Various small things with regard to how things are logged or shown on screen.
-
Changed all
DeprecationWarnings
toFutureWarnings
, meaning they will
be removed in the next release. -
Bug fix with regards to data selection in the CLI; moved to
Survey
(see
above).