Source code for pycif.plugins.obsoperators.standard.transforms.utils.precursors_successors
import itertools
[docs]
def add_precursors_successors(
self, all_transforms, transforms_ids,
mapper, pipe_links, pipe_subend, transf, simu, mode="adjoint",
fetch_precursors=True):
"""Find the precursors/successors in backward and forward mode
:param self:
:param all_transforms:
:param transforms_ids:
:param mapper:
:param pipe_links:
:param transf:
:param simu:
:param mode:
:param precursors:
:param fetch_precursors:
:return:
"""
out_mode = "adjoint" if fetch_precursors else "forward"
transf_id = (simu, transf, out_mode)
if transf_id not in transforms_ids:
transforms_ids.append(transf_id)
# If the transform is not already in the pipe,
# add it only if it has some successors (resp. precursors),
# or if it is related to the observation vector (resp. control vector)
# in adjoint (resp. forward) mode
# Other transformations are dead-ends and don't need to be computed
if transf_id not in pipe_links:
all_successors = \
[success for trid in mapper[transf]["successors"]
for success in mapper[transf]["successors"][trid]]
if not all_successors:
if not getattr(all_transforms, transf).end_pipe \
and not self.force_full_operator:
return
all_precursors = \
[precurs for trid in mapper[transf]["precursors"]
for precurs in mapper[transf]["precursors"][trid]]
if not all_precursors:
if not getattr(all_transforms, transf).start_pipe \
and not self.force_full_operator:
return
pipe_links[transf_id] = []
# Loop on all precursors and check whether they produce outputs
# necessary for the present sub-simulation
transf_subsimus = mapper[transf]["subsimus"][simu]
if fetch_precursors:
neighbours_id = "precursors"
transform_inout = "inputs"
neighbour_inout = "outputs"
else:
neighbours_id = "successors"
transform_inout = "outputs"
neighbour_inout = "inputs"
transf_neighbours = mapper[transf][neighbours_id]
for trid in transf_neighbours:
if trid not in transf_subsimus[transform_inout]:
continue
# Loop on the input sub-simulation for that trid
trid_subsimus = transf_subsimus[transform_inout][trid]
if mode == "adjoint":
trid_subsimus = list(trid_subsimus.keys())[::-1]
trid_neighbours = transf_neighbours[trid]
for neigh_simu, neighbour in itertools.product(
trid_subsimus, trid_neighbours):
neighbour_subsimus = mapper[neighbour]["subsimus"]
is_in_neighbours = [
tmp_simu for tmp_simu in neighbour_subsimus
if neigh_simu in neighbour_subsimus[
tmp_simu][neighbour_inout].get(trid, [])
]
if mode == "adjoint":
is_in_neighbours = is_in_neighbours[::-1]
for tmp_simu in is_in_neighbours:
neigh_id = (tmp_simu, neighbour,
"adjoint" if fetch_precursors else "forward")
if neigh_id in transforms_ids:
transforms_ids.remove(neigh_id)
transforms_ids.append(neigh_id)
# Do not add precursor in onlyinit mode if
# no propagation of information
break_id = f"break_{'fwd' if mode == 'forward' else 'adj'}" \
f"_onlyinit_pipe"
break_transf = mapper[transf][transform_inout][trid].get(
break_id, False)
break_neighbour = mapper[neighbour][neighbour_inout][trid].get(
break_id, False)
if (
((fetch_precursors and mode == "forward")
or (not fetch_precursors and mode == "adjoint"))
and (break_transf or break_neighbour)
):
if (transf_id[0], transf_id[1], mode) \
not in pipe_links[transf_id]:
pipe_links[transf_id].append(
(transf_id[0], transf_id[1], mode))
pipe_subend.append(neigh_id)
# setattr(
# getattr(all_transforms, neigh_id[1]),
# "end_pipe" if mode == "forward" else "start_pipe",
# True
# )
continue
# # Do not add precursor in onlyinit mode if
# # no propagation of information
# if fetch_precursors and mode == "forward":
# if mapper[transf][transform_inout][trid].get(
# "break_fwd_onlyinit_pipe", False):
# pipe_links[transf_id].append(
# (transf_id[0], transf_id[1], "forward"))
# getattr(all_transforms, neigh_id[1]).end_pipe = True
# continue
#
# if not fetch_precursors and mode == "adjoint":
# if mapper[transf][transform_inout][trid].get(
# "break_adj_onlyinit_pipe", False):
# pipe_links[transf_id].append(
# (transf_id[0], transf_id[1], "adjoint"))
# getattr(all_transforms, neigh_id[1]).start_pipe = True
pipe_links[transf_id].append(neigh_id)
# When no precursor, set precursor to same transform in forward
if len(list(itertools.chain(*transf_neighbours.values()))) == 0:
if fetch_precursors and mode == "forward":
pipe_links[transf_id].append(
(transf_id[0], transf_id[1], "forward")
)
return
if not fetch_precursors and mode == "adjoint":
pipe_links[transf_id].append(
(transf_id[0], transf_id[1], "adjoint")
)
return