OOFEM 3.0
Loading...
Searching...
No Matches
skylineu.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "skylineu.h"
36#include "rowcol.h"
37#include "floatmatrix.h"
38#include "intarray.h"
39#include "domain.h"
40#include "engngm.h"
41#include "element.h"
42#include "mathfem.h"
43#include "verbose.h"
44#include "error.h"
45#include "sparsemtrxtype.h"
46#include "activebc.h"
47#include "classfactory.h"
48#ifdef __MPM_MODULE
49#include "../mpm/integral.h"
50#endif
51
52
53#ifdef TIME_REPORT
54 #include "timer.h"
55#endif
56
57namespace oofem {
59
60SkylineUnsym :: SkylineUnsym(int n) : SparseMtrx(n, n),
61 isFactorized(false)
62{
63}
64
65
66SkylineUnsym :: SkylineUnsym(const SkylineUnsym &s) : SparseMtrx(s.nRows, s.nColumns),
69{
70}
71
72
73std::unique_ptr<SparseMtrx>
74SkylineUnsym :: clone() const
75{
76 return std::make_unique<SkylineUnsym>(*this);
77}
78
79
80void
81SkylineUnsym :: toFloatMatrix(FloatMatrix &answer) const
82{
83 answer.resize(this->giveNumberOfRows(), this->giveNumberOfColumns());
84 answer.zero();
85 for ( int j = 1; j <= this->giveNumberOfColumns(); j++ ) {
86 int start = this->rowColumns[j-1].giveStart();
87 for ( int i = start; i <= j; i++ ) {
88 answer.at(i, j) = this->at(i, j);
89 answer.at(j, i) = this->at(j, i);
90 }
91 }
92}
93
94
95double &
96SkylineUnsym :: at(int i, int j)
97{
98 this->version++;
99
100 if ( i < j ) {
101 return this->rowColumns[j-1].atU(i);
102 } else if ( i > j ) {
103 return this->rowColumns[i-1].atL(j);
104 } else {
105 return this->rowColumns[i-1].atDiag();
106 }
107}
108
109
110double
111SkylineUnsym :: at(int i, int j) const
112{
113 if ( i < j ) {
114 return this->rowColumns[j-1].atU(i);
115 } else if ( i > j ) {
116 return this->rowColumns[i-1].atL(j);
117 } else {
118 return this->rowColumns[i-1].atDiag();
119 }
120}
121
122
123int
124SkylineUnsym :: assemble(const IntArray &loc, const FloatMatrix &mat)
125{
126 int dim = mat.giveNumberOfRows();
127
128# ifdef DEBUG
129 if ( dim != loc.giveSize() ) {
130 OOFEM_ERROR("dimension of 'k' and 'loc' mismatch");
131 }
132
133 this->checkSizeTowards(loc);
134# endif
135
136 // added to make it work for nonlocal model !!!!!!!!!!!!!!!!!!!!!!!!!!
137 // checkSizeTowards(loc) ;
138
139 for ( int j = 1; j <= dim; j++ ) {
140 int jj = loc.at(j);
141 if ( jj ) {
142 for ( int i = 1; i <= dim; i++ ) {
143 int ii = loc.at(i);
144 if ( ii ) {
145 this->at(ii, jj) += mat.at(i, j);
146 }
147 }
148 }
149 }
150
151 this->version++;
152
153 return 1;
154}
155
156
157int
158SkylineUnsym :: assemble(const IntArray &rloc, const IntArray &cloc, const FloatMatrix &mat)
159{
160 this->checkSizeTowards(rloc, cloc);
161
162 int dim1 = rloc.giveSize();
163 int dim2 = cloc.giveSize();
164 for ( int i = 1; i <= dim1; i++ ) {
165 int ii = rloc.at(i);
166 if ( ii ) {
167 for ( int j = 1; j <= dim2; j++ ) {
168 int jj = cloc.at(j);
169 if ( jj ) {
170 this->at(ii, jj) += mat.at(i, j);
171 }
172 }
173 }
174 }
175
176 this->version++;
177
178 return 1;
179}
180
181
182void
183SkylineUnsym :: checkSizeTowards(const IntArray &rloc, const IntArray &cloc)
184{
185 int maxCol = 0;
186
187 for ( auto r : rloc ) {
188 maxCol = max( maxCol, r );
189 }
190
191 for ( auto c : cloc ) {
192 maxCol = max( maxCol, c );
193 }
194
195 if ( maxCol > this->giveNumberOfColumns() ) {
196 growTo(maxCol);
197 }
198
199 for ( auto ii : rloc ) {
200 if ( ii ) {
201 rowColumns[ii-1].checkSizeTowards(cloc);
202 }
203 }
204
205 for ( auto jj : cloc ) {
206 if ( jj ) {
207 rowColumns[jj-1].checkSizeTowards(rloc);
208 }
209 }
210}
211
212
213int
214SkylineUnsym :: buildInternalStructure(EngngModel *eModel, int di, const UnknownNumberingScheme &s)
215{
216 // Instanciates the profile of the receiver and initializes all coefficients to zero.
217 // Warning : case diagonal (lumped) matrix to expected.
218 IntArray loc;
219 int first, nonlocal;
220 Domain *domain = eModel->giveDomain(di);
221 int neq = eModel->giveNumberOfDomainEquations(di, s);
222 int nelem = domain->giveNumberOfElements();
223 nonlocal = eModel->useNonlocalStiffnessOption();
224
225 // clear receiver if exist
226 this->rowColumns.clear();
227 this->growTo(neq); // from now on, size = MaxIndex
228
229 // Set up the array with indices of first nonzero elements in each row
230 IntArray firstIndex(neq);
231 for ( int i = 1; i <= neq; i++ ) {
232 firstIndex.at(i) = i;
233 }
234
235 for ( int n = 1; n <= nelem; n++ ) {
236 auto elem = domain->giveElement(n);
237 //elem -> giveLocationArray (loc) ;
238
239 if ( !nonlocal ) {
240 elem->giveLocationArray(loc, s);
241 }
242 //else ((StructuralElement*)elem) -> giveNonlocalLocationArray(loc) ;
243 else {
244 elem->giveLocationArray(loc, s);
245 }
246
247 // Find 'first', the smallest positive number in LocArray
248 first = neq;
249 for ( int i = 1; i <= loc.giveSize(); i++ ) {
250 int ii = loc.at(i);
251 if ( ii && ii < first ) {
252 first = ii;
253 }
254 }
255
256 // Make sure that the FirstIndex is not larger than 'first'
257 for ( int i = 1; i <= loc.giveSize(); i++ ) {
258 int ii = loc.at(i);
259 if ( ii && ( first < firstIndex.at(ii) ) ) {
260 firstIndex.at(ii) = first;
261 }
262 }
263 }
264
265 // loop over active boundary conditions
266 int nbc = domain->giveNumberOfBoundaryConditions();
267 std :: vector< IntArray >r_locs;
268 std :: vector< IntArray >c_locs;
269
270 for ( int i = 1; i <= nbc; ++i ) {
271 ActiveBoundaryCondition *bc = dynamic_cast< ActiveBoundaryCondition * >( domain->giveBc(i) );
272 if ( bc ) {
273 bc->giveLocationArrays(r_locs, c_locs, UnknownCharType, s, s);
274 for ( std :: size_t j = 0; j < r_locs.size(); j++ ) {
275 IntArray &krloc = r_locs [ j ];
276 IntArray &kcloc = c_locs [ j ];
277 first = neq;
278 for ( int k = 1; k <= kcloc.giveSize(); k++ ) {
279 int kk = kcloc.at(k);
280 if ( kk ) {
281 first = min(first, kk);
282 }
283 }
284 for ( int k = 1; k <= krloc.giveSize(); k++ ) {
285 int kk = krloc.at(k);
286 if ( kk && ( first < firstIndex.at(kk) ) ) {
287 firstIndex.at(kk) = first;
288 }
289 }
290 }
291 }
292 }
293
294#ifdef __MPM_MODULE
295 IntArray locr, locc;
296 // loop over integrals
297 for (auto &in: eModel->giveIntegralList()) {
298 // loop over integral domain
299 for (auto &elem: in->set->giveElementList()) {
300 // get code numbers for integral.term on element
301 in->getElementTermCodeNumbers (locr, locc, domain->giveElement(elem), *in->term, s) ;
302 first = neq;
303 for ( int k = 1; k <= locc.giveSize(); k++ ) {
304 int kk = locc.at(k);
305 if ( kk ) {
306 first = min(first, kk);
307 }
308 }
309 for ( int k = 1; k <= locr.giveSize(); k++ ) {
310 int kk = locr.at(k);
311 if ( kk && ( first < firstIndex.at(kk) ) ) {
312 firstIndex.at(kk) = first;
313 }
314 }
315 }
316 }
317#endif
318
319 for ( int i = 1; i <= neq; i++ ) {
320 this->rowColumns[i-1].growTo( firstIndex.at(i) );
321 }
322
323 this->printStatistics();
324
325 nRows = nColumns = neq;
326 this->version++;
327
328 return true;
329}
330
331
332int SkylineUnsym :: setInternalStructure(IntArray &adr1)
333{
334 // allocates and built structure according to given
335 // array of maximal column heights
336 //
337 IntArray mht, firstIndex;
338 int n = adr1.giveSize();
339 this->growTo(n - 1);
340
341 // build first index array
342 mht.resize(n - 1);
343 mht.zero();
344 firstIndex.resize(n - 1);
345 firstIndex.zero();
346 for ( int i = 1; i <= n - 1; i++ ) {
347 mht.at(i) = adr1.at(i + 1) - adr1.at(i);
348 firstIndex.at(i) = i - mht.at(i) + 1;
349 }
350
351 // Enlarge the rowcolumns
352 for ( int i = 1; i <= n - 1; i++ ) {
353 this->rowColumns[i-1].growTo( firstIndex.at(i) );
354 }
355
356 this->printStatistics();
357
358 nRows = nColumns = n - 1;
359
360 this->version++;
361
362 return true;
363}
364
365
366
367void
368SkylineUnsym :: checkSizeTowards(const IntArray &loc)
369{
370 int maxCol = 0; // the largest coefficient in 'loc'
371 for ( auto c: loc ) {
372 maxCol = max( maxCol, c );
373 }
374
375 if ( maxCol > (int)this->rowColumns.size() ) { // enlarge the matrix
376 growTo(maxCol);
377 }
378
379 for ( auto ii: loc ) {
380 if ( ii ) {
381 this->rowColumns[ii-1].checkSizeTowards(loc);
382 }
383 }
384}
385
386
388SkylineUnsym :: factorized()
389// Returns the receiver in L.D.U factorized form. From Golub & van Loan,
390// 1rst edition, pp 83-84.
391{
392 FloatArray r, w;
393#ifdef TIME_REPORT
394 Timer timer;
395 timer.startTimer();
396#endif
397
398 if ( isFactorized ) {
399 return this;
400 }
401
402 if ( this->rowColumns.empty() ) {
403 OOFEM_WARNING("null-sized matrix factorized");
404 isFactorized = 1;
405 return this;
406 }
407
408 for ( int k = 1; k <= this->giveNumberOfColumns(); k++ ) {
409 auto &rowColumnK = this->rowColumns[k-1];
410 int startK = rowColumnK.giveStart();
411
412 // compute vectors r and w
413 r.resize(k - 1);
414 r.zero();
415 w.resize(k - 1);
416 w.zero();
417 for ( int p = startK; p < k; p++ ) {
418 double diag = this->rowColumns[p-1].atDiag();
419 r.at(p) = diag * rowColumnK.atU(p);
420 w.at(p) = diag * rowColumnK.atL(p);
421 }
422
423 // compute diagonal coefficient of rowColumn k
424 rowColumnK.atDiag() -= rowColumnK.dot(r, 'R', startK, k - 1);
425 double diag = rowColumnK.atDiag();
426
427 // test pivot not too small
428 if ( fabs(diag) < SkylineUnsym_TINY_PIVOT ) {
429 rowColumnK.atDiag() = diag = SkylineUnsym_TINY_PIVOT;
430 OOFEM_LOG_DEBUG("SkylineUnsym :: factorized: zero pivot %d artificially set to a small value", k);
431 }
432
433 // compute off-diagonal coefficients of rowColumns i>k
434 for ( int i = k + 1; i <= this->giveNumberOfColumns(); i++ ) {
435 auto &rowColumnI = this->rowColumns[i-1];
436 int startI = rowColumnI.giveStart();
437 if ( startI <= k ) {
438 int start = max(startI, startK);
439 rowColumnI.atL(k) -= rowColumnI.dot(r, 'R', start, k - 1);
440 rowColumnI.atL(k) /= diag;
441 rowColumnI.atU(k) -= rowColumnI.dot(w, 'C', start, k - 1);
442 rowColumnI.atU(k) /= diag;
443 }
444 }
445 }
446
447 isFactorized = true;
448
449#ifdef TIME_REPORT
450 timer.stopTimer();
451 OOFEM_LOG_DEBUG( "SkylineU info: user time consumed by factorization: %.2fs\n", timer.getUtime() );
452#endif
453
454 //this->version++;
455
456 return this;
457}
458
459
460
462SkylineUnsym :: backSubstitutionWith(FloatArray &y) const
463{
464 if ( y.giveSize() != this->giveNumberOfColumns() ) {
465 OOFEM_ERROR("size mismatch");
466 }
467
468 for ( int k = 1; k <= this->giveNumberOfColumns(); k++ ) {
469 auto &rowColumnK = this->rowColumns[k-1];
470 int start = rowColumnK.giveStart();
471 y.at(k) -= rowColumnK.dot(y, 'R', start, k - 1);
472 }
473
474 // diagonalScaling
475 for ( int k = 1; k <= this->giveNumberOfColumns(); k++ ) {
476 double diag = this->rowColumns[k-1].atDiag();
477# ifdef DEBUG
478 if ( fabs(diag) < SkylineUnsym_TINY_PIVOT ) {
479 OOFEM_ERROR("pivot %d is small", k);
480 }
481
482# endif
483 y.at(k) /= diag;
484 }
485
486
487 for ( int k = this->giveNumberOfColumns(); k > 0; k-- ) {
488 auto &rowColumnK = this->rowColumns[k-1];
489 double yK = y.at(k);
490 int start = rowColumnK.giveStart();
491 for ( int i = start; i < k; i++ ) {
492 y.at(i) -= rowColumnK.atU(i) * yK;
493 }
494 }
495
496 return & y;
497}
498
499
500void
501SkylineUnsym :: times(const FloatArray &x, FloatArray &answer) const
502{
503 if ( this->giveNumberOfColumns() != x.giveSize() ) {
504 OOFEM_ERROR("size mismatch");
505 }
506
507 answer.resize(this->giveNumberOfRows());
508 answer.zero();
509
510 for ( int i = 1; i <= this->giveNumberOfColumns(); i++ ) {
511 auto &rowColumni = this->rowColumns[i-1];
512 int starti = rowColumni.giveStart();
513 answer.at(i) += rowColumni.dot(x, 'R', starti, i - 1);
514 answer.at(i) += rowColumni.atDiag() * x.at(i);
515
516 for ( int j = starti; j <= i - 1; j++ ) {
517 answer.at(j) += rowColumni.atU(j) * x.at(i);
518 }
519 }
520}
521
522
523void SkylineUnsym :: times(double x)
524{
525 for ( int i = 1; i <= this->giveNumberOfColumns(); i++ ) {
526 auto &rowColumni = this->rowColumns[i-1];
527 int starti = rowColumni.giveStart();
528 for ( int j = starti; j <= i - 1; j++ ) {
529 rowColumni.atU(j) *= x;
530 rowColumni.atL(j) *= x;
531 }
532
533 rowColumni.atDiag() *= x;
534 }
535
536 this->version++;
537}
538
539
540void
541SkylineUnsym :: growTo(int n)
542{
543 this->rowColumns.reserve(n);
544 for (int i = 1; i <= n; ++i ) {
545 this->rowColumns.emplace_back(i);
546 }
547 this->nRows = n;
548 this->nColumns = n;
549}
550
551void
552SkylineUnsym :: printStatistics() const
553{
554 int nelem = 0;
555 for ( auto &rc : this->rowColumns ) {
556 nelem += rc.giveSize();
557 }
558
559 OOFEM_LOG_INFO("Skylineu info: neq is %d, nwk is %d\n", this->giveNumberOfRows(), nelem);
560}
561
562
563void
564SkylineUnsym :: writeToFile(const char *fname) const
565{
566 FILE *file = fopen(fname, "w");
567 FloatMatrix copy;
568 this->toFloatMatrix(copy);
569 for ( int i = 1; i <= nRows; ++i ) {
570 for ( int j = 1; j <= nColumns; ++j ) {
571 fprintf( file, "%.16e ", copy.at(i, j) );
572 }
573 fprintf(file, "\n");
574 }
575 fclose(file);
576}
577
578
579void
580SkylineUnsym :: printYourself() const
581{
582 FloatMatrix copy;
583 this->toFloatMatrix(copy);
584 copy.printYourself();
585 for ( auto &rc : this->rowColumns ) {
586 rc.printYourself();
587 }
588}
589
590void
591SkylineUnsym :: zero()
592{
593 for ( auto &rc : this->rowColumns ) {
594 rc.zero();
595 }
596
597 isFactorized = false;
598
599 this->version++;
600}
601
602
603void SkylineUnsym :: timesT(const FloatArray &x, FloatArray &answer) const
604{
605 if ( this->giveNumberOfRows() != x.giveSize() ) {
606 OOFEM_ERROR("size mismatch");
607 }
608
609 answer.resize(this->giveNumberOfColumns());
610 answer.zero();
611
612 for ( int i = 1; i <= this->giveNumberOfRows(); i++ ) {
613 auto &rowColumni = this->rowColumns[i-1];
614 int starti = rowColumni.giveStart();
615 answer.at(i) += rowColumni.dot(x, 'C', starti, i - 1);
616 answer.at(i) += rowColumni.atDiag() * x.at(i);
617
618 for ( int j = starti; j <= i - 1; j++ ) {
619 answer.at(j) += rowColumni.atL(j) * x.at(i);
620 }
621 }
622}
623} // end namespace oofem
#define REGISTER_SparseMtrx(class, type)
virtual void giveLocationArrays(std ::vector< IntArray > &rows, std ::vector< IntArray > &cols, CharType type, const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
Definition activebc.h:137
int giveNumberOfBoundaryConditions() const
Returns number of boundary conditions in domain.
Definition domain.h:469
int giveNumberOfElements() const
Returns number of elements in domain.
Definition domain.h:463
Element * giveElement(int n)
Definition domain.C:165
GeneralBoundaryCondition * giveBc(int n)
Definition domain.C:246
virtual int giveNumberOfDomainEquations(int di, const UnknownNumberingScheme &num)
Definition engngm.C:452
Domain * giveDomain(int n)
Definition engngm.C:1936
virtual int useNonlocalStiffnessOption()
Returns nonzero if nonlocal stiffness option activated.
Definition engngm.h:1150
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void zero()
Zeroes all coefficient of receiver.
*Prints matrix to stdout Useful for debugging void printYourself() const
int giveNumberOfRows() const
Returns number of rows of receiver.
double at(std::size_t i, std::size_t j) const
void resize(int n)
Definition intarray.C:73
void zero()
Sets all component to zero.
Definition intarray.C:52
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
std::vector< RowColumn > rowColumns
Row column segments.
Definition skylineu.h:58
void printStatistics() const override
Prints the receiver statistics (one-line) to stdout.
Definition skylineu.C:552
void checkSizeTowards(const IntArray &)
Definition skylineu.C:368
int isFactorized
Factorization flag.
Definition skylineu.h:60
SkylineUnsym(int n=0)
Definition skylineu.C:60
void toFloatMatrix(FloatMatrix &answer) const override
Converts receiving sparse matrix to a dense float matrix.
Definition skylineu.C:81
double & at(int i, int j) override
Returns coefficient at position (i,j).
Definition skylineu.C:96
int nColumns
Number of columns.
Definition sparsemtrx.h:71
SparseMtrxVersionType version
Definition sparsemtrx.h:82
int giveNumberOfRows() const
Returns number of rows of receiver.
Definition sparsemtrx.h:114
int giveNumberOfColumns() const
Returns number of columns of receiver.
Definition sparsemtrx.h:116
SparseMtrx(int n=0, int m=0)
Definition sparsemtrx.h:89
int nRows
Number of rows.
Definition sparsemtrx.h:69
double getUtime()
Returns total user time elapsed in seconds.
Definition timer.C:105
void startTimer()
Definition timer.C:69
void stopTimer()
Definition timer.C:77
#define OOFEM_WARNING(...)
Definition error.h:80
#define OOFEM_ERROR(...)
Definition error.h:79
#define OOFEM_LOG_INFO(...)
Definition logger.h:143
#define OOFEM_LOG_DEBUG(...)
Definition logger.h:144
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatMatrixF< N, N > diag(const FloatArrayF< N > &v)
@ SMT_SkylineU
Unsymmetric skyline.
#define SkylineUnsym_TINY_PIVOT
"zero" pivot for SkylineUnsym class
Definition skylineu.h:46

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011