void AssembleBilaplaceProblem_AD(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // call the adept stack object adept::Stack& s = FemusInit::_adeptStack; // extract pointers to the several objects that we are going to use NonLinearImplicitSystem* mlPdeSys = &ml_prob.get_system<NonLinearImplicitSystem> ("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); const unsigned levelMax = mlPdeSys->GetLevelMax(); const bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned soluIndex; soluIndex = mlSol->GetIndex("u"); // get the position of "u" in the ml_sol object unsigned soluType = mlSol->GetSolutionType(soluIndex); // get the finite element type for "u" unsigned soluPdeIndex; soluPdeIndex = mlPdeSys->GetSolPdeIndex("u"); // get the position of "u" in the pdeSys object vector < adept::adouble > solu; // local solution unsigned solvIndex; solvIndex = mlSol->GetIndex("v"); // get the position of "v" in the ml_sol object unsigned solvType = mlSol->GetSolutionType(solvIndex); // get the finite element type for "v" unsigned solvPdeIndex; solvPdeIndex = mlPdeSys->GetSolPdeIndex("v"); // get the position of "v" in the pdeSys object vector < adept::adouble > solv; // local solution vector < vector < double > > x(dim); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) vector< int > KKDof; // local to global pdeSys dofs vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives vector <double> phi_xx; // local test function second order partial derivatives double weight; // gauss point weight vector< double > Res; // local redidual vector vector< adept::adouble > aResu; // local redidual vector vector< adept::adouble > aResv; // local redidual vector // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 solu.reserve(maxSize); solv.reserve(maxSize); for (unsigned i = 0; i < dim; i++) x[i].reserve(maxSize); KKDof.reserve(2 * maxSize); phi.reserve(maxSize); phi_x.reserve(maxSize * dim); unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) phi_xx.reserve(maxSize * dim2); Res.reserve(2 * maxSize); aResu.reserve(maxSize); aResv.reserve(maxSize); vector < double > Jac; // local Jacobian matrix (ordered by column, adept) Jac.reserve(4 * maxSize * maxSize); vector< double > Jact; // local Jacobian matrix (ordered by raw, PETSC) Jact.reserve(4 * maxSize * maxSize); if (assembleMatrix) KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel = msh->IS_Mts2Gmt_elem_offset[iproc]; iel < msh->IS_Mts2Gmt_elem_offset[iproc + 1]; iel++) { unsigned kel = msh->IS_Mts2Gmt_elem[iel]; // mapping between paralell dof and mesh dof short unsigned kelGeom = el->GetElementType(kel); // element geometry type unsigned nDofs = el->GetElementDofNumber(kel, soluType); // number of solution element dofs unsigned nDofs2 = el->GetElementDofNumber(kel, xType); // number of coordinate element dofs // resize local arrays KKDof.resize(2 * nDofs); solu.resize(nDofs); solv.resize(nDofs); for (int i = 0; i < dim; i++) { x[i].resize(nDofs2); } Res.resize(2 * nDofs); //resize aResu.resize(nDofs); //resize aResv.resize(nDofs); //resize std::fill(aResu.begin(), aResu.end(), 0); //set aRes to zero std::fill(aResv.begin(), aResv.end(), 0); //set aRes to zero if (assembleMatrix) { //resize Jact.resize(4 * nDofs * nDofs); Jac.resize(4 * nDofs * nDofs); } // local storage of global mapping and solution for (unsigned i = 0; i < nDofs; i++) { unsigned iNode = el->GetMeshDof(kel, i, soluType); // local to global solution node unsigned solDof = msh->GetMetisDof(iNode, soluType); // global to global mapping between solution node and solution dof solu[i] = (*sol->_Sol[soluIndex])(solDof); // global extraction and local storage for the solution solv[i] = (*sol->_Sol[solvIndex])(solDof); // global extraction and local storage for the solution KKDof[i] = pdeSys->GetKKDof(soluIndex, soluPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof KKDof[nDofs + i] = pdeSys->GetKKDof(solvIndex, solvPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofs2; i++) { unsigned iNode = el->GetMeshDof(kel, i, xType); // local to global coordinates node unsigned xDof = msh->GetMetisDof(iNode, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_coordinate->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } if (level == levelMax || !el->GetRefinedElementIndex(kel)) { // do not care about this if now (it is used for the AMR) // start a new recording of all the operations involving adept::adouble variables s.new_recording(); // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[kelGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point adept::adouble soluGauss = 0; vector < adept::adouble > soluGauss_x(dim, 0.); adept::adouble solvGauss = 0; vector < adept::adouble > solvGauss_x(dim, 0.); vector < double > xGauss(dim, 0.); for (unsigned i = 0; i < nDofs; i++) { soluGauss += phi[i] * solu[i]; solvGauss += phi[i] * solv[i]; for (unsigned jdim = 0; jdim < dim; jdim++) { soluGauss_x[jdim] += phi_x[i * dim + jdim] * solu[i]; solvGauss_x[jdim] += phi_x[i * dim + jdim] * solv[i]; xGauss[jdim] += x[jdim][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nDofs; i++) { adept::adouble Laplace_u = 0.; adept::adouble Laplace_v = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { Laplace_u += - phi_x[i * dim + jdim] * soluGauss_x[jdim]; Laplace_v += - phi_x[i * dim + jdim] * solvGauss_x[jdim]; } double exactSolValue = GetExactSolutionValue(xGauss); double pi = acos(-1.); aResv[i] += (solvGauss * phi[i] - Laplace_u) * weight; aResu[i] += (4.*pi * pi * pi * pi * exactSolValue * phi[i] - Laplace_v) * weight; } // end phi_i loop } // end gauss point loop } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store for (int i = 0; i < nDofs; i++) { Res[i] = aResu[i].value(); Res[nDofs + i] = aResv[i].value(); } RES->add_vector_blocked(Res, KKDof); if (assembleMatrix) { // define the dependent variables s.dependent(&aResu[0], nDofs); s.dependent(&aResv[0], nDofs); // define the independent variables s.independent(&solu[0], nDofs); s.independent(&solv[0], nDofs); // get the jacobian matrix (ordered by column) s.jacobian(&Jac[0]); // get the jacobian matrix (ordered by raw, i.e. Jact=Jac^t) for (int inode = 0; inode < 2 * nDofs; inode++) { for (int jnode = 0; jnode < 2 * nDofs; jnode++) { Jact[inode * 2 * nDofs + jnode] = -Jac[jnode * 2 * nDofs + inode]; } } //store Jact in the global matrix KK KK->add_matrix_blocked(Jact, KKDof, KKDof); s.clear_independents(); s.clear_dependents(); } } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }
void AssembleBoussinesqAppoximation(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // extract pointers to the several objects that we are going to use double Mu; if(counter < c0 ) Mu = 2. * Miu; else if ( counter <= cn ) { Mu = 2*Miu*(cn-counter)/(cn-c0) + Miu*(counter-c0)/(cn-c0); } else{ Mu = Miu; } std::cout << counter << " " << Mu <<std::endl; counter++; NonLinearImplicitSystem* mlPdeSys = &ml_prob.get_system<NonLinearImplicitSystem> ("NS"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); // call the adept stack object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 //solution variable vector < unsigned > solVIndex(dim); solVIndex[0] = mlSol->GetIndex("U"); // get the position of "U" in the ml_sol object solVIndex[1] = mlSol->GetIndex("V"); // get the position of "V" in the ml_sol object if (dim == 3) solVIndex[2] = mlSol->GetIndex("W"); // get the position of "V" in the ml_sol object unsigned solVType = mlSol->GetSolutionType(solVIndex[0]); // get the finite element type for "u" unsigned solPIndex; solPIndex = mlSol->GetIndex("P"); // get the position of "P" in the ml_sol object unsigned solPType = mlSol->GetSolutionType(solPIndex); // get the finite element type for "u" vector < unsigned > solVPdeIndex(dim); solVPdeIndex[0] = mlPdeSys->GetSolPdeIndex("U"); // get the position of "U" in the pdeSys object solVPdeIndex[1] = mlPdeSys->GetSolPdeIndex("V"); // get the position of "V" in the pdeSys object if (dim == 3) solVPdeIndex[2] = mlPdeSys->GetSolPdeIndex("W"); unsigned solPPdeIndex; solPPdeIndex = mlPdeSys->GetSolPdeIndex("P"); // get the position of "P" in the pdeSys object vector < vector < double > > solV(dim); // local solution vector < double > solP; // local solution vector < vector < double > > coordX(dim); // local coordinates unsigned coordXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) for (unsigned k = 0; k < dim; k++) { solV[k].reserve(maxSize); coordX[k].reserve(maxSize); } solP.reserve(maxSize); vector <double> phiV; // local test function vector <double> phiV_x; // local test function first order partial derivatives vector <double> phiV_xx; // local test function second order partial derivatives phiV.reserve(maxSize); phiV_x.reserve(maxSize * dim); phiV_xx.reserve(maxSize * dim2); double* phiP; double weight; // gauss point weight vector< int > sysDof; // local to global pdeSys dofs sysDof.reserve((dim + 2) *maxSize); vector< double > Res; // local redidual vector Res.reserve((dim + 2) *maxSize); vector < double > Jac; Jac.reserve((dim + 2) *maxSize * (dim + 2) *maxSize); if (assembleMatrix) KK->zero(); // Set to zero all the entries of the Global Matrix //BEGIN element loop for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { //BEGIN local dof number extraction unsigned nDofsV = msh->GetElementDofNumber(iel, solVType); //velocity unsigned nDofsP = msh->GetElementDofNumber(iel, solPType); //pressure unsigned nDofsX = msh->GetElementDofNumber(iel, coordXType); // coordinates unsigned nDofsVP = dim * nDofsV + nDofsP; // all solutions //END local dof number extraction //BEGIN memory allocation Res.resize(nDofsVP); std::fill(Res.begin(), Res.end(), 0); Jac.resize(nDofsVP * nDofsVP); std::fill(Jac.begin(), Jac.end(), 0); sysDof.resize(nDofsVP); for (unsigned k = 0; k < dim; k++) { solV[k].resize(nDofsV); coordX[k].resize(nDofsX); } std::vector <double> M(nDofsP); solP.resize(nDofsP); //END memory allocation //BEGIN global to local extraction for (unsigned i = 0; i < nDofsV; i++) { //velocity unsigned solVDof = msh->GetSolutionDof(i, iel, solVType); //local to global solution dof for (unsigned k = 0; k < dim; k++) { solV[k][i] = (*sol->_Sol[solVIndex[k]])(solVDof); //global to local solution value sysDof[i + k * nDofsV] = pdeSys->GetSystemDof(solVIndex[k], solVPdeIndex[k], i, iel); //local to global system dof } } for (unsigned i = 0; i < nDofsP; i++) { //pressure unsigned solPDof = msh->GetSolutionDof(i, iel, solPType); //local to global solution dof solP[i] = (*sol->_Sol[solPIndex])(solPDof); //global to local solution value sysDof[i + dim * nDofsV] = pdeSys->GetSystemDof(solPIndex, solPPdeIndex, i, iel); //local to global system dof } for (unsigned i = 0; i < nDofsX; i++) { //coordinates unsigned coordXDof = msh->GetSolutionDof(i, iel, coordXType); //local to global coordinate dof for (unsigned k = 0; k < dim; k++) { coordX[k][i] = (*msh->_topology->_Sol[k])(coordXDof); //global to local coordinate value } } //END global to local extraction //BEGIN Gauss point loop short unsigned ielGeom = msh->GetElementType(iel); for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solVType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][solVType]->Jacobian(coordX, ig, weight, phiV, phiV_x, phiV_xx); phiP = msh->_finiteElement[ielGeom][solPType]->GetPhi(ig); // evaluate the solution, the solution derivatives and the coordinates in the gauss point vector < double > solV_gss(dim, 0); vector < vector < double > > gradSolV_gss(dim); for (unsigned k = 0; k < dim; k++) { gradSolV_gss[k].resize(dim); std::fill(gradSolV_gss[k].begin(), gradSolV_gss[k].end(), 0); } for (unsigned i = 0; i < nDofsV; i++) { for (unsigned k = 0; k < dim; k++) { solV_gss[k] += phiV[i] * solV[k][i]; } for (unsigned j = 0; j < dim; j++) { for (unsigned k = 0; k < dim; k++) { gradSolV_gss[k][j] += phiV_x[i * dim + j] * solV[k][i]; } } } double solP_gss = 0; for (unsigned i = 0; i < nDofsP; i++) { solP_gss += phiP[i] * solP[i]; } // //BEGIN phiT_i loop: Energy balance // for(unsigned i = 0; i < nDofsT; i++) { // unsigned irow = i; // // for(unsigned k = 0; k < dim; k++) { // Res[irow] += -alpha / sqrt(Ra * Pr) * phiT_x[i * dim + k] * gradSolT_gss[k] * weight; // Res[irow] += -phiT[i] * solV_gss[k] * gradSolT_gss[k] * weight; // // if(assembleMatrix) { // unsigned irowMat = irow * nDofsTVP; // // for(unsigned j = 0; j < nDofsT; j++) { // Jac[ irowMat + j ] += alpha / sqrt(Ra * Pr) * phiT_x[i * dim + k] * phiT_x[j * dim + k] * weight; // Jac[ irowMat + j ] += phiT[i] * solV_gss[k] * phiT_x[j * dim + k] * weight; // } // // for(unsigned j = 0; j < nDofsV; j++) { // unsigned jcol = nDofsT + k * nDofsV + j; // Jac[ irowMat + jcol ] += phiT[i] * phiV[j] * gradSolT_gss[k] * weight; // } // } // // } // } // // //END phiT_i loop //BEGIN phiV_i loop: Momentum balance for (unsigned i = 0; i < nDofsV; i++) { for (unsigned k = 0; k < dim; k++) { unsigned irow = k * nDofsV + i; for (unsigned l = 0; l < dim; l++) { Res[irow] += -Mu * phiV_x[i * dim + l] * (gradSolV_gss[k][l] + gradSolV_gss[l][k]) * weight; Res[irow] += -phiV[i] * solV_gss[l] * gradSolV_gss[k][l] * weight; } Res[irow] += solP_gss * phiV_x[i * dim + k] * weight; if (assembleMatrix) { unsigned irowMat = nDofsVP * irow; for (unsigned l = 0; l < dim; l++) { for (unsigned j = 0; j < nDofsV; j++) { unsigned jcol1 = (k * nDofsV + j); unsigned jcol2 = (l * nDofsV + j); Jac[ irowMat + jcol1] += Mu * phiV_x[i * dim + l] * phiV_x[j * dim + l] * weight; Jac[ irowMat + jcol2] += Mu * phiV_x[i * dim + l] * phiV_x[j * dim + k] * weight; Jac[ irowMat + jcol1] += phiV[i] * solV_gss[l] * phiV_x[j * dim + l] * weight; Jac[ irowMat + jcol2] += phiV[i] * phiV[j] * gradSolV_gss[k][l] * weight; } } for (unsigned j = 0; j < nDofsP; j++) { unsigned jcol = (dim * nDofsV) + j; Jac[ irowMat + jcol] += - phiV_x[i * dim + k] * phiP[j] * weight; } } } } //END phiV_i loop //BEGIN phiP_i loop: mass balance for (unsigned i = 0; i < nDofsP; i++) { unsigned irow = dim * nDofsV + i; for (int k = 0; k < dim; k++) { Res[irow] += +(gradSolV_gss[k][k]) * phiP[i] * weight; if (assembleMatrix) { unsigned irowMat = nDofsVP * irow; for (unsigned j = 0; j < nDofsV; j++) { unsigned jcol = ( k * nDofsV + j); Jac[ irowMat + jcol ] -= phiP[i] * phiV_x[j * dim + k] * weight; } M[i] += phiP[i] * phiP[i] * weight; // for (unsigned j = 0; j < nDofsP; j++) { // M[i] += phiP[i] * phiP[j] * weight; // } } } } //END phiP_i loop } //END Gauss point loop std::vector<std::vector<double> > BtMinv (dim * nDofsV); for(unsigned i=0; i< dim * nDofsV; i++){ BtMinv[i].resize(nDofsP); } std::vector<std::vector<double> > B(nDofsP); for(unsigned i=0; i< nDofsP; i++){ B[i].resize(dim * nDofsV); } for(unsigned i = 0; i < dim * nDofsV; i++){ unsigned irow = i * nDofsVP; for(unsigned j = 0; j < nDofsP; j++){ unsigned jcol = (dim * nDofsV) + j; BtMinv[i][j] = .1 * Jac[ irow + jcol] / M[j]; } } for(unsigned i = 0; i < nDofsP; i++){ unsigned irow = ( (dim * nDofsV) + i) * nDofsVP; for(unsigned j = 0; j < dim * nDofsV; j++){ B[i][j] = Jac[irow + j]; } } std::vector<std::vector<double> > Jg (dim * nDofsV); for(unsigned i=0; i< dim * nDofsV; i++){ Jg[i].resize(dim * nDofsV); } for(unsigned i = 0; i < dim * nDofsV; i++){ for(unsigned j = 0; j < dim * nDofsV; j++){ Jg[i][j] = 0.; for(unsigned k = 0; k < nDofsP; k++){ Jg[i][j] += BtMinv[i][k] * B[k][j]; } } } std::vector<double> fg (dim * nDofsV); for(unsigned i = 0; i < dim * nDofsV; i++){ fg[i] = 0; for(unsigned j = 0; j < nDofsP; j++){ fg[i] += BtMinv[i][j] * Res[dim * nDofsV + j]; } } for(unsigned i = 0; i < dim * nDofsV; i++){ unsigned irow = i * nDofsVP; for(unsigned j = 0; j < dim * nDofsV; j++){ Jac[irow + j] += Jg[i][j]; //std::cout<< Jg[i][j]<<" "; //std::cout<< Jac[irow + j]<<" "; } //std::cout<<"\n"; Res[i] += fg[i]; } //std::cout<<"\n"; //BEGIN local to global Matrix/Vector assembly RES->add_vector_blocked(Res, sysDof); if (assembleMatrix) { KK->add_matrix_blocked(Jac, sysDof, sysDof); } //END local to global Matrix/Vector assembly } //END element loop RES->close(); if (assembleMatrix) { KK->close(); } // ***************** END ASSEMBLY ******************* }
void AssemblePoisson_AD(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // call the adept stack object adept::Stack& s = FemusInit::_adeptStack; // extract pointers to the several objects that we are going to use NonLinearImplicitSystem* mlPdeSys = &ml_prob.get_system<NonLinearImplicitSystem> ("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 //solution variable unsigned solUIndex; solUIndex = mlSol->GetIndex("U"); // get the position of "U" in the ml_sol object = 0 unsigned solUType = mlSol->GetSolutionType(solUIndex); // get the finite element type for "T" unsigned solUPdeIndex; solUPdeIndex = mlPdeSys->GetSolPdeIndex("U"); // get the position of "U" in the pdeSys object = 0 std::cout << solUIndex << " " << solUPdeIndex << std::endl; vector < adept::adouble > solU; // local solution vector< adept::adouble > aResU; // local redidual vector vector < vector < double > > crdX(dim); // local coordinates unsigned crdXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) solU.reserve(maxSize); aResU.reserve(maxSize); for (unsigned k = 0; k < dim; k++) { crdX[k].reserve(maxSize); } vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives vector <double> phi_xx; // local test function second order partial derivatives phi.reserve(maxSize); phi_x.reserve(maxSize * dim); phi_xx.reserve(maxSize * dim2); double weight; // gauss point weight vector< int > sysDof; // local to global pdeSys dofs sysDof.reserve(maxSize); vector< double > ResU; // local redidual vector ResU.reserve(maxSize); vector < double > Jac; Jac.reserve(maxSize * maxSize); KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { unsigned kel = iel; //msh->IS_Mts2Gmt_elem[iel]; // mapping between paralell dof and mesh dof short unsigned kelGeom = el->GetElementType(kel); // element geometry type unsigned nDofsU = el->GetElementDofNumber(kel, solUType); // number of solution element dofs unsigned nDofsX = el->GetElementDofNumber(kel, crdXType); // number of solution element dofs // resize local arrays sysDof.resize(nDofsU); solU.resize(nDofsU); for (unsigned k = 0; k < dim; k++) { crdX[k].resize(nDofsX); } aResU.assign(nDofsU, 0); // local storage of global mapping and solution for (unsigned i = 0; i < nDofsU; i++) { unsigned solUDof = msh->GetSolutionDof(i, iel, solUType); // local to global mapping of the solution U solU[i] = (*sol->_Sol[solUIndex])(solUDof); // value of the solution U in the dofs sysDof[i] = pdeSys->GetSystemDof(solUIndex, solUPdeIndex, i, iel); // local to global mapping between solution U and system } // local storage of coordinates for (unsigned i = 0; i < nDofsX; i++) { unsigned coordXDof = msh->GetSolutionDof(i, iel, crdXType); // local to global mapping of the coordinate X[dim] for (unsigned k = 0; k < dim; k++) { crdX[k][i] = (*msh->_topology->_Sol[k])(coordXDof); // value of the solution X[dim] } } s.new_recording(); // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[kelGeom][solUType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][solUType]->Jacobian(crdX, ig, weight, phi, phi_x, phi_xx); adept::adouble solUig = 0; // solution U in the gauss point vector < adept::adouble > gradSolUig(dim, 0.); // graadient of solution U in the gauss point for (unsigned i = 0; i < nDofsU; i++) { solUig += phi[i] * solU[i]; for (unsigned j = 0; j < dim; j++) { gradSolUig[j] += phi_x[i * dim + j] * solU[i]; } } double nu = 1.; // *** phiU_i loop *** for (unsigned i = 0; i < nDofsU; i++) { adept::adouble LaplaceU = 0.; for (unsigned j = 0; j < dim; j++) { LaplaceU += nu * phi_x[i * dim + j] * gradSolUig[j]; } aResU[i] += (phi[i] - LaplaceU) * weight; } // end phiU_i loop } // end gauss point loop // } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store them in RES ResU.resize(nDofsU); //resize for (int i = 0; i < nDofsU; i++) { ResU[i] = -aResU[i].value(); } RES->add_vector_blocked(ResU, sysDof); //Extarct and store the Jacobian Jac.resize(nDofsU * nDofsU); // define the dependent variables s.dependent(&aResU[0], nDofsU); // define the independent variables s.independent(&solU[0], nDofsU); // get the and store jacobian matrix (row-major) s.jacobian(&Jac[0] , true); KK->add_matrix_blocked(Jac, sysDof, sysDof); s.clear_independents(); s.clear_dependents(); } //end element loop for each process RES->close(); KK->close(); // ***************** END ASSEMBLY ******************* }
Real NewtonSolver::line_search(Real tol, Real last_residual, Real ¤t_residual, NumericVector<Number> &newton_iterate, const NumericVector<Number> &linear_solution) { // Take a full step if we got a residual reduction or if we // aren't substepping if ((current_residual < last_residual) || (!require_residual_reduction && (!require_finite_residual || !libmesh_isnan(current_residual)))) return 1.; // The residual vector NumericVector<Number> &rhs = *(_system.rhs); Real ax = 0.; // First abscissa, don't take negative steps Real cx = 1.; // Second abscissa, don't extrapolate steps // Find bx, a step length that gives lower residual than ax or cx Real bx = 1.; while (libmesh_isnan(current_residual) || (current_residual > last_residual && require_residual_reduction)) { // Reduce step size to 1/2, 1/4, etc. Real substepdivision; if (brent_line_search && !libmesh_isnan(current_residual)) { substepdivision = std::min(0.5, last_residual/current_residual); substepdivision = std::max(substepdivision, tol*2.); } else substepdivision = 0.5; newton_iterate.add (bx * (1.-substepdivision), linear_solution); newton_iterate.close(); bx *= substepdivision; if (verbose) libMesh::out << " Shrinking Newton step to " << bx << std::endl; // Check residual with fractional Newton step _system.assembly (true, false); rhs.close(); current_residual = rhs.l2_norm(); if (verbose) libMesh::out << " Current Residual: " << current_residual << std::endl; if (bx/2. < minsteplength && (libmesh_isnan(current_residual) || (current_residual > last_residual))) { libMesh::out << "Inexact Newton step FAILED at step " << _outer_iterations << std::endl; if (!continue_after_backtrack_failure) { libmesh_convergence_failure(); } else { libMesh::out << "Continuing anyway ..." << std::endl; _solve_result = DiffSolver::DIVERGED_BACKTRACKING_FAILURE; return bx; } } } // end while (current_residual > last_residual) // Now return that reduced-residual step, or use Brent's method to // find a more optimal step. if (!brent_line_search) return bx; // Brent's method adapted from Numerical Recipes in C, ch. 10.2 Real e = 0.; Real x = bx, w = bx, v = bx; // Residuals at bx Real fx = current_residual, fw = current_residual, fv = current_residual; // Max iterations for Brent's method loop const unsigned int max_i = 20; // for golden ratio steps const Real golden_ratio = 1.-(std::sqrt(5.)-1.)/2.; for (unsigned int i=1; i <= max_i; i++) { Real xm = (ax+cx)*0.5; Real tol1 = tol * std::abs(x) + tol*tol; Real tol2 = 2.0 * tol1; // Test if we're done if (std::abs(x-xm) <= (tol2 - 0.5 * (cx - ax))) return x; Real d; // Construct a parabolic fit if (std::abs(e) > tol1) { Real r = (x-w)*(fx-fv); Real q = (x-v)*(fx-fw); Real p = (x-v)*q-(x-w)*r; q = 2. * (q-r); if (q > 0.) p = -p; else q = std::abs(q); if (std::abs(p) >= std::abs(0.5*q*e) || p <= q * (ax-x) || p >= q * (cx-x)) { // Take a golden section step e = x >= xm ? ax-x : cx-x; d = golden_ratio * e; } else { // Take a parabolic fit step d = p/q; if (x+d-ax < tol2 || cx-(x+d) < tol2) d = SIGN(tol1, xm - x); } } else { // Take a golden section step e = x >= xm ? ax-x : cx-x; d = golden_ratio * e; } Real u = std::abs(d) >= tol1 ? x+d : x + SIGN(tol1,d); // Assemble the residual at the new steplength u newton_iterate.add (bx - u, linear_solution); newton_iterate.close(); bx = u; if (verbose) libMesh::out << " Shrinking Newton step to " << bx << std::endl; _system.assembly (true, false); rhs.close(); Real fu = current_residual = rhs.l2_norm(); if (verbose) libMesh::out << " Current Residual: " << fu << std::endl; if (fu <= fx) { if (u >= x) ax = x; else cx = x; v = w; w = x; x = u; fv = fw; fw = fx; fx = fu; } else { if (u < x) ax = u; else cx = u; if (fu <= fw || w == x) { v = w; w = u; fv = fw; fw = fu; } else if (fu <= fv || v == x || v == w) { v = u; fv = fu; } } } if (!quiet) libMesh::out << "Warning! Too many iterations used in Brent line search!" << std::endl; return bx; }
void AssembleBoussinesqAppoximation_AD(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // extract pointers to the several objects that we are going to use TransientNonlinearImplicitSystem* mlPdeSys = &ml_prob.get_system<TransientNonlinearImplicitSystem> ("NS"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); // call the adept stack object adept::Stack& s = FemusInit::_adeptStack; if(assembleMatrix) s.continue_recording(); else s.pause_recording(); SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 //solution variable unsigned solTIndex; solTIndex = mlSol->GetIndex("T"); // get the position of "T" in the ml_sol object unsigned solTType = mlSol->GetSolutionType(solTIndex); // get the finite element type for "T" vector < unsigned > solVIndex(dim); solVIndex[0] = mlSol->GetIndex("U"); // get the position of "U" in the ml_sol object solVIndex[1] = mlSol->GetIndex("V"); // get the position of "V" in the ml_sol object if(dim == 3) solVIndex[2] = mlSol->GetIndex("W"); // get the position of "V" in the ml_sol object unsigned solVType = mlSol->GetSolutionType(solVIndex[0]); // get the finite element type for "u" unsigned solPIndex; solPIndex = mlSol->GetIndex("P"); // get the position of "P" in the ml_sol object unsigned solPType = mlSol->GetSolutionType(solPIndex); // get the finite element type for "u" unsigned solTPdeIndex; solTPdeIndex = mlPdeSys->GetSolPdeIndex("T"); // get the position of "T" in the pdeSys object // std::cout << solTIndex <<" "<<solTPdeIndex<<std::endl; vector < unsigned > solVPdeIndex(dim); solVPdeIndex[0] = mlPdeSys->GetSolPdeIndex("U"); // get the position of "U" in the pdeSys object solVPdeIndex[1] = mlPdeSys->GetSolPdeIndex("V"); // get the position of "V" in the pdeSys object if(dim == 3) solVPdeIndex[2] = mlPdeSys->GetSolPdeIndex("W"); unsigned solPPdeIndex; solPPdeIndex = mlPdeSys->GetSolPdeIndex("P"); // get the position of "P" in the pdeSys object vector < adept::adouble > solT; // local solution vector < vector < adept::adouble > > solV(dim); // local solution vector < adept::adouble > solP; // local solution vector < double > solTold; // local solution vector < vector < double > > solVold(dim); // local solution vector < double > solPold; // local solution vector< adept::adouble > aResT; // local redidual vector vector< vector < adept::adouble > > aResV(dim); // local redidual vector vector< adept::adouble > aResP; // local redidual vector vector < vector < double > > coordX(dim); // local coordinates unsigned coordXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) solT.reserve(maxSize); solTold.reserve(maxSize); aResT.reserve(maxSize); for(unsigned k = 0; k < dim; k++) { solV[k].reserve(maxSize); solVold[k].reserve(maxSize); aResV[k].reserve(maxSize); coordX[k].reserve(maxSize); } solP.reserve(maxSize); solPold.reserve(maxSize); aResP.reserve(maxSize); vector <double> phiV; // local test function vector <double> phiV_x; // local test function first order partial derivatives vector <double> phiV_xx; // local test function second order partial derivatives phiV.reserve(maxSize); phiV_x.reserve(maxSize * dim); phiV_xx.reserve(maxSize * dim2); vector <double> phiT; // local test function vector <double> phiT_x; // local test function first order partial derivatives vector <double> phiT_xx; // local test function second order partial derivatives phiT.reserve(maxSize); phiT_x.reserve(maxSize * dim); phiT_xx.reserve(maxSize * dim2); double* phiP; double weight; // gauss point weight vector< int > sysDof; // local to global pdeSys dofs sysDof.reserve((dim + 2) *maxSize); vector< double > Res; // local redidual vector Res.reserve((dim + 2) *maxSize); vector < double > Jac; Jac.reserve((dim + 2) *maxSize * (dim + 2) *maxSize); if(assembleMatrix) KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { // element geometry type short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofsT = msh->GetElementDofNumber(iel, solTType); // number of solution element dofs unsigned nDofsV = msh->GetElementDofNumber(iel, solVType); // number of solution element dofs unsigned nDofsP = msh->GetElementDofNumber(iel, solPType); // number of solution element dofs unsigned nDofsX = msh->GetElementDofNumber(iel, coordXType); // number of coordinate element dofs unsigned nDofsTVP = nDofsT + dim * nDofsV + nDofsP; // resize local arrays sysDof.resize(nDofsTVP); solT.resize(nDofsV); solTold.resize(nDofsV); for(unsigned k = 0; k < dim; k++) { solV[k].resize(nDofsV); solVold[k].resize(nDofsV); coordX[k].resize(nDofsX); } solP.resize(nDofsP); solPold.resize(nDofsP); aResT.resize(nDofsV); //resize std::fill(aResT.begin(), aResT.end(), 0); //set aRes to zero for(unsigned k = 0; k < dim; k++) { aResV[k].resize(nDofsV); //resize std::fill(aResV[k].begin(), aResV[k].end(), 0); //set aRes to zero } aResP.resize(nDofsP); //resize std::fill(aResP.begin(), aResP.end(), 0); //set aRes to zero // local storage of global mapping and solution for(unsigned i = 0; i < nDofsT; i++) { unsigned solTDof = msh->GetSolutionDof(i, iel, solTType); // global to global mapping between solution node and solution dof solT[i] = (*sol->_Sol[solTIndex])(solTDof); // global extraction and local storage for the solution solTold[i] = (*sol->_SolOld[solTIndex])(solTDof); // global extraction and local storage for the solution sysDof[i] = pdeSys->GetSystemDof(solTIndex, solTPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dofs } // local storage of global mapping and solution for(unsigned i = 0; i < nDofsV; i++) { unsigned solVDof = msh->GetSolutionDof(i, iel, solVType); // global to global mapping between solution node and solution dof for(unsigned k = 0; k < dim; k++) { solV[k][i] = (*sol->_Sol[solVIndex[k]])(solVDof); // global extraction and local storage for the solution solVold[k][i] = (*sol->_SolOld[solVIndex[k]])(solVDof); // global extraction and local storage for the solution sysDof[i + nDofsT + k * nDofsV] = pdeSys->GetSystemDof(solVIndex[k], solVPdeIndex[k], i, iel); // global to global mapping between solution node and pdeSys dof } } for(unsigned i = 0; i < nDofsP; i++) { unsigned solPDof = msh->GetSolutionDof(i, iel, solPType); // global to global mapping between solution node and solution dof solP[i] = (*sol->_Sol[solPIndex])(solPDof); // global extraction and local storage for the solution solPold[i] = (*sol->_SolOld[solPIndex])(solPDof); // global extraction and local storage for the solution sysDof[i + nDofsT + dim * nDofsV] = pdeSys->GetSystemDof(solPIndex, solPPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for(unsigned i = 0; i < nDofsX; i++) { unsigned coordXDof = msh->GetSolutionDof(i, iel, coordXType); // global to global mapping between coordinates node and coordinate dof for(unsigned k = 0; k < dim; k++) { coordX[k][i] = (*msh->_topology->_Sol[k])(coordXDof); // global extraction and local storage for the element coordinates } } // start a new recording of all the operations involving adept::adouble variables if(assembleMatrix) s.new_recording(); // *** Gauss point loop *** for(unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solVType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][solTType]->Jacobian(coordX, ig, weight, phiT, phiT_x, phiT_xx); msh->_finiteElement[ielGeom][solVType]->Jacobian(coordX, ig, weight, phiV, phiV_x, phiV_xx); phiP = msh->_finiteElement[ielGeom][solPType]->GetPhi(ig); // evaluate the solution, the solution derivatives and the coordinates in the gauss point adept::adouble solT_gss = 0; double solTold_gss = 0; vector < adept::adouble > gradSolT_gss(dim, 0.); vector < double > gradSolTold_gss(dim, 0.); for(unsigned i = 0; i < nDofsT; i++) { solT_gss += phiT[i] * solT[i]; solTold_gss += phiT[i] * solTold[i]; for(unsigned j = 0; j < dim; j++) { gradSolT_gss[j] += phiT_x[i * dim + j] * solT[i]; gradSolTold_gss[j] += phiT_x[i * dim + j] * solTold[i]; } } vector < adept::adouble > solV_gss(dim, 0); vector < double > solVold_gss(dim, 0); vector < vector < adept::adouble > > gradSolV_gss(dim); vector < vector < double > > gradSolVold_gss(dim); for(unsigned k = 0; k < dim; k++) { gradSolV_gss[k].resize(dim); gradSolVold_gss[k].resize(dim); std::fill(gradSolV_gss[k].begin(), gradSolV_gss[k].end(), 0); std::fill(gradSolVold_gss[k].begin(), gradSolVold_gss[k].end(), 0); } for(unsigned i = 0; i < nDofsV; i++) { for(unsigned k = 0; k < dim; k++) { solV_gss[k] += phiV[i] * solV[k][i]; solVold_gss[k] += phiV[i] * solVold[k][i]; } for(unsigned j = 0; j < dim; j++) { for(unsigned k = 0; k < dim; k++) { gradSolV_gss[k][j] += phiV_x[i * dim + j] * solV[k][i]; gradSolVold_gss[k][j] += phiV_x[i * dim + j] * solVold[k][i]; } } } adept::adouble solP_gss = 0; double solPold_gss = 0; for(unsigned i = 0; i < nDofsP; i++) { solP_gss += phiP[i] * solP[i]; solPold_gss += phiP[i] * solPold[i]; } double alpha = 1.; double beta = 1.;//40000.; double Pr = Prandtl; double Ra = Rayleigh; double dt = mlPdeSys -> GetIntervalTime(); // *** phiT_i loop *** for(unsigned i = 0; i < nDofsT; i++) { adept::adouble Temp = 0.; adept::adouble TempOld = 0.; for(unsigned j = 0; j < dim; j++) { Temp += 1. / sqrt(Ra * Pr) * alpha * phiT_x[i * dim + j] * gradSolT_gss[j]; Temp += phiT[i] * (solV_gss[j] * gradSolT_gss[j]); TempOld += 1. / sqrt(Ra * Pr) * alpha * phiT_x[i * dim + j] * gradSolTold_gss[j]; TempOld += phiT[i] * (solVold_gss[j] * gradSolTold_gss[j]); } aResT[i] += (- (solT_gss - solTold_gss) * phiT[i] / dt - 0.5 * (Temp + TempOld)) * weight; } // end phiT_i loop // *** phiV_i loop *** for(unsigned i = 0; i < nDofsV; i++) { vector < adept::adouble > NSV(dim, 0.); vector < double > NSVold(dim, 0.); for(unsigned j = 0; j < dim; j++) { for(unsigned k = 0; k < dim; k++) { NSV[k] += sqrt(Pr / Ra) * phiV_x[i * dim + j] * (gradSolV_gss[k][j] + gradSolV_gss[j][k]); NSV[k] += phiV[i] * (solV_gss[j] * gradSolV_gss[k][j]); NSVold[k] += sqrt(Pr / Ra) * phiV_x[i * dim + j] * (gradSolVold_gss[k][j] + gradSolVold_gss[j][k]); NSVold[k] += phiV[i] * (solVold_gss[j] * gradSolVold_gss[k][j]); } } for(unsigned k = 0; k < dim; k++) { NSV[k] += -solP_gss * phiV_x[i * dim + k]; NSVold[k] += -solPold_gss * phiV_x[i * dim + k]; } NSV[1] += -beta * solT_gss * phiV[i]; NSVold[1] += -beta * solTold_gss * phiV[i]; for(unsigned k = 0; k < dim; k++) { aResV[k][i] += (- (solV_gss[k] - solVold_gss[k]) * phiV[i] / dt - 0.5 * (NSV[k] + NSVold[k])) * weight; } } // end phiV_i loop // *** phiP_i loop *** for(unsigned i = 0; i < nDofsP; i++) { for(int k = 0; k < dim; k++) { aResP[i] += - (gradSolV_gss[k][k]) * phiP[i] * weight; } } // end phiP_i loop } // end gauss point loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store them in RES Res.resize(nDofsTVP); //resize for(int i = 0; i < nDofsT; i++) { Res[i] = -aResT[i].value(); } for(int i = 0; i < nDofsV; i++) { for(unsigned k = 0; k < dim; k++) { Res[ i + nDofsT + k * nDofsV ] = -aResV[k][i].value(); } } for(int i = 0; i < nDofsP; i++) { Res[ i + nDofsT + dim * nDofsV ] = -aResP[i].value(); } RES->add_vector_blocked(Res, sysDof); //Extarct and store the Jacobian if(assembleMatrix) { Jac.resize(nDofsTVP * nDofsTVP); // define the dependent variables s.dependent(&aResT[0], nDofsT); for(unsigned k = 0; k < dim; k++) { s.dependent(&aResV[k][0], nDofsV); } s.dependent(&aResP[0], nDofsP); // define the independent variables s.independent(&solT[0], nDofsT); for(unsigned k = 0; k < dim; k++) { s.independent(&solV[k][0], nDofsV); } s.independent(&solP[0], nDofsP); // get the and store jacobian matrix (row-major) s.jacobian(&Jac[0] , true); KK->add_matrix_blocked(Jac, sysDof, sysDof); s.clear_independents(); s.clear_dependents(); } } //end element loop for each process RES->close(); if(assembleMatrix) { KK->close(); } // ***************** END ASSEMBLY ******************* }