Source code for pycif.plugins.transforms.complex.isotopes.adjoint
import copy
[docs]
def adjoint(
transf,
data,
mapper,
di,
df,
mode,
runsubdir,
workdir,
**kwargs
):
"""Propagate two-isotopologue sensitivities back to δ and total-concentration sensitivities.
The adjoint of :func:`forward`. Uses forward data stored in
``transf.fwd_data`` to compute:
* **Sensitivity to total concentration**:
:math:`\\partial J/\\partial C_{tot} = (a \\cdot s_{iso_2} + s_{iso_1}) / (1+a)`
* **Sensitivity to δ-signature**:
:math:`\\partial J/\\partial\\delta = R_{std} \\cdot C_{tot}
\\cdot (s_{iso_2} - s_{iso_1}) / (1000 \\cdot (1+a)^2)`
Returns immediately when ``mode != 'adj'``.
Args:
transf (Plugin): isotopes plugin instance (carries ``fwd_data``).
data: datastore object.
mapper (dict): transform mapper.
di (datetime): sub-simulation start date.
df (datetime): sub-simulation end date.
mode (str): must be ``'adj'``; returns unchanged data otherwise.
runsubdir (str): unused.
workdir (str): unused.
**kwargs: unused.
Returns:
data: updated datastore object.
"""
if mode != "adj":
return data
xmod = data.datastore
inputs = transf.parameters_in.names
outputs = transf.parameters_out.names
unit = transf.unit
r_std = transf.parameters_in.standard
iso_mass = transf.parameters_out.iso_mass
spec_mass = transf.parameters_out.spec_mass
in_types = transf.component
out_types = 2 * [transf.component[1]]
for (trid, trid_out) in zip(mapper["inputs"], mapper["outputs"]):
xmod[trid] = {k: xmod[trid_out][k] for k in xmod[trid_out]}
xmod[trid]["adj_out"] = copy.deepcopy(xmod[trid_out]["adj_out"])
signature = transf.fwd_data["signature"]
spec_data = transf.fwd_data["spec_data"]
isotopologue_adj = xmod[(out_types[1], outputs[1])]["adj_out"]
spec_ref_adj = xmod[(out_types[0], outputs[0])]["adj_out"]
a_factor = (1 + signature / 1000) * r_std
# Mass correction if units are in mass
if unit == "mass":
isotopologue_adj *= iso_mass[1] / spec_mass
spec_ref_adj *= iso_mass[0] / spec_mass
# Sensitivity to total
xmod[(in_types[1], inputs[1])]["adj_out"] = (
a_factor * isotopologue_adj + spec_ref_adj
) / (1 + a_factor)
# Sensitivity to signature
xmod[(in_types[0], inputs[0])]["adj_out"] = (
r_std
* spec_data
* (isotopologue_adj - spec_ref_adj)
/ 1000
/ (1 + a_factor) ** 2
)
del xmod[(out_types[0], outputs[0])]
del xmod[(out_types[1], outputs[1])]
data.datastore = xmod
return data