Source code for pycif.plugins.transforms.complex.isotopes.forward

import numpy as np
import pandas as pd
import copy


[docs] def forward( transf, data, mapper, ddi, ddf, mode, runsubdir, workdir, **kwargs ): """Compute two-isotopologue concentrations from a δ-value and total concentration. Given one isotopic signature δ and total concentration :math:`C_{tot}`: .. math:: a = (1 + \\delta/1000) \\cdot R_{std} [iso_1] = C_{tot} / (1 + a), \\quad [iso_2] = C_{tot} \\cdot a / (1 + a) Saves ``signature`` and ``spec_data`` on ``transf.fwd_data`` for use by the adjoint. Applies an optional mass correction (``unit = 'mass'``). Args: transf (Plugin): isotopes plugin instance (carries ``parameters_in`` with ``standard``, ``parameters_out`` with ``iso_mass`` / ``spec_mass``, ``unit``, and ``component``). data: datastore object carrying ``.datastore`` dict. mapper (dict): transform mapper. ddi (datetime): sub-simulation start date. ddf (datetime): sub-simulation end date. mode (str): ``'fwd'`` or ``'tl'``. runsubdir (str): unused. workdir (str): unused. **kwargs: unused. Returns: data: updated datastore object. """ xmod = data.datastore inputs = transf.parameters_in.names outputs = transf.parameters_out.names r_std = transf.parameters_in.standard iso_mass = transf.parameters_out.iso_mass spec_mass = transf.parameters_out.spec_mass unit = transf.unit in_types = transf.component out_types = 2 * [transf.component[1]] keys = ['spec'] if mode == 'tl': keys.append('incr') for (trid, trid_out) in zip(mapper["inputs"], mapper["outputs"]): xmod[trid_out] = {k: xmod[trid][k] for k in xmod[trid]} xmod[trid_out]["spec"] = copy.deepcopy(xmod[trid]["spec"]) if mode == 'tl': xmod[trid_out]["incr"] = copy.deepcopy(xmod[trid]["incr"]) signature = xmod[(in_types[0], inputs[0])]['spec'] spec_data = xmod[(in_types[1], inputs[1])]['spec'] # Save signature and data for later use by adjoint transf.fwd_data = { 'signature': signature.values, 'spec_data': spec_data.values} a_factor = (1 + signature / 1000) * r_std xmod[(out_types[0], outputs[0])]['spec'] = \ spec_data / (1 + a_factor) xmod[(out_types[1], outputs[1])]['spec'] = \ spec_data * a_factor / (1 + a_factor) # Applying tangent linear if mode == 'tl': spec_data_tl = xmod[(in_types[1], inputs[1])]['incr'] signature_tl = xmod[(in_types[0], inputs[0])]['incr'] xmod[(out_types[0], outputs[0])]['incr'] = \ spec_data_tl / (1 + a_factor) \ - spec_data * r_std * signature_tl \ / (1000 * (1 + a_factor) ** 2) xmod[(out_types[1], outputs[1])]['incr'] = \ spec_data_tl * a_factor / (1 + a_factor) \ + spec_data * r_std * signature_tl \ / (1000 * (1 + a_factor) ** 2) # Mass correction if units are in mass if unit == 'mass': xmod[(out_types[0], outputs[0])]['spec'] *= \ (iso_mass[0] / spec_mass) xmod[(out_types[1], outputs[1])]['spec'] *= \ (iso_mass[1] / spec_mass) if mode == 'tl': xmod[(out_types[0], outputs[0])]['incr'] *= \ (iso_mass[0] / spec_mass) xmod[(out_types[1], outputs[1])]['incr'] *= \ (iso_mass[1] / spec_mass) # del xmod[(in_types[0], inputs[0])] # del xmod[(in_types[1], inputs[1])] data.datastore = xmod return data