sum_of_matrices.h
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26#ifndef OOMPH_SUM_OF_MATRICES_H
27#define OOMPH_SUM_OF_MATRICES_H
28
29
30#include "mesh.h"
31#include "matrices.h"
32#include "Vector.h"
33#include "oomph_utilities.h"
34
35#include <map>
36
37
38namespace oomph
39{
40 using namespace StringConversion;
41
42 // =================================================================
43 /// Class to store bi-directional lookup between added matrix row/col
44 /// numbers to main matrix (SumOfMatrix) row/col numbers.
45 // =================================================================
47 {
48 public:
49 /// Default constructor
51
52 /// Real constructor: construct lookup from node numbers in mesh and
53 /// global equation numbers. Useful for the case when the main matrix is
54 /// a Jacobian and the added matrix is a contribution only on a certain
55 /// mesh.
56 AddedMainNumberingLookup(const Mesh* mesh_pt, const unsigned& dof_index)
57 {
58 this->build(mesh_pt, dof_index);
59 }
60
61 /// Construct lookup schemes from int array (HLib's format for this
62 /// data).
63 AddedMainNumberingLookup(const int* lookup_array, const unsigned& length)
64 {
65 this->build(lookup_array, length);
66 }
67
68 /// Destructor
70
71 /// Given a main matrix row/col number get the equivalent row/col
72 /// in the added matrix. Throw an error if not found.
73 unsigned main_to_added(const int& main) const
74 {
76#ifdef PARANOID
77 // If it's -1 then we failed to find it:
78 if (result == -1)
79 {
80 std::string err = "Main matrix row/col number " + to_string(main) +
81 " not found in lookup.";
82 throw OomphLibError(
84 }
85
86 if (result < 0)
87 {
88 std::string err = "Something crazy went wrong here.";
89 throw OomphLibError(
91 }
92#endif
93
94 return unsigned(result);
95 }
96
97 /// Given a main matrix row/col number get the equivalent row/col
98 /// in the added matrix. Return -1 if not found.
99 int unsafe_main_to_added(const int& main) const
100 {
101 // Find the entry
102 std::map<unsigned, unsigned>::const_iterator it =
103 Main_to_added_mapping.find(unsigned(main));
104
105 // Check the entry existed, it not then return -1.
106 if (it == main_to_added_mapping_pt()->end())
107 {
108 return -1;
109 }
110 else
111 {
112 return it->second;
113 }
114 }
115
116 /// Given a row/col number in the added matrix return the equivalent
117 /// row/col number in the main matrix.
118 unsigned added_to_main(const unsigned& added) const
119 {
121 }
122
123 /// Construct the lookup schemes given a mesh and the degree of freedom
124 /// to lookup main equation numbers for.
125 void build(const Mesh* mesh_pt, const unsigned& dof_index)
126 {
129 }
130
131 /// Construct lookup schemes from int array (HLib's format for this
132 /// data).
133 void build(const int* lookup_array, const unsigned& length)
134 {
135#ifdef PARANOID
136 // Check for negative entries just in case (since it's an integer
137 // array).
138 for (unsigned j = 0; j < length; j++)
139 {
140 if (lookup_array[j] < 0)
141 {
142 std::string err = "negative entry in lookup array!";
143 throw OomphLibError(
145 }
146 }
147#endif
148
149 // Copy array into mapping and generate the inverse lookup
152 }
153
154 /// Construct lookup using node vector
155 void build(const Vector<const Node*>& bem_lookup, const unsigned& dof_index)
156 {
157 const unsigned ni = bem_lookup.size();
158 Added_to_main_mapping.assign(ni, -1);
159
160 for (unsigned i = 0; i < ni; i++)
161 {
163 }
164
166 }
167
168 /// Construct an identity map (mostly for testing).
169 void build_identity_map(const unsigned& n)
170 {
171 Added_to_main_mapping.assign(n, 0);
172 for (unsigned j = 0; j < n; j++)
173 {
175 }
177 }
178
179
180 // Access functions
181 // ============================================================
182
183 /// Const access function for mapping.
185 {
186 return &Added_to_main_mapping;
187 }
188
189 /// Const access function for mapping.
190 const std::map<unsigned, unsigned>* main_to_added_mapping_pt() const
191 {
192 return &Main_to_added_mapping;
193 }
194
195 private:
196 /// Set up the lookup from added matrix row/col to main matrix.
198 const unsigned& dof_index)
199 {
200 // Basically just copy from the node data.
201 Added_to_main_mapping.resize(mesh_pt->nnode());
202 for (unsigned nd = 0, nnode = mesh_pt->nnode(); nd < nnode; nd++)
203 {
205 }
206 }
207
208 /// Set up the main to added mapping using the added to main mapping.
210 {
211#ifdef PARANOID
212 if (Added_to_main_mapping.size() == 0)
213 {
214 std::ostringstream error_msg;
215 error_msg << "Must set up Added_to_main_mapping first.";
216 throw OomphLibError(
218 }
219#endif
220
221 // Clear old data
222 Main_to_added_mapping.clear();
223
224 // Copy from Added_to_main_mapping with order reversed.
225 for (unsigned j = 0; j < Added_to_main_mapping.size(); j++)
226 {
228 std::make_pair(Added_to_main_mapping[j], j));
229 }
230 }
231
232 /// Mapping from added matrix row/col numbers to main matrix row/col
233 /// numbers.
235
236 /// Mapping from main matrix row/col numbers to added matrix row/col
237 /// numbers. Note that we cannot use a vector here because the main
238 /// matrix rows/cols mapped onto are probably not contiguous. Access
239 /// times are O(log N) so if you need to iterate over all elements then
240 /// use the pointer access functions and use stl iterators properly.
241 std::map<unsigned, unsigned> Main_to_added_mapping;
242
243 /// Inaccessible copy constructor
245
246 /// Inaccessible assignment operator
248 };
249
250
251 //======================================================================
252 /// Class for a matrix of the form M = S + G + H + ... where S is the main
253 /// matrix and G,H etc. are matrices of size S or smaller. This may be useful
254 /// if, for example, G,H etc. are subblocks of M that must be stored in a
255 /// different format to S.
256
257 /// Maps mut be provided which gives a map from the rows/cols of the main
258 /// matrix to the rows/cols of each of the added matrices.
259 //======================================================================
261 public Matrix<double, SumOfMatrices>
262 {
263 private:
264 /// Pointer to the matrix which we are adding the others to
266
267 /// List of pointers to the matrices that are added to the main matrix
269
270 /// List of maps between row numbers of the main matrix and the
271 /// added matrices.
273
274 /// List of maps between col numbers of the main matrix and the
275 /// added matrices.
277
278 /// Should we delete the sub matrices when destructor is called?
280
281 /// Should we delete the main matrix when destructor is called?
282 /// Default is no.
284
285 public:
286 /// Default constructor
296
297 /// Constructor taking a pointer to the main matrix as input.
307
308 /// Broken copy constructor
310
311 /// Broken assignment operator
312 void operator=(const SumOfMatrices&) = delete;
313
314 /// Destructor: delete matrices as instructed by
315 /// Should_delete_added_matrix vector and Should_delete_main_matrix.
317 {
318 for (unsigned i_matrix = 0; i_matrix < Added_matrix_pt.size(); i_matrix++)
319 {
321 {
323 }
324 }
325
327 {
328 delete Main_matrix_pt;
329 }
330 }
331
332 /// Access to the main matrix
334 {
335 return Main_matrix_pt;
336 }
338 {
339 return Main_matrix_pt;
340 }
341
342 /// Set the main matrix to be deleted by the destructor of the
343 /// SumOfMatrices (default is to not delete it).
345 {
347 }
348
349
350 /// Output the "bottom right" entry regardless of it being
351 /// zero or not (this allows automatic detection of matrix size in
352 /// e.g. matlab, python).
353 void output_bottom_right_zero_helper(std::ostream& outfile) const
354 {
355 int last_row = this->nrow() - 1;
356 int last_col = this->ncol() - 1;
357
359
360 if (last_value == 0.0)
361 {
362 outfile << last_row << " " << last_col << " " << 0.0 << std::endl;
363 }
364 }
365
366
367 /// Output the matrix in sparse format. Note that this is going to be
368 /// slow because we have to check every entry of every matrix for non-zeros.
369 void sparse_indexed_output_helper(std::ostream& outfile) const
370 {
371 for (unsigned long i = 0; i < nrow(); i++)
372 {
373 for (unsigned long j = 0; j < ncol(); j++)
374 {
375 double entry = operator()(i, j);
376 // Output if non-zero entry
377 if (entry != 0.0)
378 {
379 outfile << i << " " << j << " " << entry << std::endl;
380 }
381 }
382 }
383 }
384
385
386 /// Get a list of row/col indices and total entry for non-zeros in
387 /// the matrix. e.g. for use as input to other matrix classes. Warning this
388 /// is SLOW! for sparse matrices.
391 Vector<double>& values)
392 {
393 row.clear();
394 col.clear();
395 values.clear();
396
397 for (int i = 0; i < int(nrow()); i++)
398 {
399 for (int j = 0; j < int(ncol()); j++)
400 {
401 double entry = operator()(i, j);
402 // Output if non-zero entry
403 if (entry != 0.0)
404 {
405 row.push_back(i);
406 col.push_back(j);
407 values.push_back(entry);
408 }
409 }
410 }
411 }
412
413 /// Add a new matrix to the sum by giving a matrix pointer and a
414 /// mapping from the main matrix numbering to the added matrix's numbering.
418 bool should_delete_matrix = false)
419 {
420#ifdef PARANOID
421 // Check that row mapping has correct size
422 if (main_to_added_rows_pt->main_to_added_mapping_pt()->size() >
423 added_matrix_pt_in->nrow())
424 {
425 throw OomphLibError(
426 "Row mapping size should be less than or equal to nrow (less than if "
427 "it is a sparse matrix and there are some empty rows).",
430 }
431
432 // Check that col mapping has correct size
433 if (main_to_added_cols_pt->main_to_added_mapping_pt()->size() >
434 added_matrix_pt_in->ncol())
435 {
436 throw OomphLibError(
437 "Col mapping size should be less than or equal to ncol (less than if "
438 "it is a sparse matrix and there are some empty cols).",
441 }
442#endif
443#ifdef RANGE_CHECKING
444 // Check that all entries in the row mapping are "in range" for the
445 // main matrix.
447 main_to_added_rows_pt->added_to_main_mapping_pt();
448 unsigned max_row =
449 *std::max_element(rowmap_pt->begin(), rowmap_pt->end());
450 if (max_row > main_matrix_pt()->nrow())
451 {
452 std::string err =
453 "Trying to add a matrix with a mapping which specifices";
454 err += " a max row of " + to_string(max_row) + " but the main matrix ";
455 err += "only has " + to_string(main_matrix_pt()->nrow()) + " rows!";
456 throw OomphLibError(
458 }
459
460 // Check that all entries in the row mapping are "in range" for the
461 // main matrix.
463 main_to_added_cols_pt->added_to_main_mapping_pt();
464 unsigned max_col =
465 *std::max_element(colmap_pt->begin(), colmap_pt->end());
466 if (max_col > main_matrix_pt()->ncol())
467 {
468 std::string err =
469 "Trying to add a matrix with a mapping which specifices";
470 err += " a max col of " + to_string(max_col) + " but the main matrix ";
471 err += "only has " + to_string(main_matrix_pt()->ncol()) + " cols!";
472 throw OomphLibError(
474 }
475#endif
476
481 }
482
483 /// Access function for ith added matrix (main matrix not included in
484 /// numbering).
485 inline DoubleMatrixBase* added_matrix_pt(const unsigned& i) const
486 {
487 return Added_matrix_pt[i];
488 }
489
490 /// Access to the maps
491 const AddedMainNumberingLookup* row_map_pt(const unsigned& i) const
492 {
493 return Row_map_pt[i];
494 }
495 const AddedMainNumberingLookup* col_map_pt(const unsigned& i) const
496 {
497 return Col_map_pt[i];
498 }
499
500 /// Return the number of rows of the main matrix.
501 inline unsigned long nrow() const
502 {
503#ifdef PARANOID
504 if (Main_matrix_pt == 0)
505 {
506 throw OomphLibError("Main_matrix_pt not set",
509 }
510#endif
511 return Main_matrix_pt->nrow();
512 }
513
514 /// Return the number of columns of the main matrix.
515 inline unsigned long ncol() const
516 {
517#ifdef PARANOID
518 if (Main_matrix_pt == 0)
519 {
520 throw OomphLibError("Main_matrix_pt not set",
523 }
524#endif
525 return Main_matrix_pt->ncol();
526 }
527
528 /// Return the number of added matrices in the sum
529 inline unsigned n_added_matrix() const
530 {
531 return Added_matrix_pt.size();
532 }
533
534 /// Multiply: just call multiply on each of the matrices and add up
535 /// the results (with appropriate bookeeping of the relative positions).
536 void multiply(const DoubleVector& x, DoubleVector& soln) const;
537
538 /// Broken operator() because it does not make sense to return
539 /// anything by reference.
540 double& entry(const unsigned long& i, const unsigned long& j) const
541 {
542 throw OomphLibError(
543 "Broken write to entry: it does not make sense to write to a sum, you "
544 "must write to one of the component matrices.",
547 }
548
549 /// Access function to get the total value of entries in position
550 /// (i,j). Warning: this way of getting entries is far too slow to use
551 /// inside of loops.
552 double operator()(const unsigned long& i, const unsigned long& j) const
553 {
554 // Get contributions from all matrices
555 double sum = main_matrix_pt()->operator()(i, j);
556 for (unsigned i_matrix = 0; i_matrix < n_added_matrix(); i_matrix++)
557 {
558 int li = Row_map_pt[i_matrix]->unsafe_main_to_added(i);
559 int lj = Col_map_pt[i_matrix]->unsafe_main_to_added(j);
560
561 // If the added matrix contributes to this entry then add it
562 if ((li != -1) && (lj != -1))
563 {
564 sum += added_matrix_pt(i_matrix)->operator()(li, lj);
565 }
566 }
567
568 return sum;
569 }
570
571 /// Dummy overload of a pure virtual function. I'm not sure how best
572 /// to implement this and I don't think I need it.
573 virtual void multiply_transpose(const DoubleVector& x,
574 DoubleVector& soln) const
575 {
576 std::ostringstream error_msg;
577 error_msg << "Function not yet implemented.";
578 throw OomphLibError(
580
581 // Possible implementations (not really thought through):
582 // - just call multiply transpose on submatrices?
583 // - do something funny with switching row and column maps?
584 }
585 };
586
587
588} // namespace oomph
589#endif
cstr elem_len * i
Definition cfortran.h:603
Class to store bi-directional lookup between added matrix row/col numbers to main matrix (SumOfMatrix...
AddedMainNumberingLookup(const Mesh *mesh_pt, const unsigned &dof_index)
Real constructor: construct lookup from node numbers in mesh and global equation numbers....
unsigned main_to_added(const int &main) const
Given a main matrix row/col number get the equivalent row/col in the added matrix....
AddedMainNumberingLookup()
Default constructor.
void construct_reverse_mapping()
Set up the main to added mapping using the added to main mapping.
AddedMainNumberingLookup(const int *lookup_array, const unsigned &length)
Construct lookup schemes from int array (HLib's format for this data).
unsigned added_to_main(const unsigned &added) const
Given a row/col number in the added matrix return the equivalent row/col number in the main matrix.
const std::map< unsigned, unsigned > * main_to_added_mapping_pt() const
Const access function for mapping.
Vector< unsigned > Added_to_main_mapping
Mapping from added matrix row/col numbers to main matrix row/col numbers.
AddedMainNumberingLookup(const AddedMainNumberingLookup &dummy)=delete
Inaccessible copy constructor.
int unsafe_main_to_added(const int &main) const
Given a main matrix row/col number get the equivalent row/col in the added matrix....
void build(const Mesh *mesh_pt, const unsigned &dof_index)
Construct the lookup schemes given a mesh and the degree of freedom to lookup main equation numbers f...
void operator=(const AddedMainNumberingLookup &dummy)=delete
Inaccessible assignment operator.
void build_identity_map(const unsigned &n)
Construct an identity map (mostly for testing).
void construct_added_to_main_mapping(const Mesh *mesh_pt, const unsigned &dof_index)
Set up the lookup from added matrix row/col to main matrix.
void build(const Vector< const Node * > &bem_lookup, const unsigned &dof_index)
Construct lookup using node vector.
const Vector< unsigned > * added_to_main_mapping_pt() const
Const access function for mapping.
std::map< unsigned, unsigned > Main_to_added_mapping
Mapping from main matrix row/col numbers to added matrix row/col numbers. Note that we cannot use a v...
void build(const int *lookup_array, const unsigned &length)
Construct lookup schemes from int array (HLib's format for this data).
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition nodes.h:367
Abstract base class for matrices of doubles – adds abstract interfaces for solving,...
Definition matrices.h:261
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
A vector in the mathematical sense, initially developed for linear algebra type applications....
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
Definition elements.h:691
Abstract base class for matrices, templated by the type of object that is stored in them and the type...
Definition matrices.h:74
A general mesh class.
Definition mesh.h:67
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition mesh.h:440
unsigned long nnode() const
Return number of nodes in the mesh.
Definition mesh.h:604
An OomphLibError object which should be thrown when an run-time error is encountered....
Class for a matrix of the form M = S + G + H + ... where S is the main matrix and G,...
virtual void multiply_transpose(const DoubleVector &x, DoubleVector &soln) const
Dummy overload of a pure virtual function. I'm not sure how best to implement this and I don't think ...
SumOfMatrices(const SumOfMatrices &matrix)=delete
Broken copy constructor.
void output_bottom_right_zero_helper(std::ostream &outfile) const
Output the "bottom right" entry regardless of it being zero or not (this allows automatic detection o...
SumOfMatrices(DoubleMatrixBase *main_matrix_pt)
Constructor taking a pointer to the main matrix as input.
DoubleMatrixBase *& main_matrix_pt()
unsigned n_added_matrix() const
Return the number of added matrices in the sum.
const AddedMainNumberingLookup * row_map_pt(const unsigned &i) const
Access to the maps.
unsigned long nrow() const
Return the number of rows of the main matrix.
SumOfMatrices()
Default constructor.
Vector< DoubleMatrixBase * > Added_matrix_pt
List of pointers to the matrices that are added to the main matrix.
Vector< const AddedMainNumberingLookup * > Col_map_pt
List of maps between col numbers of the main matrix and the added matrices.
void set_delete_main_matrix()
Set the main matrix to be deleted by the destructor of the SumOfMatrices (default is to not delete it...
double operator()(const unsigned long &i, const unsigned long &j) const
Access function to get the total value of entries in position (i,j). Warning: this way of getting ent...
void add_matrix(DoubleMatrixBase *added_matrix_pt_in, const AddedMainNumberingLookup *main_to_added_rows_pt, const AddedMainNumberingLookup *main_to_added_cols_pt, bool should_delete_matrix=false)
Add a new matrix to the sum by giving a matrix pointer and a mapping from the main matrix numbering t...
const AddedMainNumberingLookup * col_map_pt(const unsigned &i) const
void operator=(const SumOfMatrices &)=delete
Broken assignment operator.
const DoubleMatrixBase * main_matrix_pt() const
Access to the main matrix.
Vector< const AddedMainNumberingLookup * > Row_map_pt
List of maps between row numbers of the main matrix and the added matrices.
Vector< unsigned > Should_delete_added_matrix
Should we delete the sub matrices when destructor is called?
void get_as_indices(Vector< int > &row, Vector< int > &col, Vector< double > &values)
Get a list of row/col indices and total entry for non-zeros in the matrix. e.g. for use as input to o...
double & entry(const unsigned long &i, const unsigned long &j) const
Broken operator() because it does not make sense to return anything by reference.
unsigned long ncol() const
Return the number of columns of the main matrix.
void multiply(const DoubleVector &x, DoubleVector &soln) const
Multiply: just call multiply on each of the matrices and add up the results (with appropriate bookeep...
DoubleMatrixBase * added_matrix_pt(const unsigned &i) const
Access function for ith added matrix (main matrix not included in numbering).
bool Should_delete_main_matrix
Should we delete the main matrix when destructor is called? Default is no.
~SumOfMatrices()
Destructor: delete matrices as instructed by Should_delete_added_matrix vector and Should_delete_main...
void sparse_indexed_output_helper(std::ostream &outfile) const
Output the matrix in sparse format. Note that this is going to be slow because we have to check every...
DoubleMatrixBase * Main_matrix_pt
Pointer to the matrix which we are adding the others to.
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types).
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).