Skip to content

Commit

Permalink
Improve construct_mesh (#158)
Browse files Browse the repository at this point in the history
* Remove precision-keyword; closes #157
* Make doc (update) the default
* Deprecate collect_classes
  • Loading branch information
prisae committed Dec 8, 2020
1 parent f8c768b commit 62d479b
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 95 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ recent versions
"""""""""""""""


*latest*
--------

- Removed ``precision`` from ``skin_depth``, ``wavelength``,
``min_cell_width``; all in ``meshes``. It caused problems for high
frequencies.
- Deprecated ``collect_classes`` in ``io``.


*v0.15.2* : Bugfix deploy II
----------------------------

Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ help:
@echo " dev-install install in editable mode with dev requirements"
@echo " pytest run the test suite and report coverage"
@echo " flake8 style check with flake8"
@echo " doc build docs (new, removing any existing)"
@echo " doc-update build docs (update existing)"
@echo " doc build docs (update existing)"
@echo " doc-clean build docs (new, removing any existing)"
@echo " linkcheck check all links in docs"
@echo " clean clean up all generated files"
@echo ""
Expand All @@ -24,11 +24,11 @@ flake8:
flake8 docs/conf.py setup.py emg3d/ tests/

doc:
cd docs && rm -rf api/ && rm -rf _build/ && make html && cd ..

doc-update:
cd docs && make html && cd ..

doc-clean:
cd docs && rm -rf api/ && rm -rf _build/ && make html && cd ..

linkcheck:
cd docs && make html -b linkcheck && cd ..

Expand Down
16 changes: 8 additions & 8 deletions emg3d/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import os
import json
import warnings
from datetime import datetime

import numpy as np
Expand Down Expand Up @@ -50,9 +51,7 @@ def save(fname, **kwargs):
"""Save surveys, meshes, models, fields, and more to disk.
Serialize and save data to disk in different formats (see parameter
description of `fname` for the supported file formats). The main
emg3d-classes (type `emg3d.io.KNOWN_CLASSES` to get a list) can be
collected in corresponding root-folders by setting `collect_classes=True`.
description of `fname` for the supported file formats).
Any other (non-emg3d) object can be added too, as long as it knows how to
serialize itself.
Expand Down Expand Up @@ -80,11 +79,6 @@ def save(fname, **kwargs):
json_indent : int or None
Passed through to json, default is 2.
collect_classes : bool
If True, input data is collected in folders for the principal
emg3d-classes (type `emg3d.io.KNOWN_CLASSES` to get a list) and
everything else collected in a `Data`-folder. Defaults to False.
verb : int
If 1 (default) verbose, if 0 silent.
Expand All @@ -105,6 +99,12 @@ def save(fname, **kwargs):
collect_classes = kwargs.pop('collect_classes', False)
verb = kwargs.pop('verb', 1)

# Throw deprecation warning for collect_classes.
if collect_classes:
warnings.warn(
"`collect_classes` is deprecated and will be removed "
"in the future.", DeprecationWarning)

# Get absolute path.
full_path = os.path.abspath(fname)

Expand Down
55 changes: 25 additions & 30 deletions emg3d/meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ def get_origin_widths(frequency, properties, center, domain=None, vector=None,
cond[0], cond[min(cond.size-1, 1)], cond[min(cond.size-1, 2)]])

# Get skin depth.
skind = skin_depth(frequency, cond_arr, precision=0)
skind = skin_depth(frequency, cond_arr)

# Minimum cell width.
dmin = min_cell_width(skind[0], min_width_pps, min_width_limits)
Expand Down Expand Up @@ -768,30 +768,36 @@ def get_origin_widths(frequency, properties, center, domain=None, vector=None,
sa_adj = np.max([hxo[1:]/hxo[:-1], hxo[:-1]/hxo[1:]])
sa_limit = min(1.5, stretching[0]+0.25)

# Display precision.
prec = int(np.ceil(max(0, -np.log10(min(hx))+1)))

if verb > 1:
end = ""
else:
end = "\n"

print(f"Skin depth [m] : {skind[0]:.0f}", end="")
print(f"Skin depth [m] : {skind[0]:.{prec}f}", end="")
if cond.size == 2:
print(f" / {skind[1]:.0f}", end=end)
print(f" / {skind[1]:.{prec}f}", end=end)
elif cond.size == 3:
print(f" / {skind[1]:.0f} / {skind[2]:.0f}", end=end)
print(f" / {skind[1]:.{prec}f} / {skind[2]:.{prec}f}", end=end)
else:
print(end=end)
if verb > 1:
print(" [corresponding to `properties`]")

print(f"Survey domain DS [m] : {domain[0]:.0f} - {domain[1]:.0f}")
print(f"Survey domain DS [m] : {domain[0]:.{prec}f} - "
f"{domain[1]:.{prec}f}")

print(f"Comp. domain DC [m] : {comp_domain[0]:.0f} - "
f"{comp_domain[1]:.0f}")
print(f"Comp. domain DC [m] : {comp_domain[0]:.{prec}f} - "
f"{comp_domain[1]:.{prec}f}")

print(f"Final extent [m] : {x0:.0f} - {x0+np.sum(hx):.0f}")
print(f"Final extent [m] : {x0:.{prec}f} - "
f"{x0+np.sum(hx):.{prec}f}")

print(f"Cell widths [m] : "
f"{min(hxo):.0f} / {max(hxo):.0f} / {max(hx):.0f}", end=end)
f"{min(hxo):.{prec}f} / {max(hxo):.{prec}f} / "
f"{max(hx):.{prec}f}", end=end)
if verb > 1:
print(" [min(DS) / max(DS) / max(DC)]")

Expand Down Expand Up @@ -867,7 +873,7 @@ def good_mg_cell_nr(max_nr=1024, max_prime=5, min_div=3):
return numbers[numbers <= max_nr]


def skin_depth(frequency, conductivity, mu=mu_0, precision=0):
def skin_depth(frequency, conductivity, mu=mu_0):
r"""Return skin depth for provided frequency and conductivity.
The skin depth :math:`\delta` (m) is given by
Expand All @@ -893,10 +899,6 @@ def skin_depth(frequency, conductivity, mu=mu_0, precision=0):
mu : float, optional
Magnetic permeability (H/m); default is :math:`\mu_0`.
precision : int, optional
Precision of the return skin depth.
Default is 0, hence meters.
Returns
-------
Expand All @@ -907,10 +909,11 @@ def skin_depth(frequency, conductivity, mu=mu_0, precision=0):
skind = 1/np.sqrt(np.pi*abs(frequency)*conductivity*mu)
if frequency < 0: # For Laplace-domain computations.
skind /= np.sqrt(2*np.pi)
return np.round(skind, precision)

return skind

def wavelength(skin_depth, precision=0):

def wavelength(skin_depth):
r"""Return the wavelength.
The wavelength :math:`\lambda` (m) is given by
Expand All @@ -929,21 +932,17 @@ def wavelength(skin_depth, precision=0):
skin_depth : float or ndarray.
Skin depth (m).
precision : int, optional
Precision of the returned wave length.
Default is 0, hence meters.
Returns
-------
wavelength : float or ndarray
Wavelength (m).
"""
return np.round(2*np.pi*skin_depth, precision)
return 2*np.pi*skin_depth


def min_cell_width(skin_depth, pps=3, limits=None, precision=0):
def min_cell_width(skin_depth, pps=3, limits=None):
r"""Return the minimum cell width.
The minimum cell width is defined by the desired points per skin depth,
Expand Down Expand Up @@ -973,10 +972,6 @@ def min_cell_width(skin_depth, pps=3, limits=None, precision=0):
- float: Returns limits as dmin.
- [min, max]: dmin is limited to this range.
precision : int, optional
Precision of the cell width. Provided limits are not rounded.
Default is 0, hence meters.
Returns
-------
Expand All @@ -985,7 +980,7 @@ def min_cell_width(skin_depth, pps=3, limits=None, precision=0):
"""
# Calculate min cell width.
dmin = np.round(skin_depth/pps, precision)
dmin = skin_depth/pps

# Respect user limits.
if limits is not None:
Expand Down Expand Up @@ -1170,7 +1165,7 @@ def get_hx_h0(freq, res, domain, fixed=0., possible_nx=None, min_width=None,
f"Provided: [{fixed[0]}, {fixed[1]}, {fixed[2]}]")

# Get skin depth.
skind = skin_depth(freq, 1/res_arr, precision=3)
skind = skin_depth(freq, 1/res_arr)

# Minimum cell width.
dmin = min_cell_width(skind[0], pps, min_width)
Expand All @@ -1192,7 +1187,7 @@ def get_hx_h0(freq, res, domain, fixed=0., possible_nx=None, min_width=None,
dist_in_domain = abs(domain - fixed[0])

# (b) Two wavelengths.
two_lambda = 2*wavelength(skind[1:], precision=3)
two_lambda = 2*wavelength(skind[1:])

# (c) Required buffer, additional to domain.
dist_buff = np.max([np.zeros(2), (two_lambda - dist_in_domain)/2], axis=0)
Expand Down Expand Up @@ -1572,7 +1567,7 @@ def get_domain(x0=0, freq=1, res=0.3, limits=None, min_width=None,
fact_pos = fact_neg

# Get skin depth.
skind = skin_depth(freq, 1/res, precision=3)
skind = skin_depth(freq, 1/res)

# Estimate minimum cell width.
h_min = fact_min*skind
Expand Down
Binary file modified tests/data/regression.npz
Binary file not shown.
26 changes: 15 additions & 11 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ class TensorMesh:
model = models.Model(grid, property_x, property_y, property_z, mu_r=mu_r)

# Save it.
io.save(tmpdir+'/test.npz', emg3d=grid, discretize=grid2, model=model,
broken=grid3, a=None, b=True,
field=field, what={'f': field.fx, 12: 12}, collect_classes=True)
with pytest.warns(DeprecationWarning):
io.save(tmpdir+'/test.npz', emg3d=grid, discretize=grid2, model=model,
broken=grid3, a=None, b=True,
field=field, what={'f': field.fx, 12: 12},
collect_classes=True)
outstr, _ = capsys.readouterr()
assert 'Data saved to «' in outstr
assert utils.__version__ in outstr
Expand Down Expand Up @@ -109,10 +111,11 @@ class TensorMesh:

# Test h5py.
if h5py:
io.save(tmpdir+'/test.h5', emg3d=grid, discretize=grid2,
a=1.0, b=1+1j, c=True,
model=model, field=field, what={'f': field.fx},
collect_classes=True)
with pytest.warns(DeprecationWarning):
io.save(tmpdir+'/test.h5', emg3d=grid, discretize=grid2,
a=1.0, b=1+1j, c=True,
model=model, field=field, what={'f': field.fx},
collect_classes=True)
out_h5 = io.load(str(tmpdir+'/test.h5'))
assert out_h5['Model']['model'] == model
assert out_h5['Data']['a'] == 1.0
Expand All @@ -133,10 +136,11 @@ class TensorMesh:
io.load(str(tmpdir+'/test-h5.h5'))

# Test json.
io.save(tmpdir+'/test.json', emg3d=grid, discretize=grid2,
a=1.0, b=1+1j,
model=model, field=field, what={'f': field.fx},
collect_classes=True)
with pytest.warns(DeprecationWarning):
io.save(tmpdir+'/test.json', emg3d=grid, discretize=grid2,
a=1.0, b=1+1j,
model=model, field=field, what={'f': field.fx},
collect_classes=True)
out_json = io.load(str(tmpdir+'/test.json'))
assert out_json['Model']['model'] == model
assert out_json['Data']['a'] == 1.0
Expand Down

0 comments on commit 62d479b

Please sign in to comment.