Пример #1
0
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 *******************
}
Пример #2
0
//------------------------------------------------------------------------------------------------------------
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 *******************
  
}
Пример #3
0
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 *******************

  }  
Пример #4
0
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 *******************
}
Пример #5
0
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 *******************
}
Пример #6
0
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 *******************
}
Пример #7
0
/**
 * 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 *******************
}