mumps_interface.cpp
1 
2 /*
3  * This file is part of CasADi.
4  *
5  * CasADi -- A symbolic framework for dynamic optimization.
6  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
7  * KU Leuven. All rights reserved.
8  * Copyright (C) 2011-2014 Greg Horn
9  *
10  * CasADi is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * CasADi is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with CasADi; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 
27 #include "mumps_interface.hpp"
28 #include "casadi/core/global_options.hpp"
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_LINSOL_MUMPS_EXPORT
34  casadi_register_linsol_mumps(LinsolInternal::Plugin* plugin) {
35  plugin->creator = MumpsInterface::creator;
36  plugin->name = "mumps";
37  plugin->doc = MumpsInterface::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &MumpsInterface::options_;
40  plugin->deserialize = &MumpsInterface::deserialize;
41  return 0;
42  }
43 
44  extern "C"
45  void CASADI_LINSOL_MUMPS_EXPORT casadi_load_linsol_mumps() {
47  }
48 
49  MumpsInterface::MumpsInterface(const std::string& name, const Sparsity& sp)
50  : LinsolInternal(name, sp) {
51  }
52 
54  clear_mem();
55  }
56 
59  {{"symmetric",
60  {OT_BOOL,
61  "Symmetric matrix"}},
62  {"posdef",
63  {OT_BOOL,
64  "Positive definite"}}
65  }
66  };
67 
68  void MumpsInterface::init(const Dict& opts) {
69  // Call the init method of the base class
71 
72  // Default options
73  symmetric_ = false;
74  posdef_ = false;
75 
76  // Read user options
77  for (auto&& op : opts) {
78  if (op.first=="symmetric") {
79  symmetric_ = op.second;
80  } else if (op.first=="posdef") {
81  posdef_ = op.second;
82  }
83  }
84 
85  // Options consistency
86  if (posdef_ && !symmetric_) casadi_error("Inconsistent options");
87  }
88 
89  int MumpsInterface::init_mem(void* mem) const {
90  if (LinsolInternal::init_mem(mem)) return 1;
91  auto m = static_cast<MumpsMemory*>(mem);
92  // Free existing MUMPS instance, if any
93  if (m->id) {
94  // Terminate the instance of the package
95  m->id->job = -2;
96  dmumps_c(m->id);
97  // Delete the memory structure
98  delete m->id;
99  }
100  m->id = new DMUMPS_STRUC_C();
101 
102  // Initialize MUMPS
103  m->id->job = -1; // initializes an instance of the package
104  m->id->par = 1;
105  m->id->sym = symmetric_ ? posdef_ ? 2 : 1 : 0;
106  m->id->comm_fortran = -987654;
107  dmumps_c(m->id);
108 
109  // Sparsity pattern in MUMPS format
110  casadi_int n = this->nrow();
111  casadi_int nnz = symmetric_ ? sp_.nnz_upper() : this->nnz();
112  m->nz.resize(nnz);
113  m->irn.clear();
114  m->jcn.clear();
115  m->irn.reserve(nnz);
116  m->jcn.reserve(nnz);
117  const casadi_int* colind = this->colind();
118  const casadi_int* row = this->row();
119  for (casadi_int c = 0; c < n; ++c) {
120  for (casadi_int k = colind[c]; k < colind[c + 1]; ++k) {
121  if (!symmetric_ || row[k] <= c) {
122  m->irn.push_back(row[k] + 1);
123  m->jcn.push_back(c + 1);
124  }
125  }
126  }
127 
128  return 0;
129  }
130 
131  int MumpsInterface::nfact(void* mem, const double* A) const {
132  auto m = static_cast<MumpsMemory*>(mem);
133  casadi_assert_dev(A!=nullptr);
134 
135  // Copy nonzero entries to m->nz
136  auto nz_it = m->nz.begin();
137  if (symmetric_) {
138  // Get upper triangular entries
139  casadi_int n = this->nrow();
140  const casadi_int* colind = this->colind();
141  const casadi_int* row = this->row();
142  for (casadi_int c = 0; c < n; ++c) {
143  for (casadi_int k = colind[c]; k < colind[c + 1]; ++k) {
144  if (row[k] <= c) *nz_it++ = A[k];
145  }
146  }
147  } else {
148  // Copy all entries
149  std::copy(A, A + this->nnz(), nz_it);
150  }
151 
152  // Define problem
153  m->id->n = this->nrow();
154  m->id->nnz = m->nz.size();
155  m->id->irn = get_ptr(m->irn);
156  m->id->jcn = get_ptr(m->jcn);
157  m->id->a = get_ptr(m->nz);
158 
159  // No outputs
160  m->id->icntl[1 - 1] = -1;
161  m->id->icntl[2 - 1] = -1;
162  m->id->icntl[3 - 1] = -1;
163  m->id->icntl[4 - 1] = 0;
164 
165  // Symbolic and numeric factorization
166  m->id->job = 4;
167  dmumps_c(m->id);
168 
169  return 0;
170  }
171 
172  int MumpsInterface::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
173  auto m = static_cast<MumpsMemory*>(mem);
174 
175  // Transpose or not?
176  m->id->icntl[9 - 1] = tr ? 0 : 1;
177 
178  // Solve factorized linear system
179  m->id->job = 3;
180 
181  for (casadi_int i=0;i<nrhs;++i) {
182  m->id->rhs = x;
183  dmumps_c(m->id);
184  x += m->id->n;
185  }
186 
187  return 0;
188  }
189 
191  this->id = 0;
192  }
193 
195  if (this->id) {
196  // Terminate the instance of the package
197  this->id->job = -2;
198  dmumps_c(this->id);
199  // Delete the structure
200  delete this->id;
201  }
202  }
203 
205  s.version("Mumps", 1);
206  s.unpack("MumpsInterface::symmetric", symmetric_);
207  s.unpack("MumpsInterface::posdef", posdef_);
208  }
209 
212  s.version("Mumps", 1);
213  s.pack("MumpsInterface::symmetric", symmetric_);
214  s.pack("MumpsInterface::posdef", posdef_);
215  }
216 
217 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
const casadi_int * colind() const
void init(const Dict &opts) override
Initialize.
const casadi_int * row() const
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int nnz() const
casadi_int nrow() const
Get sparsity pattern.
int init_mem(void *mem) const override
Initalize memory block.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int init_mem(void *mem) const override
Initalize memory block.
static const Options options_
Options.
int nfact(void *mem, const double *A) const override
Numeric factorization.
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new Linsol.
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
static const std::string meta_doc
A documentation string.
MumpsInterface(const std::string &name, const Sparsity &sp)
void init(const Dict &opts) override
Initialize.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
static const Options options_
Options.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
General sparsity class.
Definition: sparsity.hpp:106
casadi_int nnz_upper(bool strictly=false) const
Number of non-zeros in the upper triangular half,.
Definition: sparsity.cpp:356
The casadi namespace.
Definition: archiver.cpp:28
void CASADI_LINSOL_MUMPS_EXPORT casadi_load_linsol_mumps()
int CASADI_LINSOL_MUMPS_EXPORT casadi_register_linsol_mumps(LinsolInternal::Plugin *plugin)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
DMUMPS_STRUC_C * id
Options metadata for a class.
Definition: options.hpp:40