void multiply ( scalarSquareMatrix& ans, // value changed in return const scalarDiagonalMatrix& A, const scalarSquareMatrix& B, const scalarDiagonalMatrix& C ) { if (A.size() != B.n()) { FatalErrorIn ( "multiply(" "scalarRectangularMatrix& answer)," "const DiagonalMatrix<scalar>& A, " "const scalarRectangularMatrix& B, " "const DiagonalMatrix<scalar>& C" ) << "A and B must have identical inner dimensions but A.m = " << A.size() << " and B.n = " << B.n() << abort(FatalError); } if (B.m() != C.size()) { FatalErrorIn ( "multiply(" "scalarRectangularMatrix& answer)," "const DiagonalMatrix<scalar>& A, " "const scalarRectangularMatrix& B, " "const DiagonalMatrix<scalar>& C" ) << "B and C must have identical inner dimensions but B.m = " << B.m() << " and C.n = " << C.size() << abort(FatalError); } ans = scalarSquareMatrix(B.n(), B.n(), scalar(0)); for (register label i = 0; i < A.size(); i++) { for (register label j = 0; j < C.size(); j++) { ans[i][j] = A[i] * B[i][j] * C[j]; } } }
bool Foam::chemPointISAT<CompType, ThermoType>::grow(const scalarField& phiq) { scalarField dphi(phiq - phi()); label dim = completeSpaceSize(); label initNActiveSpecies(nActiveSpecies_); bool isMechRedActive = chemistry_.mechRed()->active(); if (isMechRedActive) { label activeAdded(0); DynamicList<label> dimToAdd(0); // check if the difference of active species is lower than the maximum // number of new dimensions allowed for (label i=0; i<completeSpaceSize()-nAdditionalEqns_; i++) { // first test if the current chemPoint has an inactive species // corresponding to an active one in the query point if ( completeToSimplifiedIndex_[i] == -1 && chemistry_.completeToSimplifiedIndex()[i]!=-1 ) { activeAdded++; dimToAdd.append(i); } // then test if an active species in the current chemPoint // corresponds to an inactive on the query side if ( completeToSimplifiedIndex_[i] != -1 && chemistry_.completeToSimplifiedIndex()[i] == -1 ) { activeAdded++; // we don't need to add a new dimension but we count it to have // control on the difference through maxNumNewDim } // finally test if both points have inactive species but // with a dphi!=0 if ( completeToSimplifiedIndex_[i] == -1 && chemistry_.completeToSimplifiedIndex()[i] == -1 && dphi[i] != 0 ) { activeAdded++; dimToAdd.append(i); } } // if the number of added dimension is too large, growth fail if (activeAdded > maxNumNewDim_) { return false; } // the number of added dimension to the current chemPoint nActiveSpecies_ += dimToAdd.size(); simplifiedToCompleteIndex_.setSize(nActiveSpecies_); forAll(dimToAdd, i) { label si = nActiveSpecies_ - dimToAdd.size() + i; // add the new active species simplifiedToCompleteIndex_[si] = dimToAdd[i]; completeToSimplifiedIndex_[dimToAdd[i]] = si; } // update LT and A : //-add new column and line for the new active species //-transfer last two lines of the previous matrix (p and T) to the end // (change the diagonal position) //-set all element of the new lines and columns to zero except diagonal // (=1/(tolerance*scaleFactor)) if (nActiveSpecies_ > initNActiveSpecies) { scalarSquareMatrix LTvar = LT_; // take a copy of LT_ scalarSquareMatrix Avar = A_; // take a copy of A_ LT_ = scalarSquareMatrix(nActiveSpecies_+nAdditionalEqns_, Zero); A_ = scalarSquareMatrix(nActiveSpecies_+nAdditionalEqns_, Zero); // write the initial active species for (label i=0; i<initNActiveSpecies; i++) { for (label j=0; j<initNActiveSpecies; j++) { LT_(i, j) = LTvar(i, j); A_(i, j) = Avar(i, j); } } // write the columns for temperature and pressure for (label i=0; i<initNActiveSpecies; i++) { for (label j=1; j>=0; j--) { LT_(i, nActiveSpecies_+j)=LTvar(i, initNActiveSpecies+j); A_(i, nActiveSpecies_+j)=Avar(i, initNActiveSpecies+j); LT_(nActiveSpecies_+j, i)=LTvar(initNActiveSpecies+j, i); A_(nActiveSpecies_+j, i)=Avar(initNActiveSpecies+j, i); } } // end with the diagonal elements for temperature and pressure LT_(nActiveSpecies_, nActiveSpecies_)= LTvar(initNActiveSpecies, initNActiveSpecies); A_(nActiveSpecies_, nActiveSpecies_)= Avar(initNActiveSpecies, initNActiveSpecies); LT_(nActiveSpecies_+1, nActiveSpecies_+1)= LTvar(initNActiveSpecies+1, initNActiveSpecies+1); A_(nActiveSpecies_+1, nActiveSpecies_+1)= Avar(initNActiveSpecies+1, initNActiveSpecies+1); if (variableTimeStep()) { LT_(nActiveSpecies_+2, nActiveSpecies_+2)= LTvar(initNActiveSpecies+2, initNActiveSpecies+2); A_(nActiveSpecies_+2, nActiveSpecies_+2)= Avar(initNActiveSpecies+2, initNActiveSpecies+2); } for (label i=initNActiveSpecies; i<nActiveSpecies_;i++) { LT_(i, i)= 1.0 /(tolerance_*scaleFactor_[simplifiedToCompleteIndex_[i]]); A_(i, i) = 1; } } dim = nActiveSpecies_ + nAdditionalEqns_; }
Foam::chemPointISAT<CompType, ThermoType>::chemPointISAT ( TDACChemistryModel<CompType, ThermoType>& chemistry, const scalarField& phi, const scalarField& Rphi, const scalarSquareMatrix& A, const scalarField& scaleFactor, const scalar& tolerance, const label& completeSpaceSize, const dictionary& coeffsDict, binaryNode<CompType, ThermoType>* node ) : chemistry_(chemistry), phi_(phi), Rphi_(Rphi), A_(A), scaleFactor_(scaleFactor), node_(node), completeSpaceSize_(completeSpaceSize), nGrowth_(0), nActiveSpecies_(chemistry.mechRed()->NsSimp()), simplifiedToCompleteIndex_(nActiveSpecies_), timeTag_(chemistry_.timeSteps()), lastTimeUsed_(chemistry_.timeSteps()), toRemove_(false), maxNumNewDim_(coeffsDict.lookupOrDefault("maxNumNewDim",0)), printProportion_(coeffsDict.lookupOrDefault("printProportion",false)), numRetrieve_(0), nLifeTime_(0), completeToSimplifiedIndex_ ( completeSpaceSize - (2 + (variableTimeStep() == 1 ? 1 : 0)) ) { tolerance_ = tolerance; if (variableTimeStep()) { nAdditionalEqns_ = 3; iddeltaT_ = completeSpaceSize - 1; scaleFactor_[iddeltaT_] *= phi_[iddeltaT_] / tolerance_; } else { nAdditionalEqns_ = 2; iddeltaT_ = completeSpaceSize; // will not be used } idT_ = completeSpaceSize - nAdditionalEqns_; idp_ = completeSpaceSize - nAdditionalEqns_ + 1; bool isMechRedActive = chemistry_.mechRed()->active(); if (isMechRedActive) { for (label i=0; i<completeSpaceSize-nAdditionalEqns_; i++) { completeToSimplifiedIndex_[i] = chemistry.completeToSimplifiedIndex()[i]; } for (label i=0; i<nActiveSpecies_; i++) { simplifiedToCompleteIndex_[i] = chemistry.simplifiedToCompleteIndex()[i]; } } label reduOrCompDim = completeSpaceSize; if (isMechRedActive) { reduOrCompDim = nActiveSpecies_+nAdditionalEqns_; } // SVD decomposition A = U*D*V^T SVD svdA(A); scalarDiagonalMatrix D(reduOrCompDim); const scalarDiagonalMatrix& S = svdA.S(); // Replace the value of vector D by max(D, 1/2), first ISAT paper for (label i=0; i<reduOrCompDim; i++) { D[i] = max(S[i], 0.5); } // Rebuild A with max length, tol and scale factor before QR decomposition scalarRectangularMatrix Atilde(reduOrCompDim); // Result stored in Atilde multiply(Atilde, svdA.U(), D, svdA.V().T()); for (label i=0; i<reduOrCompDim; i++) { for (label j=0; j<reduOrCompDim; j++) { label compi = i; if (isMechRedActive) { compi = simplifiedToCompleteIndex(i); } // SF*A/tolerance // (where SF is diagonal with inverse of scale factors) // SF*A is the same as dividing each line by the scale factor // corresponding to the species of this line Atilde(i, j) /= (tolerance*scaleFactor[compi]); } } // The object LT_ (the transpose of the Q) describe the EOA, since we have // A^T B^T B A that should be factorized into L Q^T Q L^T and is set in the // qrDecompose function LT_ = scalarSquareMatrix(Atilde); qrDecompose(reduOrCompDim, LT_); }
void multiply ( scalarSquareMatrix& ans, // value changed in return const scalarRectangularMatrix& A, const scalarRectangularMatrix& B, const scalarRectangularMatrix& C, const scalarDiagonalMatrix& D ) { if (A.m() != B.n()) { FatalErrorIn ( "multiply(" "scalarRectangularMatrix& answer)," "const scalarRectangularMatrix& A, " "const scalarRectangularMatrix& B, " "const scalarRectangularMatrix& C, " "const DiagonalMatrix<scalar>& D" ) << "A and B must have identical inner dimensions but A.m = " << A.m() << " and B.n = " << B.n() << abort(FatalError); } if (B.m() != C.n()) { FatalErrorIn ( "multiply(" "scalarRectangularMatrix& answer)," "const scalarRectangularMatrix& A, " "const scalarRectangularMatrix& B, " "const scalarRectangularMatrix& C, " "const DiagonalMatrix<scalar>& D" ) << "B and C must have identical inner dimensions but B.m = " << B.m() << " and C.n = " << C.n() << abort(FatalError); } if (C.m() != D.size()) { FatalErrorIn ( "multiply(" "scalarRectangularMatrix& answer)," "const scalarRectangularMatrix& A, " "const scalarRectangularMatrix& B, " "const scalarRectangularMatrix& C, " "const DiagonalMatrix<scalar>& D" ) << "C and D must have identical inner dimensions but C.m = " << C.m() << " and D.n = " << D.size() << abort(FatalError); } ans = scalarSquareMatrix(D.size(), D.size(), scalar(0)); for (register label i = 0; i < A.n(); i++) { for (register label g = 0; g < C.m(); g++) { for (register label l = 0; l < C.n(); l++) { scalar ab = 0; for (register label j = 0; j < A.m(); j++) { ab += A[i][j]*B[j][l]; } ans[i][g] += C[l][g] * ab; } ans[i][g] = ans[i][g] * D[g]; } } }