Source code for openmdao.core.data_transfer
""" Class definition for the DataTransfer object."""
import numpy as np
from openmdao.util.array_util import to_slices
from openmdao.core.mpi_wrap import MPI
[docs]class DataTransfer(object):
"""
An object that performs data transfer between a source vector and a
target vector.
Args
----
src_idxs : array
Indices of the source variables in the source vector.
tgt_idxs : array
Indices of the target variables in the target vector.
vec_conns : dict
Mapping of 'pass by vector' variables to the source variables that
they are connected to.
byobj_conns : dict
Mapping of 'pass by object' variables to the source variables that
they are connected to.
mode : str
Either 'fwd' or 'rev', indicating a forward or reverse scatter.
"""
def __init__(self, src_idxs, tgt_idxs, vec_conns, byobj_conns, mode):
self.src_idxs = src_idxs
self.tgt_idxs = tgt_idxs
self.vec_conns = vec_conns
self.byobj_conns = byobj_conns
if not MPI:
# if in fwd mode, sort using src indices and in rev mode sort using tgt indices,
# to increase the likelihood of slice conversion for 'get' access in order to
# avoid array copies.
if mode == 'fwd':
self.src_idxs, self.tgt_idxs = to_slices(self.src_idxs, self.tgt_idxs)
else:
self.tgt_idxs, self.src_idxs = to_slices(self.tgt_idxs, self.src_idxs)
if isinstance(self.src_idxs, slice):
self._src_unique = True
else:
# check uniqueness of src_idxs to see if we can avoid calling np.add.at
self._src_unique = np.unique(self.src_idxs).size == self.src_idxs.size
[docs] def transfer(self, srcvec, tgtvec, mode='fwd', deriv=False):
"""
Performs data transfer between a source vector and a target vector.
Args
----
srcvec : `VecWrapper`
Variables that are the source of the transfer in fwd mode and
the destination of the transfer in rev mode.
tgtvec : `VecWrapper`
Variables that are the destination of the transfer in fwd mode and
the source of the transfer in rev mode.
mode : 'fwd' or 'rev', optional
Direction of the data transfer, source to target ('fwd', the default)
or target to source ('rev').
deriv : bool, optional
If True, this is a derivative data transfer, so no pass_by_obj
variables will be transferred.
"""
if mode == 'rev':
# in reverse mode, srcvec and tgtvec are switched. Note, we only
# run in reverse for derivatives, and derivatives accumulate from
# all targets. byobjs are never scattered in reverse
if self._src_unique:
srcvec.vec[self.src_idxs] += tgtvec.vec[self.tgt_idxs]
else:
np.add.at(srcvec.vec, self.src_idxs, tgtvec.vec[self.tgt_idxs])
else:
tgtvec.vec[self.tgt_idxs] = srcvec.vec[self.src_idxs]
# forward, include byobjs if not a deriv scatter
if not deriv:
for tgt, src in self.byobj_conns:
tgtvec[tgt] = srcvec[src]