Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend BaseScr to that Pole and Dipole DC are simply minor extensions… #1007

Merged
merged 24 commits into from Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f377191
Extend BaseScr to that Pole and Dipole DC are simply minor extensions…
Apr 22, 2021
72de234
Modify IO utils to expect BaseSrc.Pole to have locations as list.
May 20, 2021
2076e58
raise valueerror in locations where presence of mesh.h is assumed. Ad…
ngodber Jun 7, 2021
9edf8ad
bug fixes for pole source. Utilise new mesh method that uses cKDTree …
ngodber Sep 7, 2021
66aa981
fix loophole where locations_n is none and not caught.
ngodber Oct 2, 2021
1968006
minor changes removing redundant lines from rebase.
ngodber Feb 4, 2022
8038db8
add test for multipole based on dipole test.
ngodber Feb 4, 2022
007c76e
Merge branch 'simpeg:main' into dc_general_source
ngodber Feb 26, 2022
0439199
modify multipole test to make it truly an example that could not be c…
ngodber Feb 26, 2022
83262e6
Merge branch 'main' into dc_general_source
ngodber Apr 22, 2022
abbec5a
updated minimum discretize version in setup.py
ngodber Apr 23, 2022
21b9bf7
run black
jcapriot Apr 27, 2022
d7861f2
update discretize version in install script
jcapriot Apr 27, 2022
d110771
this was a receiver
jcapriot Apr 27, 2022
e436e27
re-do black with newer version
jcapriot Apr 27, 2022
692be4a
make this ambivalent to the mesh type
jcapriot Apr 27, 2022
897c871
simplify logic
jcapriot Apr 27, 2022
304faba
consolidate a bit of survey
jcapriot Apr 27, 2022
4989e27
make general for all unsupported meshes
jcapriot Apr 27, 2022
92a8b18
make mesh tests more general
jcapriot Apr 27, 2022
5c87f8b
fix syntax bug and simplify tests
jcapriot Apr 27, 2022
c4b9d04
update build script command line syntax
jcapriot Apr 27, 2022
589295a
fix for plot_psuedosection
jcapriot Apr 29, 2022
d4d6522
this should work for broadcasting a single value for all current values
jcapriot Apr 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions SimPEG/electromagnetics/static/resistivity/receivers.py
Expand Up @@ -144,8 +144,8 @@ def __init__(self, locations_m=None, locations_n=None, locations=None, **kwargs)
)

# if locations_m set, then use locations_m, locations_n
if locations_m is not None:
if locations_n is None:
if locations_m is not None or locations_n is not None:
if locations_n is None or locations_m is None:
raise ValueError(
"For a dipole source both locations_m and locations_n "
"must be set"
Expand Down
24 changes: 15 additions & 9 deletions SimPEG/electromagnetics/static/resistivity/simulation_2d.py
Expand Up @@ -2,6 +2,8 @@
from scipy.optimize import minimize
import warnings
import properties

import discretize
from ....utils.code_utils import deprecate_class

from ....utils import mkvc, sdiag, Zero
Expand Down Expand Up @@ -60,9 +62,13 @@ def g(k):

return phi, g

# find the minimum cell spacing, and the maximum side of the mesh
min_r = min(*[np.min(h) for h in self.mesh.h])
max_r = max(*[np.sum(h) for h in self.mesh.h])
if isinstance(self.mesh, discretize.CurvilinearMesh):
ngodber marked this conversation as resolved.
Show resolved Hide resolved
min_r = min(self.mesh.edge_lengths)
max_r = max(self.mesh.edge_lengths)
else:
# find the minimum cell spacing, and the maximum side of the mesh
min_r = min(*[np.min(h) for h in self.mesh.h])
max_r = max(*[np.sum(h) for h in self.mesh.h])
# generate test points log spaced between these two end members
rs = np.logspace(np.log10(min_r / 4), np.log10(max_r * 4), 100)

Expand Down Expand Up @@ -113,7 +119,7 @@ def g(k):
if miniaturize:
self._dipoles, self._invs, self._mini_survey = _mini_pole_pole(self.survey)

def fields(self, m):
def fields(self, m=None):
if self.verbose:
print(">> Compute fields")
if m is not None:
Expand Down Expand Up @@ -163,7 +169,7 @@ def dpred(self, m=None, f=None):
for src in survey.source_list:
for rx in src.receiver_list:
d = rx.eval(src, self.mesh, f).dot(weights)
temp[count : count + len(d)] = d
temp[count: count + len(d)] = d
count += len(d)

return self._mini_survey_data(temp)
Expand Down Expand Up @@ -223,7 +229,7 @@ def Jvec(self, m, v, f=None):
df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False)
Jv1_temp = rx.evalDeriv(src, self.mesh, f, df_dm_v)
# Trapezoidal intergration
Jv[count : count + len(Jv1_temp)] += weights[iky] * Jv1_temp
Jv[count: count + len(Jv1_temp)] += weights[iky] * Jv1_temp
count += len(Jv1_temp)

return self._mini_survey_data(Jv)
Expand Down Expand Up @@ -271,7 +277,7 @@ def _Jtvec(self, m, v=None, f=None):
df_duT_sum = 0
df_dmT_sum = 0
for rx in src.receiver_list:
my_v = v[count : count + rx.nD]
my_v = v[count: count + rx.nD]
count += rx.nD
# wrt f, need possibility wrt m
PTv = rx.evalDeriv(src, self.mesh, f, my_v, adjoint=True)
Expand Down Expand Up @@ -587,7 +593,7 @@ def setBC(self, ky=None):
is_t[:, -1] = True
is_t = is_t.reshape(-1, order="F")[is_b]
not_top = np.zeros(boundary_faces.shape[0], dtype=bool)
not_top[-len(is_t) :] = ~is_t
not_top[-len(is_t):] = ~is_t

# use the exponentialy scaled modified bessel function of second kind,
# (the division will cancel out the scaling)
Expand Down Expand Up @@ -742,7 +748,7 @@ def setBC(self, ky=None):
is_t[:, -1] = True
is_t = is_t.reshape(-1, order="F")[is_b]
not_top = np.zeros(boundary_faces.shape[0], dtype=bool)
not_top[-len(is_t) :] = ~is_t
not_top[-len(is_t):] = ~is_t

# use the exponentiall scaled modified bessel function of second kind,
# (the division will cancel out the scaling)
Expand Down
121 changes: 75 additions & 46 deletions SimPEG/electromagnetics/static/resistivity/sources.py
Expand Up @@ -2,31 +2,90 @@
import properties

from .... import survey
from ....utils import Zero, closestPoints
from ....utils.code_utils import deprecate_property

import warnings
from ....utils import Zero


class BaseSrc(survey.BaseSrc):
"""
Base DC source
"""

current = properties.Float("amplitude of the source current", default=1.0)
current = properties.List(doc="amplitudes of the source currents", default=[1.0])
location = properties.List(
"location of the source electrodes",
survey.SourceLocationArray("location of electrode"),
)

_q = None

def __init__(self, receiver_list, **kwargs):
def __init__(self, receiver_list, location, current=None, **kwargs):
super(BaseSrc, self).__init__(receiver_list, **kwargs)
if type(location) is np.ndarray:
if location.ndim == 2:
location = list(location)
else:
location = [location]
if current is None:
current = self.current
if type(current) == float or type(current) == int:
current = [float(current)]
elif type(current) == np.ndarray:
if current.ndim == 2:
current = list(current)
else:
location = [location]
if len(current) != 1 and len(current) != len(location):
raise ValueError(
"Current must be constant or equal to the number of specified source locations."
)
if type(current) != list:
current = np.repeat(current, len(location)).tolist()

self.current = current
self.location = location

def eval(self, sim):
raise NotImplementedError
if self._q is not None:
return self._q
else:
if sim._formulation == "HJ":
inds = sim.mesh.closest_points_index(self.location, grid_loc="CC")
self._q = np.zeros(sim.mesh.nC)
self._q[inds] = self.current
elif sim._formulation == "EB":
loc = np.row_stack(self.location)
cur = np.asarray(self.current)
interpolation_matrix = sim.mesh.get_interpolation_matrix(loc, locType='N').toarray()
q = np.sum(cur[:, np.newaxis] * interpolation_matrix, axis=0)
self._q = q
return self._q

def evalDeriv(self, sim):
return Zero()


class Multipole(BaseSrc):
ngodber marked this conversation as resolved.
Show resolved Hide resolved
"""
Generic Multipole Source
"""

def __init__(self, receiver_list=[], location=None, **kwargs):
super(Multipole, self).__init__(receiver_list, location, **kwargs)

@property
def location_a(self):
"""Locations of the A electrode"""
return self.location

@property
def location_b(self):
"""Location of the B electrode"""
return list(np.tile((len(self.location), 1),
np.full_like(self.location[0], np.nan)
)
)


class Dipole(BaseSrc):
"""
Dipole source
Expand All @@ -36,9 +95,6 @@ class Dipole(BaseSrc):
"location of the source electrodes",
survey.SourceLocationArray("location of electrode"),
)
loc = deprecate_property(
location, "loc", new_name="location", removal_version="0.16.0", error=True
)

def __init__(
self,
Expand All @@ -62,6 +118,11 @@ def __init__(
"The locationB property has been removed. Please set the "
"location_b property instead.",
)
if "current" in kwargs.keys():
value = kwargs.pop('current')
current = [value, -value]
else:
current = [1.0, -1.0]

# if location_a set, then use location_a, location_b
if location_a is not None:
Expand Down Expand Up @@ -95,8 +156,7 @@ def __init__(
)

# instantiate
super(Dipole, self).__init__(receiver_list, **kwargs)
self.location = location
super(Dipole, self).__init__(receiver_list, location, current, **kwargs)

def __repr__(self):
return (
Expand All @@ -113,48 +173,17 @@ def location_b(self):
"""Location of the B-electrode"""
return self.location[1]

def eval(self, sim):
if self._q is not None:
return self._q
else:
if sim._formulation == "HJ":
inds = closestPoints(sim.mesh, self.location, gridLoc="CC")
self._q = np.zeros(sim.mesh.nC)
self._q[inds] = self.current * np.r_[1.0, -1.0]
elif sim._formulation == "EB":
qa = sim.mesh.getInterpolationMat(
self.location[0], locType="N"
).toarray()
qb = -sim.mesh.getInterpolationMat(
self.location[1], locType="N"
).toarray()
self._q = self.current * (qa + qb)
return self._q


class Pole(BaseSrc):
def __init__(self, receiver_list=[], location=None, **kwargs):
super(Pole, self).__init__(receiver_list, location=location, **kwargs)

def eval(self, sim):
if self._q is not None:
return self._q
else:
if sim._formulation == "HJ":
inds = closestPoints(sim.mesh, self.location)
self._q = np.zeros(sim.mesh.nC)
self._q[inds] = self.current * np.r_[1.0]
elif sim._formulation == "EB":
q = sim.mesh.getInterpolationMat(self.location, locType="N")
self._q = self.current * q.toarray()
return self._q
super(Pole, self).__init__(receiver_list, location, **kwargs)

@property
def location_a(self):
"""Locations of the A electrode"""
return self.location
return self.location[0]

@property
def location_b(self):
"""Location of the B electrode"""
return np.nan * np.ones_like(self.location)
return np.nan * np.ones_like(self.location[0])
29 changes: 18 additions & 11 deletions SimPEG/electromagnetics/static/resistivity/survey.py
Expand Up @@ -4,11 +4,9 @@
from __future__ import unicode_literals

import numpy as np
from scipy.interpolate import interp1d, NearestNDInterpolator
import properties
from ....utils.code_utils import deprecate_class, deprecate_property

from ....utils import uniqueRows
from ....survey import BaseSurvey
from ..utils import drapeTopotoLoc
from . import receivers as Rx
Expand Down Expand Up @@ -158,7 +156,7 @@ def source_locations(self):
return [np.vstack(src_a), np.vstack(src_b)]

def set_geometric_factor(
self, space_type="half-space", data_type=None, survey_type=None,
self, space_type="half-space", data_type=None, survey_type=None,
):
if data_type is not None:
raise TypeError(
Expand Down Expand Up @@ -190,10 +188,10 @@ def _set_abmn_locations(self):
# Pole Source
if isinstance(source, Src.Pole):
locations_a.append(
source.location.reshape([1, -1]).repeat(nRx, axis=0)
source.location[0].reshape([1, -1]).repeat(nRx, axis=0)
)
locations_b.append(
source.location.reshape([1, -1]).repeat(nRx, axis=0)
source.location[0].reshape([1, -1]).repeat(nRx, axis=0)
)
# Dipole Source
elif isinstance(source, Src.Dipole):
Expand All @@ -203,6 +201,15 @@ def _set_abmn_locations(self):
locations_b.append(
source.location[1].reshape([1, -1]).repeat(nRx, axis=0)
)
elif isinstance(source, Src.Multipole):
ngodber marked this conversation as resolved.
Show resolved Hide resolved
location_as_array = np.asarray(source.location)
location_as_array = np.tile(location_as_array, (nRx, 1))
locations_a.append(
location_as_array
)
locations_b.append(
location_as_array
)
# Pole RX
if isinstance(rx, Rx.Pole):
locations_m.append(rx.locations)
Expand All @@ -226,7 +233,7 @@ def getABMN_locations(self):
)

def drape_electrodes_on_topography(
self, mesh, actind, option="top", topography=None, force=False
self, mesh, actind, option="top", topography=None, force=False
):
"""Shift electrode locations to be on [top] of the active cells."""
if self.survey_geometry == "surface":
Expand All @@ -237,9 +244,9 @@ def drape_electrodes_on_topography(
unique_electrodes, inv = np.unique(
np.vstack((loc_a, loc_b, loc_m, loc_n)), return_inverse=True, axis=0
)
inv_a, inv = inv[: len(loc_a)], inv[len(loc_a) :]
inv_b, inv = inv[: len(loc_b)], inv[len(loc_b) :]
inv_m, inv_n = inv[: len(loc_m)], inv[len(loc_m) :]
inv_a, inv = inv[: len(loc_a)], inv[len(loc_a):]
inv_b, inv = inv[: len(loc_b)], inv[len(loc_b):]
inv_m, inv_n = inv[: len(loc_m)], inv[len(loc_m):]

electrodes_shifted = drapeTopotoLoc(
mesh, unique_electrodes, actind=actind, option=option
Expand All @@ -252,8 +259,8 @@ def drape_electrodes_on_topography(
ind = 0
for src in self.source_list:
a_loc, b_loc = a_shifted[ind], b_shifted[ind]
if isinstance(src, Src.Pole):
src.location = a_loc
if type(src) is Src.Pole or type(src) is Src.BaseSrc:
src.location = [a_loc]
else:
src.location = [a_loc, b_loc]
for rx in src.receiver_list:
Expand Down