Source code for openmdao.core.petscimpl

"""PETSc vector and data transfer implementation factory."""

from __future__ import print_function

import os
from collections import OrderedDict

import petsc4py
#petsc4py.init(['-start_in_debugger']) # add petsc init args here
from petsc4py import PETSc


from openmdao.core.vecwrapper import SrcVecWrapper, TgtVecWrapper
from openmdao.core.dataxfer import DataXfer

trace = os.environ.get('TRACE_PETSC')
if trace:
    from openmdao.devtools.debug import debug

[docs]class PetscImpl(object): """PETSc vector and data transfer implementation factory.""" @staticmethod
[docs] def create_src_vecwrapper(pathname, comm): """ Create a`PetscSrcVecWrapper`. Returns ------- `PetscSrcVecWrapper` """ return PetscSrcVecWrapper(pathname, comm)
@staticmethod
[docs] def create_tgt_vecwrapper(pathname, comm): """ Create a `PetscTgtVecWrapper`. Returns ------- `PetscTgtVecWrapper` """ return PetscTgtVecWrapper(pathname, comm)
@staticmethod
[docs] def create_data_xfer(src_vec, tgt_vec, src_idxs, tgt_idxs, vec_conns, byobj_conns): """ Create an object for performing data transfer between source and target vectors. Args ---- src_vec : `VecWrapper` Variables that are the source of the transfer in fwd mode and the destination of the transfer in rev mode. tgt_vec : `VecWrapper` Variables that are the destination of the transfer in fwd mode and the source of the transfer in rev mode. 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. Returns ------- `PetscDataXfer` A `PetscDataXfer` object. """ return PetscDataXfer(src_vec, tgt_vec, src_idxs, tgt_idxs, vec_conns, byobj_conns)
[docs]class PetscSrcVecWrapper(SrcVecWrapper): idx_arr_type = PETSc.IntType
[docs] def setup(self, unknowns_dict, relevant_vars=None, store_byobjs=False): """ Create internal data storage for variables in unknowns_dict. Args ---- unknowns_dict : `OrderedDict` A dictionary of absolute variable names keyed to an associated metadata dictionary. relevant_vars : iter of str Names of variables that are relevant a particular variable of interest. store_byobjs : bool, optional Indicates that 'pass by object' vars should be stored. This is only true for the unknowns vecwrapper. """ super(PetscSrcVecWrapper, self).setup(unknowns_dict, relevant_vars=relevant_vars, store_byobjs=store_byobjs) if trace: debug("'%s': creating src petsc_vec: %s vec=%s" % (self.pathname, self.keys(), self.vec)) self.petsc_vec = PETSc.Vec().createWithArray(self.vec, comm=self.comm)
def _get_flattened_sizes(self): """ Collect all flattened sizes of vars stored in our internal array. Returns ------- list of `OrderedDict` Contains an entry for each process in this object's communicator. Each entry is an `OrderedDict` mapping var name to local size for 'pass by vector' variables. """ sizes = OrderedDict() for name, meta in self.get_vecvars(): if meta.get('remote'): sizes[name] = 0 else: sizes[name] = meta['size'] # collect local var sizes from all of the processes that share the same comm # these sizes will be the same in all processes except in cases # where a variable belongs to a multiprocessor component. In that # case, the part of the component that runs in a given process will # only have a slice of each of the component's variables. if trace: debug("'%s': allgathering local unknown sizes: local=%s" % (self.pathname, sizes)) return self.comm.allgather(sizes)
[docs] def norm(self): """ Returns ------- float The norm of the distributed vector. """ if trace: debug("%s: norm: petsc_vec.assemble" % self.pathname) self.petsc_vec.assemble() return self.petsc_vec.norm()
[docs] def get_view(self, sys_pathname, comm, varmap, relevance, var_of_interest): view = super(PetscSrcVecWrapper, self).get_view(sys_pathname, comm, varmap, relevance, var_of_interest) if trace: debug("'%s': creating src petsc_vec (view): %s: voi=%s, vec=%s" % (sys_pathname, view.keys(), var_of_interest, view.vec)) view.petsc_vec = PETSc.Vec().createWithArray(view.vec, comm=comm) return view
[docs]class PetscTgtVecWrapper(TgtVecWrapper): idx_arr_type = PETSc.IntType
[docs] def setup(self, parent_params_vec, params_dict, srcvec, my_params, connections, relevant_vars=None, store_byobjs=False): """ Configure this vector to store a flattened array of the variables in params_dict. Variable shape and value are retrieved from srcvec. Args ---- parent_params_vec : `VecWrapper` or None `VecWrapper` of parameters from the parent `System`. params_dict : `OrderedDict` Dictionary of parameter absolute name mapped to metadata dict. srcvec : `VecWrapper` Source `VecWrapper` corresponding to the target `VecWrapper` we're building. my_params : list of str A list of absolute names of parameters that the `VecWrapper` we're building will 'own'. connections : dict of str : str A dict of absolute target names mapped to the absolute name of their source variable. store_byobjs : bool, optional If True, store 'pass by object' variables in the `VecWrapper` we're building. """ super(PetscTgtVecWrapper, self).setup(parent_params_vec, params_dict, srcvec, my_params, connections, relevant_vars=relevant_vars, store_byobjs=store_byobjs) if trace: debug("'%s': creating tgt petsc_vec: %s: vec=%s" % (self.pathname, self.keys(), self.vec)) self.petsc_vec = PETSc.Vec().createWithArray(self.vec, comm=self.comm)
def _get_flattened_sizes(self): """ Returns ------- list of `OrderedDict` Contains an entry for each process in this object's communicator. Each entry is an `OrderedDict` mapping var name to local size for 'pass by vector' params. """ psizes = super(PetscTgtVecWrapper, self)._get_flattened_sizes()[0] if trace: msg = "'%s': allgathering param sizes. local param sizes = %s" debug(msg % (self.pathname, psizes)) return self.comm.allgather(psizes)
[docs]class PetscDataXfer(DataXfer): """ Args ---- src_vec : `VecWrapper` Variables that are the source of the transfer in fwd mode and the destination of the transfer in rev mode. tgt_vec : `VecWrapper` Variables that are the destination of the transfer in fwd mode and the source of the transfer in rev mode. 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. """ def __init__(self, src_vec, tgt_vec, src_idxs, tgt_idxs, vec_conns, byobj_conns): super(PetscDataXfer, self).__init__(src_idxs, tgt_idxs, vec_conns, byobj_conns) self.comm = comm = src_vec.comm uvec = src_vec.petsc_vec pvec = tgt_vec.petsc_vec name = src_vec.pathname if trace: debug("'%s': creating index sets for '%s' DataXfer: %s %s" % (name, src_vec.pathname, src_idxs, tgt_idxs)) src_idx_set = PETSc.IS().createGeneral(src_idxs, comm=comm) tgt_idx_set = PETSc.IS().createGeneral(tgt_idxs, comm=comm) try: if trace: self.src_idxs = src_idxs self.tgt_idxs = tgt_idxs debug("'%s': creating scatter %s --> %s %s --> %s" % (name, [v for u, v in vec_conns], [u for u, v in vec_conns], src_idx_set.indices, tgt_idx_set.indices)) self.scatter = PETSc.Scatter().create(uvec, src_idx_set, pvec, tgt_idx_set) except Exception as err: raise RuntimeError("ERROR in %s (src_idxs=%s, tgt_idxs=%s, usize=%d, psize=%d): %s" % (name, src_idxs, tgt_idxs, src_vec.vec.size, tgt_vec.vec.size, str(err)))
[docs] def transfer(self, srcvec, tgtvec, mode='fwd', deriv=False): """Performs data transfer between a distributed source vector and a distributed 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. This does not involve pass_by_object. if trace: conns = ['%s <-- %s' % (u, v) for u, v in self.vec_conns] debug("'%s': rev scatter %s %s <-- %s" % (srcvec.pathname, conns, self.src_idxs, self.tgt_idxs)) debug("%s: srcvec = %s\ntgtvec = %s" % (srcvec.pathname, srcvec.petsc_vec.array, tgtvec.petsc_vec.array)) self.scatter.scatter(tgtvec.petsc_vec, srcvec.petsc_vec, True, True) else: # forward mode, source to target including pass_by_object if trace: conns = ['%s --> %s' % (u, v) for u, v in self.vec_conns] debug("'%s': fwd scatter %s %s --> %s" % (srcvec.pathname, conns, self.tgt_idxs, self.src_idxs)) debug("%s: srcvec = %s\n%s: tgtvec = %s" % (srcvec.pathname, srcvec.petsc_vec.array, srcvec.pathname, tgtvec.petsc_vec.array)) self.scatter.scatter(srcvec.petsc_vec, tgtvec.petsc_vec, False, False) if trace: debug("scatter done") if not deriv: for tgt, src in self.byobj_conns: raise NotImplementedError("can't transfer '%s' to '%s'" % (src, tgt))