def __init__(self, obj_id, functional=False, vector=False, with_apply2=False, pickle_subtypes=True, array_type=MPIVectorArray): assert not (functional and vector) self.obj_id = obj_id self.op = op = mpi.get_object(obj_id) self.functional = functional self.vector = vector self.with_apply2 = with_apply2 self.pickle_subtypes = pickle_subtypes self.array_type = array_type self.linear = op.linear self.name = op.name self.build_parameter_type(inherits=(op,)) if vector: self.source = NumpyVectorSpace(1) assert self.source == op.source else: subtypes = mpi.call(_MPIOperator_get_source_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0],) self.source = VectorSpace(array_type, (op.source.type, subtypes)) if functional: self.range = NumpyVectorSpace(1) assert self.range == op.range else: subtypes = mpi.call(_MPIOperator_get_range_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0],) self.range = VectorSpace(array_type, (op.range.type, subtypes))
def mpi_wrap_operator(obj_id, functional=False, vector=False, with_apply2=False, pickle_subtypes=True, array_type=MPIVectorArray): """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0. Given MPI distributed local |Operators| referred to by the `~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator| which manages these distributed operators from rank 0. This is done by instantiating :class:`MPIOperator`. Additionally, the structure of the wrapped operators is preserved. E.g. |LincombOperators| will be wrapped as a |LincombOperator| of :class:`MPIOperators`. Parameters ---------- See :class:`MPIOperator`. Returns ------- The wrapped |Operator|. """ op = mpi.get_object(obj_id) if isinstance(op, LincombOperator): obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id) return LincombOperator([mpi_wrap_operator(o, functional, vector, with_apply2, pickle_subtypes, array_type) for o in obj_ids], op.coefficients, name=op.name) elif isinstance(op, VectorArrayOperator): array_obj_id, subtypes = mpi.call(_mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0],) return VectorArrayOperator(array_type(type(op._array), subtypes, array_obj_id), transposed=op.transposed, name=op.name) else: return MPIOperator(obj_id, functional, vector, with_apply2, pickle_subtypes, array_type)
def apply_adjoint(self, U, ind=None, mu=None, source_product=None, range_product=None): assert U in self.range mu = self.parse_parameter(mu) U = U if self.functional else U.obj_id source_product = source_product and source_product.obj_id range_product = range_product and range_product.obj_id if self.vector: return mpi.call( mpi.method_call, self.obj_id, "apply_adjoint", U, ind=ind, mu=mu, source_product=source_product, range_product=range_product, ) else: space = self.source return space.type( space.subtype[0], space.subtype[1], mpi.call( mpi.method_call_manage, self.obj_id, "apply_adjoint", U, ind=ind, mu=mu, source_product=source_product, range_product=range_product, ), )
def __init__(self, obj_id, mpi_range, mpi_source, with_apply2=False, pickle_local_spaces=True, space_type=MPIVectorSpace): assert mpi_source or mpi_range self.obj_id = obj_id self.mpi_source = mpi_source self.mpi_range = mpi_range self.op = op = mpi.get_object(obj_id) self.with_apply2 = with_apply2 self.pickle_local_spaces = pickle_local_spaces self.space_type = space_type self.linear = op.linear self.name = op.name self.build_parameter_type(op) if mpi_source: local_spaces = mpi.call(_MPIOperator_get_local_spaces, obj_id, True, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) self.source = space_type(local_spaces) else: self.source = op.source if mpi_range: local_spaces = mpi.call(_MPIOperator_get_local_spaces, obj_id, False, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) self.range = space_type(local_spaces) else: self.range = op.range
def mpi_wrap_operator(obj_id, mpi_range, mpi_source, with_apply2=False, pickle_local_spaces=True, space_type=MPIVectorSpace): """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0. Given MPI distributed local |Operators| referred to by the :class:`~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator| which manages these distributed operators from rank 0. This is done by instantiating :class:`MPIOperator`. Additionally, the structure of the wrapped operators is preserved. E.g. |LincombOperators| will be wrapped as a |LincombOperator| of :class:`MPIOperators <MPIOperator>`. Parameters ---------- See :class:`MPIOperator`. Returns ------- The wrapped |Operator|. """ op = mpi.get_object(obj_id) if isinstance(op, LincombOperator): obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id) return LincombOperator([mpi_wrap_operator(o, mpi_range, mpi_source, with_apply2, pickle_local_spaces, space_type) for o in obj_ids], op.coefficients, name=op.name) elif isinstance(op, VectorArrayOperator): array_obj_id, local_spaces = mpi.call(_mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) return VectorArrayOperator(space_type(local_spaces).make_array(array_obj_id), adjoint=op.adjoint, name=op.name) else: return MPIOperator(obj_id, mpi_range, mpi_source, with_apply2, pickle_local_spaces, space_type)
def apply(self, U, mu=None): assert U in self.source mu = self.parse_parameter(mu) U = U.obj_id if self.mpi_source else U if self.mpi_range: return self.range.make_array(mpi.call(mpi.method_call_manage, self.obj_id, 'apply', U, mu=mu)) else: return mpi.call(mpi.method_call, self.obj_id, 'apply', U, mu=mu)
def apply(self, U, ind=None, mu=None): assert U in self.source mu = self.parse_parameter(mu) U = U if self.vector else U.obj_id if self.functional: return mpi.call(mpi.method_call, self.obj_id, 'apply', U, ind=ind, mu=mu) else: space = self.range return space.type(space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'apply', U, ind=ind, mu=mu))
def apply_transpose(self, V, mu=None): assert V in self.range mu = self.parse_parameter(mu) V = V if self.range.id is None else V.obj_id if self.source.id is None: return mpi.call(mpi.method_call, self.obj_id, 'apply_transpose', V, mu=mu) else: return self.source.make_array( mpi.call(mpi.method_call_manage, self.obj_id, 'apply_transpose', V, mu=mu) )
def apply_adjoint(self, V, mu=None): assert V in self.range mu = self.parse_parameter(mu) V = V.obj_id if self.mpi_range else V if self.mpi_source: return self.source.make_array( mpi.call(mpi.method_call_manage, self.obj_id, 'apply_adjoint', V, mu=mu) ) else: return mpi.call(mpi.method_call, self.obj_id, 'apply_adjoint', V, mu=mu)
def assemble_lincomb(self, operators, coefficients, solver_options=None, name=None): if not all(isinstance(op, MPIOperator) for op in operators): return None assert solver_options is None operators = [op.obj_id for op in operators] obj_id = mpi.call(_MPIOperator_assemble_lincomb, operators, coefficients, name=name) op = mpi.get_object(obj_id) if op is None: mpi.call(mpi.remove_object, obj_id) return None else: return self.with_(obj_id=obj_id)
def apply_inverse(self, V, mu=None, least_squares=False): if self.source.id is None or self.range.id is None: raise NotImplementedError assert V in self.range mu = self.parse_parameter(mu) return self.source.make_array(mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse', V.obj_id, mu=mu, least_squares=least_squares))
def apply_inverse_adjoint(self, U, mu=None, least_squares=False): if not self.mpi_source or not self.mpi_range: raise NotImplementedError assert U in self.source mu = self.parse_parameter(mu) return self.source.make_array(mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse_adjoint', U.obj_id, mu=mu, least_squares=least_squares))
def mpi_wrap_discretization(obj_id, use_with=False, with_apply2=False, array_type=MPIVectorArray): """Wrap MPI distributed local |Discretizations| to a global |Discretization| on rank 0. Given MPI distributed local |Discretizations| referred to by the `~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Discretization| which manages these distributed discretizations from rank 0. This is done by first wrapping all |Operators| of the |Discretization| using :func:`~pymor.operators.mpi.mpi_wrap_operator`. When `use_with` is `False`, an :class:`MPIDiscretization` is instatiated with the wrapped operators. A call to :meth:`~pymor.discretizations.interfaces.DiscretizationInterface.solve` will then use an MPI parallel call to the :meth:`~pymor.discretizations.interfaces.DiscretizationInterface.solve` methods of the wrapped local |Discretizations| to obtain the solution. This is usually what you want when the actual solve is performed by an implementation in the external solver. When `use_with` is `True`, :meth:`~pymor.core.interfaces.ImmutableInterface.with_` is called on the local |Discretization| on rank 0, to obtain a new |Discretization| with the wrapped MPI |Operators|. This is mainly useful when the local discretizations are generic |Discretizations| as in :mod:`pymor.discretizations.basic` and :meth:`~pymor.discretizations.interfaces.DiscretizationInterface.solve` is implemented directly in pyMOR via operations on the contained |Operators|. Parameters ---------- obj_id :class:`~pymor.tools.mpi.ObjectId` of the local |Discretization| on each rank. use_with See above. with_apply2 See :class:`~pymor.operators.mpi.MPIOperator`. array_type See :class:`~pymor.operators.mpi.MPIOperator`. """ operators, functionals, vectors, products = \ mpi.call(_mpi_wrap_discretization_manage_operators, obj_id) operators = {k: mpi_wrap_operator(v, with_apply2=with_apply2, array_type=array_type) if v else None for k, v in operators.iteritems()} functionals = {k: mpi_wrap_operator(v, functional=True, with_apply2=with_apply2, array_type=array_type) if v else None for k, v in functionals.iteritems()} vectors = {k: mpi_wrap_operator(v, vector=True, with_apply2=with_apply2, array_type=array_type) if v else None for k, v in vectors.iteritems()} products = {k: mpi_wrap_operator(v, with_apply2=with_apply2, array_type=array_type) if v else None for k, v in products.iteritems()} if products else None if use_with: d = mpi.get_object(obj_id) visualizer = MPIVisualizer(obj_id) return d.with_(operators=operators, functionals=functionals, vector_operators=vectors, products=products, visualizer=visualizer, cache_region=None) else: return MPIDiscretization(obj_id, operators, functionals, vectors, products, array_type=array_type)
def as_vector(self, mu=None): mu = self.parse_parameter(mu) if self.functional: space = self.source return space.type(space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'as_vector', mu=mu)) else: raise NotImplementedError
def _map(self, function, chunks, **kwargs): payload = mpi.get_object(self._payload) payload[0] = chunks try: result = mpi.call(mpi.function_call, _worker_map_function, self._payload, function, **kwargs) finally: payload[0] = None return result
def _apply_only(self, function, worker, *args, **kwargs): payload = mpi.get_object(self._payload) payload[0] = (function, args, kwargs) try: result = mpi.call(mpi.function_call, _single_worker_call_function, self._payload, worker) finally: payload[0] = None return result
def random_list_array(dims, length, seed): if isinstance(dims, Number): dims = (dims,) return ListVectorArray([MPIVectorAutoComm(NumpyVector, tuple(dims), mpi.call(_random_vector, dims, seed + i)) for i in range(length)], copy=False, subtype=(MPIVectorAutoComm, (NumpyVector, tuple(dims))))
def pairwise_apply2(self, V, U, mu=None): if not self.with_apply2: return super().pairwise_apply2(V, U, mu=mu) assert V in self.range assert U in self.source mu = self.parse_parameter(mu) U = U.obj_id if self.mpi_source else U V = V.obj_id if self.mpi_range else V return mpi.call(mpi.method_call, self.obj_id, 'pairwise_apply2', V, U, mu=mu)
def apply2(self, V, U, mu=None): if not self.with_apply2: return super().apply2(V, U, mu=mu) assert V in self.range assert U in self.source mu = self.parse_parameter(mu) U = U if self.source.id is None else U.obj_id V = V if self.range.id is None else V.obj_id return mpi.call(mpi.method_call, self.obj_id, 'apply2', V, U, mu=mu)
def pairwise_apply2(self, V, U, U_ind=None, V_ind=None, mu=None): if not self.with_apply2: return super().pairwise_apply2(V, U, U_ind=U_ind, V_ind=V_ind, mu=mu) assert V in self.range assert U in self.source mu = self.parse_parameter(mu) U = U if self.vector else U.obj_id V = V if self.functional else V.obj_id return mpi.call(mpi.method_call, self.obj_id, "pairwise_apply2", V, U, U_ind=U_ind, V_ind=V_ind, mu=mu)
def apply_inverse(self, V, ind=None, mu=None, least_squares=False): if self.vector or self.functional: raise NotImplementedError assert V in self.range mu = self.parse_parameter(mu) space = self.source return space.type(space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse', V.obj_id, ind=ind, mu=mu, least_squares=least_squares))
def mpi_wrap_operator(obj_id, with_apply2=False, pickle_local_spaces=True, space_type=MPIVectorSpace): """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0. Given MPI distributed local |Operators| referred to by the :class:`~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator| which manages these distributed operators from rank 0. This is done by instantiating :class:`MPIOperator`. Additionally, the structure of the wrapped operators is preserved. E.g. |LincombOperators| will be wrapped as a |LincombOperator| of :class:`MPIOperators <MPIOperator>`. Parameters ---------- See :class:`MPIOperator`. Returns ------- The wrapped |Operator|. """ op = mpi.get_object(obj_id) if isinstance(op, LincombOperator): obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id) return LincombOperator([ mpi_wrap_operator(o, with_apply2, pickle_local_spaces, space_type) for o in obj_ids ], op.coefficients, name=op.name) elif isinstance(op, VectorArrayOperator): array_obj_id, local_spaces = mpi.call( _mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0], ) return VectorArrayOperator( space_type(local_spaces).make_array(array_obj_id), transposed=op.transposed, name=op.name) else: return MPIOperator(obj_id, with_apply2, pickle_local_spaces, space_type)
def components(self, component_indices, ind=None): offsets = getattr(self, '_offsets', None) if offsets is None: offsets = self._get_dims()[1] component_indices = np.array(component_indices) return mpi.call(_MPIVectorArrayAutoComm_components, self.obj_id, offsets, component_indices, ind=ind)
def __init__(self, obj_id, operators, products=None, pickle_local_spaces=True, space_type=MPIVectorSpace): d = mpi.get_object(obj_id) visualizer = MPIVisualizer(obj_id) super().__init__(operators=operators, products=products, visualizer=visualizer, cache_region=None, name=d.name) self.obj_id = obj_id local_spaces = mpi.call(_MPIDiscretization_get_local_spaces, obj_id, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) self.solution_space = space_type(local_spaces) self.build_parameter_type(d) self.parameter_space = d.parameter_space
def random_list_array(dims, length, seed): if isinstance(dims, Number): dims = (dims, ) return ListVectorArray([ MPIVectorAutoComm(NumpyVector, tuple(dims), mpi.call(_random_vector, dims, seed + i)) for i in range(length) ], copy=False, subtype=(MPIVectorAutoComm, (NumpyVector, tuple(dims))))
def amax(self): offsets = getattr(self, '_offsets', None) if offsets is None: offsets = self.space._get_dims()[1] inds, vals = mpi.call(_MPIVectorArrayAutoComm_amax, self.obj_id) inds += offsets[:, np.newaxis] max_inds = np.argmax(vals, axis=0) # np.choose does not work due to # https://github.com/numpy/numpy/issues/3259 return (np.array([inds[max_inds[i], i] for i in range(len(max_inds))]), np.array([vals[max_inds[i], i] for i in range(len(max_inds))]))
def pairwise_apply2(self, V, U, U_ind=None, V_ind=None, mu=None, product=None): if not self.with_apply2: return super(MPIOperator, self).pairwise_apply2(V, U, U_ind=U_ind, V_ind=V_ind, mu=mu, product=product) assert V in self.range assert U in self.source mu = self.parse_parameter(mu) U = U if self.vector else U.obj_id V = V if self.functional else V.obj_id product = product and product.obj_id return mpi.call(mpi.method_call, self.obj_id, 'pairwise_apply2', V, U, U_ind=U_ind, V_ind=V_ind, mu=mu, product=product)
def amax(self, ind=None): offsets = getattr(self, '_offsets', None) if offsets is None: offsets = self._get_dims()[1] inds, vals = mpi.call(_MPIVectorArrayAutoComm_amax, self.obj_id, ind=ind) inds += offsets[:, np.newaxis] max_inds = np.argmax(vals, axis=0) # np.choose does not work due to # https://github.com/numpy/numpy/issues/3259 return (np.array([inds[max_inds[i], i] for i in range(len(max_inds))]), np.array([vals[max_inds[i], i] for i in range(len(max_inds))]))
def apply_inverse_adjoint(self, U, mu=None, least_squares=False): if not self.mpi_source or not self.mpi_range: raise NotImplementedError assert U in self.source mu = self.parse_parameter(mu) return self.source.make_array( mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse_adjoint', U.obj_id, mu=mu, least_squares=least_squares))
def __init__(self, obj_id, operators, functionals, vector_operators, products=None, array_type=MPIVectorArray): d = mpi.get_object(obj_id) visualizer = MPIVisualizer(obj_id) super(MPIDiscretization, self).__init__(operators, functionals, vector_operators, products=products, visualizer=visualizer, cache_region=None, name=d.name) self.obj_id = obj_id subtypes = mpi.call(_MPIDiscretization_get_subtypes, obj_id) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0],) self.solution_space = VectorSpace(array_type, (d.solution_space.type, subtypes)) self.build_parameter_type(inherits=(d,)) self.parameter_space = d.parameter_space
def apply(self, U, ind=None, mu=None): assert U in self.source mu = self.parse_parameter(mu) U = U if self.vector else U.obj_id if self.functional: return mpi.call(mpi.method_call, self.obj_id, 'apply', U, ind=ind, mu=mu) else: space = self.range return space.type( space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'apply', U, ind=ind, mu=mu))
def as_vector(self, mu=None): mu = self.parse_parameter(mu) if self.functional: space = self.source return space.type( space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'as_vector', mu=mu)) else: raise NotImplementedError
def apply_inverse(self, V, mu=None, least_squares=False): if self.source.id is None or self.range.id is None: raise NotImplementedError assert V in self.range mu = self.parse_parameter(mu) return self.source.make_array( mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse', V.obj_id, mu=mu, least_squares=least_squares))
def apply_inverse(self, V, ind=None, mu=None, least_squares=False): if self.vector or self.functional: raise NotImplementedError assert V in self.range mu = self.parse_parameter(mu) space = self.source return space.type( space.subtype[0], space.subtype[1], mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse', V.obj_id, ind=ind, mu=mu, least_squares=least_squares))
def __init__(self, obj_id, functional=False, vector=False, with_apply2=False, pickle_subtypes=True, array_type=MPIVectorArray): assert not (functional and vector) self.obj_id = obj_id self.op = op = mpi.get_object(obj_id) self.functional = functional self.vector = vector self.with_apply2 = with_apply2 self.pickle_subtypes = pickle_subtypes self.array_type = array_type self.linear = op.linear self.name = op.name self.build_parameter_type(inherits=(op, )) if vector: self.source = NumpyVectorSpace(1) assert self.source == op.source else: subtypes = mpi.call(_MPIOperator_get_source_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) self.source = VectorSpace(array_type, (op.source.type, subtypes)) if functional: self.range = NumpyVectorSpace(1) assert self.range == op.range else: subtypes = mpi.call(_MPIOperator_get_range_subtypes, obj_id, pickle_subtypes) if all(subtype == subtypes[0] for subtype in subtypes): subtypes = (subtypes[0], ) self.range = VectorSpace(array_type, (op.range.type, subtypes))
def __init__(self, obj_id, mpi_range, mpi_source, with_apply2=False, pickle_local_spaces=True, space_type=MPIVectorSpace): assert mpi_source or mpi_range self.__auto_init(locals()) self.op = op = mpi.get_object(obj_id) self.linear = op.linear self.name = op.name self.build_parameter_type(op) if mpi_source: local_spaces = mpi.call(_MPIOperator_get_local_spaces, obj_id, True, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) self.source = space_type(local_spaces) else: self.source = op.source if mpi_range: local_spaces = mpi.call(_MPIOperator_get_local_spaces, obj_id, False, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0],) self.range = space_type(local_spaces) else: self.range = op.range self.solver_options = op.solver_options
def make_array(self, obj_id): """Create array from rank-local |VectorArray| instances. Parameters ---------- obj_id :class:`~pymor.tools.mpi.ObjectId` of the MPI distributed instances of `cls` wrapped by this array. Returns ------- The newly created :class:`MPIVectorArray`. """ assert mpi.call(_MPIVectorSpace_check_local_spaces, self.local_spaces, obj_id) return self.array_type(obj_id, self)
def apply_inverse_adjoint(self, U, mu=None, initial_guess=None, least_squares=False): if not self.mpi_source or not self.mpi_range: raise NotImplementedError assert U in self.source assert initial_guess is None or initial_guess in self.range and len( initial_guess) == len(U) assert self.parameters.assert_compatible(mu) return self.source.make_array( mpi.call(mpi.method_call_manage, self.obj_id, 'apply_inverse_adjoint', U.obj_id, mu=mu, initial_guess=(initial_guess.obj_id if initial_guess is not None else None), least_squares=least_squares))
def __init__(self, obj_id, operators, products=None, pickle_local_spaces=True, space_type=MPIVectorSpace): d = mpi.get_object(obj_id) visualizer = MPIVisualizer(obj_id) super().__init__(operators=operators, products=products, visualizer=visualizer, cache_region=None, name=d.name) self.obj_id = obj_id local_spaces = mpi.call(_MPIDiscretization_get_local_spaces, obj_id, pickle_local_spaces) if all(ls == local_spaces[0] for ls in local_spaces): local_spaces = (local_spaces[0], ) self.solution_space = space_type(local_spaces) self.build_parameter_type(d) self.parameter_space = d.parameter_space
def apply2(self, V, U, U_ind=None, V_ind=None, mu=None, product=None): if not self.with_apply2: return super().apply2(V, U, U_ind=U_ind, V_ind=V_ind, mu=mu, product=product) assert V in self.range assert U in self.source mu = self.parse_parameter(mu) U = U if self.vector else U.obj_id V = V if self.functional else V.obj_id product = product and product.obj_id return mpi.call(mpi.method_call, self.obj_id, 'apply2', V, U, U_ind=U_ind, V_ind=V_ind, mu=mu, product=product)
def _remove_object(self, remote_id): mpi.call(mpi.remove_object, remote_id)
def _apply(self, function, *args, **kwargs): return mpi.call(mpi.function_call, _worker_call_function, function, *args, **kwargs)
def _push_object(self, obj): return mpi.call(mpi.function_call_manage, _push_object, obj)
def __del__(self): mpi.call(mpi.remove_object, self._payload)
def __init__(self): super().__init__() self.logger.info(f'Connected to {mpi.size} ranks') self._payload = mpi.call(mpi.function_call_manage, _setup_worker) self._apply(os.chdir, os.getcwd())
def l1_norm(self): return mpi.call(mpi.method_call, self.obj_id, 'l1_norm')
def lincomb(self, coefficients): return type(self)(mpi.call(mpi.method_call_manage, self.obj_id, 'lincomb', coefficients), self.space)
def pairwise_dot(self, other): return mpi.call(mpi.method_call, self.obj_id, 'pairwise_dot', other.obj_id)
def dot(self, other): return mpi.call(mpi.method_call, self.obj_id, 'dot', other.obj_id)
def l2_norm2(self): return mpi.call(mpi.method_call, self.obj_id, 'l2_norm2')
def scal(self, alpha): mpi.call(mpi.method_call, self.obj_id, 'scal', alpha)
def components(self, component_indices): return mpi.call(mpi.method_call, self.obj_id, 'components', component_indices)
def random_array(dims, length, seed): if isinstance(dims, Number): dims = (dims,) return MPIVectorSpaceAutoComm(tuple(NumpyVectorSpace(dim) for dim in dims)).make_array( mpi.call(_random_array, dims, length, seed) )
def axpy(self, alpha, x): mpi.call(_MPIVectorArray_axpy, self.obj_id, alpha, x.obj_id)