|
OOFEM
2.1
|
00001 /* 00002 * 00003 * ##### ##### ###### ###### ### ### 00004 * ## ## ## ## ## ## ## ### ## 00005 * ## ## ## ## #### #### ## # ## 00006 * ## ## ## ## ## ## ## ## 00007 * ## ## ## ## ## ## ## ## 00008 * ##### ##### ## ###### ## ## 00009 * 00010 * 00011 * OOFEM : Object Oriented Finite Element Code 00012 * 00013 * Copyright (C) 1993 - 2013 Borek Patzak 00014 * 00015 * 00016 * 00017 * Czech Technical University, Faculty of Civil Engineering, 00018 * Department of Structural Mechanics, 166 29 Prague, Czech Republic 00019 * 00020 * This program is free software; you can redistribute it and/or modify 00021 * it under the terms of the GNU General Public License as published by 00022 * the Free Software Foundation; either version 2 of the License, or 00023 * (at your option) any later version. 00024 * 00025 * This program is distributed in the hope that it will be useful, 00026 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00027 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00028 * GNU General Public License for more details. 00029 * 00030 * You should have received a copy of the GNU General Public License 00031 * along with this program; if not, write to the Free Software 00032 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00033 */ 00034 /* 00035 * The original idea for this class comes from 00036 * Dubois-Pelerin, Y.: "Object-Oriented Finite Elements: Programming concepts and Implementation", 00037 * PhD Thesis, EPFL, Lausanne, 1992. 00038 */ 00039 00040 #include "flotmtrx.h" 00041 #include "flotarry.h" 00042 #include "intarray.h" 00043 #include "mathfem.h" 00044 #include "error.h" 00045 #include "datastream.h" 00046 #include "classtype.h" 00047 #include "freestor.h" 00048 00049 #ifdef BOOST_PYTHON 00050 #include <boost/python.hpp> 00051 #include <boost/python/extract.hpp> 00052 #endif 00053 00054 // Some forward declarations for LAPACK. Remember to append the underscore to the function name. 00055 #ifdef __LAPACK_MODULE 00056 extern "C" { 00058 extern void dgecon_(const char *norm, const int *n, const double *a, const int *lda, 00059 const double *anorm, double *rcond, double *work, int *iwork, int *info, int norm_len); 00061 extern int dgetrf_(const int *m, const int *n, double *a, const int *lda, int *lpiv, int *info); 00063 extern int dgetri_( const int *n, double *a, const int *lda, int *ipiv, double *work, const int *lwork, int *info ); 00065 extern int dgesv_( const int *n, const int *nrhs, double *a, const int *lda, int *ipiv, const double *b, const int *ldb, int *info ); 00067 extern double dlange_(const char *norm, const int *m, const int *n, const double *a, const int *lda, double *work, int norm_len); 00069 extern int dsyevx_(const char *jobz, const char *range, const char *uplo, const int *n, double *a, const int *lda, 00070 const double *vl, const double *vu, const int *il, const int *iu, 00071 const double *abstol, int *m, double *w, double *z, const int *ldz, 00072 double *work, int *lwork, int *iwork, int *ifail, int *info, 00073 int jobz_len, int range_len, int uplo_len); 00075 extern void dgetrs_(const char *trans, const int *n, const int *nrhs, double *a, const int *lda, int *ipiv, const double *b, const int *ldb, int *info ); 00076 } 00077 #endif 00078 00079 #ifdef __PARALLEL_MODE 00080 #include "combuff.h" 00081 #endif 00082 00083 namespace oofem { 00084 00085 FloatMatrix :: FloatMatrix(int n, int m) : Matrix(n, m) 00086 { 00087 allocatedSize = n * m; 00088 values = allocDouble(n * m); 00089 } 00090 00091 00092 FloatMatrix :: FloatMatrix() : Matrix(0, 0) 00093 { 00094 allocatedSize = 0; 00095 values = NULL; 00096 } 00097 00098 00099 FloatMatrix :: FloatMatrix(const FloatArray *vector, bool transpose) 00100 // 00101 // constructor : creates (vector->giveSize(),1) FloatMatrix 00102 // if transpose = 1 creates (1,vector->giveSize()) FloatMatrix 00103 // 00104 { 00105 if ( transpose ) { 00106 nRows = 1; // column vector 00107 nColumns = vector->giveSize(); 00108 } else { 00109 nRows = vector->giveSize(); // row vector- default 00110 nColumns = 1; 00111 } 00112 00113 allocatedSize = nRows * nColumns; 00114 values = allocDouble(allocatedSize); 00115 00116 if ( transpose ) { 00117 for ( int i = 1; i <= nColumns; i++ ) { 00118 this->at(1, i) = vector->at(i); 00119 } 00120 } else { 00121 for ( int i = 1; i <= nRows; i++ ) { 00122 this->at(i, 1) = vector->at(i); 00123 } 00124 } 00125 } 00126 00127 00128 FloatMatrix :: FloatMatrix(const FloatMatrix &src) : Matrix(src.nRows, src.nColumns) 00129 { 00130 // copy constructor 00131 double *P1, *P2; 00132 00133 //this->nRows = src.nRows; 00134 //this->nColumns = src.nColumns; 00135 00136 allocatedSize = nRows * nColumns; 00137 values = allocDouble(allocatedSize); 00138 00139 P1 = values; 00140 P2 = src.values; 00141 for ( int i = 0; i < nRows * nColumns; i++ ) { 00142 P1 [ i ] = P2 [ i ]; 00143 } 00144 } 00145 00146 00147 FloatMatrix :: ~FloatMatrix() 00148 { 00149 if ( values ) { 00150 freeDouble(values); 00151 } 00152 } 00153 00154 00155 00156 FloatMatrix & FloatMatrix :: operator = ( const FloatMatrix & src ) 00157 { 00158 // assignment: cleanup and copy 00159 this->resize(src.nRows, src.nColumns); 00160 00161 for ( int i = 0; i < nRows * nColumns; i++ ) { 00162 values [ i ] = src.values [ i ]; 00163 } 00164 00165 return * this; 00166 } 00167 00168 00169 #ifdef DEBUG 00170 double &FloatMatrix :: at(int i, int j) 00171 // Returns the coefficient (i,j) of the receiver. Safer but slower than 00172 // the inline version of method 'at'. 00173 { 00174 this->checkBounds(i, j); 00175 return values [ ( j - 1 ) * nRows + i - 1 ]; 00176 } 00177 00178 double FloatMatrix :: at(int i, int j) const 00179 // Returns the coefficient (i,j) of the receiver. Safer but slower than 00180 // the inline version of method 'at'. 00181 { 00182 this->checkBounds(i, j); 00183 return values [ ( j - 1 ) * nRows + i - 1 ]; 00184 } 00185 00186 double &FloatMatrix :: operator() (int i, int j) 00187 { 00188 this->checkBounds(i+1, j+1); 00189 return values [ j * nRows + i ]; 00190 } 00191 00192 double FloatMatrix :: operator() (int i, int j) const 00193 { 00194 this->checkBounds(i+1, j+1); 00195 return values [ j * nRows + i ]; 00196 } 00197 #endif 00198 00199 00200 void FloatMatrix :: assemble(const FloatMatrix &src, const IntArray &loc) 00201 { 00202 int ii, jj, size = src.giveNumberOfRows(); 00203 00204 #if DEBUG 00205 if ( size != loc.giveSize() ) { 00206 OOFEM_ERROR("FloatMatrix :: assemble : dimensions of 'src' and 'loc' mismatch"); 00207 } 00208 00209 if ( !src.isSquare() ) { 00210 OOFEM_ERROR("FloatMatrix :: assemble : 'src' is not sqaure matrix"); 00211 } 00212 #endif 00213 00214 for ( int i = 1; i <= size; i++ ) { 00215 if ( ( ii = loc.at(i) ) ) { 00216 for ( int j = 1; j <= size; j++ ) { 00217 if ( ( jj = loc.at(j) ) ) { 00218 this->at(ii, jj) += src.at(i, j); 00219 } 00220 } 00221 } 00222 } 00223 } 00224 00225 00226 void FloatMatrix :: assemble(const FloatMatrix &src, const IntArray &rowind, const IntArray &colind) 00227 { 00228 int ii, jj; 00229 int nr = src.giveNumberOfRows(); 00230 int nc = src.giveNumberOfColumns(); 00231 00232 #if DEBUG 00233 if ( nr != rowind.giveSize() ) { 00234 OOFEM_ERROR("FloatMatrix :: assemble : row dimensions of 'src' and 'rowind' mismatch"); 00235 } 00236 00237 if ( nc != colind.giveSize() ) { 00238 OOFEM_ERROR("FloatMatrix :: assemble : column dimensions of 'src' and 'colind' mismatch"); 00239 } 00240 #endif 00241 00242 for ( int i = 1; i <= nr; i++ ) { 00243 if ( ( ii = rowind.at(i) ) ) { 00244 for ( int j = 1; j <= nc; j++ ) { 00245 if ( ( jj = colind.at(j) ) ) { 00246 this->at(ii, jj) += src.at(i, j); 00247 } 00248 } 00249 } 00250 } 00251 } 00252 00253 00254 void FloatMatrix :: assemble(const FloatMatrix &src, const int *rowind, const int *colind) 00255 { 00256 int ii, jj; 00257 int nr = src.giveNumberOfRows(); 00258 int nc = src.giveNumberOfColumns(); 00259 00260 for ( int i = 1; i <= nr; i++ ) { 00261 if ( ( ii = rowind [ i - 1 ] ) ) { 00262 for ( int j = 1; j <= nc; j++ ) { 00263 if ( ( jj = colind [ j - 1 ] ) ) { 00264 this->at(ii, jj) += src.at(i, j); 00265 } 00266 } 00267 } 00268 } 00269 } 00270 00271 00272 void FloatMatrix :: beTranspositionOf(const FloatMatrix &src) 00273 { 00274 // receiver becomes a transposition of src 00275 int nrows = src.giveNumberOfColumns(), ncols = src.giveNumberOfRows(); 00276 this->resize(nrows, ncols); 00277 00278 for ( int i = 1; i <= nrows; i++ ) { 00279 for ( int j = 1; j <= ncols; j++ ) { 00280 this->at(i, j) = src.at(j, i); 00281 } 00282 } 00283 } 00284 00285 00286 void FloatMatrix :: beProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix) 00287 // Receiver = aMatrix * bMatrix 00288 { 00289 # ifdef DEBUG 00290 if ( aMatrix.nColumns != bMatrix.nRows ) { 00291 OOFEM_ERROR("FloatMatrix::beProductOf : error in product A*B : dimensions do not match"); 00292 } 00293 # endif 00294 00295 this->resize(aMatrix.nRows, bMatrix.nColumns); 00296 for ( int i = 1; i <= aMatrix.nRows; i++ ) { 00297 for ( int j = 1; j <= bMatrix.nColumns; j++ ) { 00298 double coeff = 0.; 00299 for ( int k = 1; k <= aMatrix.nColumns; k++ ) { 00300 coeff += aMatrix.at(i, k) * bMatrix.at(k, j); 00301 } 00302 00303 this->at(i, j) = coeff; 00304 } 00305 } 00306 } 00307 00308 00309 void FloatMatrix :: addProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix) 00310 // Receiver = aMatrix * bMatrix 00311 { 00312 int p; 00313 double coeff; 00314 00315 # ifdef DEBUG 00316 if ( aMatrix.nColumns != bMatrix.nRows ) { 00317 OOFEM_ERROR("FloatMatrix::addProductOf : error in product A*B : dimensions do not match"); 00318 } 00319 # endif 00320 00321 p = bMatrix.nColumns; 00322 for ( int i = 1; i <= aMatrix.nRows; i++ ) { 00323 for ( int j = 1; j <= p; j++ ) { 00324 coeff = 0.; 00325 for ( int k = 1; k <= aMatrix.nColumns; k++ ) { 00326 coeff += aMatrix.at(i, k) * bMatrix.at(k, j); 00327 } 00328 00329 this->at(i, j) += coeff; 00330 } 00331 } 00332 } 00333 00334 00335 void FloatMatrix :: addTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix) 00336 // Receiver += aMatrix^T * bMatrix 00337 { 00338 int p; 00339 double coeff; 00340 00341 # ifdef DEBUG 00342 if ( aMatrix.nRows != bMatrix.nRows ) { 00343 OOFEM_ERROR("FloatMatrix::addTProductOf : error in product A*B : dimensions do not match"); 00344 } 00345 # endif 00346 00347 p = bMatrix.nColumns; 00348 this->resize(aMatrix.nColumns, p); 00349 for ( int i = 1; i <= aMatrix.nColumns; i++ ) { 00350 for ( int j = 1; j <= p; j++ ) { 00351 coeff = 0.; 00352 for ( int k = 1; k <= aMatrix.nRows; k++ ) { 00353 coeff += aMatrix.at(k, i) * bMatrix.at(k, j); 00354 } 00355 00356 this->at(i, j) += coeff; 00357 } 00358 } 00359 } 00360 00361 00362 void FloatMatrix :: beDyadicProductOf(const FloatArray &vec1, const FloatArray &vec2) 00363 // Receiver = vec1 * vec2^T 00364 { 00365 int n1 = vec1.giveSize(); 00366 int n2 = vec2.giveSize(); 00367 this->resize(n1, n2); 00368 for ( int i = 1; i <= n1; i++ ) { 00369 for ( int j = 1; j <= n2; j++ ) { 00370 this->at(i, j) = vec1.at(i) * vec2.at(j); 00371 } 00372 } 00373 } 00374 00375 void FloatMatrix :: beNMatrixOf(const FloatArray &n, int nsd) 00376 { 00377 this->resize(nsd, n.giveSize()*nsd); 00378 this->zero(); 00379 for (int i = 0; i < n.giveSize(); ++i) { 00380 for (int j = 0; j < nsd; ++j) { 00381 (*this)(j, i*nsd+j) = n(i); 00382 } 00383 } 00384 } 00385 00386 void FloatMatrix :: beLocalCoordSys(const FloatArray &normal) 00387 { 00388 if (normal.giveSize() == 1) { 00389 this->resize(1,1); 00390 this->at(1,1) = normal(0); 00391 } else if (normal.giveSize() == 2) { 00392 this->resize(2,2); 00393 this->at(1,1) = normal(1); 00394 this->at(1,2) = -normal(0); 00395 00396 this->at(2,1) = normal(0); 00397 this->at(2,2) = normal(1); 00398 } else if (normal.giveSize() == 3) { 00399 // Create a permutated vector of n, *always* length 1 and significantly different from n. 00400 FloatArray t(3), b; // tangent and binormal 00401 t(0) = normal(1); 00402 t(1) = -normal(2); 00403 t(2) = normal(0); 00404 00405 // Construct orthogonal vector 00406 double npn = t.dotProduct(normal); 00407 t.add(-npn,normal); 00408 t.normalize(); 00409 b.beVectorProductOf(t,normal); 00410 00411 this->resize(3,3); 00412 00413 this->at(1,1) = t(0); 00414 this->at(1,2) = t(1); 00415 this->at(1,3) = t(2); 00416 00417 this->at(1,1) = b(0); 00418 this->at(1,2) = b(1); 00419 this->at(1,3) = b(2); 00420 00421 this->at(2,1) = normal(0); 00422 this->at(2,2) = normal(1); 00423 this->at(2,3) = normal(2); 00424 } else { 00425 OOFEM_ERROR("FloatMatrix :: beLocalCoordinateTransformation - Normal needs 1 to 3 components."); 00426 } 00427 } 00428 00429 void FloatMatrix :: beTProductOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix) 00430 // Receiver = aMatrix^T * bMatrix 00431 { 00432 # ifdef DEBUG 00433 if ( aMatrix.nRows != bMatrix.nRows ) { 00434 OOFEM_ERROR("FloatMatrix::beTProductOf : error in product A*B : dimensions do not match"); 00435 } 00436 # endif 00437 00438 this->resize(aMatrix.nColumns, bMatrix.nColumns); 00439 for ( int i = 1; i <= aMatrix.nColumns; i++ ) { 00440 for ( int j = 1; j <= bMatrix.nColumns; j++ ) { 00441 double coeff = 0.; 00442 for ( int k = 1; k <= aMatrix.nRows; k++ ) { 00443 coeff += aMatrix.at(k, i) * bMatrix.at(k, j); 00444 } 00445 00446 this->at(i, j) = coeff; 00447 } 00448 } 00449 } 00450 00451 00452 void FloatMatrix :: beProductTOf(const FloatMatrix &aMatrix, const FloatMatrix &bMatrix) 00453 // Receiver = aMatrix * bMatrix^T 00454 { 00455 # ifdef DEBUG 00456 if ( aMatrix.nColumns != bMatrix.nColumns ) { 00457 OOFEM_ERROR("FloatMatrix::beProductTOf : error in product A*B : dimensions do not match"); 00458 } 00459 # endif 00460 00461 this->resize(aMatrix.nRows, bMatrix.nRows); 00462 for ( int i = 1; i <= aMatrix.nRows; i++ ) { 00463 for ( int j = 1; j <= bMatrix.nRows; j++ ) { 00464 double coeff = 0.; 00465 for ( int k = 1; k <= aMatrix.nColumns; k++ ) { 00466 coeff += aMatrix.at(i, k) * bMatrix.at(j, k); 00467 } 00468 00469 this->at(i, j) = coeff; 00470 } 00471 } 00472 } 00473 00474 00475 void FloatMatrix :: setSubMatrix(const FloatMatrix &src, int sr, int sc) 00476 { 00477 sr--; 00478 sc--; 00479 00480 int srcRows = src.giveNumberOfRows(), srcCols = src.giveNumberOfColumns(); 00481 #if DEBUG 00482 int nr = sr + srcRows; 00483 int nc = sc + srcCols; 00484 00485 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) { 00486 OOFEM_ERROR("FloatMatrix :: setSubMatrix - Sub matrix doesn't fit inside allocated space."); 00487 } 00488 #endif 00489 00490 // add sub-matrix 00491 for ( int i = 0; i < srcRows; i++ ) { 00492 for ( int j = 0; j < srcCols; j++ ) { 00493 (*this)(sr + i, sc + j) = src(i, j); 00494 } 00495 } 00496 } 00497 00498 00499 void FloatMatrix :: setTSubMatrix(const FloatMatrix &src, int sr, int sc) 00500 { 00501 sr--; 00502 sc--; 00503 00504 int srcRows = src.giveNumberOfRows(), srcCols = src.giveNumberOfColumns(); 00505 #if DEBUG 00506 int nr = sr + srcCols; 00507 int nc = sc + srcRows; 00508 00509 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) { 00510 OOFEM_ERROR("FloatMatrix :: setTSubMatrix - Sub matrix doesn't fit inside allocated space"); 00511 } 00512 #endif 00513 00514 // add sub-matrix 00515 for ( int i = 0; i < srcCols; i++ ) { 00516 for ( int j = 0; j < srcRows; j++ ) { 00517 (*this)(sr + i, sc + j) = src(j, i); 00518 } 00519 } 00520 } 00521 00522 00523 void FloatMatrix :: beSubMatrixOf(const FloatMatrix &src, 00524 int topRow, int bottomRow, int topCol, int bottomCol) 00525 /* 00526 * modifies receiver to be submatrix of the src matrix 00527 * size of receiver submatrix is determined from 00528 * input parameters 00529 */ 00530 { 00531 #ifdef DEBUG 00532 if ( ( topRow < 1 ) || ( bottomRow < 1 ) || ( topCol < 1 ) || ( bottomCol < 1 ) ) { 00533 OOFEM_ERROR("FloatMatrix::beSubMatrixOf : subindexes size mismatch"); 00534 } 00535 00536 if ( ( src.nRows < bottomRow ) || ( src.nColumns < bottomCol ) || ( ( bottomRow - topRow ) > src.nRows ) || 00537 ( ( bottomCol - topCol ) > src.nColumns ) ) { 00538 OOFEM_ERROR("FloatMatrix::beSubMatrixOf : subindexes size mismatch"); 00539 } 00540 #endif 00541 00542 00543 int topRm1, topCm1; 00544 topRm1 = topRow - 1; 00545 topCm1 = topCol - 1; 00546 00547 // allocate return value 00548 this->resize(bottomRow - topRm1, bottomCol - topCm1); 00549 for ( int i = topRow; i <= bottomRow; i++ ) { 00550 for ( int j = topCol; j <= bottomCol; j++ ) { 00551 this->at(i - topRm1, j - topCm1) = src.at(i, j); 00552 } 00553 } 00554 } 00555 00556 00557 void FloatMatrix :: addSubVectorRow(const FloatArray &src, int sr, int sc) 00558 { 00559 sc--; 00560 00561 int srcCols = src.giveSize(); 00562 00563 int nr = sr; 00564 int nc = sc + srcCols; 00565 00566 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) { 00567 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) ); 00568 } 00569 00570 // add sub-matrix 00571 for ( int j = 1; j <= srcCols; j++ ) { 00572 this->at(sr, sc + j) += src.at(j); 00573 } 00574 } 00575 00576 00577 void FloatMatrix :: addSubVectorCol(const FloatArray &src, int sr, int sc) 00578 { 00579 sr--; 00580 00581 int srcRows = src.giveSize(); 00582 00583 int nr = sr + srcRows; 00584 int nc = sc; 00585 00586 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) { 00587 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) ); 00588 } 00589 00590 // add sub-matrix 00591 for ( int j = 1; j <= srcRows; j++ ) { 00592 this->at(sr + j, sc) += src.at(j); 00593 } 00594 } 00595 00596 00597 00598 void FloatMatrix :: setColumn(const FloatArray &src, int c) 00599 { 00600 int nr = src.giveSize(); 00601 #ifdef DEBUG 00602 if ( this->giveNumberOfRows() != nr || c < 1 || c > this->giveNumberOfColumns()) { 00603 OOFEM_ERROR("FloatMatrix :: setColumn - Size mismatch"); 00604 } 00605 #endif 00606 00607 double *P = this->values + (c-1)*nr; 00608 double *srcP = src.givePointer(); 00609 for (int j = 0; j < nr; ++j ) 00610 *P++ = *srcP++; 00611 } 00612 00613 00614 void FloatMatrix :: copyColumn(FloatArray &dest, int c) const 00615 { 00616 int nr = this->giveNumberOfRows(); 00617 #ifdef DEBUG 00618 if ( c < 1 || c > this->giveNumberOfColumns()) { 00619 OOFEM_ERROR2("FloatMatrix :: copyColumn - Column outside range (%d)", c); 00620 } 00621 #endif 00622 00623 dest.resize(nr); 00624 double *P = this->values + (c-1)*nr; 00625 double *destP = dest.givePointer(); 00626 for (int j = 0; j < nr; ++j ) 00627 *destP++ = *P++; 00628 } 00629 00630 00631 void FloatMatrix :: copySubVectorRow(const FloatArray &src, int sr, int sc) 00632 { 00633 sc--; 00634 00635 int srcCols = src.giveSize(); 00636 00637 int nr = sr; 00638 int nc = sc + srcCols; 00639 00640 if ( ( this->giveNumberOfRows() < nr ) || ( this->giveNumberOfColumns() < nc ) ) { 00641 this->resizeWithData( max(this->giveNumberOfRows(), nr), max(this->giveNumberOfColumns(), nc) ); 00642 } 00643 00644 // add sub-matrix 00645 for ( int j = 1; j <= srcCols; j++ ) { 00646 this->at(sr, sc + j) = src.at(j); 00647 } 00648 } 00649 00650 00651 00652 void FloatMatrix :: plusProductSymmUpper(const FloatMatrix &a, const FloatMatrix &b, double dV) 00653 // Adds to the receiver the product a(transposed).b dV . 00654 // The receiver size is adjusted, if necessary. 00655 // This method assumes that both the receiver and the product above are 00656 // symmetric matrices, and therefore computes only the upper half of the 00657 // receiver ; the lower half is not modified. Other advantage : it does 00658 // not compute the transposition of matrix a. 00659 { 00660 if ( !this->isNotEmpty() ) { 00661 this->resize(a.nColumns, b.nColumns); 00662 this->zero(); 00663 } 00664 00665 for ( int i = 1; i <= nRows; i++ ) { 00666 for ( int j = i; j <= nColumns; j++ ) { 00667 double summ = 0.; 00668 for ( int k = 1; k <= a.nRows; k++ ) { 00669 summ += a.at(k, i) * b.at(k, j); 00670 } 00671 00672 this->at(i, j) += summ * dV; 00673 } 00674 } 00675 } 00676 00677 00678 void FloatMatrix :: plusDyadSymmUpper(const FloatArray &a, const FloatArray &b, double dV) 00679 { 00680 if ( !this->isNotEmpty() ) { 00681 this->resize(a.giveSize(), b.giveSize()); 00682 this->zero(); 00683 } 00684 00685 for ( int i = 1; i <= nRows; i++ ) { 00686 for ( int j = i; j <= nColumns; j++ ) { 00687 this->at(i, j) += a.at(i)*b.at(j) * dV; 00688 } 00689 } 00690 } 00691 00692 00693 00694 void FloatMatrix :: plusProductUnsym(const FloatMatrix &a, const FloatMatrix &b, double dV) 00695 // Adds to the receiver the product a(transposed).b dV . 00696 // If the receiver has a null size, it is expanded. 00697 // Advantage : does not compute the transposition of matrix a. 00698 { 00699 if ( !this->isNotEmpty() ) { 00700 this->resize(a.nColumns, b.nColumns); 00701 this->zero(); 00702 } 00703 00704 for ( int i = 1; i <= nRows; i++ ) { 00705 for ( int j = 1; j <= nColumns; j++ ) { 00706 double summ = 0.; 00707 for ( int k = 1; k <= a.nRows; k++ ) { 00708 summ += a.at(k, i) * b.at(k, j); 00709 } 00710 00711 this->at(i, j) += summ * dV; 00712 } 00713 } 00714 } 00715 00716 00717 void FloatMatrix :: plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV) 00718 { 00719 if ( !this->isNotEmpty() ) { 00720 this->resize(a.giveSize(), b.giveSize()); 00721 this->zero(); 00722 } 00723 00724 for ( int i = 1; i <= nRows; i++ ) { 00725 for ( int j = 1; j <= nColumns; j++ ) { 00726 this->at(i, j) += a.at(i) * b.at(j) * dV; 00727 } 00728 } 00729 } 00730 00731 00732 void FloatMatrix :: beInverseOf(const FloatMatrix &src) 00733 // Receiver becomes inverse of given parameter src. If necessary, size is adjusted. 00734 { 00735 double det; 00736 00737 # ifdef DEBUG 00738 if ( !src.isSquare() ) { 00739 OOFEM_ERROR3("FloatMatrix::beInverseOf : cannot inverse a %d by %d matrix", src.nRows, src.nColumns); 00740 } 00741 # endif 00742 00743 this->resize(src.nRows, src.nColumns); 00744 00745 if ( nRows == 1 ) { 00746 this->at(1, 1) = 1. / src.at(1, 1); 00747 return; 00748 } else if ( nRows == 2 ) { 00749 det = src.at(1, 1) * src.at(2, 2) - src.at(1, 2) * src.at(2, 1); 00750 this->at(1, 1) = src.at(2, 2) / det; 00751 this->at(2, 1) = -src.at(2, 1) / det; 00752 this->at(1, 2) = -src.at(1, 2) / det; 00753 this->at(2, 2) = src.at(1, 1) / det; 00754 return; 00755 } else if ( nRows == 3 ) { 00756 det = src.at(1, 1) * src.at(2, 2) * src.at(3, 3) + src.at(1, 2) * src.at(2, 3) * src.at(3, 1) + 00757 src.at(1, 3) * src.at(2, 1) * src.at(3, 2) - src.at(1, 3) * src.at(2, 2) * src.at(3, 1) - 00758 src.at(2, 3) * src.at(3, 2) * src.at(1, 1) - src.at(3, 3) * src.at(1, 2) * src.at(2, 1); 00759 00760 this->at(1, 1) = ( src.at(2, 2) * src.at(3, 3) - src.at(2, 3) * src.at(3, 2) ) / det; 00761 this->at(2, 1) = ( src.at(2, 3) * src.at(3, 1) - src.at(2, 1) * src.at(3, 3) ) / det; 00762 this->at(3, 1) = ( src.at(2, 1) * src.at(3, 2) - src.at(2, 2) * src.at(3, 1) ) / det; 00763 this->at(1, 2) = ( src.at(1, 3) * src.at(3, 2) - src.at(1, 2) * src.at(3, 3) ) / det; 00764 this->at(2, 2) = ( src.at(1, 1) * src.at(3, 3) - src.at(1, 3) * src.at(3, 1) ) / det; 00765 this->at(3, 2) = ( src.at(1, 2) * src.at(3, 1) - src.at(1, 1) * src.at(3, 2) ) / det; 00766 this->at(1, 3) = ( src.at(1, 2) * src.at(2, 3) - src.at(1, 3) * src.at(2, 2) ) / det; 00767 this->at(2, 3) = ( src.at(1, 3) * src.at(2, 1) - src.at(1, 1) * src.at(2, 3) ) / det; 00768 this->at(3, 3) = ( src.at(1, 1) * src.at(2, 2) - src.at(1, 2) * src.at(2, 1) ) / det; 00769 00770 //p[0]= (values[4]*values[8]-values[7]*values[5])/det ; 00771 //p[1]= (values[7]*values[2]-values[1]*values[8])/det ; 00772 //p[2]= (values[1]*values[5]-values[4]*values[2])/det ; 00773 //p[3]= (values[6]*values[5]-values[3]*values[8])/det ; 00774 //p[4]= (values[0]*values[8]-values[6]*values[2])/det ; 00775 //p[5]= (values[3]*values[2]-values[0]*values[5])/det ; 00776 //p[6]= (values[3]*values[7]-values[6]*values[4])/det ; 00777 //p[7]= (values[6]*values[1]-values[0]*values[7])/det ; 00778 //p[8]= (values[0]*values[4]-values[3]*values[1])/det ; 00779 return; 00780 } else { 00781 #ifdef __LAPACK_MODULE 00782 int n = this->nRows; 00783 IntArray ipiv(n); 00784 int lwork, info; 00785 *this = src; 00786 00787 // LU-factorization 00788 dgetrf_(&n, &n, this->values, &n, ipiv.givePointer(), &info); 00789 if (info != 0) { 00790 OOFEM_ERROR2("FloatMatrix::beInverseOf : dgetrf error %d", info); 00791 } 00792 00793 // Inverse 00794 lwork = n*n; 00795 FloatArray work(lwork); 00796 dgetri_( &this->nRows, this->values, &this->nRows, ipiv.givePointer(), work.givePointer(), &lwork, &info ); 00797 if (info > 0) { 00798 OOFEM_ERROR2("FloatMatrix::beInverseOf : Singular at %d", info); 00799 } else if (info < 0) { 00800 OOFEM_ERROR2("FloatMatrix::beInverseOf : Error on input %d", info); 00801 } 00802 #else 00803 // size >3 ... gaussian elimination - slow but safe 00804 // 00805 double piv, linkomb; 00806 FloatMatrix tmp = src; 00807 this->zero(); 00808 // initialize answer to be unity matrix; 00809 for ( int i = 1; i <= nRows; i++ ) { 00810 this->at(i, i) = 1.0; 00811 } 00812 00813 // lower triangle elimination by columns 00814 for ( int i = 1; i < nRows; i++ ) { 00815 piv = tmp.at(i, i); 00816 if ( fabs(piv) < 1.e-20 ) { 00817 OOFEM_ERROR3("FloatMatrix::beInverseOf : cannot inverse a %d by %d matrix", nRows, nColumns); 00818 } 00819 00820 for ( int j = i + 1; j <= nRows; j++ ) { 00821 linkomb = tmp.at(j, i) / tmp.at(i, i); 00822 for ( int k = i; k <= nRows; k++ ) { 00823 tmp.at(j, k) -= tmp.at(i, k) * linkomb; 00824 } 00825 00826 for ( int k = 1; k <= nRows; k++ ) { 00827 this->at(j, k) -= this->at(i, k) * linkomb; 00828 } 00829 } 00830 } 00831 00832 // upper triangle elimination by columns 00833 for ( int i = nRows; i > 1; i-- ) { 00834 piv = tmp.at(i, i); 00835 for ( int j = i - 1; j > 0; j-- ) { 00836 linkomb = tmp.at(j, i) / piv; 00837 for ( int k = i; k > 0; k-- ) { 00838 tmp.at(j, k) -= tmp.at(i, k) * linkomb; 00839 } 00840 00841 for ( int k = nRows; k > 0; k-- ) { 00842 // tmp -> at(j,k)-= tmp ->at(i,k)*linkomb; 00843 this->at(j, k) -= this->at(i, k) * linkomb; 00844 } 00845 } 00846 } 00847 00848 // diagonal scaling 00849 for ( int i = 1; i <= nRows; i++ ) { 00850 for ( int j = 1; j <= nRows; j++ ) { 00851 this->at(i, j) /= tmp.at(i, i); 00852 } 00853 } 00854 #endif 00855 } 00856 } 00857 00858 00859 void 00860 FloatMatrix :: beSubMatrixOf(const FloatMatrix &src, const IntArray &indx) 00861 /* 00862 * modifies receiver to be (sub)matrix of the src. 00863 * (sub)matrix has size of max value in indx 00864 * and on its position (indx->at(i),indx->at(j)) are values from src at (i, j). 00865 * if indx->at(i) or indx->at(j) are <= 0 then at position i,j is zero. 00866 * 00867 * Warning: 00868 * This method should produce also bigger matrix than src 00869 * Works only for square matrices. 00870 */ 00871 { 00872 int size, n, ii, jj; 00873 00874 if ( ( n = indx.giveSize() ) == 0 ) { 00875 this->resize(0, 0); 00876 return; 00877 } 00878 00879 # ifdef DEBUG 00880 if ( !src.isSquare() ) { 00881 OOFEM_ERROR("FloatMatrix::beSubMatrixOf : cannot construct required submatrix"); 00882 } 00883 # endif 00884 00885 if ( n != src.nRows ) { 00886 OOFEM_ERROR("FloatMatrix::beSubMatrixOf : giveSubMatrix size mismatch"); 00887 } 00888 00889 size = indx.maximum(); 00890 00891 this->resize(size, size); 00892 00893 for ( int i = 1; i <= n; i++ ) { 00894 for ( int j = 1; j <= n; j++ ) { 00895 if ( ( ( ii = indx.at(i) ) != 0 ) && ( ( jj = indx.at(j) ) != 0 ) ) { 00896 this->at(ii, jj) = src.at(i, j); 00897 } 00898 } 00899 } 00900 } 00901 00902 00903 00904 void 00905 FloatMatrix :: beSubMatrixOfSizeOf(const FloatMatrix &src, const IntArray &indx, int size) 00906 /* 00907 * modifies receiver to be (sub)matrix of the src matrix. 00908 * (sub)matrix has size size 00909 * and on its position (indx->at(i),indx->at(j)) are values from src at (i, j). 00910 * if indx->at(i) or indx->at(j) are <= 0 then at position i,j is zero. 00911 * 00912 * Warning: 00913 * This method should produce also bigger matrix than src 00914 * Works only for square matrices. 00915 */ 00916 { 00917 int n, ii, jj; 00918 00919 if ( ( n = indx.giveSize() ) == 0 ) { 00920 this->resize(0, 0); 00921 return; 00922 } 00923 00924 # ifdef DEBUG 00925 if ( !src.isSquare() ) { 00926 OOFEM_ERROR("FloatMatrix::beSubMatrixOfSizeOf : cannot construct submatrix"); 00927 } 00928 00929 if ( n != src.nRows ) { 00930 OOFEM_ERROR("FloatMatrix::beSubMatrixOfSizeOf : giveSubMatrix size mismatch"); 00931 } 00932 00933 if ( indx.maximum() > size ) { 00934 OOFEM_ERROR("FloatMatrix::beSubMatrixOfSizeOf : index in mask exceed size"); 00935 } 00936 # endif 00937 00938 this->resize(size, size); 00939 00940 for ( int i = 1; i <= n; i++ ) { 00941 for ( int j = 1; j <= n; j++ ) { 00942 if ( ( ( ii = indx.at(i) ) != 0 ) && ( ( jj = indx.at(j) ) != 0 ) ) { 00943 this->at(ii, jj) = src.at(i, j); 00944 } 00945 } 00946 } 00947 } 00948 00949 void FloatMatrix :: add(const FloatMatrix &aMatrix) 00950 // Adds aMatrix to the receiver. If the receiver has a null size, 00951 // adjusts its size to that of aMatrix. Returns the modified receiver. 00952 { 00953 register int i; 00954 int n, m; 00955 double *P1, *P2; 00956 00957 n = aMatrix.nRows; 00958 m = aMatrix.nColumns; 00959 if ( nRows * nColumns == 0 ) { 00960 this->operator = ( aMatrix ); 00961 } else { 00962 # ifdef DEBUG 00963 if ( (n != nRows || m != nColumns) && aMatrix.isNotEmpty() ) 00964 OOFEM_ERROR5("FloatMatrix::add : dimensions mismatch : (r1,c1)+(r2,c2) : (%d,%d)+(%d,%d)", nRows, nColumns, n, m); 00965 # endif 00966 00967 P1 = values; 00968 P2 = aMatrix.values; 00969 i = n * m; 00970 while ( i-- ) { 00971 * P1++ += * P2++; 00972 } 00973 } 00974 } 00975 00976 00977 void FloatMatrix :: add(double s, const FloatMatrix &aMatrix) 00978 // Adds aMatrix to the receiver. If the receiver has a null size, 00979 // adjusts its size to that of aMatrix. Returns the modified receiver. 00980 { 00981 register int i; 00982 int n, m; 00983 double *P1, *P2; 00984 00985 n = aMatrix.nRows; 00986 m = aMatrix.nColumns; 00987 if ( nRows * nColumns == 0 ) { 00988 this->operator = ( aMatrix ); 00989 this->times(s); 00990 } else { 00991 # ifdef DEBUG 00992 if ( (n != nRows || m != nColumns) && aMatrix.isNotEmpty() ) 00993 OOFEM_ERROR5("FloatMatrix::add : dimensions mismatch : (r1,c1)+(r2,c2) : (%d,%d)+(%d,%d)", nRows, nColumns, n, m); 00994 # endif 00995 00996 P1 = values; 00997 P2 = aMatrix.values; 00998 i = n * m; 00999 while ( i-- ) { 01000 * P1++ += s *(* P2++); 01001 } 01002 } 01003 } 01004 01005 void FloatMatrix :: subtract(const FloatMatrix &aMatrix) 01006 // Adds aMatrix to the receiver. If the receiver has a null size, 01007 // adjusts its size to that of aMatrix. Returns the modified receiver. 01008 { 01009 register int i; 01010 int n, m; 01011 double *P1, *P2; 01012 01013 n = aMatrix.nRows; 01014 m = aMatrix.nColumns; 01015 if ( nRows * nColumns == 0 ) { 01016 this->operator=(aMatrix); 01017 } else { 01018 # ifdef DEBUG 01019 if ( (n != nRows || m != nColumns) && aMatrix.isNotEmpty() ) 01020 OOFEM_ERROR5("FloatMatrix::subtract : dimensions mismatch : (r1,c1)-(r2,c2) : (%d,%d)-(%d,%d)", nRows, nColumns, n, m); 01021 # endif 01022 01023 P1 = values; 01024 P2 = aMatrix.values; 01025 i = n * m; 01026 while ( i-- ) { 01027 * P1++ -= * P2++; 01028 } 01029 } 01030 } 01031 01032 01033 void FloatMatrix :: solveForRhs(const FloatArray &b, FloatArray &answer, bool transpose) 01034 // solves equation b = this * x 01035 { 01036 # ifdef DEBUG 01037 if ( !this->isSquare() ) { 01038 OOFEM_ERROR3("FloatMatrix::solveForRhs : cannot solve a %d by %d matrix", nRows, nColumns); 01039 } 01040 01041 if ( nRows != b.giveSize() ) { 01042 OOFEM_ERROR("FloatMatrix::solveForRhs : dimension mismatch"); 01043 } 01044 # endif 01045 01046 #ifdef __LAPACK_MODULE 01047 int info, nrhs = 1; 01048 IntArray ipiv(this->nRows); 01049 answer = b; 01050 //dgesv_( &this->nRows, &nrhs, this->values, &this->nRows, ipiv.givePointer(), answer.givePointer(), &this->nRows, &info ); 01051 dgetrf_( &this->nRows, &this->nRows, this->values, &this->nRows, ipiv.givePointer(), &info ); 01052 if (info == 0) 01053 dgetrs_( transpose ? "Transpose" : "No transpose", &this->nRows, &nrhs, this->values, &this->nRows, ipiv.givePointer(), answer.givePointer(), &this->nRows, &info ); 01054 if (info != 0) { 01055 OOFEM_ERROR2("FloatMatrix::solveForRhs : error %d", info); 01056 } 01057 #else 01058 int pivRow; 01059 double piv, linkomb, help; 01060 FloatMatrix *mtrx, trans; 01061 if (transpose) { 01062 trans.beTranspositionOf(*this); 01063 mtrx = &trans; 01064 } else { 01065 mtrx = this; 01066 } 01067 01068 answer = b; 01069 01070 // initialize answer to be unity matrix; 01071 // lower triangle elimination by columns 01072 for ( int i = 1; i < nRows; i++ ) { 01073 // find the suitable row and pivot 01074 piv = fabs( mtrx->at(i, i) ); 01075 pivRow = i; 01076 for ( int j = i + 1; j <= nRows; j++ ) { 01077 if ( fabs( mtrx->at(j, i) ) > piv ) { 01078 pivRow = j; 01079 piv = fabs( mtrx->at(j, i) ); 01080 } 01081 } 01082 01083 if ( piv < 1.e-20 ) { 01084 OOFEM_ERROR2("FloatMatrix::solveForRhs : cannot solve, seems to be singular at row %d", pivRow); 01085 } 01086 01087 // exchange rows 01088 if ( pivRow != i ) { 01089 for ( int j = i; j <= nRows; j++ ) { 01090 help = mtrx->at(i, j); 01091 mtrx->at(i, j) = mtrx->at(pivRow, j); 01092 mtrx->at(pivRow, j) = help; 01093 } 01094 help = answer.at(i); 01095 answer.at(i) = answer.at(pivRow); 01096 answer.at(pivRow) = help; 01097 } 01098 01099 for ( int j = i + 1; j <= nRows; j++ ) { 01100 linkomb = mtrx->at(j, i) / mtrx->at(i, i); 01101 for ( int k = i; k <= nRows; k++ ) { 01102 this->at(j, k) -= mtrx->at(i, k) * linkomb; 01103 } 01104 01105 answer.at(j) -= answer.at(i) * linkomb; 01106 } 01107 } 01108 01109 // back substitution 01110 for ( int i = nRows; i >= 1; i-- ) { 01111 help = 0.; 01112 for ( int j = i + 1; j <= nRows; j++ ) { 01113 help += mtrx->at(i, j) * answer.at(j); 01114 } 01115 01116 answer.at(i) = ( answer.at(i) - help ) / mtrx->at(i, i); 01117 } 01118 #endif 01119 } 01120 01121 01122 void FloatMatrix :: solveForRhs(const FloatMatrix &b, FloatMatrix &answer, bool transpose) 01123 // solves equation b = this * x 01124 // returns x. this and b are kept untouched 01125 // 01126 // gaussian elimination - slow but safe 01127 // 01128 { 01129 # ifdef DEBUG 01130 if ( !this->isSquare() ) { 01131 OOFEM_ERROR3("FloatMatrix::solveForRhs : cannot solve a %d by %d matrix", nRows, nColumns); 01132 } 01133 01134 if ( nRows != b.giveNumberOfRows() ) { 01135 OOFEM_ERROR("FloatMatrix::solveForRhs : dimension mismatch"); 01136 } 01137 # endif 01138 01139 #ifdef __LAPACK_MODULE 01140 int info; 01141 IntArray ipiv(this->nRows); 01142 answer = b; 01143 dgetrf_( &this->nRows, &this->nRows, this->values, &this->nRows, ipiv.givePointer(), &info ); 01144 if (info == 0) 01145 dgetrs_( transpose ? "Transpose" : "No transpose", &this->nRows, &this->nRows, this->values, &this->nRows, ipiv.givePointer(), answer.givePointer(), &this->nRows, &info ); 01146 if (info != 0) { 01147 OOFEM_ERROR2("FloatMatrix::solveForRhs : error %d", info); 01148 } 01149 #else 01150 int pivRow, nPs; 01151 double piv, linkomb, help; 01152 FloatMatrix *mtrx, trans; 01153 if (transpose) { 01154 trans.beTranspositionOf(*this); 01155 mtrx = &trans; 01156 } else { 01157 mtrx = this; 01158 } 01159 01160 nPs = b.giveNumberOfColumns(); 01161 answer = b; 01162 // initialize answer to be unity matrix; 01163 // lower triangle elimination by columns 01164 for ( int i = 1; i < nRows; i++ ) { 01165 // find the suitable row and pivot 01166 piv = fabs( mtrx->at(i, i) ); 01167 pivRow = i; 01168 for ( int j = i + 1; j <= nRows; j++ ) { 01169 if ( fabs( mtrx->at(j, i) ) > piv ) { 01170 pivRow = j; 01171 piv = fabs( mtrx->at(j, i) ); 01172 } 01173 } 01174 01175 if ( fabs(piv) < 1.e-20 ) { 01176 OOFEM_ERROR3("FloatMatrix::solveForRhs : pivot too small, cannot solve %d by %d matrix", nRows, nColumns); 01177 } 01178 01179 // exchange rows 01180 if ( pivRow != i ) { 01181 for ( int j = i; j <= nRows; j++ ) { 01182 help = mtrx->at(i, j); 01183 mtrx->at(i, j) = mtrx->at(pivRow, j); 01184 mtrx->at(pivRow, j) = help; 01185 } 01186 01187 for ( int j = 1; j <= nPs; j++ ) { 01188 help = answer.at(i, j); 01189 answer.at(i, j) = answer.at(pivRow, j); 01190 answer.at(pivRow, j) = help; 01191 } 01192 } 01193 01194 if ( fabs(piv) < 1.e-20 ) { 01195 OOFEM_ERROR("FloatMatrix::solveForRhs : cannot solve, zero pivot encountered"); 01196 } 01197 01198 for ( int j = i + 1; j <= nRows; j++ ) { 01199 linkomb = mtrx->at(j, i) / mtrx->at(i, i); 01200 for ( int k = i; k <= nRows; k++ ) { 01201 mtrx->at(j, k) -= mtrx->at(i, k) * linkomb; 01202 } 01203 01204 for ( int k = 1; k <= nPs; k++ ) { 01205 answer.at(j, k) -= answer.at(i, k) * linkomb; 01206 } 01207 } 01208 } 01209 01210 // back substitution 01211 for ( int i = nRows; i >= 1; i-- ) { 01212 for ( int k = 1; k <= nPs; k++ ) { 01213 help = 0.; 01214 for ( int j = i + 1; j <= nRows; j++ ) { 01215 help += mtrx->at(i, j) * answer.at(j, k); 01216 } 01217 01218 answer.at(i, k) = ( answer.at(i, k) - help ) / mtrx->at(i, i); 01219 } 01220 } 01221 #endif 01222 } 01223 01224 01225 void FloatMatrix :: initFromVector(const FloatArray &vector, bool transposed) 01226 // 01227 // constructor : creates (vector->giveSize(),1) FloatMatrix 01228 // if transpose = 1 creates (1,vector->giveSize()) FloatMatrix 01229 // 01230 { 01231 if ( transposed ) { 01232 resize( 1, vector.giveSize() ); 01233 } else { 01234 resize(vector.giveSize(), 1); // row vector- default 01235 } 01236 01237 if ( transposed ) { 01238 for ( int i = 1; i <= nColumns; i++ ) { 01239 this->at(1, i) = vector.at(i); 01240 } 01241 } else { 01242 for ( int i = 1; i <= nRows; i++ ) { 01243 this->at(i, 1) = vector.at(i); 01244 } 01245 } 01246 } 01247 01248 01249 void FloatMatrix :: zero() const 01250 { 01251 // zeroing the receiver - fast implementation 01252 double *P1; 01253 int i; 01254 01255 P1 = this->values; 01256 i = nRows * nColumns; 01257 while ( i-- ) { 01258 * P1++ = 0.; 01259 } 01260 } 01261 01262 01263 void FloatMatrix :: beUnitMatrix() 01264 { 01265 #ifdef DEBUG 01266 if ( !this->isSquare() ) { 01267 OOFEM_ERROR3("FloatMatrix::beUnitMatrix : cannot make unit matrix of %d by %d matrix", nRows, nColumns); 01268 } 01269 #endif 01270 01271 this->zero(); 01272 for ( int i = 1; i <= nRows; i++ ) { 01273 this->at(i, i) = 1.0; 01274 } 01275 } 01276 01277 01278 void FloatMatrix :: bePinvID() 01279 // this matrix is the product of the 6x6 deviatoric projection matrix ID 01280 // and the inverse scaling matrix Pinv 01281 { 01282 this->resize(6, 6); 01283 this->zero(); 01284 values [ 0 ] = values [ 7 ] = values [ 14 ] = 2. / 3.; 01285 values [ 1 ] = values [ 2 ] = values [ 6 ] = values [ 8 ] = values [ 12 ] = values [ 13 ] = -1. / 3.; 01286 values [ 21 ] = values [ 28 ] = values [ 35 ] = 0.5; 01287 } 01288 01289 01290 void FloatMatrix :: resize(int rows, int columns, int allocChunk) 01291 // 01292 // resizes receiver, all data will be lost 01293 // 01294 { 01295 if ( rows * columns > allocatedSize ) { 01296 // memory realocation necessary 01297 if ( values ) { 01298 freeDouble(values); 01299 } 01300 01301 if ( allocChunk < 0 ) { 01302 allocChunk = 0; 01303 } 01304 01305 allocatedSize = rows * columns + allocChunk; // REMEMBER NEW ALLOCATED SIZE 01306 values = allocDouble(allocatedSize); 01307 } else { 01308 // reuse previously allocated space 01309 } 01310 01311 this->nRows = rows; 01312 this->nColumns = columns; 01313 } 01314 01315 01316 void FloatMatrix :: resizeWithData(int rows, int columns) 01317 // 01318 // resizes receiver, all data kept 01319 // 01320 { 01321 FloatMatrix old(*this); 01322 01323 if ( rows * columns > allocatedSize ) { 01324 // memory realocation necessary 01325 if ( values ) { 01326 freeDouble(values); 01327 } 01328 01329 allocatedSize = rows * columns; // REMEMBER NEW ALLOCATED SIZE 01330 values = allocDouble(allocatedSize); 01331 } else { 01332 // reuse previously allocated space 01333 } 01334 01335 this->nRows = rows; 01336 this->nColumns = columns; 01337 01338 int ii, jj; 01339 01340 ii = min( rows, old.giveNumberOfRows() ); 01341 jj = min( columns, old.giveNumberOfColumns() ); 01342 // copy old values if possible 01343 for ( int i = 1; i <= ii; i++ ) { 01344 for ( int j = 1; j <= jj; j++ ) { 01345 this->at(i, j) = old.at(i, j); 01346 } 01347 } 01348 } 01349 01350 01351 void FloatMatrix :: hardResize(int rows, int columns) 01352 // 01353 // resizes receiver, all data will be lost 01354 // 01355 { 01356 // memory realocation necessary 01357 if ( values ) { 01358 freeDouble(values); 01359 } 01360 01361 allocatedSize = rows * columns; // REMEMBER NEW ALLOCATED SIZE 01362 values = allocDouble(allocatedSize); 01363 01364 this->nRows = rows; 01365 this->nColumns = columns; 01366 } 01367 01368 01369 double FloatMatrix :: giveDeterminant() const 01370 // Returns the determinant of the receiver. 01371 { 01372 # ifdef DEBUG 01373 if ( !this->isSquare() ) { 01374 OOFEM_ERROR3("FloatMatrix::giveDeterminant : cannot compute determinant of a %d by %d matrix", nRows, nColumns); 01375 } 01376 01377 # endif 01378 01379 if ( nRows == 1 ) { 01380 return values [ 0 ]; 01381 } else if ( nRows == 2 ) { 01382 return ( values [ 0 ] * values [ 3 ] - values [ 1 ] * values [ 2 ] ); 01383 } else if ( nRows == 3 ) { 01384 return ( values [ 0 ] * values [ 4 ] * values [ 8 ] + values [ 3 ] * values [ 7 ] * values [ 2 ] + 01385 values [ 6 ] * values [ 1 ] * values [ 5 ] - values [ 6 ] * values [ 4 ] * values [ 2 ] - 01386 values [ 7 ] * values [ 5 ] * values [ 0 ] - values [ 8 ] * values [ 3 ] * values [ 1 ] ); 01387 } else { 01388 OOFEM_ERROR3("FloatMatrix::giveDeterminant : sorry, cannot inverse %d by %d matrices", nRows, nColumns); 01389 } 01390 01391 return 0.; 01392 } 01393 01394 01395 void FloatMatrix :: printYourself() const 01396 // Prints the receiver on screen. 01397 { 01398 printf("FloatMatrix with dimensions : %d %d\n", 01399 nRows, nColumns); 01400 if ( nRows <= 250 && nColumns <= 250 ) { 01401 for ( int i = 1; i <= nRows; ++i ) { 01402 for ( int j = 1; j <= nColumns && j <= 50; ++j ) { 01403 printf( "%10.3e ", this->at(i, j) ); 01404 } 01405 01406 printf("\n"); 01407 } 01408 } else { 01409 printf(" large matrix : coefficients not printed \n"); 01410 } 01411 } 01412 01413 01414 void FloatMatrix :: pY() const 01415 // Prints the receiver on screen with higher accuracy than printYourself. 01416 { 01417 printf("["); 01418 for ( int i = 1; i <= nRows; ++i ) { 01419 for ( int j = 1; j <= nColumns; ++j ) { 01420 printf( "%20.15e", this->at(i, j) ); 01421 if ( j < nColumns ) { 01422 printf(","); 01423 } else { 01424 printf(";"); 01425 } 01426 } 01427 } 01428 01429 printf("];\n"); 01430 } 01431 01432 01433 void FloatMatrix :: rotatedWith(const FloatMatrix &r) 01434 // Returns the receiver 'a' rotated according the change-of-base matrix r. 01435 // The method performs the operation a = r^T . a . r . 01436 { 01437 FloatMatrix rta; 01438 01439 rta.beTProductOf(r, * this); // r^T . a 01440 this->beProductOf(rta, r); // r^T . a . r 01441 } 01442 01443 01444 void FloatMatrix :: symmetrized() 01445 // Initializes the lower half of the receiver to the upper half. 01446 { 01447 # ifdef DEBUG 01448 if ( nRows != nColumns ) { 01449 OOFEM_ERROR("FloatMatrix::symmetrized : cannot symmetrize a non-square matrix"); 01450 } 01451 01452 # endif 01453 01454 for ( int i = 2; i <= nRows; i++ ) { 01455 for ( int j = 1; j < i; j++ ) { 01456 this->at(i, j) = this->at(j, i); 01457 } 01458 } 01459 } 01460 01461 01462 void FloatMatrix :: times(double factor) 01463 // Multiplies every coefficient of the receiver by factor. Answers the 01464 // modified receiver. 01465 { 01466 int i; 01467 double *p; 01468 01469 p = values; 01470 i = nRows * nColumns; 01471 while ( i-- ) { 01472 * p++ *= factor; 01473 } 01474 } 01475 01476 01477 void FloatMatrix :: negated() 01478 { 01479 int i; 01480 double *p; 01481 01482 p = values; 01483 i = nRows * nColumns; 01484 while ( i-- ) { 01485 *p = -(*p); 01486 p++; 01487 } 01488 } 01489 01490 01491 double FloatMatrix :: computeFrobeniusNorm() const 01492 { 01493 int i, j; 01494 double answer = 0.0; 01495 for ( i = 1; i <= nRows; i++ ) { 01496 for ( j = 1; j <= nColumns; j++ ) { 01497 answer += this->at(i, j) * this->at(i, j); 01498 } 01499 } 01500 01501 return sqrt(answer); 01502 } 01503 01504 double FloatMatrix :: computeNorm(char p) const 01505 { 01506 # ifdef __LAPACK_MODULE 01507 FloatArray work(this->giveNumberOfRows()); 01508 int lda = max(this->nRows, 1); 01509 double norm = dlange_(&p, &this->nRows, &this->nColumns, this->values, &lda, work.givePointer(), 1); 01510 return norm; 01511 # else 01512 if (p == '1') { // Maximum absolute column sum. 01513 double col_sum, max_col = 0.0; 01514 for (int j = 1; j <= this->nColumns; j++) { 01515 col_sum = 0.0; 01516 for (int i = 1; i <= this->nRows; i++) { 01517 col_sum += fabs(this->at(i, j)); 01518 } 01519 if (col_sum > max_col) { 01520 max_col = col_sum; 01521 } 01522 } 01523 return max_col; 01524 } 01526 /*else if (p == '2') { 01527 double lambda_max; 01528 FloatMatrix AtA; 01529 FloatArray eigs; 01530 AtA.beTProductOf(*this,this); 01531 Ata.eigenValues(eigs, 1); 01532 return sqrt(eigs(0)); 01533 } */else { 01534 OOFEM_ERROR2("FloatMatrix::computeNorm(p) : p == %d not implemented.\n",p); 01535 return 0.0; 01536 } 01537 # endif 01538 } 01539 01540 double FloatMatrix :: computeReciprocalCondition(char p) const 01541 { 01542 # ifdef DEBUG 01543 if ( !this->isSquare() ) { 01544 OOFEM_ERROR3("FloatMatrix::computeReciprocalCondition : receiver must be square (is %d by %d)", this->nRows, this->nColumns); 01545 } 01546 # endif 01547 double anorm = this->computeNorm(p); 01548 01549 # ifdef __LAPACK_MODULE 01550 int n = this->nRows; 01551 FloatArray work(4*n); 01552 IntArray iwork(n); 01553 int info; 01554 double rcond; 01555 01556 if (n > 3) { // Only use this routine for larger matrices. (not sure if it's suitable for n = 3) // Mikael 01557 FloatMatrix a_cpy = *this; 01558 dgetrf_(&n, &n, a_cpy.values, &n, iwork.givePointer(), &info); 01559 if (info < 0) { 01560 OOFEM_ERROR2("FloatMatrix::computeReciprocalCondition : dgetfr error %d\n",info); 01561 } 01562 dgecon_(&p, &(this->nRows), a_cpy.values, &this->nRows, &anorm, &rcond, work.givePointer(), iwork.givePointer(), &info, 1); 01563 if (info < 0) { 01564 OOFEM_ERROR2("FloatMatrix::computeReciprocalCondition : dgecon error %d\n",info); 01565 } 01566 return rcond; 01567 } 01568 # endif 01569 if (this->giveDeterminant() <= 1e-6*anorm) { 01570 return 0.0; 01571 } 01572 FloatMatrix inv; 01573 inv.beInverseOf(*this); 01574 return 1.0/(inv.computeNorm(p)*anorm); 01575 } 01576 01577 void FloatMatrix ::beMatrixForm(const FloatArray &aArray) 01578 { 01579 // Revrites the matrix on vector form (symmetrized matrix used), order: 11, 22, 33, 23, 13, 12 01580 # ifdef DEBUG 01581 if ( aArray.giveSize() !=6 && aArray.giveSize() !=9 ) { 01582 OOFEM_ERROR("FloatArray :: beMatrixForm : matrix dimension is not 3x3"); 01583 } 01584 # endif 01585 this->resize(3,3); 01586 if ( aArray.giveSize() == 9 ) { 01587 this->at(1,1) = aArray.at(1); this->at(2,2) = aArray.at(2); this->at(3,3) = aArray.at(3); 01588 this->at(2,3) = aArray.at(4); this->at(1,3) = aArray.at(5); this->at(1,2) = aArray.at(6); 01589 this->at(3,2) = aArray.at(7); this->at(3,1) = aArray.at(8); this->at(2,1) = aArray.at(9); 01590 } 01591 else if ( aArray.giveSize() == 6 ) { 01592 this->at(1,1) = aArray.at(1); this->at(2,2) = aArray.at(2); this->at(3,3) = aArray.at(3); 01593 this->at(2,3) = aArray.at(4); this->at(1,3) = aArray.at(5); this->at(1,2) = aArray.at(6); 01594 this->at(3,2) = aArray.at(4); this->at(3,1) = aArray.at(5); this->at(2,1) = aArray.at(6); 01595 } 01596 } 01597 01598 #if 0 01599 bool FloatMatrix :: computeEigenValuesSymmetric(FloatArray &lambda, FloatMatrix &v, int neigs) const 01600 { 01601 #ifdef __LAPACK_MODULE 01602 double abstol = 1.0; 01603 int lda, n, ldz, info, found, lwork; 01604 n = this->nRows; 01605 lda = n; 01606 ldz = n; 01607 FloatMatrix a; 01608 a = *this; 01609 if (neigs == 0) { 01610 neigs = n; 01611 } 01612 01613 lambda.resize(neigs); 01614 v.resize(n, neigs); 01615 01616 IntArray ifail(n), iwork(5*n); 01617 FloatArray work((n+3)*n); // maximum block size should be less than n (?) 01618 lwork = (n+3)*n; 01619 if ( neigs > 0 ) { 01620 int one = 1; 01621 dsyevx_("N", "I", "U", 01622 &n, a.values, &n, 01623 NULL, NULL, &one, &neigs, 01624 &abstol, &found, lambda.givePointer(), v.givePointer(), &ldz, 01625 work.givePointer(), &lwork, iwork.givePointer(), ifail.givePointer(), &info, 1, 1, 1); 01626 } else { 01627 dsyevx_("N", "A", "U", 01628 &n, a.values, &n, 01629 NULL, NULL, NULL, NULL, 01630 &abstol, &found, lambda.givePointer(), v.givePointer(), &ldz, 01631 work.givePointer(), &lwork, iwork.givePointer(), ifail.givePointer(), &info, 1, 1, 1); 01632 } 01633 01634 return info == 0; 01635 #else 01636 OOFEM_ERROR("FloatMatrix::computeEigenValuesSymmetric : Requires LAPACK\n"); 01637 return false; 01638 #endif 01639 } 01640 #endif 01641 01642 contextIOResultType FloatMatrix :: storeYourself(DataStream *stream, ContextMode mode) 01643 // writes receiver's binary image into stream 01644 // use id to distinguish some instances 01645 // return value >0 success 01646 // =0 file i/o error 01647 { 01648 // write size 01649 if ( !stream->write(& nRows, 1) ) { 01650 return ( CIO_IOERR ); 01651 } 01652 01653 if ( !stream->write(& nColumns, 1) ) { 01654 return ( CIO_IOERR ); 01655 } 01656 01657 // write raw data 01658 if ( !stream->write(values, nRows * nColumns) ) { 01659 return ( CIO_IOERR ); 01660 } 01661 01662 // return result back 01663 return CIO_OK; 01664 } 01665 01666 01667 contextIOResultType FloatMatrix :: restoreYourself(DataStream *stream, ContextMode mode) 01668 // reads receiver from stream 01669 // warning - overwrites existing data! 01670 // returns 0 if file i/o error 01671 // -1 if id of class id is not correct 01672 { 01673 // read size 01674 if ( !stream->read(& nRows, 1) ) { 01675 return ( CIO_IOERR ); 01676 } 01677 01678 if ( !stream->read(& nColumns, 1) ) { 01679 return ( CIO_IOERR ); 01680 } 01681 01682 if ( values != NULL ) { 01683 freeDouble(values); 01684 } 01685 01686 if ( nRows * nColumns ) { 01687 values = allocDouble(nRows * nColumns); 01688 allocatedSize = nRows * nColumns; 01689 } else { 01690 values = NULL; 01691 allocatedSize = 0; 01692 } 01693 01694 // read raw data 01695 if ( !stream->read(values, nRows * nColumns) ) { 01696 return ( CIO_IOERR ); 01697 } 01698 01699 // return result back 01700 return CIO_OK; 01701 } 01702 01703 01704 bool FloatMatrix :: jaco_(FloatArray &eval, FloatMatrix &v, int nf) 01705 { 01706 /* 01707 * Solves the eigenvalues and eigenvectors of real 01708 * symmetric matrix by jacobi method. 01709 * Written by bp. Inspired by ED WILSON jaco_ procedure. 01710 * 01711 * Parameters (input): 01712 * nf - number of significant figures 01713 * 01714 * Output params: 01715 * eval - eigen values (not sorted) 01716 * v - eigenvectors (stored columvise) 01717 */ 01718 01719 01720 /* Local variables */ 01721 double ssum, aa, co, si, tt, tol, sum, aij, aji; 01722 int ite, i, j, k, ih; 01723 int neq = this->giveNumberOfRows(); 01724 01725 double c_b2 = .10; 01726 //double c_b27 = .01; 01727 01728 /* Function Body */ 01729 #ifdef DEBUG 01730 if ( !isSquare() ) { 01731 OOFEM_ERROR("FloatMatrix::jaco_: Not square matrix"); 01732 } 01733 // check for symmetry 01734 for ( i = 1; i <= neq; i++ ) { 01735 for ( j = i + 1; j <= neq; j++ ) { 01736 //if ( this->at(i, j) != this->at(j, i) ) { 01737 if ( fabs( this->at(i, j) - this->at(j, i) ) > 1.0e-6 ) { 01738 OOFEM_ERROR("FloatMatrix::jaco_: Not Symmetric matrix"); 01739 } 01740 } 01741 } 01742 01743 #endif 01744 01745 eval.resize(neq); 01746 v.resize(neq, neq); 01747 01748 for ( i = 1; i <= neq; i++ ) { 01749 eval.at(i) = this->at(i, i); 01750 } 01751 01752 tol = pow(c_b2, nf); 01753 sum = 0.0; 01754 for ( i = 1; i <= neq; ++i ) { 01755 for ( j = 1; j <= neq; ++j ) { 01756 sum += fabs( this->at(i, j) ); 01757 v.at(i, j) = 0.0; 01758 } 01759 01760 v.at(i, i) = 1.0; 01761 } 01762 01763 if ( sum <= 0.0 ) { 01764 return 0; 01765 } 01766 01767 01768 /* ---- REDUCE MATRIX TO DIAGONAL ---------------- */ 01769 ite = 0; 01770 do { 01771 ssum = 0.0; 01772 for ( j = 2; j <= neq; ++j ) { 01773 ih = j - 1; 01774 for ( i = 1; i <= ih; ++i ) { 01775 if ( ( fabs( this->at(i, j) ) / sum ) > tol ) { 01776 ssum += fabs( this->at(i, j) ); 01777 /* ---- CALCULATE ROTATION ANGLE ----------------- */ 01778 aa = atan2( this->at(i, j) * 2.0, eval.at(i) - eval.at(j) ) / 2.0; 01779 si = sin(aa); 01780 co = cos(aa); 01781 /* 01782 * // ---- MODIFY "I" AND "J" COLUMNS OF "A" AND "V" 01783 * for (k = 1; k <= neq; ++k) { 01784 * tt = this->at(k, i); 01785 * this->at(k, i) = co * tt + si * this->at(k, j); 01786 * this->at(k, j) = -si * tt + co * this->at(k, j); 01787 * tt = v.at(k, i); 01788 * v.at(k, i) = co * tt + si * v.at(k, j); 01789 * // L500: 01790 * v.at(k, j) = -si * tt + co * v.at(k, j); 01791 * } 01792 * // ---- MODIFY DIAGONAL TERMS -------------------- 01793 * this->at(i, i) = co * this->at(i, i) + si * this->at(j, i); 01794 * this->at(j, j) = -si * this->at(i, j) + co * this->at(j, j); 01795 * this->at(i, j) = 0.0; 01796 * // ---- MAKE "A" MATRIX SYMMETRICAL -------------- 01797 * for (k = 1; k <= neq; ++k) { 01798 * this->at(i, k) = this->at(k, i); 01799 * this->at(j, k) = this->at(k, j); 01800 * // L600: 01801 * } 01802 */ 01803 // ---- MODIFY "I" AND "J" COLUMNS OF "A" AND "V" 01804 for ( k = 1; k < i; ++k ) { 01805 tt = this->at(k, i); 01806 this->at(k, i) = co * tt + si *this->at(k, j); 01807 this->at(k, j) = -si * tt + co *this->at(k, j); 01808 tt = v.at(k, i); 01809 v.at(k, i) = co * tt + si *v.at(k, j); 01810 v.at(k, j) = -si * tt + co *v.at(k, j); 01811 } 01812 01813 // diagonal term (i,i) 01814 tt = eval.at(i); 01815 eval.at(i) = co * tt + si *this->at(i, j); 01816 aij = -si * tt + co *this->at(i, j); 01817 tt = v.at(i, i); 01818 v.at(i, i) = co * tt + si *v.at(i, j); 01819 v.at(i, j) = -si * tt + co *v.at(i, j); 01820 01821 for ( k = i + 1; k < j; ++k ) { 01822 tt = this->at(i, k); 01823 this->at(i, k) = co * tt + si *this->at(k, j); 01824 this->at(k, j) = -si * tt + co *this->at(k, j); 01825 tt = v.at(k, i); 01826 v.at(k, i) = co * tt + si *v.at(k, j); 01827 v.at(k, j) = -si * tt + co *v.at(k, j); 01828 } 01829 01830 // diagonal term (j,j) 01831 tt = this->at(i, j); 01832 aji = co * tt + si *eval.at(j); 01833 eval.at(j) = -si * tt + co *eval.at(j); 01834 01835 tt = v.at(j, i); 01836 v.at(j, i) = co * tt + si *v.at(j, j); 01837 v.at(j, j) = -si * tt + co *v.at(j, j); 01838 // 01839 for ( k = j + 1; k <= neq; ++k ) { 01840 tt = this->at(i, k); 01841 this->at(i, k) = co * tt + si *this->at(j, k); 01842 this->at(j, k) = -si * tt + co *this->at(j, k); 01843 tt = v.at(k, i); 01844 v.at(k, i) = co * tt + si *v.at(k, j); 01845 v.at(k, j) = -si * tt + co *v.at(k, j); 01846 } 01847 01848 // ---- MODIFY DIAGONAL TERMS -------------------- 01849 eval.at(i) = co * eval.at(i) + si * aji; 01850 eval.at(j) = -si * aij + co *eval.at(j); 01851 this->at(i, j) = 0.0; 01852 } else { 01853 /* ---- A(I,J) MADE ZERO BY ROTATION ------------- */ 01854 ; 01855 } 01856 } 01857 } 01858 01859 /* ---- CHECK FOR CONVERGENCE -------------------- */ 01860 if ( ++ite > 50 ) { 01861 OOFEM_ERROR("FloatMatrix::jaco_: too many iterations"); 01862 } 01863 } while ( fabs(ssum) / sum > tol ); 01864 01865 // restore original matrix 01866 for ( i = 1; i <= neq; i++ ) { 01867 for ( j = i; j <= neq; j++ ) { 01868 this->at(i, j) = this->at(j, i); 01869 } 01870 } 01871 01872 return 0; 01873 } /* jaco_ */ 01874 01875 01876 01877 #ifdef __PARALLEL_MODE 01878 int 01879 FloatMatrix :: packToCommBuffer(CommunicationBuffer &buff) const 01880 { 01881 int result = 1; 01882 // pack size 01883 result &= buff.packInt(nRows); 01884 result &= buff.packInt(nColumns); 01885 // pack data 01886 result &= buff.packArray(this->values, nRows * nColumns); 01887 01888 return result; 01889 } 01890 01891 int 01892 FloatMatrix :: unpackFromCommBuffer(CommunicationBuffer &buff) 01893 { 01894 int newNRows, newNColumns, result = 1; 01895 // unpack size 01896 result &= buff.unpackInt(newNRows); 01897 result &= buff.unpackInt(newNColumns); 01898 // resize yourself 01899 this->resize(newNRows, newNColumns); 01900 result &= buff.unpackArray(this->values, newNRows * newNColumns); 01901 01902 return result; 01903 } 01904 01905 int 01906 FloatMatrix :: givePackSize(CommunicationBuffer &buff) 01907 { 01908 return buff.givePackSize(MPI_INT, 1) + buff.givePackSize(MPI_INT, 1) + 01909 buff.givePackSize(MPI_DOUBLE, nRows * nColumns); 01910 } 01911 #endif 01912 01913 #ifdef BOOST_PYTHON 01914 void 01915 FloatMatrix :: __setitem__ (boost::python::api::object t, double val) 01916 { 01917 this->at(boost::python::extract<int>(t[0])+1, boost::python::extract<int>(t[1])+1 ) = val; 01918 } 01919 01920 double 01921 FloatMatrix :: __getitem__ (boost::python::api::object t) 01922 { 01923 return this->at(boost::python::extract<int>(t[0])+1, boost::python::extract<int>(t[1])+1 ); 01924 } 01925 #endif 01926 01927 } // end namespace oofem