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-2026 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 /// Final optional argument specifies the largest abs value below which
370 /// entries are suppressed
372 const double& cutoff = 0.0) const
373 {
374 for (unsigned long i = 0; i < nrow(); i++)
375 {
376 for (unsigned long j = 0; j < ncol(); j++)
377 {
378 double entry = operator()(i, j);
379 // Output if non-zero entry
380 if (entry != 0.0)
381 {
382 if (std::abs(entry) > cutoff)
383 {
384 outfile << i << " " << j << " " << entry << std::endl;
385 }
386 }
387 }
388 }
389 }
390
391
392 /// Get a list of row/col indices and total entry for non-zeros in
393 /// the matrix. e.g. for use as input to other matrix classes. Warning this
394 /// is SLOW! for sparse matrices.
397 Vector<double>& values)
398 {
399 row.clear();
400 col.clear();
401 values.clear();
402
403 for (int i = 0; i < int(nrow()); i++)
404 {
405 for (int j = 0; j < int(ncol()); j++)
406 {
407 double entry = operator()(i, j);
408 // Output if non-zero entry
409 if (entry != 0.0)
410 {
411 row.push_back(i);
412 col.push_back(j);
413 values.push_back(entry);
414 }
415 }
416 }
417 }
418
419 /// Add a new matrix to the sum by giving a matrix pointer and a
420 /// mapping from the main matrix numbering to the added matrix's numbering.
424 bool should_delete_matrix = false)
425 {
426#ifdef PARANOID
427 // Check that row mapping has correct size
428 if (main_to_added_rows_pt->main_to_added_mapping_pt()->size() >
429 added_matrix_pt_in->nrow())
430 {
431 throw OomphLibError(
432 "Row mapping size should be less than or equal to nrow (less than if "
433 "it is a sparse matrix and there are some empty rows).",
436 }
437
438 // Check that col mapping has correct size
439 if (main_to_added_cols_pt->main_to_added_mapping_pt()->size() >
440 added_matrix_pt_in->ncol())
441 {
442 throw OomphLibError(
443 "Col mapping size should be less than or equal to ncol (less than if "
444 "it is a sparse matrix and there are some empty cols).",
447 }
448#endif
449#ifdef RANGE_CHECKING
450 // Check that all entries in the row mapping are "in range" for the
451 // main matrix.
453 main_to_added_rows_pt->added_to_main_mapping_pt();
454 unsigned max_row =
455 *std::max_element(rowmap_pt->begin(), rowmap_pt->end());
456 if (max_row > main_matrix_pt()->nrow())
457 {
458 std::string err =
459 "Trying to add a matrix with a mapping which specifices";
460 err += " a max row of " + to_string(max_row) + " but the main matrix ";
461 err += "only has " + to_string(main_matrix_pt()->nrow()) + " rows!";
462 throw OomphLibError(
464 }
465
466 // Check that all entries in the row mapping are "in range" for the
467 // main matrix.
469 main_to_added_cols_pt->added_to_main_mapping_pt();
470 unsigned max_col =
471 *std::max_element(colmap_pt->begin(), colmap_pt->end());
472 if (max_col > main_matrix_pt()->ncol())
473 {
474 std::string err =
475 "Trying to add a matrix with a mapping which specifices";
476 err += " a max col of " + to_string(max_col) + " but the main matrix ";
477 err += "only has " + to_string(main_matrix_pt()->ncol()) + " cols!";
478 throw OomphLibError(
480 }
481#endif
482
487 }
488
489 /// Access function for ith added matrix (main matrix not included in
490 /// numbering).
491 inline DoubleMatrixBase* added_matrix_pt(const unsigned& i) const
492 {
493 return Added_matrix_pt[i];
494 }
495
496 /// Access to the maps
497 const AddedMainNumberingLookup* row_map_pt(const unsigned& i) const
498 {
499 return Row_map_pt[i];
500 }
501 const AddedMainNumberingLookup* col_map_pt(const unsigned& i) const
502 {
503 return Col_map_pt[i];
504 }
505
506 /// Return the number of rows of the main matrix.
507 inline unsigned long nrow() const
508 {
509#ifdef PARANOID
510 if (Main_matrix_pt == 0)
511 {
512 throw OomphLibError("Main_matrix_pt not set",
515 }
516#endif
517 return Main_matrix_pt->nrow();
518 }
519
520 /// Return the number of columns of the main matrix.
521 inline unsigned long ncol() const
522 {
523#ifdef PARANOID
524 if (Main_matrix_pt == 0)
525 {
526 throw OomphLibError("Main_matrix_pt not set",
529 }
530#endif
531 return Main_matrix_pt->ncol();
532 }
533
534 /// Return the number of added matrices in the sum
535 inline unsigned n_added_matrix() const
536 {
537 return Added_matrix_pt.size();
538 }
539
540 /// Multiply: just call multiply on each of the matrices and add up
541 /// the results (with appropriate bookeeping of the relative positions).
542 void multiply(const DoubleVector& x, DoubleVector& soln) const;
543
544 /// Broken operator() because it does not make sense to return
545 /// anything by reference.
546 double& entry(const unsigned long& i, const unsigned long& j) const
547 {
548 throw OomphLibError(
549 "Broken write to entry: it does not make sense to write to a sum, you "
550 "must write to one of the component matrices.",
553 }
554
555 /// Access function to get the total value of entries in position
556 /// (i,j). Warning: this way of getting entries is far too slow to use
557 /// inside of loops.
558 double operator()(const unsigned long& i, const unsigned long& j) const
559 {
560 // Get contributions from all matrices
561 double sum = main_matrix_pt()->operator()(i, j);
562 for (unsigned i_matrix = 0; i_matrix < n_added_matrix(); i_matrix++)
563 {
564 int li = Row_map_pt[i_matrix]->unsafe_main_to_added(i);
565 int lj = Col_map_pt[i_matrix]->unsafe_main_to_added(j);
566
567 // If the added matrix contributes to this entry then add it
568 if ((li != -1) && (lj != -1))
569 {
570 sum += added_matrix_pt(i_matrix)->operator()(li, lj);
571 }
572 }
573
574 return sum;
575 }
576
577 /// Dummy overload of a pure virtual function. I'm not sure how best
578 /// to implement this and I don't think I need it.
579 virtual void multiply_transpose(const DoubleVector& x,
580 DoubleVector& soln) const
581 {
582 std::ostringstream error_msg;
583 error_msg << "Function not yet implemented.";
584 throw OomphLibError(
586
587 // Possible implementations (not really thought through):
588 // - just call multiply transpose on submatrices?
589 // - do something funny with switching row and column maps?
590 }
591 };
592
593
594} // namespace oomph
595#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:291
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:75
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 ...
void sparse_indexed_output_helper(std::ostream &outfile, const double &cutoff=0.0) const
Output the matrix in sparse format. Note that this is going to be slow because we have to check every...
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...
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).