Skip to content

Commit

Permalink
Merge branch 'master' into work
Browse files Browse the repository at this point in the history
  • Loading branch information
swryan committed Apr 16, 2020
2 parents 98a83d5 + 487350c commit 36e9cf7
Show file tree
Hide file tree
Showing 18 changed files with 620 additions and 319 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -123,6 +123,7 @@ install:
# NOTE: not using -e on purpose here, to catch packaging errors
- echo ">>> Installing OpenMDAO";
pip install .[all];
pyppeteer-install;

# display summary of installed packages and their versions
- conda list
Expand Down
14 changes: 1 addition & 13 deletions openmdao/core/problem.py
Expand Up @@ -93,8 +93,6 @@ class Problem(object):
Derivatives calculation mode assigned by the user. If set to 'auto', _mode will be
automatically assigned to 'fwd' or 'rev' based on relative sizes of design variables vs.
responses.
_solver_print_cache : list
Allows solver iprints to be set to requested values after setup calls.
_initial_condition_cache : dict
Any initial conditions that are set at the problem level via setitem are cached here
until they can be processed.
Expand Down Expand Up @@ -174,8 +172,6 @@ def __init__(self, model=None, driver=None, comm=None, name=None, **options):

self.comm = comm

self._solver_print_cache = []

self._mode = None # mode is assigned in setup()

self._initial_condition_cache = {}
Expand Down Expand Up @@ -825,11 +821,6 @@ def final_setup(self):
self._setup_recording()
record_viewer_data(self)

# Now that setup has been called, we can set the iprints.
for items in self._solver_print_cache:
self.set_solver_print(level=items[0], depth=items[1], type_=items[2])
self._solver_print_cache = []

if self._setup_status < 2:
self._setup_status = 2
self._set_initial_conditions()
Expand Down Expand Up @@ -1400,10 +1391,7 @@ def set_solver_print(self, level=2, depth=1e99, type_='all'):
type_ : str
Type of solver to set: 'LN' for linear, 'NL' for nonlinear, or 'all' for all.
"""
if (level, depth, type_) not in self._solver_print_cache:
self._solver_print_cache.append((level, depth, type_))

self.model._set_solver_print(level=level, depth=depth, type_=type_)
self.model.set_solver_print(level=level, depth=depth, type_=type_)

def list_problem_vars(self,
show_promoted_name=True,
Expand Down
45 changes: 43 additions & 2 deletions openmdao/core/system.py
Expand Up @@ -34,7 +34,7 @@
from openmdao.utils.coloring import _compute_coloring, Coloring, \
_STD_COLORING_FNAME, _DEF_COMP_SPARSITY_ARGS
import openmdao.utils.coloring as coloring_mod
from openmdao.utils.general_utils import determine_adder_scaler, find_matches, \
from openmdao.utils.general_utils import determine_adder_scaler, \
format_as_float_or_array, ContainsAll, all_ancestors, \
simple_warning, make_set, match_includes_excludes
from openmdao.approximation_schemes.complex_step import ComplexStep
Expand Down Expand Up @@ -118,6 +118,8 @@ class System(object):
publishing work that uses this class.
_full_comm : MPI.Comm or None
MPI communicator object used when System's comm is split for parallel FD.
_solver_print_cache : list
Allows solver iprints to be set to requested values after setup calls.
_subsystems_allprocs : [<System>, ...]
List of all subsystems (children of this system).
_subsystems_myproc : [<System>, ...]
Expand Down Expand Up @@ -369,6 +371,8 @@ def __init__(self, num_par_fd=1, **kwargs):

self.cite = ""

self._solver_print_cache = []

self._subsystems_allprocs = []
self._subsystems_myproc = []
self._subsystems_inds = {}
Expand Down Expand Up @@ -899,6 +903,7 @@ def _final_setup(self, comm, setup_mode, force_alloc_complex=False):
# Same situation with solvers, partials, and Jacobians.
# If we're updating, we just need to re-run setup on these, but no recursion necessary.
self._setup_solvers(recurse=recurse)
self._setup_solver_print(recurse=recurse)
if self._use_derivatives:
self._setup_partials(recurse=recurse)
self._setup_jacobians(recurse=recurse)
Expand Down Expand Up @@ -2419,7 +2424,7 @@ def linear_solver(self, solver):

def _set_solver_print(self, level=2, depth=1e99, type_='all'):
"""
Control printing for solvers and subsolvers in the model.
Apply the given print settings to the internal solvers, recursively.
Parameters
----------
Expand Down Expand Up @@ -2452,6 +2457,42 @@ def _set_solver_print(self, level=2, depth=1e99, type_='all'):
if subsys.nonlinear_solver is not None and type_ != 'LN':
subsys.nonlinear_solver._set_solver_print(level=level, type_=type_)

def _setup_solver_print(self, recurse=True):
"""
Apply the cached solver print settings during setup.
Parameters
----------
recurse : bool
Whether to call this method in subsystems.
"""
for level, depth, type_ in self._solver_print_cache:
self._set_solver_print(level, depth, type_)

if recurse:
for subsys in self._subsystems_myproc:
subsys._setup_solver_print(recurse=recurse)

def set_solver_print(self, level=2, depth=1e99, type_='all'):
"""
Control printing for solvers and subsolvers in the model.
Parameters
----------
level : int
iprint level. Set to 2 to print residuals each iteration; set to 1
to print just the iteration totals; set to 0 to disable all printing
except for failures, and set to -1 to disable all printing including failures.
depth : int
How deep to recurse. For example, you can set this to 0 if you only want
to print the top level linear and nonlinear solver messages. Default
prints everything.
type_ : str
Type of solver to set: 'LN' for linear, 'NL' for nonlinear, or 'all' for all.
"""
if (level, depth, type_) not in self._solver_print_cache:
self._solver_print_cache.append((level, depth, type_))

def _set_approx_partials_meta(self):
# this will load a static coloring (if any) and will populate wrt_matches if
# there is any coloring (static or dynamic).
Expand Down
Expand Up @@ -97,5 +97,15 @@ top solver and the solver in 'g2', but not the solver in 'sub1.sub2.g1'.
openmdao.solvers.tests.test_solver_iprint.TestSolverPrint.test_feature_set_solver_print3
:layout: interleave

The `set_solver_print` method can also be called on Systems.
For instance, if we want to print detailed output from group 'g2' down, we can first call
`set_solver_print` on the problem or the top level model with a level of "-1", and then call it
on group 'g2' with a level of "2".

.. embed-code::
openmdao.solvers.tests.test_solver_iprint.TestSolverPrint.test_feature_set_solver_print4
:layout: interleave



.. tags:: Solver
Expand Up @@ -50,7 +50,7 @@ indented based on its location in the call stack. :
LinearRunOnce#2.Solver.__init__
LinearRunOnce#2.Solver._declare_options
Problem#1.Problem.set_solver_print
Group#1().System._set_solver_print
Group#1().System.set_solver_print
LinearRunOnce#2.Solver._set_solver_print
NonlinearRunOnce#2.Solver._set_solver_print
Problem#1.Problem.setup
Expand Down
18 changes: 4 additions & 14 deletions openmdao/jacobians/assembled_jacobian.py
Expand Up @@ -11,8 +11,6 @@
from openmdao.matrices.csc_matrix import CSCMatrix
from openmdao.utils.units import unit_conversion
from openmdao.utils.array_utils import _flatten_src_indices
from openmdao.utils.mpi import MPI
from openmdao.vectors.vector import INT_DTYPE

_empty_dict = {}

Expand Down Expand Up @@ -114,13 +112,11 @@ def _initialize(self, system):
ext_mtx = self._matrix_class(system.comm, False)

iproc = system.comm.rank
abs2idx = system._var_allprocs_abs2idx['nonlinear']
in_sizes = system._var_sizes['nonlinear']['input']
out_ranges = self._out_ranges
in_ranges = self._in_ranges

abs2prom_out = system._var_abs2prom['output']
owns = system._owning_rank
conns = {} if isinstance(system, Component) else system._conn_global_abs_in2out
abs_key2shape = self._abs_key2shape

Expand Down Expand Up @@ -280,23 +276,16 @@ def _get_subjac_iters(self, system):
int_mtx = self._int_mtx
ext_mtx = self._ext_mtx[system.pathname]
subjacs = system._subjacs_info
owned = system._owning_rank
irank = system.comm.rank
meta = system._var_allprocs_abs2meta
sys_inputs = system._var_allprocs_abs2prom['input']
sys_outputs = system._var_allprocs_abs2prom['output']

if isinstance(system, Component):
global_conns = _empty_dict
iscomp = True
else:
global_conns = system._conn_global_abs_in2out
iscomp = False

output_names = set(n for n in system._var_abs_names['output']
if iscomp or owned[n] == irank or meta[n]['distributed'])
input_names = set(n for n in system._var_abs_names['input']
if iscomp or owned[n] == irank or meta[n]['distributed'])
output_names = set(system._var_abs_names['output'])
input_names = set(system._var_abs_names['input'])

rev_conns = defaultdict(list)
for tgt, src in global_conns.items():
Expand All @@ -310,7 +299,7 @@ def _get_subjac_iters(self, system):
iters_in_ext = []

for abs_key in subjacs:
ofname, wrtname = abs_key
_, wrtname = abs_key
if wrtname in sys_outputs:
if wrtname in output_names:
if abs_key in int_mtx._submats:
Expand Down Expand Up @@ -378,6 +367,7 @@ def _update(self, system):
ext_mtx._update_submat(key, subjacs[key]['value'])

int_mtx._post_update()

if ext_mtx is not None:
ext_mtx._post_update()

Expand Down
62 changes: 5 additions & 57 deletions openmdao/matrices/coo_matrix.py
@@ -1,12 +1,11 @@
"""Define the COOmatrix class."""
from collections import Counter, defaultdict
import numpy as np
from numpy import ndarray
from scipy.sparse import coo_matrix, csc_matrix

from collections import OrderedDict

from openmdao.matrices.matrix import Matrix, _compute_index_map, sparse_types
from openmdao.matrices.matrix import Matrix, _compute_index_map


class COOMatrix(Matrix):
Expand All @@ -17,8 +16,6 @@ class COOMatrix(Matrix):
----------
_coo : coo_matrix
COO matrix. Used as a basis for conversion to CSC, CSR, Dense in inherited classes.
_first_gather : bool
If True, this is the first time the matrix has been gathered (MPI only).
"""

def __init__(self, comm, is_internal):
Expand All @@ -34,7 +31,6 @@ def __init__(self, comm, is_internal):
"""
super(COOMatrix, self).__init__(comm, is_internal)
self._coo = None
self._first_gather = True

def _build_coo(self, system):
"""
Expand All @@ -53,20 +49,9 @@ def _build_coo(self, system):
submats = self._submats
metadata = self._metadata
pre_metadata = self._key_ranges = OrderedDict()
if system is None:
owns = None
iproc = 0
abs2meta = None
else:
owns = system._owning_rank
iproc = system.comm.rank
abs2meta = system._var_allprocs_abs2meta

start = end = 0
for key, (info, loc, src_indices, shape, factor) in submats.items():
wrt_dist = abs2meta[key[1]]['distributed'] if abs2meta and owns else False
if owns and not (owns[key[1]] == iproc or wrt_dist or abs2meta[key[0]]['distributed']):
continue # only keep stuff that this rank owns

val = info['value']
rows = info['rows']
Expand All @@ -75,17 +60,13 @@ def _build_coo(self, system):
full_size = np.prod(shape)
if dense:
if src_indices is None:
if wrt_dist:
delta = np.prod(info['shape'])
else:
delta = full_size
delta = full_size
else:
if wrt_dist:
delta = info['shape'][0] * len(src_indices)
else:
delta = shape[0] * len(src_indices)
delta = shape[0] * len(src_indices)

elif rows is None: # sparse matrix
delta = val.data.size

else: # list sparse format
delta = len(rows)

Expand Down Expand Up @@ -310,36 +291,3 @@ def _convert_mask(self, mask):
The converted mask array.
"""
return mask

def _get_assembled_matrix(self, system):
assert self._is_internal
if self._first_gather:
self._first_gather = False

# only need to gather the row/col indices the first time. After that we only need
# the data.
all_mtx = system.comm.gather(self._coo, root=0)

if system.comm.rank == 0:
data = []
rows = []
cols = []
for i, mtx in enumerate(all_mtx):
data.append(mtx.data)
rows.append(mtx.row)
cols.append(mtx.col)

data = np.hstack(data)
self._gathered_rows = rows = np.hstack(rows)
self._gathered_cols = cols = np.hstack(cols)

return csc_matrix((data, (rows, cols)), shape=self._matrix.shape)
else:
all_data = system.comm.gather(self._coo.data, root=0)

if system.comm.rank == 0:
data = np.hstack(all_data)
rows = self._gathered_rows
cols = self._gathered_cols

return csc_matrix((data, (rows, cols)), shape=self._matrix.shape)
10 changes: 0 additions & 10 deletions openmdao/matrices/dense_matrix.py
@@ -1,8 +1,5 @@
"""Define the DenseMatrix class."""
import numpy as np
from numpy import ndarray

from scipy.sparse import coo_matrix

from openmdao.matrices.coo_matrix import COOMatrix

Expand Down Expand Up @@ -116,10 +113,3 @@ def _post_update(self):
"""
# this will add any repeated entries together
self._matrix = self._coo.toarray()

def _get_assembled_matrix(self, system):
mat = super(DenseMatrix, self)._get_assembled_matrix(system)
if mat is None:
return mat

return mat.toarray()

0 comments on commit 36e9cf7

Please sign in to comment.