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 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 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 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 AssembleBilaplaceProblem_AD(MultiLevelProblem &ml_prob){ // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // call the adept stack object adept::Stack & s = FemusInit::_adeptStack; NonLinearImplicitSystem* mlPdeSys = &ml_prob.get_system<NonLinearImplicitSystem>("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); const unsigned levelMax = mlPdeSys->GetLevelMax(); const bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); // extract pointers to the several objects that we are going to use Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned soluIndex; soluIndex = mlSol->GetIndex("u"); // get the position of "u" in the ml_sol object unsigned soluType = mlSol->GetSolutionType(soluIndex); // get the finite element type for "u" unsigned soluPdeIndex; soluPdeIndex = mlPdeSys->GetSolPdeIndex("u"); // get the position of "u" in the pdeSys object vector < adept::adouble > solu; // local solution unsigned solvIndex; solvIndex = mlSol->GetIndex("v"); // get the position of "v" in the ml_sol object unsigned solvType = mlSol->GetSolutionType(solvIndex); // get the finite element type for "v" unsigned solvPdeIndex; solvPdeIndex = mlPdeSys->GetSolPdeIndex("v"); // get the position of "v" in the pdeSys object vector < adept::adouble > solv; // local solution vector < vector < double > > x(dim); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) vector< int > KKDof; // local to global pdeSys dofs vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives vector <double> phi_xx; // local test function second order partial derivatives double weight; // gauss point weight vector< double > Res; // local redidual vector vector< adept::adouble > aResu; // local redidual vector vector< adept::adouble > aResv; // local redidual vector // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned > (ceil(pow(3,dim))); // conservative: based on line3, quad9, hex27 solu.reserve(maxSize); solv.reserve(maxSize); for(unsigned i = 0; i < dim; i++) x[i].reserve(maxSize); KKDof.reserve(2*maxSize); phi.reserve(maxSize); phi_x.reserve(maxSize*dim); unsigned dim2=(3*(dim-1)+!(dim-1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) phi_xx.reserve(maxSize*dim2); Res.reserve(2*maxSize); aResu.reserve(maxSize); aResv.reserve(maxSize); vector < double > Jac; // local Jacobian matrix (ordered by column, adept) Jac.reserve(4*maxSize*maxSize); vector< double > Jact; // local Jacobian matrix (ordered by raw, PETSC) Jact.reserve(4*maxSize*maxSize); if( assembleMatrix ) KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel=msh->IS_Mts2Gmt_elem_offset[iproc]; iel < msh->IS_Mts2Gmt_elem_offset[iproc+1]; iel++) { unsigned kel = msh->IS_Mts2Gmt_elem[iel]; // mapping between paralell dof and mesh dof short unsigned kelGeom = el->GetElementType( kel ); // element geometry type unsigned nDofs = el->GetElementDofNumber( kel, soluType); // number of solution element dofs unsigned nDofs2 = el->GetElementDofNumber( kel, xType); // number of coordinate element dofs // resize local arrays KKDof.resize(2*nDofs); solu.resize(nDofs); solv.resize(nDofs); for(int i=0; i<dim; i++) { x[i].resize(nDofs2); } Res.resize(2*nDofs); //resize aResu.resize(nDofs); //resize aResv.resize(nDofs); //resize std::fill(aResu.begin(), aResu.end(), 0); //set aRes to zero std::fill(aResv.begin(), aResv.end(), 0); //set aRes to zero if(assembleMatrix) { //resize Jact.resize(4*nDofs*nDofs); Jac.resize(4*nDofs*nDofs); } // local storage of global mapping and solution for( unsigned i=0; i<nDofs; i++) { unsigned iNode = el->GetMeshDof(kel, i, soluType); // local to global solution node unsigned solDof = msh->GetMetisDof(iNode, soluType); // global to global mapping between solution node and solution dof solu[i] = (*sol->_Sol[soluIndex])(solDof); // global extraction and local storage for the solution solv[i] = (*sol->_Sol[solvIndex])(solDof); // global extraction and local storage for the solution KKDof[i] = pdeSys->GetKKDof(soluIndex, soluPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof KKDof[nDofs+i] = pdeSys->GetKKDof(solvIndex, solvPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for( unsigned i=0; i<nDofs2; i++) { unsigned iNode = el->GetMeshDof(kel, i, xType); // local to global coordinates node unsigned xDof = msh->GetMetisDof(iNode, xType); // global to global mapping between coordinates node and coordinate dof for(unsigned jdim=0; jdim<dim; jdim++) { x[jdim][i] = (*msh->_coordinate->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } if( level == levelMax || !el->GetRefinedElementIndex(kel)) { // do not care about this if now (it is used for the AMR) // start a new recording of all the operations involving adept::adouble variables s.new_recording(); // *** Gauss point loop *** for(unsigned ig=0; ig < msh->_finiteElement[kelGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][soluType]->Jacobian(x,ig,weight,phi,phi_x,phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point adept::adouble soluGauss = 0; vector < adept::adouble > soluGauss_x(dim,0.); adept::adouble solvGauss = 0; vector < adept::adouble > solvGauss_x(dim,0.); vector < double > xGauss(dim,0.); for(unsigned i=0; i<nDofs; i++) { soluGauss+=phi[i]*solu[i]; solvGauss+=phi[i]*solv[i]; for(unsigned jdim=0; jdim<dim; jdim++) { soluGauss_x[jdim] += phi_x[i*dim+jdim]*solu[i]; solvGauss_x[jdim] += phi_x[i*dim+jdim]*solv[i]; xGauss[jdim] += x[jdim][i]*phi[i]; } } double c=.1; double Id[2][2]={{1.,0.},{0.,1.}}; adept::adouble A2 = 1.; vector < vector < adept::adouble> > B(dim); for(unsigned jdim=0; jdim<dim; jdim++){ B[jdim].resize(dim); A2 += soluGauss_x[jdim]*soluGauss_x[jdim]; } adept::adouble A = sqrt(A2); for(unsigned jdim=0; jdim<dim; jdim++){ for(unsigned kdim=0; kdim<dim; kdim++){ B[jdim][kdim]= Id[jdim][kdim] - (soluGauss_x[jdim] * soluGauss_x[kdim]) / A2; } } // *** phi_i loop *** for(unsigned i=0; i<nDofs; i++) { adept::adouble nonLinearLaplaceU = 0.; adept::adouble nonLinearLaplaceV = 0.; for(unsigned jdim=0; jdim<dim; jdim++) { nonLinearLaplaceU += - 1. / A * soluGauss_x[jdim] * phi_x[i*dim+jdim]; nonLinearLaplaceV += 1. / A * ( - ( B[jdim][0] * solvGauss_x[0] + B[jdim][1] * solvGauss_x[1] ) * phi_x[i*dim+jdim] + ( solvGauss*solvGauss/A2 + c ) * soluGauss_x[jdim] * phi_x[i*dim+jdim] ); } aResu[i]+= ( 2.*solvGauss/A * phi[i] - nonLinearLaplaceU ) * weight; aResv[i]+= nonLinearLaplaceV * weight; } // end phi_i loop } // end gauss point loop } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store for(int i=0; i<nDofs; i++) { Res[i] = aResu[i].value(); Res[nDofs+i] = aResv[i].value(); } RES->add_vector_blocked(Res,KKDof); if(assembleMatrix) { // define the dependent variables s.dependent(&aResu[0], nDofs); s.dependent(&aResv[0], nDofs); // define the independent variables s.independent(&solu[0], nDofs); s.independent(&solv[0], nDofs); // get the jacobian matrix (ordered by column) s.jacobian(&Jac[0]); // get the jacobian matrix (ordered by raw, i.e. Jact=Jac^t) for (int inode=0;inode<2*nDofs;inode++){ for (int jnode=0;jnode<2*nDofs;jnode++){ Jact[inode*2*nDofs+jnode]=-Jac[jnode*2*nDofs+inode]; } } //store Jact in the global matrix KK KK->add_matrix_blocked(Jact,KKDof,KKDof); s.clear_independents(); s.clear_dependents(); } } //end element loop for each process RES->close(); if( assembleMatrix ) KK->close(); // ***************** END ASSEMBLY ******************* }
void AssembleNonlinearProblem(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // extract pointers to the several objects that we are going to use NonLinearImplicitSystem* mlPdeSys = &ml_prob.get_system< NonLinearImplicitSystem > ("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); const unsigned levelMax = mlPdeSys->GetLevelMax(); bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned soluIndex; soluIndex = mlSol->GetIndex("u"); // get the position of "u" in the ml_sol object unsigned soluType = mlSol->GetSolutionType(soluIndex); // get the finite element type for "u" unsigned soluPdeIndex; soluPdeIndex = mlPdeSys->GetSolPdeIndex("u"); // get the position of "u" in the pdeSys object vector < double > solu; // local solution vector < vector < double > > x(dim); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) vector< int > KKDof; // local to global pdeSys dofs vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives vector <double> phi_xx; // local test function second order partial derivatives double weight; // gauss point weight vector< double > Res; // local redidual vector vector< double > J; // local Jacobian matrix // reserve memory for the local standar vectors const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 solu.reserve(maxSize); for (unsigned i = 0; i < dim; i++) x[i].reserve(maxSize); KKDof.reserve(maxSize); phi.reserve(maxSize); phi_x.reserve(maxSize * dim); unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) phi_xx.reserve(maxSize * dim2); Res.reserve(maxSize); J.reserve(maxSize * maxSize); if (assembleMatrix) KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel = msh->IS_Mts2Gmt_elem_offset[iproc]; iel < msh->IS_Mts2Gmt_elem_offset[iproc + 1]; iel++) { unsigned kel = msh->IS_Mts2Gmt_elem[iel]; // mapping between paralell dof and mesh dof short unsigned kelGeom = el->GetElementType(kel); // element geometry type unsigned nDofs = el->GetElementDofNumber(kel, soluType); // number of solution element dofs unsigned nDofs2 = el->GetElementDofNumber(kel, xType); // number of coordinate element dofs // resize local arrays KKDof.resize(nDofs); solu.resize(nDofs); for (int i = 0; i < dim; i++) { x[i].resize(nDofs2); } Res.resize(nDofs); //resize std::fill(Res.begin(), Res.end(), 0); //set Res to zero if (assembleMatrix) { J.resize(nDofs * nDofs); //resize std::fill(J.begin(), J.end(), 0); //set K to zero } // local storage of global mapping and solution for (unsigned i = 0; i < nDofs; i++) { unsigned iNode = el->GetMeshDof(kel, i, soluType); // local to global solution node unsigned solDof = msh->GetMetisDof(iNode, soluType); // global to global mapping between solution node and solution dof solu[i] = (*sol->_Sol[soluIndex])(solDof); // global extraction and local storage for the solution KKDof[i] = pdeSys->GetKKDof(soluIndex, soluPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofs2; i++) { unsigned iNode = el->GetMeshDof(kel, i, xType); // local to global coordinates node unsigned xDof = msh->GetMetisDof(iNode, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_coordinate->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } if (level == levelMax || !el->GetRefinedElementIndex(kel)) { // do not care about this if now (it is used for the AMR) // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[kelGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point double soluGauss = 0; vector < double > soluGauss_x(dim, 0.); vector < double > xGauss(dim, 0.); for (unsigned i = 0; i < nDofs; i++) { soluGauss += phi[i] * solu[i]; for (unsigned jdim = 0; jdim < dim; jdim++) { soluGauss_x[jdim] += phi_x[i * dim + jdim] * solu[i]; xGauss[jdim] += x[jdim][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nDofs; i++) { double nonLinearTerm = 0.; double mLaplace = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { mLaplace += phi_x[i * dim + jdim] * soluGauss_x[jdim]; nonLinearTerm += soluGauss * soluGauss_x[jdim] * phi[i]; } double exactSolValue = GetExactSolutionValue(xGauss); vector < double > exactSolGrad(dim); GetExactSolutionGradient(xGauss , exactSolGrad); double exactSolLaplace = GetExactSolutionLaplace(xGauss); double f = (- exactSolLaplace + exactSolValue * (exactSolGrad[0] + exactSolGrad[1])) * phi[i] ; Res[i] += (f - (mLaplace + nonLinearTerm)) * weight; if (assembleMatrix) { // *** phi_j loop *** for (unsigned j = 0; j < nDofs; j++) { mLaplace = 0.; nonLinearTerm = 0.; for (unsigned kdim = 0; kdim < dim; kdim++) { mLaplace += (phi_x[i * dim + kdim] * phi_x[j * dim + kdim]); nonLinearTerm += phi[i] * (phi[j] * soluGauss_x[kdim] + soluGauss * phi_x[j * dim + kdim]); } J[i * nDofs + j] += (mLaplace + nonLinearTerm) * weight; } // end phi_j loop } // endif assemble_matrix } // end phi_i loop } // end gauss point loop } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector RES->add_vector_blocked(Res, KKDof); if (assembleMatrix) KK->add_matrix_blocked(J, KKDof, KKDof); } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }
/** * 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(); 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) 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); 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 nDofu = el->GetElementDofNumber(kel, soluType); // number of solution element dofs unsigned nDofx = el->GetElementDofNumber(kel, 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 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 l2GMap[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 < nDofx; 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 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 } // 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 Res.resize(nDofu); //resize for (int i = 0; i < nDofu; i++) { Res[i] = - aRes[i].value(); } RES->add_vector_blocked(Res, l2GMap); if (assembleMatrix) { // 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(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }