Skip to content

Commit d6757ee

Browse files
committed
Migrate vector directives
1 parent 09d5143 commit d6757ee

3 files changed

Lines changed: 235 additions & 220 deletions

File tree

simpeg/directives/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,28 +118,32 @@
118118
ScalingMultipleDataMisfits_ByEig,
119119
JointScalingSchedule,
120120
UpdateSensitivityWeights,
121-
VectorInversion,
122121
Update_IRLS,
123-
ProjectSphericalBounds,
124122
ScaleMisfitMultipliers,
125123
)
126124

127125
from ._save_geoh5 import (
126+
BaseSaveGeoH5,
128127
SaveDataGeoH5,
129128
SaveLogFilesGeoH5,
130129
SaveModelGeoH5,
131130
SavePropertyGroup,
132131
SaveSensitivityGeoH5,
133132
)
134133

134+
from ._regularization import UpdateIRLS, SphericalUnitsWeights
135+
136+
from ._vector_models import (
137+
VectorInversion,
138+
ProjectSphericalBounds,
139+
)
140+
135141
from .pgi_directives import (
136142
PGI_UpdateParameters,
137143
PGI_BetaAlphaSchedule,
138144
PGI_AddMrefInSmooth,
139145
)
140146

141-
from ._regularization import UpdateIRLS, SphericalUnitsWeights
142-
143147
from .sim_directives import (
144148
SimilarityMeasureInversionDirective,
145149
SimilarityMeasureSaveOutputEveryIteration,
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import numpy as np
2+
3+
from . import (
4+
BaseSaveGeoH5,
5+
InversionDirective,
6+
SaveModelGeoH5,
7+
Update_IRLS,
8+
UpdateIRLS,
9+
UpdateSensitivityWeights,
10+
)
11+
from ..maps import SphericalSystem
12+
from ..meta.simulation import MetaSimulation
13+
from ..objective_function import ComboObjectiveFunction
14+
from ..regularization import CrossGradient
15+
from ..utils.mat_utils import cartesian2amplitude_dip_azimuth
16+
from ..utils import set_kwargs, spherical2cartesian, cartesian2spherical
17+
18+
19+
class ProjectSphericalBounds(InversionDirective):
20+
r"""
21+
Trick for spherical coordinate system.
22+
Project \theta and \phi angles back to [-\pi,\pi] using
23+
back and forth conversion.
24+
spherical->cartesian->spherical
25+
"""
26+
27+
def initialize(self):
28+
x = self.invProb.model
29+
# Convert to cartesian than back to avoid over rotation
30+
nC = int(len(x) / 3)
31+
xyz = spherical2cartesian(x.reshape((nC, 3), order="F"))
32+
m = cartesian2spherical(xyz.reshape((nC, 3), order="F"))
33+
self.invProb.model = m
34+
self.opt.xc = m
35+
36+
for misfit in self.dmisfit:
37+
if getattr(misfit, "model_map", None) is not None:
38+
misfit.simulation.model = misfit.model_map @ m
39+
else:
40+
misfit.simulation.model = m
41+
42+
def endIter(self):
43+
for misfit in self.dmisfit.objfcts:
44+
if (
45+
hasattr(misfit.simulation, "model_type")
46+
and misfit.simulation.model_type == "vector"
47+
):
48+
mapping = misfit.model_map.deriv(np.zeros(misfit.model_map.shape[1]))
49+
indices = (
50+
mapping.indices
51+
) # np.array(np.sum(mapping, axis=0)).flatten() > 0
52+
nC = int(len(indices) / 3)
53+
vec = self.invProb.model[indices]
54+
# Convert to cartesian than back to avoid over rotation
55+
xyz = spherical2cartesian(vec.reshape((nC, 3), order="F"))
56+
vec = cartesian2spherical(xyz.reshape((nC, 3), order="F"))
57+
self.invProb.model[indices] = vec
58+
59+
phi_m_last = []
60+
for reg in self.reg.objfcts:
61+
reg.model = self.invProb.model
62+
phi_m_last += [reg(self.invProb.model)]
63+
64+
self.invProb.phi_m_last = phi_m_last
65+
self.opt.xc = self.invProb.model
66+
67+
for misfit in self.dmisfit.objfcts:
68+
if getattr(misfit, "model_map", None) is not None:
69+
misfit.simulation.model = misfit.model_map @ self.invProb.model
70+
else:
71+
misfit.simulation.model = self.invProb.model
72+
73+
74+
class VectorInversion(InversionDirective):
75+
"""
76+
Control a vector inversion from Cartesian to spherical coordinates.
77+
"""
78+
79+
chifact_target = 1.0
80+
reference_model = None
81+
mode = "cartesian"
82+
inversion_type = "mvis"
83+
norms = []
84+
alphas = []
85+
cartesian_model = None
86+
mappings = []
87+
regularization = []
88+
89+
def __init__(
90+
self, simulations: list, regularizations: ComboObjectiveFunction, **kwargs
91+
):
92+
self.reference_angles = (False, False, False)
93+
self.simulations = simulations
94+
self.regularizations = regularizations
95+
96+
set_kwargs(self, **kwargs)
97+
98+
@property
99+
def target(self):
100+
if getattr(self, "_target", None) is None:
101+
nD = 0
102+
for survey in self.survey:
103+
nD += survey.nD
104+
105+
self._target = nD * self.chifact_target
106+
107+
return self._target
108+
109+
@target.setter
110+
def target(self, val):
111+
self._target = val
112+
113+
def initialize(self):
114+
for reg in self.reg.objfcts:
115+
reg.model = self.invProb.model
116+
117+
self.reference_model = reg.reference_model
118+
119+
for dmisfit in self.dmisfit.objfcts:
120+
if getattr(dmisfit.simulation, "coordinate_system", None) is not None:
121+
dmisfit.simulation.coordinate_system = self.mode
122+
123+
def endIter(self):
124+
if (
125+
self.invProb.phi_d < self.target
126+
) and self.mode == "cartesian": # and self.inversion_type == 'mvis':
127+
print("Switching MVI to spherical coordinates")
128+
self.mode = "spherical"
129+
self.cartesian_model = self.invProb.model
130+
model = self.invProb.model
131+
vec_model = []
132+
vec_ref = []
133+
indices = []
134+
for reg in self.regularizations.objfcts:
135+
vec_model.append(reg.mapping * model)
136+
vec_ref.append(reg.mapping * reg.reference_model)
137+
mapping = reg.mapping.deriv(np.zeros(reg.mapping.shape[1]))
138+
indices.append(mapping.indices)
139+
140+
indices = np.hstack(indices)
141+
nC = mapping.shape[0]
142+
vec_model = cartesian2spherical(np.vstack(vec_model).T)
143+
vec_ref = cartesian2spherical(np.vstack(vec_ref).T).flatten()
144+
model[indices] = vec_model.flatten()
145+
146+
angle_map = []
147+
for ind, (reg_fun, ref_angle) in enumerate(
148+
zip(self.regularizations.objfcts, self.reference_angles)
149+
):
150+
reg_fun.model = model
151+
reg_fun.reference_model[indices] = vec_ref
152+
153+
if ind > 0:
154+
if not ref_angle:
155+
reg_fun.alpha_s = 0
156+
157+
reg_fun.eps_q = np.pi
158+
reg_fun.units = "radian"
159+
angle_map.append(reg_fun.mapping)
160+
else:
161+
reg_fun.units = "amplitude"
162+
163+
# Change units of cross-gradient on angles
164+
multipliers = []
165+
for mult, reg in self.reg:
166+
if isinstance(reg, CrossGradient):
167+
units = []
168+
for _, wire in reg.wire_map.maps:
169+
if wire in angle_map:
170+
units.append("radian")
171+
mult = 0 # TODO Make this optional
172+
else:
173+
units.append("metric")
174+
175+
reg.units = units
176+
177+
multipliers.append(mult)
178+
179+
self.reg.multipliers = multipliers
180+
self.invProb.beta *= 2
181+
self.invProb.model = model
182+
self.opt.xc = model
183+
self.opt.lower[indices] = np.kron(
184+
np.asarray([0, -np.inf, -np.inf]), np.ones(nC)
185+
)
186+
self.opt.upper[indices[nC:]] = np.inf
187+
188+
for simulation in self.simulations:
189+
if isinstance(simulation, MetaSimulation):
190+
for sim in simulation.simulations:
191+
sim.chiMap = SphericalSystem() * sim.chiMap
192+
else:
193+
simulation.chiMap = SphericalSystem() * simulation.chiMap
194+
195+
# Add and update directives
196+
for directive in self.inversion.directiveList.dList:
197+
if (
198+
isinstance(directive, SaveModelGeoH5)
199+
and cartesian2amplitude_dip_azimuth in directive.transforms
200+
):
201+
transforms = []
202+
203+
for fun in directive.transforms:
204+
if fun is cartesian2amplitude_dip_azimuth:
205+
transforms += [spherical2cartesian]
206+
transforms += [fun]
207+
208+
directive.transforms = transforms
209+
210+
elif isinstance(directive, Update_IRLS | UpdateIRLS):
211+
directive.sphericalDomain = True
212+
directive.model = model
213+
directive.coolingFactor = 1.5
214+
215+
elif isinstance(directive, UpdateSensitivityWeights):
216+
directive.every_iteration = True
217+
218+
directiveList = [
219+
ProjectSphericalBounds()
220+
] + self.inversion.directiveList.dList
221+
self.inversion.directiveList = directiveList
222+
223+
for directive in directiveList:
224+
if not isinstance(directive, BaseSaveGeoH5):
225+
directive.endIter()

0 commit comments

Comments
 (0)