void GetSolutionNorm(MultiLevelSolution& mlSol, const unsigned & group, std::vector <double> &data) { int iproc, nprocs; MPI_Comm_rank(MPI_COMM_WORLD, &iproc); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); NumericVector* p2; NumericVector* v2; NumericVector* vol; NumericVector* vol0; p2 = NumericVector::build().release(); v2 = NumericVector::build().release(); vol = NumericVector::build().release(); vol0 = NumericVector::build().release(); if(nprocs == 1) { p2->init(nprocs, 1, false, SERIAL); v2->init(nprocs, 1, false, SERIAL); vol->init(nprocs, 1, false, SERIAL); vol0->init(nprocs, 1, false, SERIAL); } else { p2->init(nprocs, 1, false, PARALLEL); v2->init(nprocs, 1, false, PARALLEL); vol->init(nprocs, 1, false, PARALLEL); vol0->init(nprocs, 1, false, PARALLEL); } p2->zero(); v2->zero(); vol->zero(); vol0->zero(); unsigned level = mlSol._mlMesh->GetNumberOfLevels() - 1; Solution* solution = mlSol.GetSolutionLevel(level); Mesh* msh = mlSol._mlMesh->GetLevel(level); const unsigned dim = msh->GetDimension(); const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim))); vector< double > solP; vector< vector < double> > solV(dim); vector< vector < double> > x0(dim); vector< vector < double> > x(dim); solP.reserve(max_size); for(unsigned d = 0; d < dim; d++) { solV[d].reserve(max_size); x0[d].reserve(max_size); x[d].reserve(max_size); } double weight; double weight0; vector <double> phiV; vector <double> gradphiV; vector <double> nablaphiV; double *phiP; phiV.reserve(max_size); gradphiV.reserve(max_size * dim); nablaphiV.reserve(max_size * (3 * (dim - 1) + !(dim - 1))); 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" vector < unsigned > solDIndex(dim); solDIndex[0] = mlSol.GetIndex("DX"); // get the position of "U" in the ml_sol object solDIndex[1] = mlSol.GetIndex("DY"); // get the position of "V" in the ml_sol object if(dim == 3) solDIndex[2] = mlSol.GetIndex("DZ"); // get the position of "V" in the ml_sol object unsigned solDType = mlSol.GetSolutionType(solDIndex[0]); unsigned solPIndex; solPIndex = mlSol.GetIndex("PS"); unsigned solPType = mlSol.GetSolutionType(solPIndex); for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { if(msh->GetElementGroup(iel) == group) { short unsigned ielt = msh->GetElementType(iel); unsigned ndofV = msh->GetElementDofNumber(iel, solVType); unsigned ndofP = msh->GetElementDofNumber(iel, solPType); unsigned ndofD = msh->GetElementDofNumber(iel, solDType); // resize phiV.resize(ndofV); gradphiV.resize(ndofV * dim); nablaphiV.resize(ndofV * (3 * (dim - 1) + !(dim - 1))); solP.resize(ndofP); for(int d = 0; d < dim; d++) { solV[d].resize(ndofV); x0[d].resize(ndofD); x[d].resize(ndofD); } // get local to global mappings for(unsigned i = 0; i < ndofD; i++) { unsigned idof = msh->GetSolutionDof(i, iel, solDType); for(unsigned d = 0; d < dim; d++) { x0[d][i] = (*msh->_topology->_Sol[d])(idof); x[d][i] = (*msh->_topology->_Sol[d])(idof) + (*solution->_Sol[solDIndex[d]])(idof); } } for(unsigned i = 0; i < ndofV; i++) { unsigned idof = msh->GetSolutionDof(i, iel, solVType); // global to global mapping between solution node and solution dof for(unsigned d = 0; d < dim; d++) { solV[d][i] = (*solution->_Sol[solVIndex[d]])(idof); // global extraction and local storage for the solution } } for(unsigned i = 0; i < ndofP; i++) { unsigned idof = msh->GetSolutionDof(i, iel, solPType); solP[i] = (*solution->_Sol[solPIndex])(idof); } for(unsigned ig = 0; ig < mlSol._mlMesh->_finiteElement[ielt][solVType]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** msh->_finiteElement[ielt][solVType]->Jacobian(x0, ig, weight0, phiV, gradphiV, nablaphiV); msh->_finiteElement[ielt][solVType]->Jacobian(x, ig, weight, phiV, gradphiV, nablaphiV); phiP = msh->_finiteElement[ielt][solPType]->GetPhi(ig); vol0->add(iproc, weight0); vol->add(iproc, weight); std::vector < double> SolV2(dim, 0.); for(unsigned i = 0; i < ndofV; i++) { for(unsigned d = 0; d < dim; d++) { SolV2[d] += solV[d][i] * phiV[i]; } } double V2 = 0.; for(unsigned d = 0; d < dim; d++) { V2 += SolV2[d] * SolV2[d]; } v2->add(iproc, V2 * weight); double P2 = 0; for(unsigned i = 0; i < ndofP; i++) { P2 += solP[i] * phiP[i]; } P2 *= P2; p2->add(iproc, P2 * weight); } } } p2->close(); v2->close(); vol0->close(); vol->close(); double p2_l2 = p2->l1_norm(); double v2_l2 = v2->l1_norm(); double VOL0 = vol0->l1_norm(); double VOL = vol->l1_norm(); std::cout.precision(14); std::scientific; std::cout << " vol0 = " << VOL0 << std::endl; std::cout << " vol = " << VOL << std::endl; std::cout << " (vol-vol0)/vol0 = " << (VOL - VOL0) / VOL0 << std::endl; std::cout << " p_l2 norm / vol = " << sqrt(p2_l2 / VOL) << std::endl; std::cout << " v_l2 norm / vol = " << sqrt(v2_l2 / VOL) << std::endl; data[1] = (VOL - VOL0) / VOL0; data[2] = VOL; data[3] = sqrt(p2_l2 / VOL); data[4] = sqrt(v2_l2 / VOL); delete p2; delete v2; delete vol; }
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 // 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 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 > sysDof; // 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); sysDof.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); 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++) { short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofs = msh->GetElementDofNumber(iel, soluType); // number of solution element dofs unsigned nDofs2 = msh->GetElementDofNumber(iel, xType); // number of coordinate element dofs // resize local arrays sysDof.resize(2 * nDofs); solu.resize(nDofs); solv.resize(nDofs); for (int i = 0; i < dim; i++) { x[i].resize(nDofs2); } aResu.assign(nDofs, 0.); //resize aResv.assign(nDofs, 0.); //resize // local storage of global mapping and solution for (unsigned i = 0; i < nDofs; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, 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 sysDof[i] = pdeSys->GetSystemDof(soluIndex, soluPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof sysDof[nDofs + i] = pdeSys->GetSystemDof(solvIndex, solvPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofs2; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } // 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[ielGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][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 // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store Res.resize(2 * nDofs); for (int i = 0; i < nDofs; i++) { Res[i] = -aResu[i].value(); Res[nDofs + i] = -aResv[i].value(); } RES->add_vector_blocked(Res, sysDof); Jac.resize( 4 * nDofs * nDofs ); // 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], 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 ******************* }
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 // 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> ("NS"); // 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 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 < adept::adouble > > solV(dim); // local solution vector < adept::adouble > solP; // local solution 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) for (unsigned k = 0; k < dim; k++) { solV[k].reserve(maxSize); aResV[k].reserve(maxSize); coordX[k].reserve(maxSize); } solP.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); double* phiP; double weight; // gauss point weight vector< int > KKDof; // local to global pdeSys dofs KKDof.reserve((dim + 1) *maxSize); vector< double > Res; // local redidual vector Res.reserve((dim + 1) *maxSize); vector < double > Jac; Jac.reserve((dim + 1) *maxSize * (dim + 1) *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 nDofsV = el->GetElementDofNumber(kel, solVType); // number of solution element dofs unsigned nDofsP = el->GetElementDofNumber(kel, solPType); // number of solution element dofs unsigned nDofsX = el->GetElementDofNumber(kel, coordXType); // number of coordinate element dofs unsigned nDofsVP = dim * nDofsV + nDofsP; // resize local arrays KKDof.resize(nDofsVP); for (unsigned k = 0; k < dim; k++) { solV[k].resize(nDofsV); coordX[k].resize(nDofsX); } solP.resize(nDofsP); 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 < nDofsV; i++) { unsigned iNode = el->GetMeshDof(kel, i, solVType); // local to global solution node unsigned solVDof = msh->GetMetisDof(iNode, 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 KKDof[i + k * nDofsV] = pdeSys->GetKKDof(solVIndex[k], solVPdeIndex[k], iNode); // global to global mapping between solution node and pdeSys dof } } for (unsigned i = 0; i < nDofsP; i++) { unsigned iNode = el->GetMeshDof(kel, i, solPType); // local to global solution node unsigned solPDof = msh->GetMetisDof(iNode, 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 KKDof[i + dim * nDofsV] = pdeSys->GetKKDof(solPIndex, solPPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofsX; i++) { unsigned iNode = el->GetMeshDof(kel, i, coordXType); // local to global coordinates node unsigned coordXDof = msh->GetMetisDof(iNode, coordXType); // global to global mapping between coordinates node and coordinate dof for (unsigned k = 0; k < dim; k++) { coordX[k][i] = (*msh->_coordinate->_Sol[k])(coordXDof); // 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][solVType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][solVType]->Jacobian(coordX, ig, weight, phiV, phiV_x, phiV_xx); phiP = msh->_finiteElement[kelGeom][solPType]->GetPhi(ig); vector < adept::adouble > solV_gss(dim, 0); vector < vector < adept::adouble > > 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]; } } } adept::adouble solP_gss = 0; for (unsigned i = 0; i < nDofsP; i++) { solP_gss += phiP[i] * solP[i]; } double nu = 1.; // *** phiV_i loop *** for (unsigned i = 0; i < nDofsV; i++) { vector < adept::adouble > NSV(dim, 0.); for (unsigned j = 0; j < dim; j++) { for (unsigned k = 0; k < dim; k++) { NSV[k] += nu * phiV_x[i * dim + j] * (gradSolV_gss[k][j] + gradSolV_gss[j][k]); NSV[k] += phiV[i] * (solV_gss[j] * gradSolV_gss[k][j]); } } for (unsigned k = 0; k < dim; k++) { NSV[k] += -solP_gss * phiV_x[i * dim + k]; } for (unsigned k = 0; k < dim; k++) { aResV[k][i] += - NSV[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 } // 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 Res.resize(nDofsVP); //resize for (int i = 0; i < nDofsV; i++) { for (unsigned k = 0; k < dim; k++) { Res[ i + k * nDofsV ] = -aResV[k][i].value(); } } for (int i = 0; i < nDofsP; i++) { Res[ i + dim * nDofsV ] = -aResP[i].value(); } RES->add_vector_blocked(Res, KKDof); //Extarct and store the Jacobian if (assembleMatrix) { Jac.resize(nDofsVP * nDofsVP); // define the dependent variables for (unsigned k = 0; k < dim; k++) { s.dependent(&aResV[k][0], nDofsV); } s.dependent(&aResP[0], nDofsP); // define the independent variables 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, KKDof, KKDof); s.clear_independents(); s.clear_dependents(); } } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }
void SetLambda(MultiLevelSolution &mlSol, const unsigned &level, const FEOrder &order, Operator operatorType){ unsigned SolType; if (order<FIRST || order> SECOND){ std::cout<<"Wong Solution Order"<<std::endl; exit(0); } else if ( order == FIRST ) SolType=0; else if ( order == SERENDIPITY ) SolType=1; else if ( order == SECOND) SolType=2; clock_t GetLambdaTime=0; clock_t start_time, end_time; start_time=clock(); adept::Stack & adeptStack = FemusInit::_adeptStack; Solution *mysolution = mlSol.GetSolutionLevel(level); Mesh *mymsh = mlSol._ml_msh->GetLevel(level); elem *myel = mymsh->el; unsigned indLmbd=mlSol.GetIndex("lmbd"); const unsigned geoDim = mymsh->GetDimension(); const unsigned nablaGoeDim = (3*(geoDim-1)+!(geoDim-1)); const unsigned max_size = static_cast< unsigned > (ceil(pow(3,geoDim))); bool diffusion, elasticity; if( operatorType == DIFFUSION ){ diffusion = true; elasticity = false; } if( operatorType == ELASTICITY ){ diffusion = false; elasticity = true; } else{ cout<<"wrong operator name in SetLambda\n" <<"valid options are diffusion or elasicity\n"; abort(); } unsigned varDim=geoDim*elasticity+diffusion; // local objects vector<vector<adept::adouble> > GradSolVAR(varDim); vector<vector<adept::adouble> > NablaSolVAR(varDim); for(int ivar=0;ivar<varDim;ivar++){ GradSolVAR[ivar].resize(geoDim); NablaSolVAR[ivar].resize(nablaGoeDim); } vector <double > phi; vector <adept::adouble> gradphi; vector <adept::adouble> nablaphi; adept::adouble Weight; phi.reserve(max_size); gradphi.reserve(max_size*geoDim); nablaphi.reserve(max_size*nablaGoeDim); vector <vector < adept::adouble> > vx(geoDim); for(int ivar=0;ivar<geoDim;ivar++){ vx[ivar].reserve(max_size); } unsigned SolTypeVx=2.; vector< vector< adept::adouble > > Soli(varDim); vector< vector< adept::adouble > > aRhs(varDim); vector< vector< adept::adouble > > aLhs(varDim); for(int ivar=0;ivar<varDim;ivar++){ Soli[ivar].reserve(max_size); aRhs[ivar].reserve(max_size); aLhs[ivar].reserve(max_size); } vector < double > K; K.reserve((max_size*varDim)*(max_size*varDim)); vector < double > M; M.reserve((max_size*varDim)*(max_size*varDim)); // mesh and procs unsigned nel = mymsh->GetNumberOfElements(); unsigned iproc = mymsh->processor_id(); // *** element loop *** for(int iel=mymsh->IS_Mts2Gmt_elem_offset[iproc]; iel < mymsh->IS_Mts2Gmt_elem_offset[iproc+1]; iel++) { unsigned kel = mymsh->IS_Mts2Gmt_elem[iel]; short unsigned kelt = myel->GetElementType(kel); unsigned nve = myel->GetElementDofNumber(kel,SolType)-1; unsigned nveVx = myel->GetElementDofNumber(kel,SolTypeVx); // -------------- resize -------------- for(int ivar=0; ivar<varDim; ivar++) { Soli[ivar].resize(nve); aRhs[ivar].resize(nve); aLhs[ivar].resize(nve); } M.resize((varDim*nve)*(varDim*nve)); K.resize((varDim*nve)*(varDim*nve)); // ------------------------------------ // ------------ get coordinates ------- for(int i=0;i<geoDim;i++){ vx[i].resize(nveVx); } for (unsigned i=0;i<nveVx;i++) { unsigned inode=myel->GetMeshDof(kel,i,SolTypeVx); unsigned inodeVx_Metis=mymsh->GetMetisDof(inode,SolTypeVx); for(int j=0; j<geoDim; j++) { //coordinates vx[j][i]= (*mymsh->_coordinate->_Sol[j])(inodeVx_Metis); } } // ------------------------------------ // ------------ init ------------------ for (unsigned i=0;i<nve;i++) { for(int ivar=0; ivar<varDim; ivar++) { Soli[ivar][i] = 1.; aRhs[ivar][i] = 0.; aLhs[ivar][i] = 0.; } } // ------------------------------------ adeptStack.new_recording(); double hk=1.; for (unsigned ig=0;ig < mymsh->_finiteElement[kelt][SolType]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives in the moving frame*** mymsh->_finiteElement[kelt][SolType]->Jacobian(vx,ig,Weight,phi,gradphi,nablaphi); if(ig==0){ double referenceElementScale[6]={8., 1./6., 1., 4., 1., 2.}; double GaussWeight = mymsh->_finiteElement[kelt][SolType]->GetGaussWeight(ig); double area=referenceElementScale[kelt]*Weight.value()/GaussWeight; hk = pow(area,1./geoDim); //cout<<hk<<endl; if(0 == SolType) break; } for(int ivar=0; ivar<varDim; ivar++){ for(int jvar=0; jvar<geoDim; jvar++) { GradSolVAR[ivar][jvar]=0.; } for(int jvar=0; jvar<nablaGoeDim; jvar++) { NablaSolVAR[ivar][jvar]=0.; } for (unsigned inode=0; inode<nve; inode++) { adept::adouble soli = Soli[ivar][inode]; for(int jvar=0; jvar<geoDim; jvar++) { GradSolVAR[ivar][jvar] += gradphi[inode*geoDim+jvar]*soli; } for(int jvar=0; jvar<nablaGoeDim; jvar++) { NablaSolVAR[ivar][jvar]+=nablaphi[inode*nablaGoeDim+jvar]*soli; } } } vector < adept::adouble > divGradSol(varDim,0.); for(unsigned ivar=0; ivar<varDim; ivar++) { for(unsigned jvar=0; jvar<geoDim; jvar++) { if(diffusion){ divGradSol[ivar] += NablaSolVAR[ivar][jvar]; } else if(elasticity){ unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = geoDim; // xy else if (2 == ivar + jvar ) kvar = geoDim+2; // xz else if (3 == ivar + jvar ) kvar = geoDim+1; // yz divGradSol[ivar] += 0.5*( NablaSolVAR[ivar][jvar] + NablaSolVAR[jvar][kvar]); } } } //BEGIN local assembly for (unsigned i=0; i<nve; i++){ for(unsigned ivar=0; ivar<varDim; ivar++) { for(unsigned jvar=0; jvar<geoDim; jvar++) { aRhs[ivar][i] += gradphi[i*geoDim+jvar]*(GradSolVAR[ivar][jvar]) * Weight; if(diffusion){ aLhs[ivar][i] += divGradSol[ivar] * nablaphi[i*nablaGoeDim+jvar] * Weight; //aRhs[ivar][i] += gradphi[i*geoDim+jvar]*(GradSolVAR[ivar][jvar]) * Weight; } else if(elasticity){ unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = geoDim; // xy else if (2 == ivar + jvar ) kvar = geoDim+2; // xz else if (3 == ivar + jvar ) kvar = geoDim+1; // yz aLhs[ivar][i] += divGradSol[ivar] * 0.5 * nablaphi[i*nablaGoeDim+jvar] * Weight; aLhs[jvar][i] += divGradSol[ivar] * 0.5 * nablaphi[i*nablaGoeDim+kvar] * Weight; //aRhs[ivar][i] += 0.5*gradphi[i*geoDim+jvar]*0.5*(GradSolVAR[ivar][jvar]+GradSolVAR[jvar][ivar]) * Weight; //aRhs[jvar][i] += 0.5*gradphi[i*geoDim+ivar]*0.5*(GradSolVAR[ivar][jvar]+GradSolVAR[jvar][ivar]) * Weight; } } } } //END local assembly } cout<<hk<<endl; double lambdak = 6./(hk*hk); //if SolType is linear if( SolType == 1 || SolType == 2){ // only if solType is quadratic or biquadratic for(int ivar=0; ivar<varDim; ivar++) { adeptStack.independent(&Soli[ivar][0], nve); } //Store RHS in M for(int ivar=0; ivar<varDim; ivar++) { adeptStack.dependent(&aRhs[ivar][0], nve); } adeptStack.jacobian(&M[0]); adeptStack.clear_dependents(); //Store LHS in K for(int ivar=0; ivar<varDim; ivar++) { adeptStack.dependent(&aLhs[ivar][0], nve); } adeptStack.jacobian(&K[0]); adeptStack.clear_dependents(); adeptStack.clear_independents(); unsigned matSize = nve*varDim; int remove[6][3]={{},{},{},{0,1,2},{0,2,2},{}}; unsigned indSize = matSize;// - remove[kelt][SolType]*elasticity; // for(int i=0;i<indSize;i++){ // for(int j=0;j<indSize;j++){ // cout<<K[matSize*i+j]<<" "; // } // cout<<endl; // } // cout<<endl; // for(int i=0;i<indSize;i++){ // for(int j=0;j<indSize;j++){ // cout<<M[matSize*i+j]<<" "; // } // cout<<endl; // } // LU = M factorization for (int k = 0 ; k < indSize-1 ; k++) { for ( int i = k+1 ; i < indSize ; i++) { M[i*matSize+k] /= M[k*matSize+k]; for ( int j= k+1 ; j < indSize ; j++) { M[i*matSize+j] -= M[i*matSize+k]*M[k*matSize+j] ; } } } // Power Method for the largest eigenvalue of K x = lambda LU x : // iteration step: // y = U^(-1) L^(-1) K x // lambda= phi(y)/phi(x) // y = y / l2norm(y) // x = y vector < double > x(matSize,1.); vector < double > y(matSize); double phik = x[0]+x[1]; lambdak=1.; double error=1.; while(error>1.0e-10 && counter <= 500){ double phikm1 = phik; double lambdakm1 = lambdak; // y = K x for(int i=0; i<indSize; i++){ y[i]=0.; for(int j=0; j<indSize; j++){ y[i] += K[ i*matSize + j ] * x[j]; } } // y = L^(-1) y for(int i=0; i<indSize; i++){ for(int j=0; j<i; j++){ y[i] -= M[i*matSize + j] * y[j]; } } // x <-- y = U^(-1) y double l2norm=0.; for(int i = indSize-1; i>=0; i--){ x[i] = y[i]; for(int j = i+1; j<indSize; j++){ x[i] -= M[ i*matSize + j] * x[j]; } x[i] /= M[i*matSize+i]; l2norm += x[i]*x[i]; } l2norm = sqrt(l2norm); phik = (x[0]+x[1]); lambdak= phik / phikm1; for(int i=0;i<indSize;i++){ x[i] /= l2norm; } phik /= l2norm; error = fabs( (lambdak-lambdakm1)/lambdak ); } } cout<<lambdak*hk*hk<<std::endl; mysolution->_Sol[indLmbd]->set(iel,sqrt(lambdak)); //abort(); } //end list of elements loop mysolution->_Sol[indLmbd]->close(); // ************************************* end_time=clock(); GetLambdaTime+=(end_time-start_time); std::cout<<"GetLambda Time = "<<GetLambdaTime/CLOCKS_PER_SEC <<std::endl; //abort(); }
void ETD(MultiLevelProblem& ml_prob) { const unsigned& NLayers = NumberOfLayers; adept::Stack& s = FemusInit::_adeptStack; LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ("SW"); // pointer to the linear implicit system named "Poisson" unsigned level = ml_prob._ml_msh->GetNumberOfLevels() - 1u; 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) NumericVector* EPS = pdeSys->_EPS; // 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) unsigned nprocs = msh->n_processors(); // get the process_id (for parallel computation) //solution variable std::vector < unsigned > solIndexh(NLayers); std::vector < unsigned > solPdeIndexh(NLayers); std::vector < unsigned > solIndexv(NLayers); std::vector < unsigned > solPdeIndexv(NLayers); std::vector < unsigned > solIndexHT(NLayers); std::vector < unsigned > solPdeIndexHT(NLayers); std::vector < unsigned > solIndexT(NLayers); vector< int > l2GMap; // local to global mapping for(unsigned i = 0; i < NLayers; i++) { char name[10]; sprintf(name, "h%d", i); solIndexh[i] = mlSol->GetIndex(name); // get the position of "hi" in the sol object solPdeIndexh[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "hi" in the pdeSys object sprintf(name, "v%d", i); solIndexv[i] = mlSol->GetIndex(name); // get the position of "vi" in the sol object solPdeIndexv[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "vi" in the pdeSys object sprintf(name, "HT%d", i); solIndexHT[i] = mlSol->GetIndex(name); // get the position of "Ti" in the sol object solPdeIndexHT[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "Ti" in the pdeSys object sprintf(name, "T%d", i); solIndexT[i] = mlSol->GetIndex(name); // get the position of "Ti" in the sol object } unsigned solTypeh = mlSol->GetSolutionType(solIndexh[0]); // get the finite element type for "hi" unsigned solTypev = mlSol->GetSolutionType(solIndexv[0]); // get the finite element type for "vi" unsigned solTypeHT = mlSol->GetSolutionType(solIndexHT[0]); // get the finite element type for "Ti" vector < double > x; // local coordinates vector< vector < adept::adouble > > solh(NLayers); // local coordinates vector< vector < adept::adouble > > solv(NLayers); // local coordinates vector< vector < adept::adouble > > solHT(NLayers); // local coordinates vector< vector < double > > solT(NLayers); // local coordinates vector< vector < bool > > bdch(NLayers); // local coordinates vector< vector < bool > > bdcv(NLayers); // local coordinates vector< vector < bool > > bdcHT(NLayers); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) vector < vector< adept::adouble > > aResh(NLayers); vector < vector< adept::adouble > > aResv(NLayers); vector < vector< adept::adouble > > aResHT(NLayers); KK->zero(); RES->zero(); double maxWaveSpeed = 0.; double dx; for(unsigned k=0; k<NumberOfLayers; k++){ for(unsigned i = msh->_dofOffset[solTypeHT][iproc]; i < msh->_dofOffset[solTypeHT][iproc + 1]; i++){ double valueT = (*sol->_Sol[solIndexT[k]])(i); double valueH = (*sol->_Sol[solIndexh[k]])(i); double valueHT = valueT * valueH; sol->_Sol[solIndexHT[k]]->set(i, valueHT); } sol->_Sol[solIndexHT[k]]->close(); } for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofh = msh->GetElementDofNumber(iel, solTypeh); // number of solution element dofs unsigned nDofv = msh->GetElementDofNumber(iel, solTypev); // number of solution element dofs unsigned nDofHT = msh->GetElementDofNumber(iel, solTypeHT); // number of coordinate element dofs unsigned nDofx = msh->GetElementDofNumber(iel, xType); // number of coordinate element dofs unsigned nDofs = nDofh + nDofv + nDofHT; // resize local arrays l2GMap.resize(NLayers * (nDofs) ); for(unsigned i = 0; i < NLayers; i++) { solh[i].resize(nDofh); solv[i].resize(nDofv); solHT[i].resize(nDofHT); solT[i].resize(nDofHT); bdch[i].resize(nDofh); bdcv[i].resize(nDofv); bdcHT[i].resize(nDofHT); aResh[i].resize(nDofh); //resize std::fill(aResh[i].begin(), aResh[i].end(), 0); //set aRes to zero aResv[i].resize(nDofv); //resize std::fill(aResv[i].begin(), aResv[i].end(), 0); //set aRes to zero aResHT[i].resize(nDofHT); //resize std::fill(aResHT[i].begin(), aResHT[i].end(), 0); //set aRes to zero } x.resize(nDofx); //local storage of global mapping and solution for(unsigned i = 0; i < nDofh; i++) { unsigned solDofh = msh->GetSolutionDof(i, iel, solTypeh); // global to global mapping between solution node and solution dof for(unsigned j = 0; j < NLayers; j++) { solh[j][i] = (*sol->_Sol[solIndexh[j]])(solDofh); // global extraction and local storage for the solution bdch[j][i] = ( (*sol->_Bdc[solIndexh[j]])(solDofh) < 1.5) ? true : false; l2GMap[ j * nDofs + i] = pdeSys->GetSystemDof(solIndexh[j], solPdeIndexh[j], i, iel); // global to global mapping between solution node and pdeSys dof } } for(unsigned i = 0; i < nDofv; i++) { unsigned solDofv = msh->GetSolutionDof(i, iel, solTypev); // global to global mapping between solution node and solution dof for(unsigned j = 0; j < NLayers; j++) { solv[j][i] = (*sol->_Sol[solIndexv[j]])(solDofv); // global extraction and local storage for the solution bdcv[j][i] = ( (*sol->_Bdc[solIndexv[j]])(solDofv) < 1.5) ? true : false; l2GMap[ j * nDofs + nDofh + i] = pdeSys->GetSystemDof(solIndexv[j], solPdeIndexv[j], i, iel); // global to global mapping between solution node and pdeSys dof } } for(unsigned i = 0; i < nDofHT; i++) { unsigned solDofHT = msh->GetSolutionDof(i, iel, solTypeHT); // global to global mapping between solution node and solution dof unsigned solDofh = msh->GetSolutionDof(i, iel, solTypeh); for(unsigned j = 0; j < NLayers; j++) { solHT[j][i] = (*sol->_Sol[solIndexHT[j]])(solDofHT); // global extraction and local storage for the solution solT[j][i] = (*sol->_Sol[solIndexT[j]])(solDofHT); // global extraction and local storage for the solution bdcHT[j][i] = ( (*sol->_Bdc[solIndexHT[j]])(solDofHT) < 1.5) ? true : false; l2GMap[ j * nDofs + nDofh + nDofv + i] = pdeSys->GetSystemDof(solIndexHT[j], solPdeIndexHT[j], i, iel); // global to global mapping between solution node and pdeSys dof //std::cout << solT[j][i] << " "; } } s.new_recording(); for(unsigned i = 0; i < nDofx; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof x[i] = (*msh->_topology->_Sol[0])(xDof); // global extraction and local storage for the element coordinates } double xmid = 0.5 * (x[0] + x[1]); //std::cout << xmid << std::endl; double zz = sqrt(aa * aa - xmid * xmid); // z coordinate of points on sphere double dd = aa * acos((zz * z_c) / (aa * aa)); // distance to center point on sphere [m] double hh = 1 - dd * dd / (bb * bb); double b = ( H_shelf + H_0 / 2 * (1 + tanh(hh / phi)) ); double hTot = 0.; double beta = 0.2; std::vector < adept::adouble > P(NLayers); for(unsigned k = 0; k < NLayers; k++) { hTot += solh[k][0].value(); adept::adouble rhok = rho1[k] - beta * solT[k][0]; P[k] = - rhok * 9.81 * b; // bottom topography for( unsigned j = 0; j < NLayers; j++){ adept::adouble rhoj = (j <= k) ? (rho1[j] - beta * solT[j][0]) : rhok; P[k] += rhoj * 9.81 * solh[j][0]; } P[k] /= 1024; } std::vector < double > hALE(NLayers, 0.); hALE[0] = hRest[0] + (hTot - b); for(unsigned k = 1; k < NLayers - 1; k++){ hALE[k] = hRest[k]; } hALE[NLayers - 1] = b - hRest[NLayers - 1]; std::vector < double > w(NLayers+1, 0.); dx = x[1] - x[0]; for(unsigned k = NLayers; k>1; k--){ w[k-1] = w[k] - solh[k-1][0].value() * (solv[k-1][1].value() - solv[k-1][0].value() )/dx- ( hALE[k-1] - solh[k-1][0].value()) / dt; //std::cout << hALE[k-1] << " " << w[k-1] << " "; } //std::cout<<std::endl; std::vector < adept::adouble > zMid(NLayers); for(unsigned k = 0; k < NLayers; k++) { zMid[k] = -b + solh[k][0]/2; for(unsigned i = k+1; i < NLayers; i++) { zMid[k] += solh[i][0]; } } double celerity = sqrt( 9.81 * hTot); for(unsigned i = 0; i<NLayers; i++){ double vmid = 0.5 * ( solv[i][0].value() + solv[i][1].value() ); maxWaveSpeed = ( maxWaveSpeed > fabs(vmid) + fabs(celerity) )? maxWaveSpeed : fabs(vmid) + fabs(celerity); } for(unsigned k = 0; k < NLayers; k++) { if(!bdch[k][0]) { for (unsigned j = 0; j < nDofv; j++) { double sign = ( j == 0) ? 1. : -1; aResh[k][0] += sign * solh[k][0] * solv[k][j] / dx; } aResh[k][0] += w[k+1] - w[k]; } adept::adouble vMid = 0.5 * (solv[k][0] + solv[k][1]); adept::adouble fv = 0.5 * vMid * vMid + P[k]; for (unsigned i = 0; i < nDofv; i++) { if(!bdcv[k][i]) { double sign = ( i == 0) ? -1. : 1; aResv[k][i] += sign * fv / dx; if ( k > 0 ){ aResv[k][i] -= 0.5 * ( w[k] * 0.5 * ( solv[k-1][i] - solv[k][i] ) / (0.5 * ( solh[k-1][0] + solh[k][0] ) ) ); } if (k < NLayers - 1) { aResv[k][i] -= 0.5 * ( w[k+1] * 0.5 * ( solv[k][i] - solv[k+1][i] ) / (0.5 * ( solh[k][0] + solh[k+1][0] ) ) ); } //aResv[k][i] += sign * 9.81 * rho1[k] / 1024. * zMid[k] / dx; } } if(!bdcHT[k][0]) { for (unsigned j = 0; j < nDofv; j++) { double sign = ( j == 0) ? 1. : -1; aResHT[k][0] += sign * solv[k][j] * solHT[k][0] / dx; } if(k<NLayers-1){ aResHT[k][0] += w[k+1] * 0.5 * (solHT[k][0]/solh[k][0] + solHT[k+1][0]/solh[k+1][0]); //aResHT[k][0] += w[k+1] * 0.5 * (solT[k][0] + solT[k+1][0]); } if( k > 0){ aResHT[k][0] -= w[k] * 0.5 * (solHT[k-1][0]/solh[k-1][0] + solHT[k][0]/solh[k][0] ); //aResHT[k][0] -= w[k] * 0.5 * (solT[k-1][0] + solT[k][0]); } } } vector< double > Res(NLayers * nDofs); // local redidual vector unsigned counter = 0; for(unsigned k = 0; k < NLayers; k++) { for(int i = 0; i < nDofh; i++) { Res[counter] = aResh[k][i].value(); counter++; } for(int i = 0; i < nDofv; i++) { Res[counter] = aResv[k][i].value(); counter++; } for(int i = 0; i < nDofHT; i++) { Res[counter] = aResHT[k][i].value(); counter++; } } RES->add_vector_blocked(Res, l2GMap); for(unsigned k = 0; k < NLayers; k++) { // define the dependent variables s.dependent(&aResh[k][0], nDofh); s.dependent(&aResv[k][0], nDofv); s.dependent(&aResHT[k][0], nDofHT); // define the independent variables s.independent(&solh[k][0], nDofh); s.independent(&solv[k][0], nDofv); s.independent(&solHT[k][0], nDofHT); } // get the jacobian matrix (ordered by row major ) vector < double > Jac(NLayers * nDofs * NLayers * nDofs); s.jacobian(&Jac[0], true); //store K in the global matrix KK KK->add_matrix_blocked(Jac, l2GMap, l2GMap); s.clear_independents(); s.clear_dependents(); } RES->close(); KK->close(); // PetscViewer viewer; // PetscViewerDrawOpen(PETSC_COMM_WORLD,NULL,NULL,0,0,900,900,&viewer); // PetscObjectSetName((PetscObject)viewer,"FSI matrix"); // PetscViewerPushFormat(viewer,PETSC_VIEWER_DRAW_LG); // MatView((static_cast<PetscMatrix*>(KK))->mat(),viewer); // double a; // std::cin>>a; // // abort(); MFN mfn; Mat A = (static_cast<PetscMatrix*>(KK))->mat(); FN f, f1, f2, f3 , f4; std::cout << "dt = " << dt << " dx = "<< dx << " maxWaveSpeed = "<<maxWaveSpeed << std::endl; //dt = 100.; Vec v = (static_cast< PetscVector* >(RES))->vec(); Vec y = (static_cast< PetscVector* >(EPS))->vec(); MFNCreate( PETSC_COMM_WORLD, &mfn ); MFNSetOperator( mfn, A ); MFNGetFN( mfn, &f ); // FNCreate(PETSC_COMM_WORLD, &f1); // FNCreate(PETSC_COMM_WORLD, &f2); // FNCreate(PETSC_COMM_WORLD, &f3); // FNCreate(PETSC_COMM_WORLD, &f4); // // FNSetType(f1, FNEXP); // // FNSetType(f2, FNRATIONAL); // double coeff1[1] = { -1}; // FNRationalSetNumerator(f2, 1, coeff1); // FNRationalSetDenominator(f2, 0, PETSC_NULL); // // FNSetType( f3, FNCOMBINE ); // // FNCombineSetChildren(f3, FN_COMBINE_ADD, f1, f2); // // FNSetType(f4, FNRATIONAL); // double coeff2[2] = {1., 0.}; // FNRationalSetNumerator(f4, 2, coeff2); // FNRationalSetDenominator(f4, 0, PETSC_NULL); // // FNSetType( f, FNCOMBINE ); // // FNCombineSetChildren(f, FN_COMBINE_DIVIDE, f3, f4); FNPhiSetIndex(f,1); FNSetType( f, FNPHI ); // FNView(f,PETSC_VIEWER_STDOUT_WORLD); FNSetScale( f, dt, dt); MFNSetFromOptions( mfn ); MFNSolve( mfn, v, y); MFNDestroy( &mfn ); // FNDestroy(&f1); // FNDestroy(&f2); // FNDestroy(&f3); // FNDestroy(&f4); sol->UpdateSol(mlPdeSys->GetSolPdeIndex(), EPS, pdeSys->KKoffset); unsigned solIndexeta = mlSol->GetIndex("eta"); unsigned solIndexb = mlSol->GetIndex("b"); sol->_Sol[solIndexeta]->zero(); for(unsigned k=0;k<NumberOfLayers;k++){ sol->_Sol[solIndexeta]->add(*sol->_Sol[solIndexh[k]]); } sol->_Sol[solIndexeta]->add(-1,*sol->_Sol[solIndexb]); for(unsigned k=0; k<NumberOfLayers; k++){ for(unsigned i = msh->_dofOffset[solTypeHT][iproc]; i < msh->_dofOffset[solTypeHT][iproc + 1]; i++){ double valueHT = (*sol->_Sol[solIndexHT[k]])(i); double valueH = (*sol->_Sol[solIndexh[k]])(i); double valueT = valueHT/valueH; sol->_Sol[solIndexT[k]]->set(i, valueT); } sol->_Sol[solIndexT[k]]->close(); } }
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 vector < adept::adouble > solU; // local solution vector< adept::adouble > aResU; // local redidual vector unsigned solVIndex; solVIndex = mlSol->GetIndex ("V"); unsigned solVType = mlSol->GetSolutionType (solVIndex); unsigned solVPdeIndex; solVPdeIndex = mlPdeSys->GetSolPdeIndex ("V"); vector < adept::adouble > solV; // local solution vector< adept::adouble > aResV; // 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); solV.reserve (maxSize); aResV.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); 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 weight; // gauss point weight vector< int > sysDof; // local to global pdeSys dofs sysDof.reserve (2 * maxSize); vector< double > Res; // local residual vector Res.reserve (2 * maxSize); vector < double > Jac; Jac.reserve (4 * 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++) { short unsigned ielGeom = msh->GetElementType (iel); // element geometry type unsigned nDofsU = msh->GetElementDofNumber (iel, solUType); // number of solution element dofs unsigned nDofsV = msh->GetElementDofNumber (iel, solVType); unsigned nDofsX = msh->GetElementDofNumber (iel, crdXType); // number of solution element dofs // resize local arrays sysDof.resize (nDofsU + nDofsV); solU.resize (nDofsU); solV.resize (nDofsV); for (unsigned k = 0; k < dim; k++) { crdX[k].resize (nDofsX); } aResU.assign (nDofsU, 0); aResV.assign (nDofsV, 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 } for (unsigned i = 0; i < nDofsV; i++) { unsigned solVDof = msh->GetSolutionDof (i, iel, solVType); solV[i] = (*sol->_Sol[solVIndex]) (solVDof); sysDof[i + nDofsU] = pdeSys->GetSystemDof (solVIndex, solVPdeIndex, i, iel); } // 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[ielGeom][solUType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][solUType]->Jacobian (crdX, ig, weight, phi, phi_x, phi_xx); msh->_finiteElement[ielGeom][solVType]->Jacobian (crdX, ig, weight, phiV, phiV_x, phiV_xx); adept::adouble solUig = 0; // solution U in the gauss point vector < adept::adouble > gradSolUig (dim, 0.); // gradient 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]; } } adept::adouble solVig = 0; // solution V in the gauss point vector < adept::adouble > gradSolVig (dim, 0.); // gradient of solution U in the gauss point for (unsigned i = 0; i < nDofsV; i++) { solVig += phiV[i] * solV[i]; for (unsigned j = 0; j < dim; j++) { gradSolVig[j] += phiV_x[i * dim + j] * solV[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 for (unsigned i = 0; i < nDofsV; i++) { adept::adouble LaplaceV = 0.; for (unsigned j = 0; j < dim; j++) { LaplaceV -= nu * phiV_x[i * dim + j] * gradSolVig[j]; } aResV[i] += (phiV[i] * solUig - LaplaceV) * weight; } // end phiV_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 Res.resize (nDofsU + nDofsV); //resize for (int i = 0; i < nDofsU; i++) { Res[i] = -aResU[i].value(); } for (int i = 0; i < nDofsV; i++) { Res[i + nDofsU] = -aResV[i].value(); } RES->add_vector_blocked (Res, sysDof); //Extarct and store the Jacobian Jac.resize ( (nDofsU + nDofsV) * (nDofsU + nDofsV)); // define the dependent variables s.dependent (&aResU[0], nDofsU); s.dependent (&aResV[0], nDofsV); // define the independent variables s.independent (&solU[0], nDofsU); s.independent (&solV[0], nDofsV); // 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 ******************* }
void GetL2Norm ( MultiLevelProblem& ml_prob, MultiLevelProblem& ml_prob2 ) { LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ( "NonLocal" ); const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel ( level ); elem* el = msh->el; MultiLevelSolution* mlSol = ml_prob._ml_sol; Solution* sol = ml_prob._ml_sol->GetSolutionLevel ( level ); LinearImplicitSystem* mlPdeSys2 = &ml_prob2.get_system<LinearImplicitSystem> ( "Local" ); MultiLevelSolution* mlSol2 = ml_prob2._ml_sol; Solution* sol2 = ml_prob2._ml_sol->GetSolutionLevel ( level ); const unsigned dim = msh->GetDimension(); unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) double error_solExact_norm2 = 0.; double error_solExact_local_norm2 = 0.; double error_solLocal_norm2 = 0.; double solNonlocal_norm2 = 0.; double solLocal_norm2 = 0.; double sol_exact_norm2 = 0.; unsigned soluIndex; soluIndex = mlSol->GetIndex ( "u" ); unsigned soluType = mlSol->GetSolutionType ( soluIndex ); unsigned soluIndexLocal; soluIndexLocal = mlSol2->GetIndex ( "u_local" ); unsigned iproc = msh->processor_id(); unsigned nprocs = msh->n_processors(); for ( int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++ ) { short unsigned ielGeom = msh->GetElementType ( iel ); unsigned nDofu = msh->GetElementDofNumber ( iel, soluType ); unsigned nDofx = msh->GetElementDofNumber ( iel, xType ); vector < vector < double > > x1 ( dim ); for ( int i = 0; i < dim; i++ ) { x1[i].resize ( nDofx ); } vector < double > soluNonLoc ( nDofu ); vector < double > soluLoc ( nDofu ); for ( unsigned i = 0; i < nDofu; i++ ) { unsigned solDof = msh->GetSolutionDof ( i, iel, soluType ); soluNonLoc[i] = ( *sol->_Sol[soluIndex] ) ( solDof ); soluLoc[i] = ( *sol2->_Sol[soluIndexLocal] ) ( solDof ); } for ( unsigned i = 0; i < nDofx; i++ ) { unsigned xDof = msh->GetSolutionDof ( i, iel, xType ); for ( unsigned jdim = 0; jdim < dim; jdim++ ) { x1[jdim][i] = ( *msh->_topology->_Sol[jdim] ) ( xDof ); } } vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives double weight; // gauss point weight // *** Gauss point loop *** for ( unsigned ig = 0; ig < msh->_finiteElement[ielGeom][soluType]->GetGaussPointNumber(); ig++ ) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][soluType]->Jacobian ( x1, ig, weight, phi, phi_x ); double soluNonLoc_gss = 0.; double soluLoc_gss = 0.; double exactSol_gss_x = 0.; double exactSol_gss_y = 0.; for ( unsigned i = 0; i < nDofu; i++ ) { soluNonLoc_gss += phi[i] * soluNonLoc[i]; soluLoc_gss += phi[i] * soluLoc[i]; exactSol_gss_x += phi[i] * x1[0][i]; // this is x at the Gauss point // exactSol_gss_y += phi[i] * x1[1][i]; // this is y at the Gauss point } exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x + 0.1 * exactSol_gss_x * exactSol_gss_x; // this is x^4 + delta * x^2 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x; // this is x^2 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x; // this is x^3 // exactSol_gss_y = exactSol_gss_y * exactSol_gss_y * exactSol_gss_y; // this is y^3 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x; // this is x^4 // exactSol_gss_x = 2 * exactSol_gss_x + exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x ; // this is 2x + x^5 error_solExact_norm2 += ( soluNonLoc_gss - exactSol_gss_x ) * ( soluNonLoc_gss - exactSol_gss_x ) * weight; // error_solExact_norm2 += (soluNonLoc_gss - (exactSol_gss_x + exactSol_gss_y)) * (soluNonLoc_gss - (exactSol_gss_x + exactSol_gss_y)) * weight; //error L2 norm of x^3 + y^3 error_solExact_local_norm2 += ( soluLoc_gss - exactSol_gss_x ) * ( soluLoc_gss - exactSol_gss_x ) * weight; error_solLocal_norm2 += ( soluNonLoc_gss - soluLoc_gss ) * ( soluNonLoc_gss - soluLoc_gss ) * weight; solNonlocal_norm2 += soluNonLoc_gss * soluNonLoc_gss * weight; solLocal_norm2 += soluLoc_gss * soluLoc_gss * weight; // sol_exact_norm2 += (exactSol_gss_x + exactSol_gss_y) * (exactSol_gss_x + exactSol_gss_y) * weight; //L2 norm of x^3 + y^3 sol_exact_norm2 += exactSol_gss_x * exactSol_gss_x * weight; } } double norm2 = 0.; MPI_Allreduce ( &error_solExact_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); double norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Nonlocal - exact = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &error_solExact_local_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Local - exact = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &error_solLocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Nonlocal - local = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &solNonlocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of NONLOCAL soln = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &solLocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of LOCAL soln = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &sol_exact_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of EXACT soln = " << norm << std::endl; double littleL2norm = 0.; std::vector<double> littleLInfinitynorm ( nprocs, 0. ); for ( unsigned i = msh->_dofOffset[soluType][iproc]; i < msh->_dofOffset[soluType][iproc + 1]; i++ ) { double nonLocalNodalValue = ( *sol->_Sol[soluIndex] ) ( i ); double LocalNodalValue = ( *sol2->_Sol[soluIndexLocal] ) ( i ); double difference = fabs ( nonLocalNodalValue - LocalNodalValue ); if ( difference > littleLInfinitynorm[iproc] ) littleLInfinitynorm[iproc] = difference; littleL2norm += difference * difference; } norm2 = 0.; MPI_Allreduce ( &littleL2norm, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "l2 norm of ERROR: Nonlocal - local = " << norm << std::endl; for ( int kproc = 0; kproc < nprocs; kproc++ ) { MPI_Bcast ( &littleLInfinitynorm[iproc], 1, MPI_DOUBLE, kproc, MPI_COMM_WORLD ); } double littleLInfinityNorm = littleLInfinitynorm[0]; for ( unsigned kproc = 0; kproc < nprocs; kproc++ ) { if ( littleLInfinitynorm[kproc] > littleLInfinityNorm ) littleLInfinityNorm = littleLInfinitynorm[kproc]; } std::cout.precision ( 14 ); std::cout << "linfinity norm of ERROR: Nonlocal - local = " << littleLInfinityNorm << std::endl; }
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 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 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 < double > solT; // local solution 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) solT.reserve(maxSize); 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); 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 //BEGIN element loop for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { //BEGIN local dof number extraction unsigned nDofsT = msh->GetElementDofNumber(iel, solTType); //temperature unsigned nDofsV = msh->GetElementDofNumber(iel, solVType); //velocity unsigned nDofsP = msh->GetElementDofNumber(iel, solPType); //pressure unsigned nDofsX = msh->GetElementDofNumber(iel, coordXType); // coordinates unsigned nDofsTVP = nDofsT + dim * nDofsV + nDofsP; // all solutions //END local dof number extraction //BEGIN memory allocation Res.resize(nDofsTVP); std::fill(Res.begin(), Res.end(), 0); Jac.resize(nDofsTVP * nDofsTVP); std::fill(Jac.begin(), Jac.end(), 0); sysDof.resize(nDofsTVP); solT.resize(nDofsV); for(unsigned k = 0; k < dim; k++) { solV[k].resize(nDofsV); coordX[k].resize(nDofsX); } solP.resize(nDofsP); //END memory allocation //BEGIN global to local extraction for(unsigned i = 0; i < nDofsT; i++) { //temperature unsigned solTDof = msh->GetSolutionDof(i, iel, solTType); //local to global solution dof solT[i] = (*sol->_Sol[solTIndex])(solTDof); //global to local solution value sysDof[i] = pdeSys->GetSystemDof(solTIndex, solTPdeIndex, i, iel); //local to global system dof } 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 + nDofsT + 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 + nDofsT + 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][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 double solT_gss = 0; vector < double > gradSolT_gss(dim, 0.); for(unsigned i = 0; i < nDofsT; i++) { solT_gss += phiT[i] * solT[i]; for(unsigned j = 0; j < dim; j++) { gradSolT_gss[j] += phiT_x[i * dim + j] * solT[i]; } } 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]; } double alpha = 1.; double beta = 1.;//40000.; double Pr = Prandtl; double Ra = Rayleigh; //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 = nDofsT + k * nDofsV + i; for(unsigned l = 0; l < dim; l++) { Res[irow] += -sqrt(Pr / Ra) * 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(k == 1) { Res[irow] += beta * solT_gss * phiV[i] * weight; } if(assembleMatrix) { unsigned irowMat = nDofsTVP * irow; for(unsigned l = 0; l < dim; l++) { for(unsigned j = 0; j < nDofsV; j++) { unsigned jcol1 = (nDofsT + k * nDofsV + j); unsigned jcol2 = (nDofsT + l * nDofsV + j); Jac[ irowMat + jcol1] += sqrt(Pr / Ra) * phiV_x[i * dim + l] * phiV_x[j * dim + l] * weight; Jac[ irowMat + jcol2] += sqrt(Pr / Ra) * 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 = (nDofsT + dim * nDofsV) + j; Jac[ irowMat + jcol] += - phiV_x[i * dim + k] * phiP[j] * weight; } if(k == 1) { for(unsigned j = 0; j < nDofsT; j++) { Jac[ irowMat + j ] += -beta * phiV[i] * phiT[j] * weight; } } } } } //END phiV_i loop //BEGIN phiP_i loop: mass balance for(unsigned i = 0; i < nDofsP; i++) { unsigned irow = nDofsT + dim * nDofsV + i; for(int k = 0; k < dim; k++) { Res[irow] += (gradSolV_gss[k][k]) * phiP[i] * weight; if(assembleMatrix) { unsigned irowMat = nDofsTVP * irow; for(unsigned j = 0; j < nDofsV; j++) { unsigned jcol = (nDofsT + k * nDofsV + j); Jac[ irowMat + jcol ] += - phiP[i] * phiV_x[j * dim + k] * weight; } } } } //END phiP_i loop } //END Gauss point loop //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 AssembleWillmoreFlow_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 TransientNonlinearImplicitSystem* mlPdeSys = &ml_prob.get_system<TransientNonlinearImplicitSystem> ("Willmore"); // 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 iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned solRIndex[3]; solRIndex[0] = mlSol->GetIndex("X"); // get the position of "X" in the ml_sol object solRIndex[1] = mlSol->GetIndex("Y"); // get the position of "Y" in the ml_sol object solRIndex[2] = mlSol->GetIndex("Z"); // get the position of "Z" in the ml_sol object unsigned solRType[3]; solRType[0] = mlSol->GetSolutionType(solRIndex[0]); // get the finite element type for "R" solRType[1] = mlSol->GetSolutionType(solRIndex[1]); // get the finite element type for "R" solRType[2] = mlSol->GetSolutionType(solRIndex[2]); // get the finite element type for "R" unsigned solRPdeIndex[3]; solRPdeIndex[0] = mlPdeSys->GetSolPdeIndex("X"); // get the position of "X" in the pdeSys object solRPdeIndex[1] = mlPdeSys->GetSolPdeIndex("Y"); // get the position of "Y" in the pdeSys object solRPdeIndex[2] = mlPdeSys->GetSolPdeIndex("Z"); // get the position of "Z" in the pdeSys object vector < adept::adouble > solR[3]; // local solution vector < double > solR_old[3]; unsigned solHIndex; solHIndex = mlSol->GetIndex("H"); // get the position of "H" in the ml_sol object unsigned solHType = mlSol->GetSolutionType(solHIndex); // get the finite element type for "H" unsigned solHPdeIndex; solHPdeIndex = mlPdeSys->GetSolPdeIndex("H"); // get the position of "H" in the pdeSys object vector < adept::adouble > solH; // 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 > sysDof; // 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 > aResR[3]; // local redidual vector vector< adept::adouble > aResH; // 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 for (int i = 0; i < 3; i++) { solR[i].reserve(maxSize); solR_old[i].reserve(maxSize); } solH.reserve(maxSize); for (unsigned i = 0; i < dim; i++) x[i].reserve(maxSize); sysDof.reserve(4 * 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(4 * maxSize); for (int i = 0; i < 3; i++) { aResR[i].reserve(maxSize); } aResH.reserve(maxSize); vector < double > Jac; // local Jacobian matrix (ordered by column, adept) Jac.reserve(4 * maxSize * 4 * 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++) { short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofs = msh->GetElementDofNumber(iel, solHType); // number of solution element dofs unsigned nDofs2 = msh->GetElementDofNumber(iel, xType); // number of coordinate element dofs // resize local arrays sysDof.resize(4 * nDofs); for (int i = 0; i < 3; i++) { solR[i].resize(nDofs); solR_old[i].resize(nDofs); } solH.resize(nDofs); for (int i = 0; i < dim; i++) { x[i].resize(nDofs2); } Res.resize(4 * nDofs); //resize for (int i = 0; i < 3; i++) { aResR[i].resize(nDofs); //resize } aResH.resize(nDofs); //resize for (int i = 0; i < 3; i++) { std::fill(aResR[i].begin(), aResR[i].end(), 0); //set aRes to zero } std::fill(aResH.begin(), aResH.end(), 0); //set aRes to zero // local storage of global mapping and solution for (unsigned i = 0; i < nDofs; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, solHType); // global to global mapping between solution node and solution dof for (int k = 0; k < 3; k++) { solR[k][i] = (*sol->_Sol[solRIndex[k]])(solDof); // global extraction and local storage for the solution solR_old[k][i] = (*sol->_SolOld[solRIndex[k]])(solDof); // global extraction and local storage for the solution } solH[i] = (*sol->_Sol[solHIndex])(solDof); // global extraction and local storage for the solution for (int k = 0; k < 3; k++) { sysDof[k * nDofs + i] = pdeSys->GetSystemDof(solRIndex[k], solRPdeIndex[k], i, iel); // global to global mapping between solution node and pdeSys dof } sysDof[3 * nDofs + i] = pdeSys->GetSystemDof(solHIndex, solHPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofs2; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned idim = 0; idim < dim; idim++) { x[idim][i] = (*msh->_topology->_Sol[idim])(xDof); // global extraction and local storage for the element coordinates } } // 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[ielGeom][solHType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][solHType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point adept::adouble solRGauss[3]; double solRGaussOld[3]; adept::adouble solRGauss_x[3][2]; adept::adouble solRGauss_xx[3][2][2]; adept::adouble sol_x[2]; sol_x[0] = sol_x[1] = 0.; for (int k = 0; k < 3; k++) { solRGauss[k] = 0.; solRGaussOld[k] = 0.; for (int i = 0; i < dim; i++) { solRGauss_x[k][i] = 0.; for (int j = 0; j < dim; j++) { solRGauss_xx[k][i][j] = 0.; } } } adept::adouble solHGauss = 0; adept::adouble solHGauss_x[2] = {0., 0.}; for (unsigned i = 0; i < nDofs; i++) { for (int k = 0; k < 3; k++) { solRGauss[k] += phi[i] * solR[k][i]; solRGaussOld[k] += phi[i] * solR_old[k][i]; } solHGauss += phi[i] * solH[i]; for (unsigned u = 0; u < dim; u++) { sol_x[u] += phi[i] * x[u][i]; } for (unsigned u = 0; u < dim; u++) { // gradient for (int k = 0; k < 3; k++) { solRGauss_x[k][u] += phi_x[i * dim + u] * solR[k][i]; } solHGauss_x[u] += phi_x[i * dim + u] * solH[i]; } for (unsigned u = 0; u < dim; u++) { // hessian for (unsigned v = 0; v < dim; v++) { unsigned uvindex = 0; //_uu if (u != v) uvindex = 2; //_uv or _vu else if (u == 1) uvindex = 1; //_vv for (int k = 0; k < 3; k++) { solRGauss_xx[k][u][v] += phi_xx[i * dim2 + uvindex] * solR[k][i]; } } } } adept::adouble g[2][2]; g[0][0] = g[0][1] = g[1][0] = g[1][1] = 0.; for (int k = 0; k < 3; k++) { for (int u = 0; u < dim; u++) { for (int v = 0; v < dim; v++) { g[u][v] += solRGauss_x[k][u] * solRGauss_x[k][v]; } } } adept::adouble detg = g[0][0] * g[1][1] - g[0][1] * g[1][0]; adept::adouble A = sqrt(detg); adept::adouble gI[2][2]; gI[0][0] = g[1][1] / detg; gI[0][1] = -g[0][1] / detg; gI[1][0] = -g[1][0] / detg; gI[1][1] = g[0][0] / detg; adept::adouble N[3]; N[0] = (solRGauss_x[1][0] * solRGauss_x[2][1] - solRGauss_x[1][1] * solRGauss_x[2][0]) / A; N[1] = (solRGauss_x[2][0] * solRGauss_x[0][1] - solRGauss_x[2][1] * solRGauss_x[0][0]) / A; N[2] = (solRGauss_x[0][0] * solRGauss_x[1][1] - solRGauss_x[0][1] * solRGauss_x[1][0]) / A; adept::adouble h[2][2]; h[0][0] = h[0][1] = h[1][0] = h[1][1] = 0.; for (int k = 0; k < 3; k++) { for (int u = 0; u < dim; u++) { for (int v = 0; v < dim; v++) { h[u][v] += solRGauss_xx[k][u][v] * N[k]; } } } //adept::adouble K = cos(sol_x[0])/(a+cos(sol_x[0]));//(h[0][0]*h[1][1]-h[0][1]*h[1][0])/detg; adept::adouble K = (h[0][0] * h[1][1] - h[0][1] * h[1][0]) / detg; adept::adouble H_exact = 0.5 * (1. + cos(sol_x[0]) / (a + cos(sol_x[0]))); // *** phi_i loop *** for (unsigned i = 0; i < nDofs; i++) { for (int k = 0; k < 3; k++) { for (int u = 0; u < dim; u++) { adept::adouble AgIgradRgradPhi = 0; for (int v = 0; v < dim; v++) { AgIgradRgradPhi += A * gI[u][v].value() * solRGauss_x[k][v]; } aResR[k][i] += AgIgradRgradPhi * phi_x[i * dim + u] * weight; } aResR[k][i] += 2.* A * solHGauss.value() * N[k] * phi[i] * weight; } for (int u = 0; u < dim; u++) { adept::adouble AgIgradHgradPhi = 0; for (int v = 0; v < dim; v++) { AgIgradHgradPhi += A * gI[u][v].value() * solHGauss_x[v]; } aResH[i] -= AgIgradHgradPhi * phi_x[i * dim + u] * weight; } aResH[i] += A * (-0 * (solRGauss[0] - solRGaussOld[0]) * N[0].value() - 0 * (solRGauss[1] - solRGaussOld[1]) * N[1].value() - 0 * (solRGauss[2] - solRGaussOld[2]) * N[2].value() + 2. * solHGauss * (solHGauss * solHGauss - K.value())) * phi[i] * weight; } // end phi_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 for (int i = 0; i < nDofs; i++) { for (int k = 0; k < 3; k++) { Res[ k * nDofs + i] = -aResR[k][i].value(); } Res[ 3 * nDofs + i] = -aResH[i].value(); } RES->add_vector_blocked(Res, sysDof); Jac.resize((4 * nDofs) * (4 * nDofs)); // define the dependent variables for (int k = 0; k < 3; k++) { s.dependent(&aResR[k][0], nDofs); } s.dependent(&aResH[0], nDofs); // define the independent variables for (int k = 0; k < 3; k++) { s.independent(&solR[k][0], nDofs); } s.independent(&solH[0], nDofs); // get the jacobian matrix (ordered by row) 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 ******************* }
/** * This function assemble the stiffnes matrix KK and the residual vector Res * Using automatic differentiation for Newton iterative scheme * J(u0) w = - F(u0) , * with u = u0 + w * - F = f(x) - J u = Res * J = \grad_u F * * thus * J w = f(x) - J u0 **/ void AssemblePoissonProblem_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 LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ("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) const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 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 solu.reserve(maxSize); vector < vector < double > > x(dim); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) for (unsigned i = 0; i < dim; i++) { x[i].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 double weight; // gauss point weight phi.reserve(maxSize); phi_x.reserve(maxSize * dim); phi_xx.reserve(maxSize * dim2); vector< adept::adouble > aRes; // local redidual vector aRes.reserve(maxSize); vector< int > l2GMap; // local to global mapping l2GMap.reserve(maxSize); vector< double > Res; // local redidual vector Res.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++) { short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofu = msh->GetElementDofNumber(iel, soluType); // number of solution element dofs unsigned nDofx = msh->GetElementDofNumber(iel, xType); // number of coordinate element dofs // resize local arrays l2GMap.resize(nDofu); solu.resize(nDofu); for (int i = 0; i < dim; i++) { x[i].resize(nDofx); } aRes.resize(nDofu); //resize std::fill(aRes.begin(), aRes.end(), 0); //set aRes to zero // local storage of global mapping and solution for (unsigned i = 0; i < nDofu; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, 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 l2GMap[i] = pdeSys->GetSystemDof(soluIndex, soluPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofx; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } // 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[ielGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][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 solu_gss = 0; vector < adept::adouble > gradSolu_gss(dim, 0.); vector < double > x_gss(dim, 0.); for (unsigned i = 0; i < nDofu; i++) { solu_gss += phi[i] * solu[i]; for (unsigned jdim = 0; jdim < dim; jdim++) { gradSolu_gss[jdim] += phi_x[i * dim + jdim] * solu[i]; x_gss[jdim] += x[jdim][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nDofu; i++) { adept::adouble laplace = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { laplace += phi_x[i * dim + jdim] * gradSolu_gss[jdim]; } double srcTerm = - GetExactSolutionLaplace(x_gss); aRes[i] += (srcTerm * phi[i] - laplace) * weight; } // end phi_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 Res.resize(nDofu); //resize for (int i = 0; i < nDofu; i++) { Res[i] = - aRes[i].value(); } RES->add_vector_blocked(Res, l2GMap); // define the dependent variables s.dependent(&aRes[0], nDofu); // define the independent variables s.independent(&solu[0], nDofu); // get the jacobian matrix (ordered by row major ) Jac.resize(nDofu * nDofu); //resize s.jacobian(&Jac[0], true); //store K in the global matrix KK KK->add_matrix_blocked(Jac, l2GMap, l2GMap); s.clear_independents(); s.clear_dependents(); } //end element loop for each process RES->close(); KK->close(); // ***************** END ASSEMBLY ******************* }
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 = 0.71; double Ra = 340000; 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 ******************* }
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; 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(); // extract pointers to the several objects that we are going to use 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]; } } double c=.1; double Id[2][2]={{1.,0.},{0.,1.}}; adept::adouble A2 = 1.; vector < vector < adept::adouble> > B(dim); for(unsigned jdim=0; jdim<dim; jdim++){ B[jdim].resize(dim); A2 += soluGauss_x[jdim]*soluGauss_x[jdim]; } adept::adouble A = sqrt(A2); for(unsigned jdim=0; jdim<dim; jdim++){ for(unsigned kdim=0; kdim<dim; kdim++){ B[jdim][kdim]= Id[jdim][kdim] - (soluGauss_x[jdim] * soluGauss_x[kdim]) / A2; } } // *** phi_i loop *** for(unsigned i=0; i<nDofs; i++) { adept::adouble nonLinearLaplaceU = 0.; adept::adouble nonLinearLaplaceV = 0.; for(unsigned jdim=0; jdim<dim; jdim++) { nonLinearLaplaceU += - 1. / A * soluGauss_x[jdim] * phi_x[i*dim+jdim]; nonLinearLaplaceV += 1. / A * ( - ( B[jdim][0] * solvGauss_x[0] + B[jdim][1] * solvGauss_x[1] ) * phi_x[i*dim+jdim] + ( solvGauss*solvGauss/A2 + c ) * soluGauss_x[jdim] * phi_x[i*dim+jdim] ); } aResu[i]+= ( 2.*solvGauss/A * phi[i] - nonLinearLaplaceU ) * weight; aResv[i]+= nonLinearLaplaceV * 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 AssembleNonlinearProblem(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 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(); 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 < double > solu; // 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< double > J; // local Jacobian matrix // 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); for (unsigned i = 0; i < dim; i++) x[i].reserve(maxSize); KKDof.reserve(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(maxSize); J.reserve(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(nDofs); solu.resize(nDofs); for (int i = 0; i < dim; i++) { x[i].resize(nDofs2); } Res.resize(nDofs); //resize std::fill(Res.begin(), Res.end(), 0); //set Res to zero if (assembleMatrix) { J.resize(nDofs * nDofs); //resize std::fill(J.begin(), J.end(), 0); //set K to zero } // 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 KKDof[i] = pdeSys->GetKKDof(soluIndex, soluPdeIndex, 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) // *** 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 double soluGauss = 0; vector < double > soluGauss_x(dim, 0.); vector < double > xGauss(dim, 0.); for (unsigned i = 0; i < nDofs; i++) { soluGauss += phi[i] * solu[i]; for (unsigned jdim = 0; jdim < dim; jdim++) { soluGauss_x[jdim] += phi_x[i * dim + jdim] * solu[i]; xGauss[jdim] += x[jdim][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nDofs; i++) { double nonLinearTerm = 0.; double mLaplace = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { mLaplace += phi_x[i * dim + jdim] * soluGauss_x[jdim]; nonLinearTerm += soluGauss * soluGauss_x[jdim] * phi[i]; } double exactSolValue = GetExactSolutionValue(xGauss); vector < double > exactSolGrad(dim); GetExactSolutionGradient(xGauss , exactSolGrad); double exactSolLaplace = GetExactSolutionLaplace(xGauss); double f = (- exactSolLaplace + exactSolValue * (exactSolGrad[0] + exactSolGrad[1])) * phi[i] ; Res[i] += (f - (mLaplace + nonLinearTerm)) * weight; if (assembleMatrix) { // *** phi_j loop *** for (unsigned j = 0; j < nDofs; j++) { mLaplace = 0.; nonLinearTerm = 0.; for (unsigned kdim = 0; kdim < dim; kdim++) { mLaplace += (phi_x[i * dim + kdim] * phi_x[j * dim + kdim]); nonLinearTerm += phi[i] * (phi[j] * soluGauss_x[kdim] + soluGauss * phi_x[j * dim + kdim]); } J[i * nDofs + j] += (mLaplace + nonLinearTerm) * weight; } // end phi_j loop } // endif assemble_matrix } // 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 RES->add_vector_blocked(Res, KKDof); if (assembleMatrix) KK->add_matrix_blocked(J, KKDof, KKDof); } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }
double GetRelativeError(MultiLevelSolution& ml_sol, const bool& H1) { int iproc, nprocs; MPI_Comm_rank(MPI_COMM_WORLD, &iproc); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); NumericVector* error_vec; NumericVector* solution_vec; error_vec = NumericVector::build().release(); solution_vec = NumericVector::build().release(); if (nprocs == 1) { error_vec->init(nprocs, 1, false, SERIAL); solution_vec->init(nprocs, 1, false, SERIAL); } else { error_vec->init(nprocs, 1, false, PARALLEL); solution_vec->init(nprocs, 1, false, PARALLEL); } error_vec->zero(); solution_vec->zero(); unsigned gridn = ml_sol._mlMesh->GetNumberOfLevels(); for (int ilevel = gridn - 1; ilevel < gridn; ilevel++) { Solution* solution = ml_sol.GetSolutionLevel(ilevel); Mesh* msh = ml_sol._mlMesh->GetLevel(ilevel); unsigned iproc = msh->processor_id(); const unsigned dim = msh->GetDimension(); vector< vector < double> > coordinates(dim); vector< int > metis_node; vector <double> phi; vector <double> gradphi; vector <double> nablaphi; double weight; // reserve const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim))); metis_node.reserve(max_size); for (int i = 0; i < dim; i++) coordinates[i].reserve(max_size); phi.reserve(max_size); gradphi.reserve(max_size * dim); nablaphi.reserve(max_size * (3 * (dim - 1) + !(dim - 1))); unsigned SolIndex; SolIndex = ml_sol.GetIndex("Sol"); unsigned SolOrder = ml_sol.GetSolutionType(SolIndex); for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { if (ilevel == gridn - 1 || !msh->el->GetRefinedElementIndex(iel)) { short unsigned ielt = msh->el->GetElementType(iel); unsigned nve = msh->el->GetElementDofNumber(iel, SolOrder); // resize metis_node.resize(nve); phi.resize(nve); gradphi.resize(nve * dim); nablaphi.resize(nve * (3 * (dim - 1) + !(dim - 1))); for (int i = 0; i < dim; i++) { coordinates[i].resize(nve); } // get local to global mappings for (unsigned i = 0; i < nve; i++) { unsigned inode_coord_metis = msh->GetSolutionDof(i, iel, 2); metis_node[i] = msh->GetSolutionDof(i, iel, SolOrder); for (unsigned idim = 0; idim < dim; idim++) { coordinates[idim][i] = (*msh->_topology->_Sol[idim])(inode_coord_metis); } } for (unsigned ig = 0; ig < ml_sol._mlMesh->_finiteElement[ielt][SolOrder]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** ml_sol._mlMesh->_finiteElement[ielt][SolOrder]->Jacobian(coordinates, ig, weight, phi, gradphi, nablaphi); //current solution double SolT = 0; vector < double > gradSolT(dim, 0.); for (unsigned ivar = 0; ivar < dim; ivar++) { gradSolT[ivar] = 0; } double pi = acos(-1.); double x[4] = {0., 0., 0., 0.}; unsigned SolType = ml_sol.GetSolutionType("Sol"); for (unsigned i = 0; i < nve; i++) { double soli = (*solution->_Sol[SolIndex])(metis_node[i]); for (unsigned ivar = 0; ivar < dim; ivar++) { x[ivar] += coordinates[ivar][i] * phi[i]; } SolT += phi[i] * soli; for (unsigned ivar2 = 0; ivar2 < dim; ivar2++) { gradSolT[ivar2] += gradphi[i * dim + ivar2] * soli; } } double SolExact, dSolExactdx, dSolExactdy; #ifdef HAVE_FPARSER SolExact = fp_sol(x); dSolExactdx = fp_dsoldx(x); dSolExactdy = fp_dsoldy(x); #endif error_vec->add(iproc, ((SolT - SolExact) * (SolT - SolExact) + H1 * ((gradSolT[0] - dSolExactdx) * (gradSolT[0] - dSolExactdx) + (gradSolT[1] - dSolExactdy) * (gradSolT[1] - dSolExactdy)) )*weight); solution_vec->add(iproc, (SolExact * SolExact + H1 * (dSolExactdx * dSolExactdx + dSolExactdy * dSolExactdy))*weight); } } } } error_vec->close(); solution_vec->close(); double l2_error = error_vec->l1_norm(); double l2_solution = solution_vec->l1_norm(); delete error_vec; delete solution_vec; return sqrt(l2_error / l2_solution); }
std::pair <vector<double>, vector <double> > GetVaribleValues(MultiLevelProblem& ml_prob, const unsigned &elem, const std::vector<double>&xi) { 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); 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 const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem //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 < double > solT; // local solution vector <unsigned> solVIndex(dim); solVIndex[0] = mlSol->GetIndex("U"); solVIndex[1] = mlSol->GetIndex("V"); if (dim==3) solVIndex[2] = mlSol->GetIndex("W"); unsigned solVType = mlSol->GetSolutionType(solVIndex[0]); vector < vector <double> > solV(dim); unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) MyVector <double> solTXi(1, 0.); solTXi.stack(); MyVector <double> solUXi(1, 0.); solUXi.stack(); MyVector <double> solVXi(1, 0.); solVXi.stack(); /* if (dim==3) { MyVector <double> solWXi(1, 0.); solWXi.stack(); } */ //BEGIN local dof number extraction if(elem >= msh->_elementOffset[iproc] && elem < msh->_elementOffset[iproc + 1]) { unsigned nDofsT = msh->GetElementDofNumber(elem, solTType); //temperature solT.reserve(nDofsT); unsigned nDofsV = msh->GetElementDofNumber(elem, solVType); //velocity for(unsigned k = 0; k < dim; k++) solV[k].reserve(nDofsV); //BEGIN global to local extraction for(unsigned i = 0; i < nDofsT; i++) { //temperature unsigned solTDof = msh->GetSolutionDof(i, elem, solTType); //local to global solution dof solT[i] = (*sol->_Sol[solTIndex])(solTDof); //global to local solution value } for(unsigned i = 0; i < nDofsV; i++){ //velocity unsigned solVDof = msh->GetSolutionDof(i, elem, solVType); for(unsigned k = 0; k < dim; k++) { solV[k][i] = (*sol->_Sol[solVIndex[k]])(solVDof); // global extraction and local storage for the solution } } short unsigned ielGeom = msh->GetElementType(elem); for(unsigned i = 0; i < nDofsT; i++) { basis *base = msh->_finiteElement[ielGeom][solTType]->GetBasis(); double phiT = base->eval_phi(base->GetIND(i), &xi[0]); solTXi[iproc] += phiT * solT[i]; } for(unsigned i = 0; i < nDofsV; i++) { basis *base = msh->_finiteElement[ielGeom][solVType]->GetBasis(); double phiV = base->eval_phi(base->GetIND(i), &xi[0]); solUXi[iproc] += phiV * solV[0][i]; solVXi[iproc] += phiV * solV[1][i]; // if(dim==3) solWXi[iproc] += phiV * solV[2][i]; } } std::pair <vector <double>, vector <double> > out_value; unsigned mproc = msh->IsdomBisectionSearch(elem , 3); solUXi.broadcast(mproc); solVXi.broadcast(mproc); solTXi.broadcast(mproc); vector <double> solV_pt(dim); solV_pt[0]= solUXi[mproc]; solV_pt[1]= solVXi[mproc]; out_value.first = solV_pt; vector <double> solPT_pt(2); solPT_pt[0]= 0.; solPT_pt[1]=solTXi[mproc]; out_value.second = solPT_pt; solUXi.clearBroadcast(); solVXi.clearBroadcast(); solTXi.clearBroadcast(); return out_value; }