Skip to content

Commit f9880cc

Browse files
committed
New Feature: field line integrals
- Tracers objects now return with an "integral" field. - By default the integral is field line length, but like in regular mapfl, additional arguments can make it do scalar field integrals: - integrate_along_fl (logical that turns it on, default False) - scalar_input_file (3D RTP H5 file path with scalar field to be integrated). - weight_integral_by_area (logical to weight integral by 1/b, default False) - max_along_fl (logical to take the max of the scalar field along the field line, defualt False) - Update mapfl to reflect current GitHub version and add this capability. - Update mapflpy fortran for compatitbility. - Update Tracers namedtuple definition. - Compatibility updates in other python files. - WARNING: Currently the scalar_input_file is the only way to read a scalar (i.e. from a file on disk). Eventually it will be possible to pass this by memory. - An example for the docs pages will be added soon (TBD).
1 parent 105d146 commit f9880cc

7 files changed

Lines changed: 262 additions & 63 deletions

File tree

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies:
3030
- ruff
3131
- coverage
3232
- nox
33+
- pre-commit
3334

3435
# -------- Docs --------
3536
- sphinx

mapflpy/globals.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
# It contains the geometry of the traces, their start and end positions,
3131
# and whether they were traced to a boundary.
3232
#------------------------------------------------------------------------------
33-
Traces = namedtuple('Traces', ['geometry', 'start_pos', 'end_pos', 'traced_to_boundary'])
33+
Traces = namedtuple('Traces', ['geometry', 'start_pos', 'end_pos', 'traced_to_boundary', 'integral'])
3434
Traces.__doc__ = (
3535
"""Named tuple for storing magnetic fieldline trace information.
3636
@@ -182,6 +182,8 @@ class Polarity(IntEnum):
182182
DEFAULT_PARAMS = MappingProxyType({
183183
'integrate_along_fl_': False,
184184
'scalar_input_file_': '',
185+
'weight_integral_by_area_': False,
186+
'max_along_fl_': False,
185187
'verbose_': False,
186188
'cubic_': False,
187189
'trace_fwd_': False,

mapflpy/tracer.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@
5454
_BS1 = np.zeros(3, order='F').astype(np.float64)
5555
"""Sentinel array for :meth:`mapfl.trace` **bs1** parameter."""
5656

57-
_S = np.zeros(1, order='F').astype(np.float64)
58-
"""Sentinel array for :meth:`mapfl.trace` **s** parameter."""
59-
6057

6158
def state_modifier(method):
6259
"""
@@ -289,19 +286,20 @@ def trace(lps, buffer_size):
289286
traces = np.full((buffer_size, *lps.shape), np.nan, order='F').astype(np.float64)
290287
s1 = np.zeros(lps.shape, np.float64, order='F')
291288
mask = np.full((1, lps.shape[1]), False, order='F')
289+
integral = np.full((1, lps.shape[1]), 0.0, order='F')
292290
for i in range(lps.shape[1]):
293291
trace_args = dict(
294292
s0=lps[:, i],
295293
s1=s1[:, i],
296294
bs0=_BS0,
297295
bs1=_BS1,
298-
s=_S,
296+
s=integral[:,i],
299297
traced_to_r_boundary=mask[:, i],
300298
svec=traces[:, :, i],
301299
svec_n=buffer_size
302300
)
303301
mapfl.trace(**trace_args)
304-
return Traces(traces, lps, s1, mask[0, :])
302+
return Traces(traces, lps, s1, mask[0, :], integral[0,:])
305303

306304
while True:
307305
method, *args = pipe.recv()
@@ -866,27 +864,29 @@ def _trace(self,
866864
Structured container with traced fieldline geometry, starting points, ending points,
867865
and whether the fieldlines reached the radial boundary of the provided mesh.
868866
"""
869-
# `traces`, `s1`, and `mask` are initialized to Fortran-contiguous arrays
870-
# and are used to store the traced fieldlines, their end points, and boundary masks.
867+
# `traces`, `s1`, `mask`, and `integral` are initialized to Fortran-contiguous arrays
868+
# and are used to store the traced fieldlines, their end points, boundary masks, and
869+
# the scalar field integral along the field line (length by default).
871870
# `mapflpy_fortran` alters these arrays in-place during tracing.
872871
# Each array must have a dimensionality > 1 so that a numpy view is passed.
873872
traces = np.full((buff, *lps.shape), np.nan, order='F').astype(np.float64)
874873
s1 = np.zeros(lps.shape, np.float64, order='F')
875874
mask = np.full((1, lps.shape[1]), False, order='F')
875+
integral = np.full((1, lps.shape[1]), 0.0, order='F')
876876

877-
# Since the parameters _bs0, _bs1, and _s are discarded after the trace,
878-
# we can use the globals `_BS0`, `_BS1`, and `_S` as placeholders to avoid having
877+
# Since the parameters _bs0 and _bs1 are discarded after the trace,
878+
# we can use the globals `_BS0` and `_BS1` as placeholders to avoid having
879879
# to repeatedly create and destruct arrays.
880880
for i in range(lps.shape[1]):
881881
self._mapfl.trace(s0=lps[:, i],
882882
s1=s1[:, i],
883883
bs0=_BS0,
884884
bs1=_BS1,
885-
s=_S,
885+
s=integral[:,i],
886886
traced_to_r_boundary=mask[:, i],
887887
svec=traces[:, :, i],
888888
svec_n=buff)
889-
return Traces(traces, lps, s1, mask[0, :])
889+
return Traces(traces, lps, s1, mask[0, :], integral[0,:])
890890

891891

892892
class TracerMP(_Tracer):

mapflpy/utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ def combine_fwd_bwd_traces(fwd_traces: Traces,
220220
fwd_traces.geometry]),
221221
bwd_traces.end_pos,
222222
fwd_traces.end_pos,
223-
fwd_traces.traced_to_boundary & bwd_traces.traced_to_boundary)
223+
fwd_traces.traced_to_boundary & bwd_traces.traced_to_boundary,
224+
fwd_traces.integral + bwd_traces.integral)
224225
return combined_traces
225226

226227

@@ -423,7 +424,8 @@ def trim_fieldline_nan_buffer(traces: Traces | np.ndarray) -> List[np.ndarray]:
423424

424425
def combine_and_pad_fieldlines(arrs: list | tuple,
425426
to_trace: bool = False,
426-
traced_to_boundary: Optional[NDArray[np.bool_]] = None
427+
traced_to_boundary: Optional[NDArray[np.bool_]] = None,
428+
integral: Optional[NDArray[np.bool_]] = None
427429
) -> np.ndarray | Traces:
428430
"""
429431
NaN-pad a list of variable-length 3D point arrays into a single dense array.
@@ -499,7 +501,7 @@ def combine_and_pad_fieldlines(arrs: list | tuple,
499501
geometry[:a.shape[1], :, i] = a.T # (3, ni) -> (ni, 3)
500502
start_pos[:, i] = a[:,0]
501503
end_pos[:, i] = a[:, -1]
502-
return Traces(geometry, start_pos, end_pos, traced_to_boundary)
504+
return Traces(geometry, start_pos, end_pos, traced_to_boundary, integral)
503505

504506

505507

0 commit comments

Comments
 (0)