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 AssembleMatrixResNS(MultiLevelProblem &ml_prob){ adept::Stack & adeptStack = FemusInit::_adeptStack; clock_t AssemblyTime=0; clock_t start_time, end_time; //pointers and references NonLinearImplicitSystem& my_nnlin_impl_sys = ml_prob.get_system<NonLinearImplicitSystem>("Navier-Stokes"); const unsigned level = my_nnlin_impl_sys.GetLevelToAssemble(); const unsigned gridn = my_nnlin_impl_sys.GetLevelMax(); bool assemble_matrix = my_nnlin_impl_sys.GetAssembleMatrix(); MultiLevelSolution* ml_sol = ml_prob._ml_sol; Solution* mysolution = ml_sol->GetSolutionLevel(level); LinearEquationSolver* myLinEqSolver = my_nnlin_impl_sys._LinSolver[level]; Mesh *mymsh = ml_prob._ml_msh->GetLevel(level); elem *myel = mymsh->el; SparseMatrix *myKK = myLinEqSolver->_KK; NumericVector *myRES = myLinEqSolver->_RES; const unsigned dim = mymsh->GetDimension(); const unsigned nabla_dim = 3*(dim-1); const unsigned max_size = static_cast< unsigned > (ceil(pow(3,dim))); // local objects vector<adept::adouble> SolVAR(dim+1); vector<vector<adept::adouble> > GradSolVAR(dim+1); vector<vector<adept::adouble> > NablaSolVAR(dim+1); for(int i=0;i<dim+1;i++){ GradSolVAR[i].resize(dim); NablaSolVAR[i].resize(nabla_dim); } vector <double > phi; vector <adept::adouble> gradphi; vector <adept::adouble> nablaphi; adept::adouble Weight; phi.reserve(max_size); gradphi.reserve(max_size*dim); nablaphi.reserve(max_size*nabla_dim); vector <double > phi1; vector <adept::adouble> gradphi1; vector <adept::adouble> nablaphi1; adept::adouble Weight1; phi1.reserve(max_size); gradphi1.reserve(max_size*dim); nablaphi1.reserve(max_size*nabla_dim); vector <vector < adept::adouble> > vx(dim); vector <vector < adept::adouble> > vx_face(dim); for(int i=0;i<dim;i++){ vx[i].reserve(max_size); vx_face[i].resize(9); } vector< vector< adept::adouble > > Soli(dim+1); vector< vector< int > > dofsVAR(dim+1); for(int i=0;i<dim+1;i++){ Soli[i].reserve(max_size); dofsVAR[i].reserve(max_size); } vector< vector< double > > Rhs(dim+1); vector< vector< adept::adouble > > aRhs(dim+1); for(int i=0;i<dim+1;i++){ aRhs[i].reserve(max_size); Rhs[i].reserve(max_size); } vector < int > dofsAll; dofsAll.reserve(max_size*(dim+1)); vector < double > KKloc; KKloc.reserve(dim*max_size*(dim+1)*dim*max_size*(dim+1)); vector < double > Jac; Jac.reserve(dim*max_size*(dim+1)*dim*max_size*(dim+1)); // ------------------------------------------------------------------------ // Physical parameters double rhof = ml_prob.parameters.get<Fluid>("Fluid").get_density(); double IRe = ml_prob.parameters.get<Fluid>("Fluid").get_IReynolds_number(); double betans = 1.; // gravity double _gravity[3]={0.,0.,0.}; double DRe = 1+(counter*counter)*5; //double DRe=150; IRe =( DRe*(counter+1) < 10000 )? 1./(DRe*(counter+1)):1./10000.; cout<<"iteration="<<counter<<" Reynolds Number = "<<1./IRe<<endl; counter++; // ----------------------------------------------------------------- // space discretization parameters unsigned SolType2 = ml_sol->GetSolutionType(ml_sol->GetIndex("U")); unsigned SolType1 = ml_sol->GetSolutionType(ml_sol->GetIndex("P")); unsigned SolTypeVx = 2; // mesh and procs unsigned nel = mymsh->GetNumberOfElements(); unsigned igrid = mymsh->GetLevel(); unsigned iproc = mymsh->processor_id(); //---------------------------------------------------------------------------------- //variable-name handling const char varname[4][3] = {"U","V","W","P"}; vector <unsigned> indexVAR(dim+1); vector <unsigned> indVAR(dim+1); vector <unsigned> SolType(dim+1); for(unsigned ivar=0; ivar<dim; ivar++) { indVAR[ivar]=ml_sol->GetIndex(&varname[ivar][0]); SolType[ivar]=ml_sol->GetSolutionType(&varname[ivar][0]); indexVAR[ivar]=my_nnlin_impl_sys.GetSolPdeIndex(&varname[ivar][0]); } indVAR[dim]=ml_sol->GetIndex(&varname[3][0]); SolType[dim]=ml_sol->GetSolutionType(&varname[3][0]); indexVAR[dim]=my_nnlin_impl_sys.GetSolPdeIndex(&varname[3][0]); unsigned indLmbd=ml_sol->GetIndex("lmbd"); //---------------------------------------------------------------------------------- start_time=clock(); myKK->zero(); // *** 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 nve2 = myel->GetElementDofNumber(kel,SolType2); unsigned nve1 = myel->GetElementDofNumber(kel,SolType1); unsigned nveVx = myel->GetElementDofNumber(kel,SolTypeVx); // ******************************************************************************************************* //cout<<SolType1<<" "<<SolType2<<" "<<SolTypeVx<<" "<<nve1<<" "<<nve2<<" "<<nveVx<<endl; //Rhs for(int i=0; i<dim; i++) { dofsVAR[i].resize(nve2); Soli[indexVAR[i]].resize(nve2); aRhs[indexVAR[i]].resize(nve2); Rhs[indexVAR[i]].resize(nve2); } dofsVAR[dim].resize(nve1); Soli[indexVAR[dim]].resize(nve1); aRhs[indexVAR[dim]].resize(nve1); Rhs[indexVAR[dim]].resize(nve1); dofsAll.resize(0); KKloc.resize((dim*nve2+nve1)*(dim*nve2+nve1)); Jac.resize((dim*nve2+nve1)*(dim*nve2+nve1)); // ---------------------------------------------------------------------------------------- // coordinates for(int i=0;i<dim;i++){ vx[i].resize(nveVx); } for (unsigned i=0;i<nveVx;i++) { unsigned inode=myel->GetMeshDof(kel,i,SolTypeVx); unsigned inode_Metis=mymsh->GetMetisDof(inode,SolTypeVx); for(int j=0; j<dim; j++) { //coordinates vx[j][i]= (*mymsh->_coordinate->_Sol[j])(inode_Metis); } } // Velocity for (unsigned i=0;i<nve2;i++) { unsigned inode=myel->GetMeshDof(kel,i,SolType2); unsigned inode_Metis=mymsh->GetMetisDof(inode,SolType2); for(int j=0; j<dim; j++) { // velocity dofs Soli[indexVAR[j]][i] = (*mysolution->_Sol[indVAR[j]])(inode_Metis); dofsVAR[j][i] = myLinEqSolver->GetKKDof(indVAR[j],indexVAR[j],inode); aRhs[indexVAR[j]][i] = 0.; } } // Pressure dofs for (unsigned i=0;i<nve1;i++) { unsigned inode=myel->GetMeshDof(kel,i,SolType1); unsigned inode_Metis =mymsh->GetMetisDof(inode,SolType1); Soli[indexVAR[dim]][i] = (*mysolution->_Sol[indVAR[dim]])(inode_Metis); dofsVAR[dim][i]=myLinEqSolver->GetKKDof(indVAR[dim],indexVAR[dim],inode); aRhs[indexVAR[dim]][i] = 0.; } // build dof composition for(int idim=0;idim<dim;idim++){ dofsAll.insert( dofsAll.end(), dofsVAR[idim].begin(), dofsVAR[idim].end() ); } dofsAll.insert( dofsAll.end(), dofsVAR[dim].begin(), dofsVAR[dim].end() ); if (igrid==gridn || !myel->GetRefinedElementIndex(kel) ) { adeptStack.new_recording(); // *** Gauss point loop *** adept::adouble hk; for (unsigned ig=0;ig < mymsh->_finiteElement[kelt][SolType2]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives in the moving frame*** mymsh->_finiteElement[kelt][SolType2]->Jacobian(vx,ig,Weight,phi,gradphi,nablaphi); mymsh->_finiteElement[kelt][SolType1]->Jacobian(vx,ig,Weight1,phi1,gradphi1,nablaphi1); for(int i=0;i<nve1;i++){ for(int j=0;j<nabla_dim;j++){ //cout<<nablaphi[i*nabla_dim+j]<<" "; } //cout<<endl; } //cout<<endl; if(ig==0){ double referenceElementArea[6]={8, 1./6., 1., 4., 1., 2.}; double GaussWeight = mymsh->_finiteElement[kelt][SolType2]->GetGaussWeight(ig); double area=referenceElementArea[kelt]*Weight.value()/GaussWeight; hk = pow(area,1./dim); //cout<<hk<<" "; } // velocity: solution, gradient and laplace for(int i=0; i<dim; i++){ SolVAR[i]=0.; for(int j=0; j<dim; j++) { GradSolVAR[i][j]=0.; } for(int j=0; j<nabla_dim; j++) { NablaSolVAR[i][j]=0.; } for (unsigned inode=0; inode<nve2; inode++) { adept::adouble soli = Soli[indexVAR[i]][inode]; SolVAR[i]+=phi[inode]*soli; for(int j=0; j<dim; j++) { GradSolVAR[i][j]+=gradphi[inode*dim+j]*soli; } for(int j=0; j<nabla_dim; j++) { NablaSolVAR[i][j]+=nablaphi[inode*nabla_dim+j]*soli; } } } // pressure, solution and gradient SolVAR[dim]=0.; for(int j=0; j<dim; j++) { GradSolVAR[dim][j]=0.; } for (unsigned inode=0; inode<nve1; inode++) { adept::adouble soli = Soli[indexVAR[dim]][inode]; SolVAR[dim]+=phi1[inode]*soli; for(int j=0; j<dim; j++) { GradSolVAR[dim][j]+=gradphi1[inode*dim+j]*soli; } } bool Tezduyare=0; bool FrancaAndFrey=!Tezduyare; if( Tezduyare ){ //BEGIN TAU_SUPG, TAU_PSPG EVALUATION // ******** T.E. Tezduyar, S. Mittal, S.E. Ray and R. Shih ***************************** // Computer Methods in Applied Mechanics and Engineering 95 (1992) 221-242 North-Holland // ************************************************************************************* // velocity vector < adept::adouble > u(dim); for(int ivar=0; ivar<dim; ivar++){ u[ivar]=SolVAR[ivar]; } // speed adept::adouble uL2Norm=0.; for(int ivar=0;ivar<dim;ivar++){ uL2Norm += u[ivar]*u[ivar]; } uL2Norm=sqrt(uL2Norm); adept::adouble tauSupg=0.; adept::adouble tauPspg=0.; if( uL2Norm/(2.*IRe) > 1.0e-10){ // velocity direction s = u/|u| vector < adept::adouble > s(dim); for(int ivar=0;ivar<dim;ivar++) s[ivar]=u[ivar]/uL2Norm; // element lenght h(s) = 2. ( \sum_i |s . gradphi_i | )^(-1) adept::adouble h=0.; for (unsigned i=0; i<nve2; i++) { adept::adouble sDotGradphi=0.; for(int ivar=0; ivar<dim; ivar++) sDotGradphi += s[ivar]*gradphi[i*dim+ivar]; //Start WARNING!!! do not change the following if into h += fabs(sDotGradphi). //Adept does not like it, and convergence is bad if( sDotGradphi.value() < 0.) h -= sDotGradphi; else h += sDotGradphi; //End WARNING } h = 2./h; //tauSupg adept::adouble Reu = 1./3.*(uL2Norm*h)/(2.*IRe); adept::adouble zReu = (Reu.value() < 1.)? Reu : 1.; tauSupg = h / (2.*uL2Norm)*zReu; uL2Norm=0.01; h = 2.*hk/sqrt(acos(-1.)); Reu = 1./3.*(uL2Norm*h)/(2.*IRe); zReu = (Reu.value() < 1.)? Reu : 1.; tauPspg = h / (2.*uL2Norm)*zReu; } //END TAU_SUPG, TAU_PSPG EVALUATION //BEGIN FLUID ASSEMBLY { vector < adept::adouble > Res(dim,0.); for(unsigned ivar=0; ivar<dim; ivar++) { Res[ivar] += 0. - GradSolVAR[dim][ivar]; for(unsigned jvar=0; jvar<dim; jvar++) { unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = dim; // xy else if (2 == ivar + jvar ) kvar = dim+2; // xz else if (3 == ivar + jvar ) kvar = dim+1; // yz Res[ivar] += - SolVAR[jvar]*GradSolVAR[ivar][jvar] + IRe * ( NablaSolVAR[ivar][jvar] + NablaSolVAR[jvar][kvar] ); } } adept::adouble div_vel=0.; for(int ivar=0; ivar<dim; ivar++) { div_vel +=GradSolVAR[ivar][ivar]; } //BEGIN redidual momentum block for (unsigned i=0; i<nve2; i++){ for(unsigned ivar=0; ivar<dim; ivar++) { adept::adouble Advection = 0.; adept::adouble Laplacian = 0.; adept::adouble phiSupg=0.; for(unsigned jvar=0; jvar<dim; jvar++) { unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = dim; // xy else if (2 == ivar + jvar ) kvar = dim+2; // xz else if (3 == ivar + jvar ) kvar = dim+1; // yz Advection += SolVAR[jvar]*GradSolVAR[ivar][jvar]*phi[i]; Laplacian += IRe*gradphi[i*dim+jvar]*(GradSolVAR[ivar][jvar]+GradSolVAR[jvar][ivar]); phiSupg += ( SolVAR[jvar]*gradphi[i*dim+jvar] ) * tauSupg; } aRhs[indexVAR[ivar]][i]+= ( - Advection - Laplacian + SolVAR[dim] * gradphi[i*dim+ivar] + Res[ivar] * phiSupg ) * Weight; } } //END redidual momentum block //BEGIN continuity block for (unsigned i=0; i<nve1; i++) { adept::adouble MinusGradPhi1DotRes = 0.; for(int ivar=0;ivar<dim;ivar++){ MinusGradPhi1DotRes += -gradphi1[i*dim+ivar] * Res[ivar] * tauPspg; } aRhs[indexVAR[dim]][i] += ( - (-div_vel) * phi1[i] + MinusGradPhi1DotRes ) * Weight; } //END continuity block } //END FLUID ASSEMBLY } else if(FrancaAndFrey){ //BEGIN TAU_SUPG EVALUATION // ********************************* Tau_Supg FRANCA and FREY ************************** // Computer Methods in Applied Mechanics and Engineering 99 (1992) 209-233 North-Holland // ************************************************************************************* // velocity // double Ck[6][3]={{1.,1.,1.},{1.,1.,1.},{1.,1.,1.},{0.5, 11./270., 11./270.},{0.,1./42.,1./42.},{1.,1.,1.}}; vector < adept::adouble > a(dim); for(int ivar=0; ivar<dim; ivar++){ a[ivar]=SolVAR[ivar]; } // speed adept::adouble aL2Norm=0.; for(int ivar=0;ivar<dim;ivar++){ aL2Norm += a[ivar]*a[ivar]; } aL2Norm=sqrt(aL2Norm); adept::adouble deltaSupg=0.; double sqrtlambdak = (*mysolution->_Sol[indLmbd])(iel); adept::adouble tauSupg=1. / ( sqrtlambdak*sqrtlambdak *4.*IRe); adept::adouble Rek = aL2Norm / ( 4.*sqrtlambdak*IRe); /*adept::adouble mk=std::min(1./3., 2.*Ck[kelt][SolType2]); adept::adouble Rek = mk * aL2Norm * hk / ( 4.*IRe); adept::adouble tauSupg = (mk*hk*hk/2.) / ( 4.*IRe); */ if( Rek > 1.0e-15){ adept::adouble xiRek = ( Rek >= 1. ) ? 1.:Rek; tauSupg = xiRek/(aL2Norm*sqrtlambdak); deltaSupg = (xiRek*aL2Norm)/sqrtlambdak; // tauSupg = hk / (2.*aL2Norm)*xiRek; // double lambda=1.; // deltaSupg = lambda*aL2Norm*hk*xiRek; } //END TAU_SUPG EVALUATION ============ //BEGIN FLUID ASSEMBLY ============ { vector < adept::adouble > Res(dim,0.); for(unsigned ivar=0; ivar<dim; ivar++) { Res[ivar] += 0. - GradSolVAR[dim][ivar]; for(unsigned jvar=0; jvar<dim; jvar++) { unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = dim; // xy else if (2 == ivar + jvar ) kvar = dim+2; // xz else if (3 == ivar + jvar ) kvar = dim+1; // yz Res[ivar] += - SolVAR[jvar]*GradSolVAR[ivar][jvar] + IRe * ( NablaSolVAR[ivar][jvar] + NablaSolVAR[jvar][kvar] ); } } adept::adouble div_vel=0.; for(int ivar=0; ivar<dim; ivar++) { div_vel +=GradSolVAR[ivar][ivar]; } //BEGIN redidual momentum block for (unsigned i=0; i<nve2; i++){ for(unsigned ivar=0; ivar<dim; ivar++) { adept::adouble Advection = 0.; adept::adouble Laplacian = 0.; adept::adouble phiSupg=0.; for(unsigned jvar=0; jvar<dim; jvar++) { unsigned kvar; if(ivar == jvar) kvar = jvar; else if (1 == ivar + jvar ) kvar = dim; // xy else if (2 == ivar + jvar ) kvar = dim+2; // xz else if (3 == ivar + jvar ) kvar = dim+1; // yz Advection += SolVAR[jvar]*GradSolVAR[ivar][jvar]*phi[i]; Laplacian += IRe*gradphi[i*dim+jvar]*(GradSolVAR[ivar][jvar]+GradSolVAR[jvar][ivar]); phiSupg += ( SolVAR[jvar]*gradphi[i*dim+jvar] ) * tauSupg; aRhs[indexVAR[ivar]][i] += Res[ivar] * (-IRe * nablaphi[i*nabla_dim+jvar])* tauSupg * Weight; aRhs[indexVAR[jvar]][i] += Res[ivar] * (-IRe * nablaphi[i*nabla_dim+kvar])* tauSupg * Weight; } aRhs[indexVAR[ivar]][i]+= ( - Advection - Laplacian + ( SolVAR[dim] - deltaSupg * div_vel) * gradphi[i*dim+ivar] + Res[ivar] * phiSupg ) * Weight; } } //END redidual momentum block //BEGIN continuity block for (unsigned i=0; i<nve1; i++) { adept::adouble MinusGradPhi1DotRes = 0.; for(int ivar=0;ivar<dim;ivar++){ MinusGradPhi1DotRes += -gradphi1[i*dim+ivar] * Res[ivar] * tauSupg; } aRhs[indexVAR[dim]][i] += ( - (-div_vel) * phi1[i] + MinusGradPhi1DotRes ) * Weight; } //END continuity block =========================== } //END FLUID ASSEMBLY ============ } } } //BEGIN local to global assembly //copy adouble aRhs into double Rhs for (unsigned i=0;i<dim;i++) { for(int j=0; j<nve2; j++) { Rhs[indexVAR[i]][j] = aRhs[indexVAR[i]][j].value(); } } for (unsigned j=0;j<nve1;j++) { Rhs[indexVAR[dim]][j] = aRhs[indexVAR[dim]][j].value(); } for(int i=0; i<dim+1; i++) { myRES->add_vector_blocked(Rhs[indexVAR[i]],dofsVAR[i]); } //Store equations for(int i=0; i<dim; i++) { adeptStack.dependent(&aRhs[indexVAR[i]][0], nve2); adeptStack.independent(&Soli[indexVAR[i]][0], nve2); } adeptStack.dependent(&aRhs[indexVAR[dim]][0], nve1); adeptStack.independent(&Soli[indexVAR[dim]][0], nve1); adeptStack.jacobian(&Jac[0]); unsigned nveAll=(dim*nve2+nve1); for (int inode=0;inode<nveAll;inode++){ for (int jnode=0;jnode<nveAll;jnode++){ KKloc[inode*nveAll+jnode]=-Jac[jnode*nveAll+inode]; } } myKK->add_matrix_blocked(KKloc,dofsAll,dofsAll); adeptStack.clear_independents(); adeptStack.clear_dependents(); //END local to global assembly } //end list of elements loop myKK->close(); myRES->close(); // ************************************* end_time=clock(); AssemblyTime+=(end_time-start_time); // ***************** END ASSEMBLY RESIDUAL + MATRIX ******************* }
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 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 ******************* }
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 ******************* }
/** * 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 AssemblePoissonMatrixandRhs(MultiLevelProblem& ml_prob) { //pointers and references LinearImplicitSystem& mylin_impl_sys = ml_prob.get_system<LinearImplicitSystem>("Poisson"); const unsigned level = mylin_impl_sys.GetLevelToAssemble(); //bool assemble_matrix = mylin_impl_sys.GetAssembleMatrix(); Solution* mysolution = ml_prob._ml_sol->GetSolutionLevel(level); LinearEquationSolver* mylsyspde = mylin_impl_sys._LinSolver[level]; Mesh* mymsh = ml_prob._ml_msh->GetLevel(level); elem* myel = mymsh->el; SparseMatrix* myKK = mylsyspde->_KK; NumericVector* myRES = mylsyspde->_RES; MultiLevelSolution* ml_sol = ml_prob._ml_sol; //data const unsigned dim = mymsh->GetDimension(); unsigned nel = mymsh->GetNumberOfElements(); unsigned igrid = mymsh->GetLevel(); unsigned iproc = mymsh->processor_id(); //solution variable unsigned SolIndex; unsigned SolPdeIndex; SolIndex = ml_sol->GetIndex("Sol"); SolPdeIndex = mylin_impl_sys.GetSolPdeIndex("Sol"); //solution order unsigned order_ind = ml_sol->GetSolutionType(SolIndex); //coordinates vector< vector < double> > coordinates(dim); // declare vector< int > metis_node; vector< int > KK_dof; vector <double> phi; vector <double> gradphi; vector <double> nablaphi; double weight; vector< double > F; vector< double > B; vector<double> normal(3.0); double src_term = 0.; vector<double> xyzt(4, 0.); ParsedFunction* bdcfunc = NULL; // reserve const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim))); metis_node.reserve(max_size); KK_dof.reserve(max_size); for (int i = 0; i < dim; i++) coordinates[i].reserve(max_size); phi.reserve(max_size); gradphi.reserve(max_size * dim); unsigned nabla_dim = (3 * (dim - 1) + !(dim - 1)); nablaphi.reserve(max_size * nabla_dim); F.reserve(max_size); B.reserve(max_size * max_size); // Set to zeto all the entries of the Global Matrix myKK->zero(); // *** element loop *** for (int iel = mymsh->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc + 1]; iel++) { short unsigned ielt = mymsh->GetElementType(iel); unsigned nve = mymsh->GetElementDofNumber(iel, order_ind); unsigned nve2 = mymsh->GetElementDofNumber(iel, 2); // resize metis_node.resize(nve); KK_dof.resize(nve); for (int i = 0; i < dim; i++) { coordinates[i].resize(nve); } // set to zero all the entries of the FE matrices F.resize(nve); memset(&F[0], 0, nve * sizeof(double)); B.assign(nve * nve, 0.); // get local to global mappings for (unsigned i = 0; i < nve2; i++) { unsigned inode_coord_metis = mymsh->GetSolutionDof(i, iel, 2); for (unsigned ivar = 0; ivar < dim; ivar++) { coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis); } if (i < nve) { metis_node[i] = mymsh->GetSolutionDof(i, iel, order_ind); KK_dof[i] = mylsyspde->GetSystemDof(SolIndex, SolPdeIndex, i, iel); } } // *** Gauss point loop *** // Supg stabilization tau evaluation double V[3] = {0., 0., 0.}; double nu = 1.; if (dim == 1) { V[0] = 1.; nu = 0.01; } else if (dim == 2) { // nu=0.0001; // V[0]=sqrt(2)/2; // V[1]=-sqrt(2)/2; nu = 1.; V[0] = 0.; V[1] = 0.; } else if (dim == 3) { nu = 1.; V[0] = V[1] = V[2] = 0.; } double barNu = 0.; double vL2Norm2 = 0.; for (int i = 0; i < dim; i++) { vL2Norm2 += V[i] * V[i]; unsigned ip = referenceElementDirection[ielt][i][1]; unsigned im = referenceElementDirection[ielt][i][0]; double VxiHxi = 0.; for (int j = 0; j < dim; j++) { VxiHxi += (coordinates[j][ip] - coordinates[j][im]) * V[j]; } double PeXi = VxiHxi / (2.*nu); double barXi = (fabs(PeXi) < 1.0e-10) ? 0. : 1. / tanh(PeXi) - 1. / PeXi; barNu += barXi * VxiHxi / 2.; } double supgTau = (vL2Norm2 > 1.0e-15) ? barNu / vL2Norm2 : 0.; // End Stabilization stabilization tau evaluation for (unsigned ig = 0; ig < mymsh->_finiteElement[ielt][order_ind]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** mymsh->_finiteElement[ielt][order_ind]->Jacobian(coordinates, ig, weight, phi, gradphi, nablaphi); //current solution double SolT = 0; vector < double > gradSolT(dim, 0.); vector < double > NablaSolT(dim, 0.); xyzt.assign(4, 0.); unsigned SolType = ml_sol->GetSolutionType("Sol"); for (unsigned i = 0; i < nve; i++) { double soli = (*mysolution->_Sol[SolIndex])(metis_node[i]); for (unsigned ivar = 0; ivar < dim; ivar++) { xyzt[ivar] += coordinates[ivar][i] * phi[i]; } SolT += phi[i] * soli; for (unsigned ivar2 = 0; ivar2 < dim; ivar2++) { gradSolT[ivar2] += gradphi[i * dim + ivar2] * soli; NablaSolT[ivar2] += nablaphi[i * nabla_dim + ivar2] * soli; } } // *** phi_i loop *** for (unsigned i = 0; i < nve; i++) { //BEGIN RESIDUALS A block =========================== double advRhs = 0.; double lapRhs = 0.; double resRhs = 0.; double supgPhi = 0.; for (unsigned ivar = 0; ivar < dim; ivar++) { lapRhs += nu * gradphi[i * dim + ivar] * gradSolT[ivar]; advRhs += V[ivar] * gradSolT[ivar] * phi[i]; resRhs += -nu * NablaSolT[ivar] + V[ivar] * gradSolT[ivar]; supgPhi += (V[ivar] * gradphi[i * dim + ivar] + nu * nablaphi[i * nabla_dim + ivar]) * supgTau; } src_term = fpsource(&xyzt[0]); F[i] += (src_term * phi[i] - lapRhs - advRhs + (src_term - resRhs) * supgPhi) * weight; //END RESIDUALS A block =========================== // *** phi_j loop *** for (unsigned j = 0; j < nve; j++) { double lap = 0; double adv = 0; for (unsigned ivar = 0; ivar < dim; ivar++) { lap += nu * (gradphi[i * dim + ivar] * gradphi[j * dim + ivar] - nablaphi[j * nabla_dim + ivar] * supgPhi) * weight; adv += V[ivar] * gradphi[j * dim + ivar] * (phi[i] + supgPhi) * weight; } B[i * nve + j] += lap + adv ; } // end phij loop } // end phii loop } // end gauss point loop if (ml_prob._ml_sol->_useParsedBCFunction) { //number of faces for each type of element unsigned nfaces = mymsh->GetElementFaceNumber(iel); // loop on faces for (unsigned jface = 0; jface < nfaces; jface++) { // look for boundary faces if (myel->GetBoundaryIndex(iel, jface) > 0) { unsigned int faceIndex = myel->GetBoundaryIndex(iel, jface); if (ml_sol->GetBoundaryCondition("Sol", faceIndex - 1u) == NEUMANN && !ml_sol->Ishomogeneous("Sol", faceIndex - 1u)) { bdcfunc = (ParsedFunction*)(ml_sol->GetBdcFunction("Sol", faceIndex - 1u)); unsigned nve = mymsh->GetElementFaceDofNumber(iel, jface, order_ind); const unsigned felt = mymsh->GetElementFaceType(iel, jface); for (unsigned i = 0; i < nve; i++) { unsigned ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i); unsigned inode_coord_metis = mymsh->GetSolutionDof(ilocal, iel, 2); for (unsigned ivar = 0; ivar < dim; ivar++) { coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis); } } if (felt != 6) { for (unsigned igs = 0; igs < mymsh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) { mymsh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal); xyzt.assign(4, 0.); for (unsigned i = 0; i < nve; i++) { for (unsigned ivar = 0; ivar < dim; ivar++) { xyzt[ivar] += coordinates[ivar][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nve; i++) { double surfterm_g = (*bdcfunc)(&xyzt[0]); double bdintegral = phi[i] * surfterm_g * weight; unsigned int ilocalnode = mymsh->GetLocalFaceVertexIndex(iel, jface, i); F[ilocalnode] += bdintegral; } } } else { // 1D : the side elems are points and does not still exist the point elem // in 1D it is only one point xyzt[0] = coordinates[0][0]; xyzt[1] = 0.; xyzt[2] = 0.; xyzt[3] = 0.; double bdintegral = (*bdcfunc)(&xyzt[0]); unsigned int ilocalnode = mymsh->GetLocalFaceVertexIndex(iel, jface, 0); F[ilocalnode] += bdintegral; } } } } } else { double tau = 0.; std::vector< double > xx(dim, 0.); vector < double > normal(dim, 0); // loop on faces for (unsigned jface = 0; jface < mymsh->GetElementFaceNumber(iel); jface++) { // look for boundary faces if (myel->GetFaceElementIndex(iel, jface) < 0) { unsigned int faceIndex = myel->GetBoundaryIndex(iel, jface); if (!ml_sol->GetBdcFunction()(xx, "Sol", tau, faceIndex, 0.) && tau != 0.) { unsigned nve = mymsh->GetElementFaceDofNumber(iel, jface, order_ind); const unsigned felt = mymsh->GetElementFaceType(iel, jface); for (unsigned i = 0; i < nve; i++) { unsigned int ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i); unsigned inode = mymsh->GetSolutionDof(ilocal, iel, 2); for (unsigned idim = 0; idim < dim; idim++) { coordinates[idim][i] = (*mymsh->_topology->_Sol[idim])(inode); } } for (unsigned igs = 0; igs < mymsh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) { mymsh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal); // *** phi_i loop *** for (unsigned i = 0; i < nve; i++) { double value = phi[i] * tau * weight; unsigned int ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i); F[ilocal] += value; } } } } } } //-------------------------------------------------------------------------------------------------------- //Sum the local matrices/vectors into the global Matrix/vector myRES->add_vector_blocked(F, KK_dof); myKK->add_matrix_blocked(B, KK_dof, KK_dof); } //end list of elements loop for each subdomain myRES->close(); myKK->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 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 ******************* }
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 AssembleMatrixRes_VC(MultiLevelProblem &ml_prob) { TransientNonlinearImplicitSystem* mlPdeSys = & ml_prob.get_system<TransientNonlinearImplicitSystem>("Timedep"); const unsigned level = mlPdeSys->GetLevelToAssemble(); MultiLevelSolution *ml_sol = ml_prob._ml_sol; Solution* sol = ml_sol->GetSolutionLevel(level); LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; const char* pdename = mlPdeSys->name().c_str(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); elem* myel = msh->el; SparseMatrix* JAC = pdeSys->_KK; NumericVector* RES = pdeSys->_RES; // data const unsigned dim = msh->GetDimension(); const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 unsigned nel = msh->GetNumberOfElements(); unsigned igrid = msh->GetLevel(); unsigned iproc = msh->processor_id(); // time dep data double dt = mlPdeSys->GetIntervalTime(); // double theta = 0.5; //************** geometry (at dofs and quadrature points) ************************************* vector < vector < double > > coords_at_dofs(dim); unsigned coords_fe_type = BIQUADR_FE; // get the finite element type for "x", it is always 2 (LAGRANGE BIQUADRATIC) for (unsigned i = 0; i < coords_at_dofs.size(); i++) coords_at_dofs[i].reserve(max_size); vector < double > coord_at_qp(dim); //************* shape functions (at dofs and quadrature points) ************************************** const int solType_max = BIQUADR_FE; //biquadratic double weight_qp; // gauss point weight vector < vector < double > > phi_fe_qp(NFE_FAMS); vector < vector < double > > phi_x_fe_qp(NFE_FAMS); vector < vector < double > > phi_xx_fe_qp(NFE_FAMS); for(int fe=0; fe < NFE_FAMS; fe++) { phi_fe_qp[fe].reserve(max_size); phi_x_fe_qp[fe].reserve(max_size*dim); phi_xx_fe_qp[fe].reserve(max_size*(3*(dim-1))); } //*************************************************** //********* WHOLE SET OF VARIABLES ****************** //*************************************************** const unsigned int n_unknowns = mlPdeSys->GetSolPdeIndex().size(); vector < std::string > Solname(n_unknowns); Solname[0] = "u"; vector < unsigned > SolPdeIndex(n_unknowns); vector < unsigned > SolIndex(n_unknowns); vector < unsigned int > SolFEType(n_unknowns); //FEtype of each MultilevelSolution vector < unsigned int > Sol_n_el_dofs(n_unknowns); //number of element dofs std::fill(Sol_n_el_dofs.begin(), Sol_n_el_dofs.end(), 0); for(unsigned ivar=0; ivar < n_unknowns; ivar++) { SolPdeIndex[ivar] = mlPdeSys->GetSolPdeIndex( Solname[ivar].c_str() ); SolIndex[ivar] = ml_sol->GetIndex ( Solname[ivar].c_str() ); SolFEType[ivar] = ml_sol->GetSolutionType ( SolIndex[ivar]); } //------------ quantities (at quadrature points) --------------------- vector<double> sol_qp(n_unknowns); vector<double> sol_old_qp(n_unknowns); vector< vector<double> > sol_grad_qp(n_unknowns); vector< vector<double> > sol_old_grad_qp(n_unknowns); std::fill(sol_qp.begin(), sol_qp.end(), 0.); std::fill(sol_old_qp.begin(), sol_old_qp.end(), 0.); for (unsigned k = 0; k < n_unknowns; k++) { sol_grad_qp[k].resize(dim); std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); sol_old_grad_qp[k].resize(dim); std::fill(sol_old_grad_qp[k].begin(), sol_old_grad_qp[k].end(), 0.); } //----------- quantities (at dof objects) ------------------------------ vector < vector < double > > sol_eldofs(n_unknowns); vector < vector < double > > sol_old_eldofs(n_unknowns); for(int k=0; k<n_unknowns; k++) { sol_eldofs[k].reserve(max_size); sol_old_eldofs[k].reserve(max_size); } //******** linear system ******************************************* vector < vector < int > > L2G_dofmap(n_unknowns); for(int i = 0; i < n_unknowns; i++) { L2G_dofmap[i].reserve(max_size); } vector< int > L2G_dofmap_AllVars; L2G_dofmap_AllVars.reserve( n_unknowns*max_size ); vector< vector< double > > Res_el(n_unknowns); vector< vector< vector< double > > > Jac_el(n_unknowns); for(int i = 0; i < n_unknowns; i++) Res_el[i].reserve(max_size); for(int i = 0; i < n_unknowns; i++) { Jac_el[i].resize(n_unknowns); for(int j = 0; j < n_unknowns; j++) { Jac_el[i][j].reserve(max_size*max_size); } } // Set to zero all the entries of the matrix RES->zero(); JAC->zero(); const double deltat_term = 1.; const double lapl_term = 1.; const double delta_g_term = 1.; // *** element loop *** for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc+1]; iel++) { short unsigned ielGeom = msh->GetElementType(iel); // element geometry type //******************** GEOMETRY ********************* unsigned nDofx = msh->GetElementDofNumber(iel, coords_fe_type); // number of coordinate element dofs for (int i = 0; i < dim; i++) coords_at_dofs[i].resize(nDofx); // local storage of coordinates for (unsigned i = 0; i < nDofx; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, coords_fe_type); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { coords_at_dofs[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } //*************************************************** //all vars################################################################### for (unsigned k = 0; k < n_unknowns; k++) { unsigned ndofs_unk = msh->GetElementDofNumber(iel, SolFEType[k]); Sol_n_el_dofs[k] = ndofs_unk; sol_eldofs[k].resize(ndofs_unk); sol_old_eldofs[k].resize(ndofs_unk); L2G_dofmap[k].resize(ndofs_unk); for (unsigned i = 0; i < ndofs_unk; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, SolFEType[k]); // global to global mapping between solution node and solution dof // via local to global solution node sol_eldofs[k][i] = (*sol->_Sol[SolIndex[k]])(solDof); // global extraction and local storage for the solution sol_old_eldofs[k][i] = (*sol->_SolOld[SolIndex[k]])(solDof); // This is OLD in TIME, not in nonlinear loop L2G_dofmap[k][i] = pdeSys->GetSystemDof(SolIndex[k], SolPdeIndex[k], i, iel); // global to global mapping between solution node and pdeSys dof } } unsigned nDof_AllVars = 0; for (unsigned k = 0; k < n_unknowns; k++) { nDof_AllVars += Sol_n_el_dofs[k]; } // TODO COMPUTE MAXIMUM maximum number of element dofs for one scalar variable int nDof_max = 0; for (unsigned k = 0; k < n_unknowns; k++) { if(Sol_n_el_dofs[k] > nDof_max) nDof_max = Sol_n_el_dofs[k]; } for(int k = 0; k < n_unknowns; k++) { L2G_dofmap[k].resize(Sol_n_el_dofs[k]); Res_el[SolPdeIndex[k]].resize(Sol_n_el_dofs[k]); memset(& Res_el[SolPdeIndex[k]][0], 0., Sol_n_el_dofs[k] * sizeof(double) ); Jac_el[SolPdeIndex[k]][SolPdeIndex[k]].resize(Sol_n_el_dofs[k] * Sol_n_el_dofs[k]); memset(& Jac_el[SolPdeIndex[k]][SolPdeIndex[k]][0], 0., Sol_n_el_dofs[k] * Sol_n_el_dofs[k] * sizeof(double)); } //all vars################################################################### // *** quadrature loop *** for(unsigned ig = 0; ig < ml_prob.GetQuadratureRule(ielGeom).GetGaussPointsNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** for(int fe=0; fe < NFE_FAMS; fe++) { msh->_finiteElement[ielGeom][fe]->Jacobian(coords_at_dofs,ig,weight_qp,phi_fe_qp[fe],phi_x_fe_qp[fe],phi_xx_fe_qp[fe]); } //HAVE TO RECALL IT TO HAVE BIQUADRATIC JACOBIAN msh->_finiteElement[ielGeom][coords_fe_type]->Jacobian(coords_at_dofs,ig,weight_qp,phi_fe_qp[coords_fe_type],phi_x_fe_qp[coords_fe_type],phi_xx_fe_qp[coords_fe_type]); //========= fill gauss value quantities ================== std::fill(sol_qp.begin(), sol_qp.end(), 0.); std::fill(sol_old_qp.begin(), sol_old_qp.end(), 0.); for (unsigned k = 0; k < n_unknowns; k++) { std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); std::fill(sol_old_grad_qp[k].begin(), sol_old_grad_qp[k].end(), 0.); } for (unsigned k = 0; k < n_unknowns; k++) { for (unsigned i = 0; i < Sol_n_el_dofs[k]; i++) { sol_qp[k] += sol_eldofs[k][i] * phi_fe_qp[SolFEType[k]][i]; sol_old_qp[k] += sol_old_eldofs[k][i] * phi_fe_qp[SolFEType[k]][i]; for (unsigned d = 0; d < dim; d++) { sol_grad_qp[k][d] += sol_eldofs[k][i] * phi_x_fe_qp[SolFEType[k]][i * dim + d]; sol_old_grad_qp[k][d] += sol_old_eldofs[k][i] * phi_x_fe_qp[SolFEType[k]][i * dim + d]; } } } //========= fill gauss value quantities ================== // *** phi_i loop *** for(unsigned i = 0; i < nDof_max; i++) { //BEGIN RESIDUALS A block =========================== double Lap_rhs_i = 0.; double Lap_old_rhs_i = 0.; for(unsigned d = 0; d < dim; d++) { Lap_rhs_i += phi_x_fe_qp[SolFEType[0]][i * dim + d] * sol_grad_qp[0][d]; Lap_old_rhs_i += phi_x_fe_qp[SolFEType[0]][i * dim + d] * sol_old_grad_qp[0][d]; } Res_el[SolPdeIndex[0]][i] += - weight_qp * ( delta_g_term * Singularity::function(sol_qp[0]) * Singularity::g_vc(sol_qp[0]) * phi_fe_qp[ SolFEType[0] ][i] - delta_g_term * Singularity::function(sol_qp[0]) * Singularity::g_vc(sol_old_qp[0]) * phi_fe_qp[ SolFEType[0] ][i] + deltat_term * Singularity::function(sol_qp[0]) * dt * phi_fe_qp[ SolFEType[0] ][i] + lapl_term * dt * Lap_rhs_i ); //END RESIDUALS A block =========================== // *** phi_j loop *** for(unsigned j = 0; j<nDof_max; j++) { double Lap_mat_i_j = 0.; for(unsigned d = 0; d < dim; d++) Lap_mat_i_j += phi_x_fe_qp[SolFEType[0]][i * dim + d] * phi_x_fe_qp[SolFEType[0]][j * dim + d]; Jac_el[SolPdeIndex[0]][SolPdeIndex[0]][i * Sol_n_el_dofs[0] + j] += weight_qp * ( + delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative( phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * Singularity::g_vc( phi_fe_qp[ SolFEType[0] ][j] ) + delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::function ( phi_fe_qp[ SolFEType[0] ][j] ) * Singularity::g_vc_derivative( phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] - delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative( phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * Singularity::g_vc( sol_old_qp[0] ) + deltat_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative( phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * dt + lapl_term * dt * Lap_mat_i_j ); } //end phij loop } //end phii loop } // end gauss point loop //-------------------------------------------------------------------------------------------------------- //Sum the local matrices/vectors into the Global Matrix/Vector for(unsigned ivar=0; ivar < n_unknowns; ivar++) { RES->add_vector_blocked(Res_el[SolPdeIndex[ivar]],L2G_dofmap[ivar]); JAC->add_matrix_blocked(Jac_el[SolPdeIndex[ivar]][SolPdeIndex[ivar]],L2G_dofmap[ivar],L2G_dofmap[ivar]); } //-------------------------------------------------------------------------------------------------------- } //end list of elements loop for each subdomain JAC->close(); RES->close(); // ***************** END ASSEMBLY ******************* }
void trymat9() { Tracer et("Ninth test of Matrix package"); Tracer::PrintTrace(); int i; int j; Matrix A(7,7); Matrix X(7,3); for (i=1;i<=7;i++) for (j=1;j<=7;j++) A(i,j)=i*i+j+((i==j) ? 1 : 0); for (i=1;i<=7;i++) for (j=1;j<=3;j++) X(i,j)=i-j; Matrix B = A.i(); DiagonalMatrix D(7); D=1.0; { Tracer et1("Stage 1"); Matrix Q = B*A-D; Clean(Q, 0.000000001); Print(Q); Q=A; Q = Q.i() * X; Q = A*Q - X; Clean(Q, 0.000000001); Print(Q); Q=X; Q = A.i() * Q; Q = A*Q - X; Clean(Q, 0.000000001); Print(Q); } for (i=1;i<=7;i++) D(i,i)=i*i+1; DiagonalMatrix E(3); for (i=1;i<=3;i++) E(i,i)=i+23; { Tracer et1("Stage 2"); Matrix DXE = D.i() * X * E; DXE = E.i() * DXE.t() * D - X.t(); Clean(DXE, 0.00000001); Print(DXE); E=D; for (i=1;i<=7;i++) E(i,i)=i*3+1; } DiagonalMatrix F=D; { Tracer et1("Stage 3"); F=E.i()*F; F=F*E-D; Clean(F,0.00000001); Print(F); F=E.i()*D; F=F*E-D; Clean(F,0.00000001); Print(F); } { Tracer et1("Stage 4"); F=E; F=F.i()*D; F=F*E-D; Clean(F,0.00000001); Print(F); } { Tracer et1("Stage 5"); // testing equal ColumnVector A(18), B(18); Matrix X(3,3); X << 3 << 5 << 7 << 5 << 8 << 2 << 7 << 2 << 9; SymmetricMatrix S; S << X; B(1) = S == X; A(1) = true; B(2) = S == (X+1); A(2) = false; B(3) = (S+2) == (X+2); A(3) = true; Matrix Y = X; B(4) = X == Y; A(4) = true; B(5) = (X*2) == (Y*2); A(5) = true; Y(3,3) = 10; B(6) = X == Y; A(6) = false; B(7) = (X*2) == (Y*2); A(7) = false; B(8) = S == Y; A(8) = false; B(9) = S == S; A(9) = true; Matrix Z = X.SubMatrix(1,2,2,3); B(10) = X == Z; A(10) = false; GenericMatrix GS = S; GenericMatrix GX = X; GenericMatrix GY = Y; B(11) = GS == GX; A(11) = true; B(12) = GS == GY; A(12) = false; CroutMatrix CS = S; CroutMatrix CX = X; CroutMatrix CY = Y; B(13) = CS == CX; A(13) = true; B(14) = CS == CY; A(14) = false; B(15) = X == CX; A(15) = false; B(16) = X == A; A(16) = false; B(17) = X == (X | X); A(17) = false; B(18) = CX == X; A(18) = false; A = A - B; Print(A); } { Tracer et1("Stage 6"); // testing equal ColumnVector A(22), B(22); BandMatrix X(6,2,1); X(1,1)=23; X(1,2)=21; X(2,1)=12; X(2,2)=17; X(2,3)=45; X(3,1)=35; X(3,2)=19; X(3,3)=24; X(3,4)=29; X(4,2)=17; X(4,3)=11; X(4,4)=19; X(4,5)=35; X(5,3)=10; X(5,4)=44; X(5,5)=23; X(5,6)=31; X(6,4)=49; X(6,5)=41; X(6,6)=17; SymmetricBandMatrix S1(6,2); S1.Inject(X); BandMatrix U(6,2,3); U = 0.0; U.Inject(X); B(1) = U == X; A(1) = true; B(2) = U == (X*3); A(2) = false; B(3) = (U*5) == (X*5); A(3) = true; Matrix Y = X; B(4) = X == Y; A(4) = true; B(5) = (X*2) == (Y*2); A(5) = true; Y(6,6) = 10; B(6) = X == Y; A(6) = false; B(7) = (X*2) == (Y*2); A(7) = false; B(8) = U == Y; A(8) = false; B(9) = U == U; A(9) = true; Matrix Z = X.SubMatrix(1,2,2,3); B(10) = X == Z; A(10) = false; GenericMatrix GU = U; GenericMatrix GX = X; GenericMatrix GY = Y; B(11) = GU == GX; A(11) = true; B(12) = GU == GY; A(12) = false; X = X + X.t(); U = U + U.t(); SymmetricBandMatrix S(6,2); S.Inject(X); Matrix D = S-X; Print(D); BandLUMatrix BS = S; BandLUMatrix BX = X; BandLUMatrix BU = U; CroutMatrix CX = X; B(13) = BS == BX; A(13) = true; B(14) = BX == BU; A(14) = false; B(15) = X == BX; A(15) = false; B(16) = X != BX; A(16) = true; B(17) = BX != BS; A(17) = false; B(18) = (2*X) != (X*2);A(18) = false; B(19) = (X*2) != (X+2);A(19) = true; B(20) = BX == CX; A(20) = false; B(21) = CX == BX; A(21) = false; B(22) = BX == X; A(22) = false; A = A - B; Print(A); DiagonalMatrix I(6); I=1.0; D = BS.i() * X - I; Clean(D,0.00000001); Print(D); D = BX.i() * X - I; Clean(D,0.00000001); Print(D); D = BU.i() * X - I; Clean(D,0.00000001); Print(D); // test row wise load SymmetricBandMatrix X1(6,2); X1.Row(1) << 23; X1.Row(2) << 12 << 17; X1.Row(3) << 35 << 19 << 24; X1.Row(4) << 17 << 11 << 19; X1.Row(5) << 10 << 44 << 23; X1.Row(6) << 49 << 41 << 17; Matrix M = X1 - S1; Print(M); // check out submatrix SymmetricBandMatrix X2(20,3); X2 = 0.0; X2.SubMatrix(2,7,2,7) = X1; X2.SymSubMatrix(11,16) = 2 * X1; Matrix MX1 = X1; Matrix MX2(20,20); MX2 = 0; MX2.SymSubMatrix(2,7) = MX1; MX2.SubMatrix(11,16,11,16) = MX1 * 2; MX2 -= X2; Print(MX2); BandMatrix X4(20,3,3); X4 = 0.0; X4.SubMatrix(2,7,3,8) = X1; X4.SubMatrix(11,16,10,15) = 2 * X1; MX1 = X1; Matrix MX4(20,20); MX4 = 0; MX4.SubMatrix(2,7,3,8) = MX1; MX4.SubMatrix(11,16,10,15) = MX1 * 2; MX4 -= X4; Print(MX4); MX1 = X1.i() * X1 - IdentityMatrix(6); Clean(MX1,0.00000001); Print(MX1); } { Tracer et1("Stage 7"); // testing equal ColumnVector A(12), B(12); BandMatrix X(6,2,1); X(1,1)=23; X(1,2)=21; X(2,1)=12; X(2,2)=17; X(2,3)=45; X(3,1)=35; X(3,2)=19; X(3,3)=24; X(3,4)=29; X(4,2)=17; X(4,3)=11; X(4,4)=19; X(4,5)=35; X(5,3)=10; X(5,4)=44; X(5,5)=23; X(5,6)=31; X(6,4)=49; X(6,5)=41; X(6,6)=17; Matrix Y = X; LinearEquationSolver LX = X; LinearEquationSolver LY = Y; CroutMatrix CX = X; CroutMatrix CY = Y; BandLUMatrix BX = X; B(1) = LX == CX; A(1) = false; B(2) = LY == CY; A(2) = true; B(3) = X == Y; A(3) = true; B(4) = BX == LX; A(4) = true; B(5) = CX == CY; A(5) = true; B(6) = LX == LY; A(6) = false; B(7) = BX == BX; A(7) = true; B(8) = CX == CX; A(8) = true; B(9) = LX == LX; A(9) = true; B(10) = LY == LY; A(10) = true; CroutMatrix CX1 = X.SubMatrix(1,4,1,4); B(11) = CX == CX1; A(11) = false; BandLUMatrix BX1 = X.SymSubMatrix(1,4); // error with SubMatrix B(12) = BX == BX1; A(12) = false; A = A - B; Print(A); DiagonalMatrix I(6); I=1.0; Matrix D; D = LX.i() * X - I; Clean(D,0.00000001); Print(D); D = LY.i() * X - I; Clean(D,0.00000001); Print(D); I.ReSize(4); I = 1; D = CX1.i() * X.SymSubMatrix(1,4) - I; Clean(D,0.00000001); Print(D); D = BX1.i() * X.SubMatrix(1,4,1,4) - I; Clean(D,0.00000001); Print(D); } { Tracer et1("Stage 8"); // test copying CroutMatrix and BandLUMatrix - see also tmtd.cpp MultWithCarry MWC; SymmetricBandMatrix SBM(50, 10); for (int i = 1; i <= 50; ++i) for (int j = 1; j <= i; ++j) if (i - j <= 10) SBM(i, j) = MWC.Next(); CroutMatrix CM = SBM; BandLUMatrix BM = SBM; CroutMatrix CM1 = CM; BandLUMatrix BM1; BM1 = BM; CM1.release(); BM1.release(); CroutMatrix CM2; CM2 = CM1; BandLUMatrix BM2 = BM1; Matrix X = SBM.i(); Matrix Y = CM2.i() - X; Matrix Z = BM2.i() - X; Clean(Y,0.00000001); Print(Y); Clean(Z,0.00000001); Print(Z); X *= SBM; X -= IdentityMatrix(50); Clean(X,0.00000001); Print(X); LogAndSign x = log_determinant(SBM); LogAndSign y = log_determinant(CM2); LogAndSign z = log_determinant(BM2); RowVector D(4); D(1) = y.value() - x.value(); D(2) = z.value() - x.value(); D(3) = y.sign() - x.sign(); D(4) = z.sign() - x.sign(); Clean(D,0.00000001); Print(D); } { Tracer et1("Stage 9"); // do it again odd matrix size MultWithCarry MWC; SymmetricBandMatrix SBM(51, 10); for (int i = 1; i <= 51; ++i) for (int j = 1; j <= i; ++j) if (i - j <= 10) SBM(i, j) = MWC.Next(); CroutMatrix CM = SBM; BandLUMatrix BM = SBM; CroutMatrix CM1 = CM; BandLUMatrix BM1; BM1 = BM; CM1.release(); BM1.release(); CroutMatrix CM2; CM2 = CM1; BandLUMatrix BM2 = BM1; Matrix X = SBM.i(); Matrix Y = CM2.i() - X; Matrix Z = BM2.i() - X; Clean(Y,0.00000001); Print(Y); Clean(Z,0.00000001); Print(Z); X *= SBM; X -= IdentityMatrix(51); Clean(X,0.00000001); Print(X); LogAndSign x = log_determinant(SBM); LogAndSign y = log_determinant(CM2); LogAndSign z = log_determinant(BM2); RowVector D(4); D(1) = y.value() - x.value(); D(2) = z.value() - x.value(); D(3) = y.sign() - x.sign(); D(4) = z.sign() - x.sign(); Clean(D,0.00000001); Print(D); } // cout << "\nEnd of ninth test\n"; }
void AssembleMatrixResNS(MultiLevelProblem &ml_prob){ //pointers NonLinearImplicitSystem& my_nnlin_impl_sys = ml_prob.get_system<NonLinearImplicitSystem>("Navier-Stokes"); const unsigned level = my_nnlin_impl_sys.GetLevelToAssemble(); const unsigned gridn = my_nnlin_impl_sys.GetLevelMax(); bool assemble_matrix = my_nnlin_impl_sys.GetAssembleMatrix(); Solution* mysolution = ml_prob._ml_sol->GetSolutionLevel(level); LinearEquationSolver* mylsyspde = my_nnlin_impl_sys._LinSolver[level]; const char* pdename = my_nnlin_impl_sys.name().c_str(); MultiLevelSolution* ml_sol=ml_prob._ml_sol; Mesh* mymsh = ml_prob._ml_msh->GetLevel(level); elem* myel = mymsh->el; SparseMatrix* myKK = mylsyspde->_KK; NumericVector* myRES = mylsyspde->_RES; //data const unsigned dim = mymsh->GetDimension(); unsigned nel= mymsh->GetNumberOfElements(); unsigned igrid= mymsh->GetLevel(); unsigned iproc = mymsh->processor_id(); double ILambda= 0; double IRe = ml_prob.parameters.get<Fluid>("Fluid").get_IReynolds_number(); bool penalty = true; //mylsyspde->GetStabilization(); const bool symm_mat = false;//mylsyspde->GetMatrixProperties(); const bool NavierStokes = true; unsigned nwtn_alg = 2; bool newton = (nwtn_alg==0) ? 0:1; // solution and coordinate variables const char Solname[4][2] = {"U","V","W","P"}; vector < unsigned > SolPdeIndex(dim+1); vector < unsigned > SolIndex(dim+1); //const char coordinate_name[3][2] = {"X","Y","Z"}; //vector < unsigned > coordinate_Index(dim); vector< vector < double> > coordinates(dim); for(unsigned ivar=0; ivar<dim; ivar++) { SolPdeIndex[ivar]=my_nnlin_impl_sys.GetSolPdeIndex(&Solname[ivar][0]); SolIndex[ivar]=ml_sol->GetIndex(&Solname[ivar][0]); //coordinate_Index[ivar]=ivar;//ml_prob.GetIndex(&coordinate_name[ivar][0]); } SolPdeIndex[dim]=my_nnlin_impl_sys.GetSolPdeIndex(&Solname[3][0]); SolIndex[dim]=ml_sol->GetIndex(&Solname[3][0]); //solution order unsigned order_ind2 = ml_sol->GetSolutionType(SolIndex[0]); unsigned order_ind1 = ml_sol->GetSolutionType(SolIndex[dim]); // declare vector < int > metis_node2; vector < int > node1; vector< vector< int > > KK_dof(dim+1); vector <double> phi2; vector <double> gradphi2; vector <double> nablaphi2; const double *phi1; double Weight2; double normal[3]; vector< vector< double > > F(dim+1); vector< vector< vector< double > > > B(dim+1); // reserve const unsigned max_size = static_cast< unsigned > (ceil(pow(3,dim))); metis_node2.reserve(max_size); node1.reserve( static_cast< unsigned > (ceil(pow(2,dim)))); for(int i=0;i<dim;i++) { coordinates[i].reserve(max_size); } phi2.reserve(max_size); gradphi2.reserve(max_size*dim); nablaphi2.reserve(max_size*(3*(dim-1)) ); for(int i=0;i<dim;i++) { KK_dof[i].reserve(max_size); } for(int i=0;i<dim+1;i++) F[i].reserve(max_size); if(assemble_matrix){ for(int i=0;i<dim+1;i++){ B[i].resize(dim+1); for(int j=0;j<dim+1;j++){ B[i][j].reserve(max_size*max_size); } } } vector < double > SolVAR(dim+1); vector < vector < double > > gradSolVAR(dim); for(int i=0;i<dim;i++) { gradSolVAR[i].resize(dim); } // Set to zeto all the entries of the matrix if(assemble_matrix) myKK->zero(); // *** 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 nve2=myel->GetElementDofNumber(kel,order_ind2); unsigned nve1=myel->GetElementDofNumber(kel,order_ind1); //set to zero all the entries of the FE matrices metis_node2.resize(nve2); node1.resize(nve1); phi2.resize(nve2); gradphi2.resize(nve2*dim); nablaphi2.resize(nve2*(3*(dim-1)) ); for(int ivar=0; ivar<dim; ivar++) { coordinates[ivar].resize(nve2); KK_dof[ivar].resize(nve2); F[SolPdeIndex[ivar]].resize(nve2); memset(&F[SolPdeIndex[ivar]][0],0,nve2*sizeof(double)); if(assemble_matrix){ B[SolPdeIndex[ivar]][SolPdeIndex[ivar]].resize(nve2*nve2); B[SolPdeIndex[ivar]][SolPdeIndex[dim]].resize(nve2*nve1); B[SolPdeIndex[dim]][SolPdeIndex[ivar]].resize(nve1*nve2); memset(&B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][0],0,nve2*nve2*sizeof(double)); memset(&B[SolPdeIndex[ivar]][SolPdeIndex[dim]][0],0,nve2*nve1*sizeof(double)); memset(&B[SolPdeIndex[dim]][SolPdeIndex[ivar]][0],0,nve1*nve2*sizeof(double)); } } KK_dof[dim].resize(nve1); F[SolPdeIndex[dim]].resize(nve1); memset(&F[SolPdeIndex[dim]][0],0,nve1*sizeof(double)); if(assemble_matrix*nwtn_alg==2){ for(int ivar=0; ivar<dim; ivar++) { for(int ivar2=1; ivar2<dim; ivar2++) { B[SolPdeIndex[ivar]][SolPdeIndex[(ivar+ivar2)%dim]].resize(nve2*nve2); memset(&B[SolPdeIndex[ivar]][SolPdeIndex[(ivar+ivar2)%dim]][0],0,nve2*nve2*sizeof(double)); } } } if(assemble_matrix*penalty){ B[SolPdeIndex[dim]][SolPdeIndex[dim]].resize(nve1*nve1,0.); memset(&B[SolPdeIndex[dim]][SolPdeIndex[dim]][0],0,nve1*nve1*sizeof(double)); } for( unsigned i=0;i<nve2;i++){ unsigned inode=myel->GetElementVertexIndex(kel,i)-1u; unsigned inode_metis=mymsh->GetMetisDof(inode,2); metis_node2[i]=inode_metis; for(unsigned ivar=0; ivar<dim; ivar++) { coordinates[ivar][i]=(*mymsh->_coordinate->_Sol[ivar])(inode_metis); KK_dof[ivar][i]=mylsyspde->GetKKDof(SolIndex[ivar],SolPdeIndex[ivar],inode); } } for(unsigned i=0;i<nve1;i++) { unsigned inode=(order_ind1<3)?(myel->GetElementVertexIndex(kel,i)-1u):(kel+i*nel); node1[i]=inode; KK_dof[dim][i]=mylsyspde->GetKKDof(SolIndex[dim],SolPdeIndex[dim],inode); } if(igrid==gridn || !myel->GetRefinedElementIndex(kel)) { // *** Gauss poit loop *** for(unsigned ig=0;ig < ml_prob._ml_msh->_finiteElement[kelt][order_ind2]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** ml_prob._ml_msh->_finiteElement[kelt][order_ind2]->Jacobian(coordinates,ig,Weight2,phi2,gradphi2,nablaphi2); phi1=ml_prob._ml_msh->_finiteElement[kelt][order_ind1]->GetPhi(ig); //velocity variable for(unsigned ivar=0; ivar<dim; ivar++) { SolVAR[ivar]=0; for(unsigned ivar2=0; ivar2<dim; ivar2++){ gradSolVAR[ivar][ivar2]=0; } unsigned SolIndex=ml_sol->GetIndex(&Solname[ivar][0]); unsigned SolType=ml_sol->GetSolutionType(&Solname[ivar][0]); for(unsigned i=0; i<nve2; i++) { double soli = (*mysolution->_Sol[SolIndex])(metis_node2[i]); SolVAR[ivar]+=phi2[i]*soli; for(unsigned ivar2=0; ivar2<dim; ivar2++){ gradSolVAR[ivar][ivar2] += gradphi2[i*dim+ivar2]*soli; } } } //pressure variable SolVAR[dim]=0; unsigned SolIndex=ml_sol->GetIndex(&Solname[3][0]); unsigned SolType=ml_sol->GetSolutionType(&Solname[3][0]); for(unsigned i=0; i<nve1; i++){ unsigned sol_dof = mymsh->GetMetisDof(node1[i],SolType); double soli = (*mysolution->_Sol[SolIndex])(sol_dof); SolVAR[dim]+=phi1[i]*soli; } // *** phi_i loop *** for(unsigned i=0; i<nve2; i++){ //BEGIN RESIDUALS A block =========================== for(unsigned ivar=0; ivar<dim; ivar++) { double Adv_rhs=0; double Lap_rhs=0; for(unsigned ivar2=0; ivar2<dim; ivar2++) { Lap_rhs += gradphi2[i*dim+ivar2]*gradSolVAR[ivar][ivar2]; Adv_rhs += SolVAR[ivar2]*gradSolVAR[ivar][ivar2]; } F[SolPdeIndex[ivar]][i]+= (-IRe*Lap_rhs-NavierStokes*Adv_rhs*phi2[i]+SolVAR[dim]*gradphi2[i*dim+ivar])*Weight2; } //END RESIDUALS A block =========================== if(assemble_matrix){ // *** phi_j loop *** for(unsigned j=0; j<nve2; j++) { double Lap=0; double Adv1=0; double Adv2 = phi2[i]*phi2[j]*Weight2; for(unsigned ivar=0; ivar<dim; ivar++) { // Laplacian Lap += gradphi2[i*dim+ivar]*gradphi2[j*dim+ivar]*Weight2; // advection term I Adv1 += SolVAR[ivar]*gradphi2[j*dim+ivar]*phi2[i]*Weight2; } for(unsigned ivar=0; ivar<dim; ivar++) { B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][i*nve2+j] += IRe*Lap+ NavierStokes*newton*Adv1; if(nwtn_alg==2){ // Advection term II B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][i*nve2+j] += Adv2*gradSolVAR[ivar][ivar]; for(unsigned ivar2=1; ivar2<dim; ivar2++) { B[SolPdeIndex[ivar]][SolPdeIndex[(ivar+ivar2)%dim]][i*nve2+j] += Adv2*gradSolVAR[ivar][(ivar+ivar2)%dim]; } } } } //end phij loop // *** phi1_j loop *** for(unsigned j=0; j<nve1; j++){ for(unsigned ivar=0; ivar<dim; ivar++) { B[SolPdeIndex[ivar]][SolPdeIndex[dim]][i*nve1+j] -= gradphi2[i*dim+ivar]*phi1[j]*Weight2; } } //end phi1_j loop } // endif assemble_matrix } //end phii loop // *** phi1_i loop *** for(unsigned i=0; i<nve1; i++){ //BEGIN RESIDUALS B block =========================== double div = 0; for(unsigned ivar=0; ivar<dim; ivar++) { div += gradSolVAR[ivar][ivar]; } F[SolPdeIndex[dim]][i]+= (phi1[i]*div +penalty*ILambda*phi1[i]*SolVAR[dim])*Weight2; //END RESIDUALS B block =========================== if(assemble_matrix){ // *** phi_j loop *** for(unsigned j=0; j<nve2; j++) { for(unsigned ivar=0; ivar<dim; ivar++) { B[SolPdeIndex[dim]][SolPdeIndex[ivar]][i*nve2+j]-= phi1[i]*gradphi2[j*dim+ivar]*Weight2; } } //end phij loop } // endif assemble_matrix } //end phi1_i loop if(assemble_matrix * penalty){ //block nve1 nve1 // *** phi_i loop *** for(unsigned i=0; i<nve1; i++){ // *** phi_j loop *** for(unsigned j=0; j<nve1; j++){ B[SolPdeIndex[dim]][SolPdeIndex[dim]][i*nve1+j]-= ILambda*phi1[i]*phi1[j]*Weight2; } } } //end if penalty } // end gauss point loop //-------------------------------------------------------------------------------------------------------- // Boundary Integral --> to be addded //number of faces for each type of element // if (igrid==gridn || !myel->GetRefinedElementIndex(kel) ) { // // unsigned nfaces = myel->GetElementFaceNumber(kel); // // // loop on faces // for(unsigned jface=0;jface<nfaces;jface++){ // // // look for boundary faces // if(myel->GetFaceElementIndex(kel,jface)<0){ // for(unsigned ivar=0; ivar<dim; ivar++) { // ml_prob.ComputeBdIntegral(pdename, &Solname[ivar][0], kel, jface, level, ivar); // } // } // } // } //-------------------------------------------------------------------------------------------------------- } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- //Sum the local matrices/vectors into the Global Matrix/Vector for(unsigned ivar=0; ivar<dim; ivar++) { myRES->add_vector_blocked(F[SolPdeIndex[ivar]],KK_dof[ivar]); if(assemble_matrix){ myKK->add_matrix_blocked(B[SolPdeIndex[ivar]][SolPdeIndex[ivar]],KK_dof[ivar],KK_dof[ivar]); myKK->add_matrix_blocked(B[SolPdeIndex[ivar]][SolPdeIndex[dim]],KK_dof[ivar],KK_dof[dim]); myKK->add_matrix_blocked(B[SolPdeIndex[dim]][SolPdeIndex[ivar]],KK_dof[dim],KK_dof[ivar]); if(nwtn_alg==2){ for(unsigned ivar2=1; ivar2<dim; ivar2++) { myKK->add_matrix_blocked(B[SolPdeIndex[ivar]][SolPdeIndex[(ivar+ivar2)%dim]],KK_dof[ivar],KK_dof[(ivar+ivar2)%dim]); } } } } //Penalty if(assemble_matrix*penalty) myKK->add_matrix_blocked(B[SolPdeIndex[dim]][SolPdeIndex[dim]],KK_dof[dim],KK_dof[dim]); myRES->add_vector_blocked(F[SolPdeIndex[dim]],KK_dof[dim]); //-------------------------------------------------------------------------------------------------------- } //end list of elements loop for each subdomain if(assemble_matrix) myKK->close(); myRES->close(); // ***************** END ASSEMBLY ******************* }
void AssembleProblem(MultiLevelProblem& ml_prob) { // ************** J dx = f - J x_old ****************** // 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 NonLinearImplicitSystemWithPrimalDualActiveSetMethod* mlPdeSys = &ml_prob.get_system<NonLinearImplicitSystemWithPrimalDualActiveSetMethod> ("OptSys"); const unsigned level = mlPdeSys->GetLevelToAssemble(); const bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); MultiLevelSolution* ml_sol = ml_prob._ml_sol; Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; SparseMatrix* KK = pdeSys->_KK; NumericVector* RES = pdeSys->_RES; const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem const 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 max_size = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 const unsigned iproc = msh->processor_id(); //************** geometry (at dofs) ************************************* vector < vector < double > > coords_at_dofs(dim); vector < unsigned int > SolFEType_domain(dim); for (unsigned d = 0; d < dim; d++) SolFEType_domain[d] = BIQUADR_FE; for (unsigned i = 0; i < coords_at_dofs.size(); i++) coords_at_dofs[i].reserve(max_size); //************** geometry (at quadrature points) ************************************* vector < double > coord_at_qp(dim); //************** geometry phi ************************** vector < vector < double > > phi_fe_qp_domain(dim); vector < vector < double > > phi_x_fe_qp_domain(dim); vector < vector < double > > phi_xx_fe_qp_domain(dim); for(int fe = 0; fe < dim; fe++) { phi_fe_qp_domain[fe].reserve(max_size); phi_x_fe_qp_domain[fe].reserve(max_size * dim); phi_xx_fe_qp_domain[fe].reserve(max_size * dim2); } //*************************************************** //********* WHOLE SET OF VARIABLES ****************** //*************************************************** const unsigned int n_unknowns = mlPdeSys->GetSolPdeIndex().size(); enum Sol_pos{pos_state = 0, pos_ctrl, pos_adj, pos_mu}; //these are known at compile-time //right now this is the same as Sol_pos = SolPdeIndex, but now I want to have flexible rows and columns // the ROW index corresponds to the EQUATION we want to solve // the COLUMN index corresponds to the column variables // Now, first of all we have to make sure that the Sparsity pattern is correctly built... // This means that we should write the Sparsity pattern with COLUMNS independent of ROWS! // But that implies that the BOUNDARY CONDITIONS will be enforced in OFF-DIAGONAL BLOCKS! // In fact, having the row order be different from the column order implies that the diagonal blocks would be RECTANGULAR. // Although this is in principle possible, I would avoid doing that for now. // const unsigned int pos_state = mlPdeSys->GetSolPdeIndex("state"); //these are known at run-time, so they are slower // const unsigned int pos_ctrl = mlPdeSys->GetSolPdeIndex("control"); //these are known at run-time, so they are slower // const unsigned int pos_adj = mlPdeSys->GetSolPdeIndex("adjoint"); //these are known at run-time, so they are slower // const unsigned int pos_mu = mlPdeSys->GetSolPdeIndex("mu"); //these are known at run-time, so they are slower assert(pos_state == mlPdeSys->GetSolPdeIndex("state")); assert(pos_ctrl == mlPdeSys->GetSolPdeIndex("control")); assert(pos_adj == mlPdeSys->GetSolPdeIndex("adjoint")); assert(pos_mu == mlPdeSys->GetSolPdeIndex("mu")); //*************************************************** const int solFEType_max = BIQUADR_FE; //biquadratic vector < std::string > Solname(n_unknowns); Solname[pos_state] = "state"; Solname[pos_ctrl] = "control"; Solname[pos_adj] = "adjoint"; Solname[pos_mu] = "mu"; //*************************************************** vector < unsigned int > SolPdeIndex(n_unknowns); //index as in the row/column of the matrix (diagonal blocks are square) vector < unsigned int > SolIndex(n_unknowns); //index as in the MultilevelSolution vector vector < unsigned int > SolFEType(n_unknowns); //FEtype of each MultilevelSolution vector < unsigned int > Sol_n_el_dofs(n_unknowns); //number of element dofs std::fill(Sol_n_el_dofs.begin(), Sol_n_el_dofs.end(), 0); for(unsigned ivar=0; ivar < n_unknowns; ivar++) { SolPdeIndex[ivar] = mlPdeSys->GetSolPdeIndex( Solname[ivar].c_str() ); assert(ivar == SolPdeIndex[ivar]); SolIndex[ivar] = ml_sol->GetIndex ( Solname[ivar].c_str() ); SolFEType[ivar] = ml_sol->GetSolutionType ( SolIndex[ivar]); } //************* shape functions (at dofs and quadrature points) ************************************** double weight_qp; vector < vector < double > > phi_fe_qp(n_unknowns); vector < vector < double > > phi_x_fe_qp(n_unknowns); vector < vector < double > > phi_xx_fe_qp(n_unknowns); vector < vector < vector < double > > > phi_x_fe_qp_vec(n_unknowns); for(int fe = 0; fe < n_unknowns; fe++) { phi_fe_qp[fe].reserve(max_size); phi_x_fe_qp[fe].reserve(max_size * dim); phi_xx_fe_qp[fe].reserve(max_size * dim2); phi_x_fe_qp_vec[fe].resize(dim); for(int d = 0; d < dim; d++) { phi_x_fe_qp_vec[fe][d].reserve(max_size); } } //----------- quantities (at dof objects) ------------------------------ vector < vector < double > > sol_eldofs(n_unknowns); for(int k=0; k<n_unknowns; k++) sol_eldofs[k].reserve(max_size); //************** act flag (at dof objects) **************************** std::string act_flag_name = "act_flag"; unsigned int solIndex_act_flag = ml_sol->GetIndex(act_flag_name.c_str()); unsigned int solFEType_act_flag = ml_sol->GetSolutionType(solIndex_act_flag); if(sol->GetSolutionTimeOrder(solIndex_act_flag) == 2) { *(sol->_SolOld[solIndex_act_flag]) = *(sol->_Sol[solIndex_act_flag]); } //********* variables for ineq constraints (at dof objects) ***************** const int ineq_flag = INEQ_FLAG; const double c_compl = C_COMPL; vector < double/*int*/ > sol_actflag; sol_actflag.reserve(max_size); //flag for active set vector < double > ctrl_lower; ctrl_lower.reserve(max_size); vector < double > ctrl_upper; ctrl_upper.reserve(max_size); //------------ quantities (at quadrature points) --------------------- vector<double> sol_qp(n_unknowns); vector< vector<double> > sol_grad_qp(n_unknowns); std::fill(sol_qp.begin(), sol_qp.end(), 0.); for (unsigned k = 0; k < n_unknowns; k++) { sol_grad_qp[k].resize(dim); std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); } //******* EQUATION RELATED STUFF ******************************************** int m_b_f[n_unknowns][n_unknowns]; m_b_f[pos_state][pos_state] = 1; //nonzero m_b_f[pos_state][pos_ctrl] = 0; //THIS IS ZERO IN NON-LIFTING APPROACHES (there are also pieces that go on top on blocks that are already meant to be different from zero) m_b_f[pos_state][pos_adj] = 1; //nonzero m_b_f[pos_state][pos_mu] = 0; //this is zero without state constraints m_b_f[pos_ctrl][pos_state] = 0;//THIS IS ZERO IN NON-LIFTING APPROACHES m_b_f[pos_ctrl][pos_ctrl] = 1;//nonzero m_b_f[pos_ctrl][pos_adj] = 1;//nonzero m_b_f[pos_ctrl][pos_mu] = 1;//nonzero m_b_f[pos_adj][pos_state] = 1; //nonzero m_b_f[pos_adj][pos_ctrl] = 1; //nonzero m_b_f[pos_adj][pos_adj] = 0; //this must always be zero m_b_f[pos_adj][pos_mu] = 0; //this must always be zero m_b_f[pos_mu][pos_state] = 0; //this is zero without state constraints m_b_f[pos_mu][pos_ctrl] = 1; //nonzero m_b_f[pos_mu][pos_adj] = 0; //this must always be zero m_b_f[pos_mu][pos_mu] = 1; //nonzero //*************************************************** vector < vector < int > > L2G_dofmap(n_unknowns); for(int i = 0; i < n_unknowns; i++) { L2G_dofmap[i].reserve(max_size); } vector< int > L2G_dofmap_AllVars; L2G_dofmap_AllVars.reserve( n_unknowns*max_size ); vector< double > Res; Res.reserve( n_unknowns*max_size ); vector< double > Jac; Jac.reserve( n_unknowns*max_size * n_unknowns*max_size); //*************************************************** //********************* DATA ************************ double alpha = ALPHA_CTRL_VOL; double beta = BETA_CTRL_VOL; double penalty_strong = 10e+14; //*************************************************** RES->zero(); if (assembleMatrix) KK->zero(); // element loop: each process loops only on the elements that it owns for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { short unsigned ielGeom = msh->GetElementType(iel); // element geometry type //******************** GEOMETRY ********************* for (unsigned jdim = 0; jdim < dim; jdim++) { unsigned nDofx = msh->GetElementDofNumber(iel, SolFEType_domain[jdim]); coords_at_dofs[jdim].resize(nDofx); // local storage of coordinates for (unsigned i = 0; i < coords_at_dofs[jdim].size(); i++) { unsigned xDof = msh->GetSolutionDof(i, iel, SolFEType_domain[jdim]); // global to global mapping between coordinates node and coordinate dof coords_at_dofs[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } // elem average point vector < double > elem_center(dim); for (unsigned j = 0; j < dim; j++) { elem_center[j] = 0.; } for (unsigned j = 0; j < dim; j++) { for (unsigned i = 0; i < coords_at_dofs[j].size(); i++) { elem_center[j] += coords_at_dofs[j][i]; } } for (unsigned j = 0; j < dim; j++) { elem_center[j] = elem_center[j]/coords_at_dofs[j].size(); } //*************************************************** //****** set target domain flag ********************* int target_flag = 0; target_flag = ElementTargetFlag(elem_center); //*************************************************** //all vars################################################################### for (unsigned k = 0; k < n_unknowns; k++) { unsigned ndofs_unk = msh->GetElementDofNumber(iel, SolFEType[k]); Sol_n_el_dofs[k] = ndofs_unk; sol_eldofs[k].resize(ndofs_unk); L2G_dofmap[k].resize(ndofs_unk); for (unsigned i = 0; i < ndofs_unk; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, SolFEType[k]); // global to global mapping between solution node and solution dof // via local to global solution node sol_eldofs[k][i] = (*sol->_Sol[SolIndex[k]])(solDof); // global extraction and local storage for the solution L2G_dofmap[k][i] = pdeSys->GetSystemDof(SolIndex[k], SolPdeIndex[k], i, iel); // global to global mapping between solution node and pdeSys dof } } //all vars################################################################### for (unsigned k = 0; k < n_unknowns; k++) { for(int d = 0; d < dim; d++) { phi_x_fe_qp_vec[k][d].resize(Sol_n_el_dofs[k]); } } //************** update active set flag for current nonlinear iteration **************************** // 0: inactive; 1: active_a; 2: active_b assert(Sol_n_el_dofs[pos_mu] == Sol_n_el_dofs[pos_ctrl]); sol_actflag.resize(Sol_n_el_dofs[pos_mu]); ctrl_lower.resize(Sol_n_el_dofs[pos_mu]); ctrl_upper.resize(Sol_n_el_dofs[pos_mu]); std::fill(sol_actflag.begin(), sol_actflag.end(), 0); std::fill(ctrl_lower.begin(), ctrl_lower.end(), 0.); std::fill(ctrl_upper.begin(), ctrl_upper.end(), 0.); for (unsigned i = 0; i < sol_actflag.size(); i++) { std::vector<double> node_coords_i(dim,0.); for (unsigned d = 0; d < dim; d++) node_coords_i[d] = coords_at_dofs[d][i]; ctrl_lower[i] = InequalityConstraint(node_coords_i,false); ctrl_upper[i] = InequalityConstraint(node_coords_i,true); if ( (sol_eldofs[pos_mu][i] + c_compl * (sol_eldofs[pos_ctrl][i] - ctrl_lower[i] )) < 0 ) sol_actflag[i] = 1; else if ( (sol_eldofs[pos_mu][i] + c_compl * (sol_eldofs[pos_ctrl][i] - ctrl_upper[i] )) > 0 ) sol_actflag[i] = 2; } //************** act flag **************************** unsigned nDof_act_flag = msh->GetElementDofNumber(iel, solFEType_act_flag); // number of solution element dofs for (unsigned i = 0; i < nDof_act_flag; i++) { unsigned solDof_mu = msh->GetSolutionDof(i, iel, solFEType_act_flag); (sol->_Sol[solIndex_act_flag])->set(solDof_mu,sol_actflag[i]); } //******************** ALL VARS ********************* unsigned nDof_AllVars = 0; for (unsigned k = 0; k < n_unknowns; k++) { nDof_AllVars += Sol_n_el_dofs[k]; } // TODO COMPUTE MAXIMUM maximum number of element dofs for one scalar variable int nDof_max = 0; for (unsigned k = 0; k < n_unknowns; k++) { if(Sol_n_el_dofs[k] > nDof_max) nDof_max = Sol_n_el_dofs[k]; } Res.resize(nDof_AllVars); std::fill(Res.begin(), Res.end(), 0.); Jac.resize(nDof_AllVars * nDof_AllVars); std::fill(Jac.begin(), Jac.end(), 0.); L2G_dofmap_AllVars.resize(0); for (unsigned k = 0; k < n_unknowns; k++) L2G_dofmap_AllVars.insert(L2G_dofmap_AllVars.end(),L2G_dofmap[k].begin(),L2G_dofmap[k].end()); //*************************************************** //***** set control flag **************************** int control_el_flag = 0; control_el_flag = ControlDomainFlag_internal_restriction(elem_center); std::vector<int> control_node_flag(Sol_n_el_dofs[pos_ctrl],0); if (control_el_flag == 1) std::fill(control_node_flag.begin(), control_node_flag.end(), 1); //*************************************************** // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solFEType_max]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** for(unsigned int k = 0; k < n_unknowns; k++) { msh->_finiteElement[ielGeom][SolFEType[k]]->Jacobian(coords_at_dofs, ig, weight_qp, phi_fe_qp[k], phi_x_fe_qp[k], phi_xx_fe_qp[k]); } for (unsigned k = 0; k < n_unknowns; k++) { for(unsigned int d = 0; d < dim; d++) { for(unsigned int i = 0; i < Sol_n_el_dofs[k]; i++) { phi_x_fe_qp_vec[k][d][i] = phi_x_fe_qp[k][i * dim + d]; } } } //HAVE TO RECALL IT TO HAVE BIQUADRATIC JACOBIAN for (unsigned int d = 0; d < dim; d++) { msh->_finiteElement[ielGeom][SolFEType_domain[d]]->Jacobian(coords_at_dofs, ig, weight_qp, phi_fe_qp_domain[d], phi_x_fe_qp_domain[d], phi_xx_fe_qp_domain[d]); } //========= fill gauss value xyz ================== std::fill(coord_at_qp.begin(), coord_at_qp.end(), 0.); for (unsigned d = 0; d < dim; d++) { for (unsigned i = 0; i < coords_at_dofs[d].size(); i++) { coord_at_qp[d] += coords_at_dofs[d][i] * phi_fe_qp_domain[d][i]; } } //========= fill gauss value xyz ================== //========= fill gauss value quantities ================== std::fill(sol_qp.begin(), sol_qp.end(), 0.); for (unsigned k = 0; k < n_unknowns; k++) { std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); } for (unsigned k = 0; k < n_unknowns; k++) { for (unsigned i = 0; i < Sol_n_el_dofs[k]; i++) { sol_qp[k] += sol_eldofs[k][i] * phi_fe_qp[k][i]; for (unsigned d = 0; d < dim; d++) sol_grad_qp[k][d] += sol_eldofs[k][i] * phi_x_fe_qp[k][i * dim + d]; } } //========= fill gauss value quantities ================== //==========FILLING THE EQUATIONS =========== for (unsigned i = 0; i < nDof_max; i++) { //======================Residuals======================= // =============== Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_state,i) ] += - weight_qp * (target_flag * phi_fe_qp[pos_state][i] * ( m_b_f[pos_state][pos_state] * sol_qp[pos_state] - DesiredTarget(coord_at_qp) ) + m_b_f[pos_state][pos_adj] * ( assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_state, pos_adj, i, dim) - sol_qp[pos_adj] * nonlin_term_derivative(phi_fe_qp[pos_state][i]) * sol_qp[pos_ctrl]) ); // ============== if ( control_el_flag == 1) Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_ctrl,i) ] += /*(control_node_flag[i]) **/ - weight_qp * ( + m_b_f[pos_ctrl][pos_ctrl] * alpha * phi_fe_qp[pos_ctrl][i] * sol_qp[pos_ctrl] + m_b_f[pos_ctrl][pos_ctrl] * beta * assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_ctrl, pos_ctrl, i, dim) - m_b_f[pos_ctrl][pos_adj] * phi_fe_qp[pos_ctrl][i] * sol_qp[pos_adj] * nonlin_term_function(sol_qp[pos_state]) ); else if ( control_el_flag == 0) Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_ctrl,i) ] += /*(1 - control_node_flag[i]) **/ m_b_f[pos_ctrl][pos_ctrl] * (- penalty_strong) * (sol_eldofs[pos_ctrl][i]); // ============= Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_adj,i) ] += - weight_qp * ( + m_b_f[pos_adj][pos_state] * assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_adj, pos_state, i, dim) - m_b_f[pos_adj][pos_ctrl] * phi_fe_qp[pos_adj][i] * sol_qp[pos_ctrl] * nonlin_term_function(sol_qp[pos_state]) ); //======================End Residuals======================= if (assembleMatrix) { // *** phi_j loop *** for (unsigned j = 0; j < nDof_max; j++) { //============ delta_state row ============================ Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_state, pos_state, i, j) ] += m_b_f[pos_state][pos_state] * weight_qp * target_flag * phi_fe_qp[pos_state][j] * phi_fe_qp[pos_state][i]; Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_state, pos_adj, i, j) ] += m_b_f[pos_state][pos_adj] * weight_qp * ( assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_state, pos_adj, i, j, dim) - phi_fe_qp[pos_adj][j] * nonlin_term_derivative(phi_fe_qp[pos_state][i]) * sol_qp[pos_ctrl] ); //=========== delta_control row =========================== if ( control_el_flag == 1) { Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_ctrl, i, j) ] += m_b_f[pos_ctrl][pos_ctrl] * ( control_node_flag[i]) * weight_qp * ( beta * control_el_flag * assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_ctrl, pos_ctrl, i, j, dim) + alpha * control_el_flag * phi_fe_qp[pos_ctrl][i] * phi_fe_qp[pos_ctrl][j] ); Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_adj, i, j) ] += m_b_f[pos_ctrl][pos_adj] * control_node_flag[i] * weight_qp * ( - phi_fe_qp[pos_ctrl][i] * phi_fe_qp[pos_adj][j] * nonlin_term_function(sol_qp[pos_state]) ); } else if ( control_el_flag == 0 && i == j) { Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_ctrl, i, j) ] += m_b_f[pos_ctrl][pos_ctrl] * (1 - control_node_flag[i]) * penalty_strong; } //=========== delta_adjoint row =========================== Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_adj, pos_state, i, j) ] += m_b_f[pos_adj][pos_state] * weight_qp * ( assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_adj, pos_state, i, j, dim) - phi_fe_qp[pos_adj][i] * nonlin_term_derivative(phi_fe_qp[pos_state][j]) * sol_qp[pos_ctrl] ); Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_adj, pos_ctrl, i, j) ] += m_b_f[pos_adj][pos_ctrl] * weight_qp * ( - phi_fe_qp[pos_adj][i] * phi_fe_qp[pos_ctrl][j] * nonlin_term_function(sol_qp[pos_state]) ); } // end phi_j loop } // endif assemble_matrix } // end phi_i loop } // end gauss point loop //std::vector<double> Res_ctrl (Sol_n_el_dofs[pos_ctrl]); std::fill(Res_ctrl.begin(),Res_ctrl.end(), 0.); for (unsigned i = 0; i < sol_eldofs[pos_ctrl].size(); i++) { unsigned n_els_that_node = 1; if ( control_el_flag == 1) { // Res[Sol_n_el_dofs[pos_state] + i] += - ( + n_els_that_node * ineq_flag * sol_eldofs[pos_mu][i] /*- ( 0.4 + sin(M_PI * x[0][i]) * sin(M_PI * x[1][i]) )*/ ); // Res_ctrl[i] = Res[Sol_n_el_dofs[pos_state] + i]; } } //========== end of integral-based part RES->add_vector_blocked(Res, L2G_dofmap_AllVars); if (assembleMatrix) KK->add_matrix_blocked(Jac, L2G_dofmap_AllVars, L2G_dofmap_AllVars); //========== dof-based part, without summation //============= delta_mu row =============================== std::vector<double> Res_mu (Sol_n_el_dofs[pos_mu]); std::fill(Res_mu.begin(),Res_mu.end(), 0.); for (unsigned i = 0; i < sol_actflag.size(); i++) { if (sol_actflag[i] == 0) { //inactive Res_mu [i] = (- ineq_flag) * ( 1. * sol_eldofs[pos_mu][i] ); // Res_mu [i] = Res[res_row_index(Sol_n_el_dofs,pos_mu,i)]; } else if (sol_actflag[i] == 1) { //active_a Res_mu [i] = (- ineq_flag) * c_compl * ( sol_eldofs[pos_ctrl][i] - ctrl_lower[i]); } else if (sol_actflag[i] == 2) { //active_b Res_mu [i] = (- ineq_flag) * c_compl * ( sol_eldofs[pos_ctrl][i] - ctrl_upper[i]); } } RES->insert(Res_mu, L2G_dofmap[pos_mu]); //============= delta_ctrl - mu =============================== KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_ctrl], L2G_dofmap[pos_mu], m_b_f[pos_ctrl][pos_mu] * ineq_flag * 1.); //============= delta_mu - ctrl row =============================== for (unsigned i = 0; i < sol_actflag.size(); i++) if (sol_actflag[i] != 0 ) sol_actflag[i] = m_b_f[pos_mu][pos_ctrl] * ineq_flag * c_compl; KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_mu], L2G_dofmap[pos_ctrl], sol_actflag); //============= delta_mu - mu row =============================== for (unsigned i = 0; i < sol_actflag.size(); i++) sol_actflag[i] = m_b_f[pos_mu][pos_mu] * ( ineq_flag * (1 - sol_actflag[i]/c_compl) + (1-ineq_flag) * 1. ); //can do better to avoid division, maybe use modulo operator KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_mu], L2G_dofmap[pos_mu], sol_actflag ); } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // std::ostringstream mat_out; mat_out << ml_prob.GetFilesHandler()->GetOutputPath() << "/" << "jacobian" << mlPdeSys->GetNonlinearIt() << ".txt"; // KK->print_matlab(mat_out.str(),"ascii"); // KK->print(); // ***************** END ASSEMBLY ******************* unsigned int global_ctrl_size = pdeSys->KKoffset[pos_ctrl+1][iproc] - pdeSys->KKoffset[pos_ctrl][iproc]; std::vector<double> one_times_mu(global_ctrl_size, 0.); std::vector<int> positions(global_ctrl_size); // double position_mu_i; for (unsigned i = 0; i < positions.size(); i++) { positions[i] = pdeSys->KKoffset[pos_ctrl][iproc] + i; // position_mu_i = pdeSys->KKoffset[pos_mu][iproc] + i; // std::cout << position_mu_i << std::endl; one_times_mu[i] = m_b_f[pos_ctrl][pos_mu] * ineq_flag * 1. * (*sol->_Sol[SolIndex[pos_mu]])(i/*position_mu_i*/) ; } RES->add_vector_blocked(one_times_mu, positions); // RES->print(); return; }
//------------------------------------------------------------------------------------------------------------ void AssembleMatrixResT(MultiLevelProblem &ml_prob){ //pointers and references LinearImplicitSystem& mylin_impl_sys = ml_prob.get_system<LinearImplicitSystem>("Temperature"); const unsigned level = mylin_impl_sys.GetLevelToAssemble(); const unsigned gridn = mylin_impl_sys.GetLevelMax(); bool assemble_matrix = mylin_impl_sys.GetAssembleMatrix(); Solution* mysolution = ml_prob._ml_sol->GetSolutionLevel(level); LinearEquationSolver* mylsyspde = mylin_impl_sys._LinSolver[level]; Mesh* mymsh = ml_prob._ml_msh->GetLevel(level); elem* myel = mymsh->el; SparseMatrix* myKK = mylsyspde->_KK; NumericVector* myRES = mylsyspde->_RES; MultiLevelSolution* ml_sol = ml_prob._ml_sol; //data const unsigned dim = mymsh->GetDimension(); unsigned nel = mymsh->GetNumberOfElements(); unsigned igrid = mymsh->GetLevel(); unsigned iproc = mymsh->processor_id(); double IPe = 1./(ml_prob.parameters.get<Fluid>("Fluid").get_Peclet_number()); //solution variable unsigned SolIndex; unsigned SolPdeIndex; SolIndex=ml_sol->GetIndex("T"); SolPdeIndex=mylin_impl_sys.GetSolPdeIndex("T"); //solution order unsigned order_ind = ml_sol->GetSolutionType(SolIndex); //coordinates vector< vector < double> > coordinates(dim); //const char coordinate_name[3][2] = {"X","Y","Z"}; //vector < unsigned > coordinate_Index(dim); // for(unsigned ivar=0; ivar<dim; ivar++) { // coordinate_Index[ivar]=ivar;//ml_prob.GetIndex(coordinate_name[ivar]); // } // declare vector< int > metis_node; vector< int > KK_dof; vector <double> phi; vector <double> gradphi; vector <double> nablaphi; double weight; vector< double > F; vector< double > B; // reserve const unsigned max_size = static_cast< unsigned > (ceil(pow(3,dim))); metis_node.reserve(max_size); KK_dof.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)) ); F.reserve(max_size); B.reserve(max_size*max_size); // Set to zeto all the entries of the Global Matrix if(assemble_matrix) myKK->zero(); // *** 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,order_ind); // resize metis_node.resize(nve); KK_dof.resize(nve); phi.resize(nve); gradphi.resize(nve*dim); nablaphi.resize( nve*(3*(dim-1)) ); for(int i=0;i<dim;i++){ coordinates[i].resize(nve); } // set to zero all the entries of the FE matrices F.resize(nve); memset(&F[0],0,nve*sizeof(double)); if(assemble_matrix){ B.resize(nve*nve); memset(&B[0],0,nve*nve*sizeof(double)); } // get local to global mappings for( unsigned i=0;i<nve;i++){ unsigned inode=myel->GetElementVertexIndex(kel,i)-1u; unsigned inode_metis=mymsh->GetMetisDof(inode,2); metis_node[i]=inode_metis; for(unsigned ivar=0; ivar<dim; ivar++) { coordinates[ivar][i]=(*mymsh->_coordinate->_Sol[ivar])(inode_metis); } KK_dof[i]=mylsyspde->GetKKDof(SolIndex,SolPdeIndex,inode); } if(igrid==gridn || !myel->GetRefinedElementIndex(kel)) { // *** Gauss poit loop *** for(unsigned ig=0;ig < ml_prob._ml_msh->_finiteElement[kelt][order_ind]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** ml_prob._ml_msh->_finiteElement[kelt][order_ind]->Jacobian(coordinates,ig,weight,phi,gradphi,nablaphi); //Temperature and velocity current solution double SolT=0; vector < double > gradSolT(dim,0.); for(unsigned ivar=0; ivar<dim; ivar++){ gradSolT[ivar]=0; } vector < double > SolU(dim,0.); vector < unsigned > SolIndexU(dim); SolIndexU[0]=ml_sol->GetIndex("U"); SolIndexU[1]=ml_sol->GetIndex("V"); if(dim==3) SolIndexU[2]=ml_sol->GetIndex("W"); unsigned SolType=ml_sol->GetSolutionType("T"); for(unsigned i=0; i<nve; i++) { double soli = (*mysolution->_Sol[SolIndex])(metis_node[i]); SolT+=phi[i]*soli; for(unsigned ivar2=0; ivar2<dim; ivar2++) gradSolT[ivar2] += gradphi[i*dim+ivar2]*soli; for(int j=0;j<dim;j++) { SolU[j]+=phi[i]*(*mysolution->_Sol[SolIndexU[j]])(metis_node[i]); } } // *** phi_i loop *** for(unsigned i=0; i<nve; i++){ //BEGIN RESIDUALS A block =========================== double Adv_rhs=0; double Lap_rhs=0; for(unsigned ivar=0; ivar<dim; ivar++) { Lap_rhs += gradphi[i*dim+ivar]*gradSolT[ivar]; Adv_rhs += SolU[ivar]*gradSolT[ivar]; } F[i]+= (-IPe*Lap_rhs-Adv_rhs*phi[i])*weight; //END RESIDUALS A block =========================== if(assemble_matrix){ // *** phi_j loop *** for(unsigned j=0; j<nve; j++) { double Lap=0; double Adv1=0; for(unsigned ivar=0; ivar<dim; ivar++) { // Laplacian Lap += gradphi[i*dim+ivar]*gradphi[j*dim+ivar]*weight; // advection term I Adv1 += SolU[ivar]*gradphi[j*dim+ivar]*phi[i]*weight; } B[i*nve+j] += IPe*Lap + Adv1; } // end phij loop } // end phii loop } // endif assemble_matrix } // end gauss point loop } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- //Sum the local matrices/vectors into the global Matrix/vector myRES->add_vector_blocked(F,KK_dof); if(assemble_matrix) myKK->add_matrix_blocked(B,KK_dof,KK_dof); } //end list of elements loop for each subdomain myRES->close(); if(assemble_matrix) myKK->close(); // ***************** END ASSEMBLY ******************* }
//------------------------------------------------------------------------------------------------------------ void AssemblePoissonMatrixandRhs(MultiLevelProblem& ml_prob) { //pointers and references LinearImplicitSystem& mylin_impl_sys = ml_prob.get_system<LinearImplicitSystem>("Poisson"); const unsigned level = mylin_impl_sys.GetLevelToAssemble(); Solution* mysolution = ml_prob._ml_sol->GetSolutionLevel(level); LinearEquationSolver* mylsyspde = mylin_impl_sys._LinSolver[level]; Mesh* mymsh = ml_prob._ml_msh->GetLevel(level); elem* myel = mymsh->el; SparseMatrix* myKK = mylsyspde->_KK; NumericVector* myRES = mylsyspde->_RES; MultiLevelSolution* ml_sol = ml_prob._ml_sol; //data const unsigned dim = mymsh->GetDimension(); unsigned nel = mymsh->GetNumberOfElements(); unsigned igrid = mymsh->GetLevel(); unsigned iproc = mymsh->processor_id(); //solution variable unsigned SolIndex; unsigned SolPdeIndex; SolIndex = ml_sol->GetIndex("Sol"); SolPdeIndex = mylin_impl_sys.GetSolPdeIndex("Sol"); //solution order unsigned order_ind = ml_sol->GetSolutionType(SolIndex); //coordinates vector< vector < double> > coordinates(dim); // declare vector< int > metis_node; vector< int > KK_dof; vector <double> phi; vector <double> gradphi; vector <double> nablaphi; double weight; vector< double > F; vector< double > B; vector<double> normal(3.0); double src_term = 0.; vector<double> xyzt(4, 0.); ParsedFunction* bdcfunc = NULL; // reserve const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim))); metis_node.reserve(max_size); KK_dof.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))); F.reserve(max_size); B.reserve(max_size * max_size); // Set to zeto all the entries of the Global Matrix myKK->zero(); // *** element loop *** for (int iel = mymsh->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc + 1]; iel++) { short unsigned ielt = myel->GetElementType(iel); unsigned nve = myel->GetElementDofNumber(iel, order_ind); // resize metis_node.resize(nve); KK_dof.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); } // set to zero all the entries of the FE matrices F.resize(nve); memset(&F[0], 0, nve * sizeof(double)); B.resize(nve * nve); memset(&B[0], 0, nve * nve * sizeof(double)); // get local to global mappings for (unsigned i = 0; i < nve; i++) { unsigned inode_coord_metis = mymsh->GetSolutionDof(i, iel, 2); metis_node[i] = mymsh->GetSolutionDof(i, iel, order_ind); for (unsigned ivar = 0; ivar < dim; ivar++) { coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis); } KK_dof[i] = mylsyspde->GetSystemDof(SolIndex, SolPdeIndex, i, iel); } // *** Gauss poit loop *** for (unsigned ig = 0; ig < ml_prob._ml_msh->_finiteElement[ielt][order_ind]->GetGaussPointNumber(); ig++) { // *** get Jacobian and test function and test function derivatives *** ml_prob._ml_msh->_finiteElement[ielt][order_ind]->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; } xyzt.assign(4, 0.); unsigned SolType = ml_sol->GetSolutionType("Sol"); for (unsigned i = 0; i < nve; i++) { double soli = (*mysolution->_Sol[SolIndex])(metis_node[i]); for (unsigned ivar = 0; ivar < dim; ivar++) { xyzt[ivar] += coordinates[ivar][i] * phi[i]; } SolT += phi[i] * soli; for (unsigned ivar2 = 0; ivar2 < dim; ivar2++) gradSolT[ivar2] += gradphi[i * dim + ivar2] * soli; } // *** phi_i loop *** for (unsigned i = 0; i < nve; i++) { //BEGIN RESIDUALS A block =========================== double Adv_rhs = 0; double Lap_rhs = 0; for (unsigned ivar = 0; ivar < dim; ivar++) { Lap_rhs += gradphi[i * dim + ivar] * gradSolT[ivar]; } //src_term = Source(xyzt); #ifdef HAVE_FPARSER //src_term = fpsource.Eval(xyzt); src_term = fpsource(&xyzt[0]); #endif F[i] += (-Lap_rhs + src_term * phi[i]) * weight; //END RESIDUALS A block =========================== // *** phi_j loop *** for (unsigned j = 0; j < nve; j++) { double Lap = 0; double Adv1 = 0; for (unsigned ivar = 0; ivar < dim; ivar++) { // Laplacian Lap += gradphi[i * dim + ivar] * gradphi[j * dim + ivar] * weight; } B[i * nve + j] += Lap; } // end phij loop } // endif assemble_matrix } // end gauss point loop //number of faces for each type of element //number of faces for each type of element unsigned nfaces = myel->GetElementFaceNumber(iel); // loop on faces for (unsigned jface = 0; jface < nfaces; jface++) { // look for boundary faces if (myel->GetBoundaryIndex(iel, jface) > 0) { unsigned int faceIndex = myel->GetBoundaryIndex(iel, jface) - 1u; if (ml_sol->GetBoundaryCondition("Sol", faceIndex) == NEUMANN && !ml_sol->Ishomogeneous("Sol", faceIndex)) { bdcfunc = (ParsedFunction*)(ml_sol->GetBdcFunction("Sol", faceIndex)); unsigned nve = mymsh->el->GetElementFaceDofNumber(iel, jface, order_ind); const unsigned felt = mymsh->el->GetElementFaceType(iel, jface); for (unsigned i = 0; i < nve; i++) { unsigned ilocal = mymsh->el->GetLocalFaceVertexIndex(iel, jface, i); unsigned inode_coord_metis = mymsh->GetSolutionDof(ilocal, iel, 2); for (unsigned ivar = 0; ivar < dim; ivar++) { coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis); } } if (felt != 6) { for (unsigned igs = 0; igs < ml_prob._ml_msh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) { ml_prob._ml_msh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal); xyzt.assign(4, 0.); for (unsigned i = 0; i < nve; i++) { for (unsigned ivar = 0; ivar < dim; ivar++) { xyzt[ivar] += coordinates[ivar][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nve; i++) { double surfterm_g = (*bdcfunc)(&xyzt[0]); double bdintegral = phi[i] * surfterm_g * weight; unsigned int ilocalnode = mymsh->el->GetLocalFaceVertexIndex(iel, jface, i); F[ilocalnode] += bdintegral; } } } else // 1D : the side elems are points and does not still exist the point elem { // in 1D it is only one point xyzt[0] = coordinates[0][0]; xyzt[1] = 0.; xyzt[2] = 0.; xyzt[3] = 0.; double bdintegral = (*bdcfunc)(&xyzt[0]); unsigned int ilocalnode = mymsh->el->GetLocalFaceVertexIndex(iel, jface, 0); F[ilocalnode] += bdintegral; } } } } //-------------------------------------------------------------------------------------------------------- //Sum the local matrices/vectors into the global Matrix/vector myRES->add_vector_blocked(F, KK_dof); myKK->add_matrix_blocked(B, KK_dof, KK_dof); } //end list of elements loop for each subdomain myRES->close(); myKK->close(); // ***************** END ASSEMBLY ******************* }