Source code for openmdao.matrices.dense_matrix
"""Define the DenseMatrix class."""
import numpy as np
from openmdao.matrices.coo_matrix import COOMatrix
# NOTE: DenseMatrix is inherited from COOMatrix so that we can easily handle use cases
# where partials overlap the same matrix entries, as in the case of repeated
# src_indices entries. This does require additional memory above storing just
# the dense matrix, but it's worth it because the code is simpler and more robust.
[docs]class DenseMatrix(COOMatrix):
"""
Dense global matrix.
Parameters
----------
comm : MPI.Comm or <FakeComm>
Communicator of the top-level system that owns the <Jacobian>.
is_internal : bool
If True, this is the int_mtx of an AssembledJacobian.
"""
def _build(self, num_rows, num_cols, system=None):
"""
Allocate the matrix.
Parameters
----------
num_rows : int
number of rows in the matrix.
num_cols : int
number of cols in the matrix.
system : <System>
owning system.
"""
super()._build(num_rows, num_cols)
self._coo = self._matrix
def _prod(self, in_vec, mode, mask=None):
"""
Perform a matrix vector product.
Parameters
----------
in_vec : ndarray[:]
incoming vector to multiply.
mode : str
'fwd' or 'rev'.
mask : ndarray of type bool, or None
Array used to mask out part of the input vector.
Returns
-------
ndarray[:]
vector resulting from the product.
"""
# when we have a derivative based solver at a level below the
# group that owns the AssembledJacobian, we need to use only
# the part of the matrix that is relevant to the lower level
# system.
mat = self._matrix
if mode == 'fwd':
if mask is None:
return mat.dot(in_vec)
else:
# Use the special dot product function from masking module so that we
# ignore masked parts.
return np.ma.dot(mat, np.ma.array(in_vec, mask=mask))
else: # rev
if mask is None:
return mat.T.dot(in_vec)
else:
# Mask need to be applied to ext_mtx so that we can ignore multiplication
# by certain columns.
mat_T = mat.T
arrmask = np.zeros(mat_T.shape, dtype=bool)
arrmask[mask, :] = True
masked_mtx = np.ma.array(mat_T, mask=arrmask, fill_value=0.0)
masked_product = np.ma.dot(masked_mtx, in_vec).flatten()
return np.ma.filled(masked_product, fill_value=0.0)
def _create_mask_cache(self, d_inputs):
"""
Create masking array for this matrix.
Note : this only applies when this Matrix is an 'ext_mtx' inside of a
Jacobian object.
Parameters
----------
d_inputs : Vector
The inputs linear vector.
Returns
-------
ndarray or None
The mask array or None.
"""
if d_inputs._in_matvec_context():
input_names = d_inputs._names
mask = np.ones(len(d_inputs), dtype=bool)
for key, val in self._metadata.items():
if key[1] in input_names:
mask[val[0]:val[1]] = False
return mask if np.any(mask) else None
def _pre_update(self):
"""
Do anything that needs to be done at the end of AssembledJacobian._update.
"""
self._matrix = self._coo
def _post_update(self):
"""
Do anything that needs to be done at the end of AssembledJacobian._update.
"""
# this will add any repeated entries together
self._matrix = self._coo.toarray()