Source code for pyomo.contrib.interior_point.linalg.mumps_interface

# ____________________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2026 National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and Engineering
# Solutions of Sandia, LLC, the U.S. Government retains certain rights in this
# software.  This software is distributed under the 3-clause BSD License.
# ____________________________________________________________________________________

from .base_linear_solver_interface import IPLinearSolverInterface
from pyomo.contrib.pynumero.linalg.base import LinearSolverStatus, LinearSolverResults
from pyomo.common.dependencies import attempt_import
from collections import OrderedDict
from typing import Union, Optional, Tuple
from pyomo.contrib.pynumero.sparse import BlockVector
import numpy as np

mumps, mumps_available = attempt_import(
    name='pyomo.contrib.pynumero.linalg.mumps_interface',
    error_message='pymumps is required to use the MumpsInterface',
)

from pyomo.contrib.pynumero.linalg.mumps_interface import (
    MumpsCentralizedAssembledLinearSolver,
)


[docs] class MumpsInterface(MumpsCentralizedAssembledLinearSolver, IPLinearSolverInterface): @classmethod def getLoggerName(cls): return 'mumps'
[docs] def __init__(self, par=1, comm=None, cntl_options=None, icntl_options=None): if icntl_options is None: icntl_options = dict() # These options are set in order to get the correct inertia. if 13 not in icntl_options: icntl_options[13] = 1 if 24 not in icntl_options: icntl_options[24] = 0 super(MumpsInterface, self).__init__( sym=2, par=par, comm=comm, cntl_options=cntl_options, icntl_options=icntl_options, ) self.error_level = self.get_icntl(11) self.log_error = bool(self.error_level) self.logger = self.getLogger() self.log_header(include_error=self.log_error)
[docs] def do_back_solve( self, rhs: Union[np.ndarray, BlockVector], raise_on_error: bool = True ) -> Tuple[Optional[Union[np.ndarray, BlockVector]], LinearSolverResults]: res, status = super(MumpsInterface, self).do_back_solve( rhs, raise_on_error=raise_on_error ) self.log_info() return res, status
def get_inertia(self): num_negative_eigenvalues = self.get_infog(12) num_zero_eigenvalues = self.get_infog(28) num_positive_eigenvalues = ( self._dim - num_negative_eigenvalues - num_zero_eigenvalues ) return num_positive_eigenvalues, num_negative_eigenvalues, num_zero_eigenvalues def get_error_info(self): # Access error level contained in ICNTL(11) (Fortran indexing). # Assuming this value has not changed since the solve was performed. error_level = self.get_icntl(11) info = OrderedDict() if error_level == 0: return info elif error_level == 1: info['||A||'] = self.get_rinfog(4) info['||x||'] = self.get_rinfog(5) info['Max resid'] = self.get_rinfog(6) info['Max error'] = self.get_rinfog(9) return info elif error_level == 2: info['||A||'] = self.get_rinfog(4) info['||x||'] = self.get_rinfog(5) info['Max resid'] = self.get_rinfog(6) return info def log_header(self, include_error=True, extra_fields=None): if extra_fields is None: extra_fields = list() header_fields = [] header_fields.append('Status') header_fields.append('n_null') header_fields.append('n_neg') if include_error: header_fields.extend(self.get_error_info().keys()) header_fields.extend(extra_fields) # Allocate 10 spaces for integer values header_string = '{0:<10}' header_string += '{1:<10}' header_string += '{2:<10}' # Allocate 15 spaces for the rest, which I assume are floats for i in range(4, len(header_fields)): header_string += '{' + str(i) + ':<15}' self.logger.info(header_string.format(*header_fields)) def log_info(self): # Which fields to log should be specified at the instance level # Any logging that should be done on an iteration-specific case # should be handled by the IP solver fields = [] fields.append(self.get_infog(1)) # Status, 0 for success fields.append(self.get_infog(28)) # Number of null pivots fields.append(self.get_infog(12)) # Number of negative pivots include_error = self.log_error if include_error: fields.extend(self.get_error_info().values()) extra_fields = [] fields.extend(extra_fields) # Allocate 10 spaces for integer values log_string = '{0:<10}' log_string += '{1:<10}' log_string += '{2:<10}' # Allocate 15 spaces for the rest, which I assume are floats for i in range(4, len(fields)): log_string += '{' + str(i) + ':<15.3e}' self.logger.info(log_string.format(*fields))