Beispiel #1
0
//------------------------------------------------------------------------------------------------------------
void AssembleMatrixResNS(MultiLevelProblem &ml_prob){
     
  //pointers
  
  TransientNonlinearImplicitSystem& my_nnlin_impl_sys = ml_prob.get_system<TransientNonlinearImplicitSystem>("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*  mylsyspde	              = my_nnlin_impl_sys._LinSolver[level];   
  const char* pdename                                 = my_nnlin_impl_sys.name().c_str();
  
  Mesh*		 mymsh    	   = ml_prob._ml_msh->GetLevel(level);
  elem*		 myel		   = mymsh->el;
  SparseMatrix*	 myKK	 	   = mylsyspde->_KK;
  NumericVector* myRES 		   = mylsyspde->_RES;
    
  //data
  double dt = my_nnlin_impl_sys.GetIntervalTime();
  double theta = 0.5;
  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 = 1; 
  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);  

  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]);
  }
  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 > Sol(dim+1);
  vector < vector < double > > gradSol(dim);
  for(int i=0;i<dim;i++) {
    gradSol[i].resize(dim);  
  }
  
  vector < double > SolOld(dim+1);
  vector < vector < double > > gradSolOld(dim);
  for(int i=0;i<dim;i++) {
    gradSolOld[i].resize(dim);  
  }
  //vector < double > AccSol(dim);
  
  // Set to zeto all the entries of the matrix
  if(assemble_matrix) myKK->zero();
  
  // *** element loop ***
 
  for (int iel=mymsh->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc+1]; iel++) {

    unsigned kel = mymsh->IS_Mts2Gmt_elem[iel];
    short unsigned kelt= mymsh->GetElementType(kel);
    unsigned nve2=mymsh->GetElementDofNumber(kel,order_ind2);
    unsigned nve1=mymsh->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->GetSolutionDof(inode,2);
      metis_node2[i]=inode_metis;
      for(unsigned ivar=0; ivar<dim; ivar++) {
	coordinates[ivar][i]=(*mymsh->_topology->_Sol[ivar])(inode_metis);
	KK_dof[ivar][i]=mylsyspde->GetSystemDof(SolIndex[ivar],SolPdeIndex[ivar],inode);
      }
    }
    
    for(unsigned i=0;i<nve1;i++) {
      unsigned inode=(order_ind1<dim)?(myel->GetElementVertexIndex(kel,i)-1u):(kel+i*nel);
      node1[i]=inode;
      KK_dof[dim][i]=mylsyspde->GetSystemDof(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++) {
	  Sol[ivar]=0.;
	  SolOld[ivar]=0.;
	  //AccSol[ivar]=0.;
	  for(unsigned ivar2=0; ivar2<dim; ivar2++){ 
	    gradSol[ivar][ivar2]=0;
	    gradSolOld[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]);
	    double sololdi = (*mysolution->_SolOld[SolIndex])(metis_node2[i]);
	    Sol[ivar]+=phi2[i]*soli;
	    SolOld[ivar]+=phi2[i]*sololdi;
	    for(unsigned ivar2=0; ivar2<dim; ivar2++){
	      gradSol[ivar][ivar2]    += gradphi2[i*dim+ivar2]*soli; 
	      gradSolOld[ivar][ivar2] += gradphi2[i*dim+ivar2]*sololdi;
	    }
	  }
	}
	//pressure variable
	Sol[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->GetSolutionDof(node1[i],SolType);
	  double soli = (*mysolution->_Sol[SolIndex])(sol_dof);
	  Sol[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 Adv_old_rhs=0;
	    double Lap_rhs=0;
	    double Lap_old_rhs=0;
	    for(unsigned ivar2=0; ivar2<dim; ivar2++) {
	      Lap_rhs 	  += gradphi2[i*dim+ivar2]*gradSol[ivar][ivar2];
	      Lap_old_rhs += gradphi2[i*dim+ivar2]*gradSolOld[ivar][ivar2];
	      Adv_rhs 	  += Sol[ivar2]*gradSol[ivar][ivar2];
	      Adv_old_rhs += SolOld[ivar2]*gradSolOld[ivar][ivar2];
	    }
	    F[SolPdeIndex[ivar]][i]+= ( -theta*dt*IRe*Lap_rhs                           // Laplacian
					-(1.-theta)*dt*IRe*Lap_old_rhs                  // Laplacian
					-theta*dt*NavierStokes*Adv_rhs*phi2[i]          // advection 
					-(1.-theta)*dt*NavierStokes*Adv_old_rhs*phi2[i] // advection 
					+dt*Sol[dim]*gradphi2[i*dim+ivar]                  // pressure
					-(Sol[ivar] - SolOld[ivar])*phi2[i]        // acceleration
	    )*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;
	      double Mass = 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 += Sol[ivar]*gradphi2[j*dim+ivar]*phi2[i]*Weight2;
	      }

	      for(unsigned ivar=0; ivar<dim; ivar++) {    
		B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][i*nve2+j] += theta*dt*IRe*Lap + theta*dt*NavierStokes*newton*Adv1 + Mass;
		if(nwtn_alg==2){
		  // Advection term II
		  B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][i*nve2+j]       += theta*dt*Adv2*gradSol[ivar][ivar];
		  for(unsigned ivar2=1; ivar2<dim; ivar2++) {
		    B[SolPdeIndex[ivar]][SolPdeIndex[(ivar+ivar2)%dim]][i*nve2+j] += theta*dt*Adv2*gradSol[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] -= dt*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 += gradSol[ivar][ivar];
	  }
	  F[SolPdeIndex[dim]][i]+= dt*(phi1[i]*div +penalty*ILambda*phi1[i]*Sol[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]-= dt*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]-=  dt*ILambda*phi1[i]*phi1[j]*Weight2;
	    }
	  }
	}   //end if penalty
      }  // end gauss point loop
      
      //--------------------------------------------------------------------------------------------------------
      // Boundary Integral --> to be added
      //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 *******************
}
Beispiel #2
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

  // call the adept stack object
  adept::Stack& s = FemusInit::_adeptStack;

  //  extract pointers to the several objects that we are going to use

  NonLinearImplicitSystem* mlPdeSys   = &ml_prob.get_system<NonLinearImplicitSystem> ("Poisson");   // pointer to the linear implicit system named "Poisson"

  const unsigned level = mlPdeSys->GetLevelToAssemble();

  Mesh*          msh          = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
  elem*          el         = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution*  mlSol        = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution*    sol        = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object

  LinearEquationSolver* pdeSys        = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object
  SparseMatrix*    KK         = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector*   RES          = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

  //solution variable
  unsigned soluIndex;
  soluIndex = mlSol->GetIndex("u");    // get the position of "u" in the ml_sol object
  unsigned soluType = mlSol->GetSolutionType(soluIndex);    // get the finite element type for "u"

  unsigned soluPdeIndex;
  soluPdeIndex = mlPdeSys->GetSolPdeIndex("u");    // get the position of "u" in the pdeSys object

  vector < adept::adouble >  solu; // local solution

  unsigned solvIndex;
  solvIndex = mlSol->GetIndex("v");    // get the position of "v" in the ml_sol object
  unsigned solvType = mlSol->GetSolutionType(solvIndex);    // get the finite element type for "v"

  unsigned solvPdeIndex;
  solvPdeIndex = mlPdeSys->GetSolPdeIndex("v");    // get the position of "v" in the pdeSys object

  vector < adept::adouble >  solv; // local solution



  vector < vector < double > > x(dim);    // local coordinates
  unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  vector< int > sysDof; // local to global pdeSys dofs
  vector <double> phi;  // local test function
  vector <double> phi_x; // local test function first order partial derivatives
  vector <double> phi_xx; // local test function second order partial derivatives
  double weight; // gauss point weight

  vector< double > Res; // local redidual vector
  vector< adept::adouble > aResu; // local redidual vector
  vector< adept::adouble > aResv; // local redidual vector


  // reserve memory for the local standar vectors
  const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27
  solu.reserve(maxSize);
  solv.reserve(maxSize);

  for (unsigned i = 0; i < dim; i++)
    x[i].reserve(maxSize);

  sysDof.reserve(2 * maxSize);
  phi.reserve(maxSize);
  phi_x.reserve(maxSize * dim);
  unsigned dim2 = (3 * (dim - 1) + !(dim - 1));        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  phi_xx.reserve(maxSize * dim2);

  Res.reserve(2 * maxSize);
  aResu.reserve(maxSize);
  aResv.reserve(maxSize);

  vector < double > Jac; // local Jacobian matrix (ordered by column, adept)
  Jac.reserve(4 * maxSize * maxSize);


  KK->zero(); // Set to zero all the entries of the Global Matrix

  // element loop: each process loops only on the elements that owns
  for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielGeom = msh->GetElementType(iel); 
    unsigned nDofs  = msh->GetElementDofNumber(iel, soluType);    // number of solution element dofs
    unsigned nDofs2 = msh->GetElementDofNumber(iel, xType);    // number of coordinate element dofs
    
    // resize local arrays
    sysDof.resize(2 * nDofs);
    solu.resize(nDofs);
    solv.resize(nDofs);

    for (int i = 0; i < dim; i++) {
      x[i].resize(nDofs2);
    }

    aResu.assign(nDofs, 0.);    //resize
    aResv.assign(nDofs, 0.);    //resize

    // local storage of global mapping and solution
    for (unsigned i = 0; i < nDofs; i++) {
      unsigned solDof = msh->GetSolutionDof(i, iel, soluType);    // global to global mapping between solution node and solution dof
      solu[i]          = (*sol->_Sol[soluIndex])(solDof);      // global extraction and local storage for the solution
      solv[i]          = (*sol->_Sol[solvIndex])(solDof);      // global extraction and local storage for the solution
      sysDof[i]         = pdeSys->GetSystemDof(soluIndex, soluPdeIndex, i, iel);    // global to global mapping between solution node and pdeSys dof
      sysDof[nDofs + i] = pdeSys->GetSystemDof(solvIndex, solvPdeIndex, i, iel);    // global to global mapping between solution node and pdeSys dof
    }

    // local storage of coordinates
    for (unsigned i = 0; i < nDofs2; i++) {
      unsigned xDof  = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof

      for (unsigned jdim = 0; jdim < dim; jdim++) {
        x[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof);  // global extraction and local storage for the element coordinates
      }
    }

    // start a new recording of all the operations involving adept::adouble variables
    s.new_recording();

    // *** Gauss point loop ***
    for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][soluType]->GetGaussPointNumber(); ig++) {
      // *** get gauss point weight, test function and test function partial derivatives ***
      msh->_finiteElement[ielGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx);

      // evaluate the solution, the solution derivatives and the coordinates in the gauss point
      adept::adouble soluGauss = 0;
      vector < adept::adouble > soluGauss_x(dim, 0.);

      adept::adouble solvGauss = 0;
      vector < adept::adouble > solvGauss_x(dim, 0.);

      vector < double > xGauss(dim, 0.);

      for (unsigned i = 0; i < nDofs; i++) {
        soluGauss += phi[i] * solu[i];
        solvGauss += phi[i] * solv[i];

        for (unsigned jdim = 0; jdim < dim; jdim++) {
          soluGauss_x[jdim] += phi_x[i * dim + jdim] * solu[i];
          solvGauss_x[jdim] += phi_x[i * dim + jdim] * solv[i];
          xGauss[jdim] += x[jdim][i] * phi[i];
        }
      }

      // *** phi_i loop ***
      for (unsigned i = 0; i < nDofs; i++) {

        adept::adouble Laplace_u = 0.;
        adept::adouble Laplace_v = 0.;

        for (unsigned jdim = 0; jdim < dim; jdim++) {
          Laplace_u   +=  - phi_x[i * dim + jdim] * soluGauss_x[jdim];
          Laplace_v   +=  - phi_x[i * dim + jdim] * solvGauss_x[jdim];
        }

        double exactSolValue = GetExactSolutionValue(xGauss);

        double pi = acos(-1.);
        aResv[i] += (solvGauss * phi[i] -  Laplace_u) * weight;
        aResu[i] += (4.*pi * pi * pi * pi * exactSolValue * phi[i] -  Laplace_v) * weight;
      } // end phi_i loop
    } // end gauss point loop


    // Add the local Matrix/Vector into the global Matrix/Vector

    //copy the value of the adept::adoube aRes in double Res and store
    Res.resize(2 * nDofs);

    for (int i = 0; i < nDofs; i++) {
      Res[i]         = -aResu[i].value();
      Res[nDofs + i] = -aResv[i].value();
    }

    RES->add_vector_blocked(Res, sysDof);

    Jac.resize( 4 * nDofs * nDofs );

    // define the dependent variables
    s.dependent(&aResu[0], nDofs);
    s.dependent(&aResv[0], nDofs);

    // define the independent variables
    s.independent(&solu[0], nDofs);
    s.independent(&solv[0], nDofs);

    // get the jacobian matrix (ordered by column)
    s.jacobian(&Jac[0], true);

    KK->add_matrix_blocked(Jac, sysDof, sysDof);

    s.clear_independents();
    s.clear_dependents();

  } //end element loop for each process

  RES->close();
  KK->close();

  // ***************** END ASSEMBLY *******************
}
Beispiel #3
0
void ETD(MultiLevelProblem& ml_prob)
{

  const unsigned& NLayers = NumberOfLayers;

  adept::Stack& s = FemusInit::_adeptStack;

  LinearImplicitSystem* mlPdeSys  = &ml_prob.get_system<LinearImplicitSystem> ("SW");   // pointer to the linear implicit system named "Poisson"

  unsigned level = ml_prob._ml_msh->GetNumberOfLevels() - 1u;

  Mesh* msh = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
  elem* el = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution* mlSol = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object

  LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object

  SparseMatrix* KK = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)
  NumericVector* EPS = pdeSys->_EPS; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem

  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)
  unsigned    nprocs = msh->n_processors(); // get the process_id (for parallel computation)


  //solution variable
  std::vector < unsigned > solIndexh(NLayers);
  std::vector < unsigned > solPdeIndexh(NLayers);

  std::vector < unsigned > solIndexv(NLayers);
  std::vector < unsigned > solPdeIndexv(NLayers);
  
  std::vector < unsigned > solIndexHT(NLayers);
  std::vector < unsigned > solPdeIndexHT(NLayers);
  
  
   std::vector < unsigned > solIndexT(NLayers);

  vector< int > l2GMap; // local to global mapping
  
  for(unsigned i = 0; i < NLayers; i++) {
    char name[10];
    sprintf(name, "h%d", i);
    solIndexh[i] = mlSol->GetIndex(name); // get the position of "hi" in the sol object
    solPdeIndexh[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "hi" in the pdeSys object

    sprintf(name, "v%d", i);
    solIndexv[i] = mlSol->GetIndex(name); // get the position of "vi" in the sol object
    solPdeIndexv[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "vi" in the pdeSys object
    
    sprintf(name, "HT%d", i);
    solIndexHT[i] = mlSol->GetIndex(name); // get the position of "Ti" in the sol object
    solPdeIndexHT[i] = mlPdeSys->GetSolPdeIndex(name); // get the position of "Ti" in the pdeSys object
    
    sprintf(name, "T%d", i);
    solIndexT[i] = mlSol->GetIndex(name); // get the position of "Ti" in the sol object
    
  }

  unsigned solTypeh = mlSol->GetSolutionType(solIndexh[0]);    // get the finite element type for "hi"
  unsigned solTypev = mlSol->GetSolutionType(solIndexv[0]);    // get the finite element type for "vi"
  unsigned solTypeHT = mlSol->GetSolutionType(solIndexHT[0]);    // get the finite element type for "Ti"
  
  vector < double > x;    // local coordinates
  vector< vector < adept::adouble > > solh(NLayers);    // local coordinates
  vector< vector < adept::adouble > > solv(NLayers);    // local coordinates
  vector< vector < adept::adouble > > solHT(NLayers);    // local coordinates
  vector< vector < double > > solT(NLayers);    // local coordinates
  
  vector< vector < bool > > bdch(NLayers);    // local coordinates
  vector< vector < bool > > bdcv(NLayers);    // local coordinates
  vector< vector < bool > > bdcHT(NLayers);    // local coordinates
  
  unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  vector < vector< adept::adouble > > aResh(NLayers);
  vector < vector< adept::adouble > > aResv(NLayers);
  vector < vector< adept::adouble > > aResHT(NLayers);
  
  KK->zero();
  RES->zero();

  double maxWaveSpeed = 0.;
  
  double dx;
  
  for(unsigned k=0; k<NumberOfLayers; k++){
    for(unsigned i =  msh->_dofOffset[solTypeHT][iproc]; i <  msh->_dofOffset[solTypeHT][iproc + 1]; i++){
      double valueT = (*sol->_Sol[solIndexT[k]])(i);
      double valueH = (*sol->_Sol[solIndexh[k]])(i);
            
      double valueHT = valueT * valueH;
    
      sol->_Sol[solIndexHT[k]]->set(i, valueHT);
    }
    sol->_Sol[solIndexHT[k]]->close();
  }
    
  for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielGeom = msh->GetElementType(iel);
    unsigned nDofh  = msh->GetElementDofNumber(iel, solTypeh);    // number of solution element dofs
    unsigned nDofv  = msh->GetElementDofNumber(iel, solTypev);    // number of solution element dofs
    unsigned nDofHT = msh->GetElementDofNumber(iel, solTypeHT);     // number of coordinate element dofs
    unsigned nDofx = msh->GetElementDofNumber(iel, xType);        // number of coordinate element dofs

    unsigned nDofs = nDofh + nDofv + nDofHT;

    // resize local arrays
    l2GMap.resize(NLayers * (nDofs) );

    for(unsigned i = 0; i < NLayers; i++) {
      solh[i].resize(nDofh);
      solv[i].resize(nDofv);
      solHT[i].resize(nDofHT);
      solT[i].resize(nDofHT);
      bdch[i].resize(nDofh);
      bdcv[i].resize(nDofv);
      bdcHT[i].resize(nDofHT);
      aResh[i].resize(nDofh);    //resize
      std::fill(aResh[i].begin(), aResh[i].end(), 0);    //set aRes to zero
      aResv[i].resize(nDofv);    //resize
      std::fill(aResv[i].begin(), aResv[i].end(), 0);    //set aRes to zero
      aResHT[i].resize(nDofHT);    //resize
      std::fill(aResHT[i].begin(), aResHT[i].end(), 0);    //set aRes to zero
    }
    x.resize(nDofx);

    //local storage of global mapping and solution
    for(unsigned i = 0; i < nDofh; i++) {
      unsigned solDofh = msh->GetSolutionDof(i, iel, solTypeh);    // global to global mapping between solution node and solution dof
      for(unsigned j = 0; j < NLayers; j++) {
        solh[j][i] = (*sol->_Sol[solIndexh[j]])(solDofh);      // global extraction and local storage for the solution
        bdch[j][i] = ( (*sol->_Bdc[solIndexh[j]])(solDofh) < 1.5) ? true : false;
        l2GMap[ j * nDofs + i] = pdeSys->GetSystemDof(solIndexh[j], solPdeIndexh[j], i, iel);    // global to global mapping between solution node and pdeSys dof
      }
    }
    for(unsigned i = 0; i < nDofv; i++) {
      unsigned solDofv = msh->GetSolutionDof(i, iel, solTypev);    // global to global mapping between solution node and solution dof
      for(unsigned j = 0; j < NLayers; j++) {
        solv[j][i] = (*sol->_Sol[solIndexv[j]])(solDofv);      // global extraction and local storage for the solution
        bdcv[j][i] = ( (*sol->_Bdc[solIndexv[j]])(solDofv) < 1.5) ? true : false;
        l2GMap[ j * nDofs + nDofh + i] = pdeSys->GetSystemDof(solIndexv[j], solPdeIndexv[j], i, iel);    // global to global mapping between solution node and pdeSys dof
      }
    }
    for(unsigned i = 0; i < nDofHT; i++) {
      unsigned solDofHT = msh->GetSolutionDof(i, iel, solTypeHT);    // global to global mapping between solution node and solution dof
      unsigned solDofh = msh->GetSolutionDof(i, iel, solTypeh);
      for(unsigned j = 0; j < NLayers; j++) {
        solHT[j][i] = (*sol->_Sol[solIndexHT[j]])(solDofHT);   // global extraction and local storage for the solution
	solT[j][i] = (*sol->_Sol[solIndexT[j]])(solDofHT);   // global extraction and local storage for the solution
        bdcHT[j][i] = ( (*sol->_Bdc[solIndexHT[j]])(solDofHT) < 1.5) ? true : false;
        l2GMap[ j * nDofs + nDofh + nDofv + i] = pdeSys->GetSystemDof(solIndexHT[j], solPdeIndexHT[j], i, iel);    // global to global mapping between solution node and pdeSys dof
	//std::cout << solT[j][i] << " ";
      }
    }

    s.new_recording();
    
    for(unsigned i = 0; i < nDofx; i++) {
      unsigned xDof  = msh->GetSolutionDof(i, iel, xType);    // global to global mapping between coordinates node and coordinate dof
      x[i] = (*msh->_topology->_Sol[0])(xDof);      // global extraction and local storage for the element coordinates
    }
    

    double xmid = 0.5 * (x[0] + x[1]);
    //std::cout << xmid << std::endl;
    double zz = sqrt(aa * aa - xmid * xmid); // z coordinate of points on sphere
    double dd = aa * acos((zz * z_c) / (aa * aa)); // distance to center point on sphere [m]
    double hh = 1 - dd * dd / (bb * bb);
    double b = ( H_shelf + H_0 / 2 * (1 + tanh(hh / phi)) ); 
    
   
   
      
    
    double hTot = 0.;
    
    double beta = 0.2;
    
     std::vector < adept::adouble > P(NLayers);
    for(unsigned k = 0; k < NLayers; k++) {
      hTot += solh[k][0].value();
      adept::adouble rhok = rho1[k] - beta * solT[k][0];
      P[k] = - rhok * 9.81 * b; // bottom topography
      for( unsigned j = 0; j < NLayers; j++){
	 adept::adouble rhoj = (j <= k) ? (rho1[j] - beta * solT[j][0]) : rhok;
	 P[k] += rhoj * 9.81 * solh[j][0];
      }
      P[k] /= 1024;
    }
       
    std::vector < double > hALE(NLayers, 0.); 
      
    hALE[0] = hRest[0] + (hTot - b);
    for(unsigned k = 1; k < NLayers - 1; k++){
      hALE[k] = hRest[k];
    }
    hALE[NLayers - 1] = b - hRest[NLayers - 1];
       
    std::vector < double > w(NLayers+1, 0.);
    
     dx = x[1] - x[0];
     
    for(unsigned k = NLayers; k>1; k--){
      w[k-1] = w[k] -  solh[k-1][0].value() * (solv[k-1][1].value() - solv[k-1][0].value() )/dx- ( hALE[k-1] - solh[k-1][0].value()) / dt;
      //std::cout << hALE[k-1] << " " << w[k-1] << " ";
    }
    //std::cout<<std::endl;
    
    std::vector < adept::adouble > zMid(NLayers);
    for(unsigned k = 0; k < NLayers; k++) {
      zMid[k] = -b + solh[k][0]/2;
      for(unsigned i = k+1; i < NLayers; i++) {
        zMid[k] += solh[i][0];
      }
    }
    
    double celerity = sqrt( 9.81 * hTot);
    for(unsigned i = 0; i<NLayers; i++){
      double vmid = 0.5 * ( solv[i][0].value() + solv[i][1].value() );
      maxWaveSpeed = ( maxWaveSpeed > fabs(vmid) + fabs(celerity) )?  maxWaveSpeed : fabs(vmid) + fabs(celerity);
    }
       

    for(unsigned k = 0; k < NLayers; k++) {
      if(!bdch[k][0]) {
        for (unsigned j = 0; j < nDofv; j++) {
          double sign = ( j == 0) ? 1. : -1;
          aResh[k][0] += sign * solh[k][0] * solv[k][j] / dx; 
	}
	aResh[k][0] += w[k+1] - w[k];	    
      }
      adept::adouble vMid = 0.5 * (solv[k][0] + solv[k][1]);
      adept::adouble fv = 0.5 * vMid * vMid + P[k];
      for (unsigned i = 0; i < nDofv; i++) {
        if(!bdcv[k][i]) {
          double sign = ( i == 0) ? -1. : 1;
          aResv[k][i] += sign * fv / dx;
	  if ( k > 0 ){
	    aResv[k][i] -= 0.5 * ( w[k]   * 0.5 * ( solv[k-1][i] - solv[k][i] ) / (0.5 * ( solh[k-1][0] + solh[k][0] ) ) );
	  }
	  if (k < NLayers - 1) {
	    aResv[k][i] -= 0.5 * ( w[k+1] * 0.5 * ( solv[k][i] - solv[k+1][i] ) / (0.5 * ( solh[k][0] + solh[k+1][0] ) ) );
	  }
	  //aResv[k][i] += sign * 9.81  * rho1[k] / 1024. * zMid[k] / dx;
        }
      }
      if(!bdcHT[k][0]) {
        for (unsigned j = 0; j < nDofv; j++) {
          double sign = ( j == 0) ? 1. : -1;
          aResHT[k][0] += sign * solv[k][j] * solHT[k][0] / dx; 
	}
	if(k<NLayers-1){
	  aResHT[k][0] += w[k+1] * 0.5 * (solHT[k][0]/solh[k][0] + solHT[k+1][0]/solh[k+1][0]);
	  //aResHT[k][0] += w[k+1] * 0.5 * (solT[k][0] + solT[k+1][0]);
	}
	if( k > 0){
	  aResHT[k][0] -= w[k] * 0.5 * (solHT[k-1][0]/solh[k-1][0] + solHT[k][0]/solh[k][0] );
	  //aResHT[k][0] -= w[k] * 0.5 * (solT[k-1][0] + solT[k][0]);
	}
      }
    } 

    vector< double > Res(NLayers * nDofs); // local redidual vector

    unsigned counter = 0;
    for(unsigned k = 0; k < NLayers; k++) {
      for(int i = 0; i < nDofh; i++) {
        Res[counter] =  aResh[k][i].value();
        counter++;
      }
      for(int i = 0; i < nDofv; i++) {
        Res[counter] =  aResv[k][i].value();
        counter++;
      }
      for(int i = 0; i < nDofHT; i++) {
        Res[counter] =  aResHT[k][i].value();
        counter++;
      }
    }

    RES->add_vector_blocked(Res, l2GMap);


    for(unsigned k = 0; k < NLayers; k++) {
      // define the dependent variables
      s.dependent(&aResh[k][0], nDofh);
      s.dependent(&aResv[k][0], nDofv);
      s.dependent(&aResHT[k][0], nDofHT);

      // define the independent variables
      s.independent(&solh[k][0], nDofh);
      s.independent(&solv[k][0], nDofv);
      s.independent(&solHT[k][0], nDofHT);
    }

    // get the jacobian matrix (ordered by row major )
    vector < double > Jac(NLayers * nDofs * NLayers * nDofs);
    s.jacobian(&Jac[0], true);

    //store K in the global matrix KK
    KK->add_matrix_blocked(Jac, l2GMap, l2GMap);

    s.clear_independents();
    s.clear_dependents();

  }

  RES->close();
  KK->close();

//   PetscViewer    viewer;
//   PetscViewerDrawOpen(PETSC_COMM_WORLD,NULL,NULL,0,0,900,900,&viewer);
//   PetscObjectSetName((PetscObject)viewer,"FSI matrix");
//   PetscViewerPushFormat(viewer,PETSC_VIEWER_DRAW_LG);
//   MatView((static_cast<PetscMatrix*>(KK))->mat(),viewer);
//   double a;
//   std::cin>>a;
//
  
//  abort();
  MFN mfn;
  Mat A = (static_cast<PetscMatrix*>(KK))->mat();
  FN f, f1, f2, f3 , f4;
  
 
  
  std::cout << "dt = " << dt << " dx = "<< dx << " maxWaveSpeed = "<<maxWaveSpeed << std::endl;
  
  //dt = 100.;

  Vec v = (static_cast< PetscVector* >(RES))->vec();
  Vec y = (static_cast< PetscVector* >(EPS))->vec();

  MFNCreate( PETSC_COMM_WORLD, &mfn );

  MFNSetOperator( mfn, A );
  MFNGetFN( mfn, &f );


//   FNCreate(PETSC_COMM_WORLD, &f1);
//   FNCreate(PETSC_COMM_WORLD, &f2);
//   FNCreate(PETSC_COMM_WORLD, &f3);
//   FNCreate(PETSC_COMM_WORLD, &f4);
// 
//   FNSetType(f1, FNEXP);
// 
//   FNSetType(f2, FNRATIONAL);
//   double coeff1[1] = { -1};
//   FNRationalSetNumerator(f2, 1, coeff1);
//   FNRationalSetDenominator(f2, 0, PETSC_NULL);
// 
//   FNSetType( f3, FNCOMBINE );
// 
//   FNCombineSetChildren(f3, FN_COMBINE_ADD, f1, f2);
// 
//   FNSetType(f4, FNRATIONAL);
//   double coeff2[2] = {1., 0.};
//   FNRationalSetNumerator(f4, 2, coeff2);
//   FNRationalSetDenominator(f4, 0, PETSC_NULL);
// 
//   FNSetType( f, FNCOMBINE );
// 
//   FNCombineSetChildren(f, FN_COMBINE_DIVIDE, f3, f4);

  FNPhiSetIndex(f,1);
  FNSetType( f, FNPHI );
// FNView(f,PETSC_VIEWER_STDOUT_WORLD);

  FNSetScale( f, dt, dt);
  MFNSetFromOptions( mfn );

  MFNSolve( mfn, v, y);
  MFNDestroy( &mfn );

//   FNDestroy(&f1);
//   FNDestroy(&f2);
//   FNDestroy(&f3);
//   FNDestroy(&f4);


  sol->UpdateSol(mlPdeSys->GetSolPdeIndex(), EPS, pdeSys->KKoffset); 

  unsigned solIndexeta = mlSol->GetIndex("eta");
  unsigned solIndexb = mlSol->GetIndex("b");
  sol->_Sol[solIndexeta]->zero();
  for(unsigned k=0;k<NumberOfLayers;k++){
    sol->_Sol[solIndexeta]->add(*sol->_Sol[solIndexh[k]]);
  }
  sol->_Sol[solIndexeta]->add(-1,*sol->_Sol[solIndexb]);

  for(unsigned k=0; k<NumberOfLayers; k++){
    for(unsigned i =  msh->_dofOffset[solTypeHT][iproc]; i <  msh->_dofOffset[solTypeHT][iproc + 1]; i++){
      double valueHT = (*sol->_Sol[solIndexHT[k]])(i);
      double valueH = (*sol->_Sol[solIndexh[k]])(i);
            
      double valueT = valueHT/valueH;
    
      sol->_Sol[solIndexT[k]]->set(i, valueT);
    }
    
    sol->_Sol[solIndexT[k]]->close();
    
  }
  
  
}
Beispiel #4
0
void AssemblePoisson_AD (MultiLevelProblem& ml_prob) {
  //  ml_prob is the global object from/to where get/set all the data
  //  level is the level of the PDE system to be assembled
  //  levelMax is the Maximum level of the MultiLevelProblem
  //  assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled

  // call the adept stack object
  adept::Stack& s = FemusInit::_adeptStack;

  //  extract pointers to the several objects that we are going to use
  NonLinearImplicitSystem* mlPdeSys   = &ml_prob.get_system<NonLinearImplicitSystem> ("Poisson");   // pointer to the linear implicit system named "Poisson"
  const unsigned level = mlPdeSys->GetLevelToAssemble();

  Mesh*           msh         = ml_prob._ml_msh->GetLevel (level);   // pointer to the mesh (level) object
  elem*           el          = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution*   mlSol = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution*   sol             = ml_prob._ml_sol->GetSolutionLevel (level);   // pointer to the solution (level) object


  LinearEquationSolver* pdeSys  = mlPdeSys->_LinSolver[level];  // pointer to the equation (level) object
  SparseMatrix*   KK          = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector*  RES         = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
  unsigned dim2 = (3 * (dim - 1) + ! (dim - 1));       // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

  // reserve memory for the local standar vectors
  const unsigned maxSize = static_cast< unsigned > (ceil (pow (3, dim)));       // conservative: based on line3, quad9, hex27

  //solution variable
  unsigned solUIndex;
  solUIndex = mlSol->GetIndex ("U");   // get the position of "U" in the ml_sol object = 0
  unsigned solUType = mlSol->GetSolutionType (solUIndex);   // get the finite element type for "T"

  unsigned solUPdeIndex;
  solUPdeIndex = mlPdeSys->GetSolPdeIndex ("U");   // get the position of "U" in the pdeSys object = 0

  vector < adept::adouble >  solU; // local solution
  vector< adept::adouble > aResU; // local redidual vector

  unsigned solVIndex;
  solVIndex = mlSol->GetIndex ("V");
  unsigned solVType = mlSol->GetSolutionType (solVIndex);

  unsigned solVPdeIndex;
  solVPdeIndex = mlPdeSys->GetSolPdeIndex ("V");

  vector < adept::adouble >  solV; // local solution
  vector< adept::adouble > aResV; // local redidual vector

  vector < vector < double > > crdX (dim);   // local coordinates
  unsigned crdXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  solU.reserve (maxSize);
  aResU.reserve (maxSize);

  solV.reserve (maxSize);
  aResV.reserve (maxSize);

  for (unsigned  k = 0; k < dim; k++) {
    crdX[k].reserve (maxSize);
  }

  vector <double> phi;  // local test function
  vector <double> phi_x; // local test function first order partial derivatives
  vector <double> phi_xx; // local test function second order partial derivatives

  phi.reserve (maxSize);
  phi_x.reserve (maxSize * dim);
  phi_xx.reserve (maxSize * dim2);

  vector <double> phiV;  // local test function
  vector <double> phiV_x; // local test function first order partial derivatives
  vector <double> phiV_xx; // local test function second order partial derivatives

  phiV.reserve (maxSize);
  phiV_x.reserve (maxSize * dim);
  phiV_xx.reserve (maxSize * dim2);

  double weight; // gauss point weight

  vector< int > sysDof; // local to global pdeSys dofs
  sysDof.reserve (2 * maxSize);

  vector< double > Res; // local residual vector
  Res.reserve (2 * maxSize);

  vector < double > Jac;
  Jac.reserve (4 * maxSize * maxSize);

  KK->zero(); // Set to zero all the entries of the Global Matrix

  // element loop: each process loops only on the elements that owns
  for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielGeom = msh->GetElementType (iel);     // element geometry type

    unsigned nDofsU = msh->GetElementDofNumber (iel, solUType);     // number of solution element dofs
    unsigned nDofsV = msh->GetElementDofNumber (iel, solVType);
    unsigned nDofsX = msh->GetElementDofNumber (iel, crdXType);     // number of solution element dofs

    // resize local arrays
    sysDof.resize (nDofsU + nDofsV);
    solU.resize (nDofsU);
    solV.resize (nDofsV);

    for (unsigned  k = 0; k < dim; k++) {
      crdX[k].resize (nDofsX);
    }

    aResU.assign (nDofsU, 0);
    aResV.assign (nDofsV, 0);

    // local storage of global mapping and solution
    for (unsigned i = 0; i < nDofsU; i++) {
      unsigned solUDof = msh->GetSolutionDof (i, iel, solUType);   // local to global mapping of the solution U
      solU[i] = (*sol->_Sol[solUIndex]) (solUDof);     // value of the solution U in the dofs
      sysDof[i] = pdeSys->GetSystemDof (solUIndex, solUPdeIndex, i, iel);   // local to global mapping between solution U and system
    }

    for (unsigned i = 0; i < nDofsV; i++) {
      unsigned solVDof = msh->GetSolutionDof (i, iel, solVType);
      solV[i] = (*sol->_Sol[solVIndex]) (solVDof);
      sysDof[i + nDofsU] = pdeSys->GetSystemDof (solVIndex, solVPdeIndex, i, iel);
    }

    // local storage of coordinates
    for (unsigned i = 0; i < nDofsX; i++) {
      unsigned coordXDof  = msh->GetSolutionDof (i, iel, crdXType);  // local to global mapping of the coordinate X[dim]

      for (unsigned k = 0; k < dim; k++) {
        crdX[k][i] = (*msh->_topology->_Sol[k]) (coordXDof);     // value of the solution X[dim]
      }
    }

    s.new_recording();

    // *** Gauss point loop *** //
    for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solUType]->GetGaussPointNumber(); ig++) {
      // *** get gauss point weight, test function and test function partial derivatives ***
      msh->_finiteElement[ielGeom][solUType]->Jacobian (crdX, ig, weight, phi, phi_x, phi_xx);
      msh->_finiteElement[ielGeom][solVType]->Jacobian (crdX, ig, weight, phiV, phiV_x, phiV_xx);

      adept::adouble solUig = 0; // solution U in the gauss point
      vector < adept::adouble > gradSolUig (dim, 0.); // gradient of solution U in the gauss point

      for (unsigned i = 0; i < nDofsU; i++) {
        solUig += phi[i] * solU[i];

        for (unsigned j = 0; j < dim; j++) {
          gradSolUig[j] += phi_x[i * dim + j] * solU[i];
        }
      }

      adept::adouble solVig = 0; // solution V in the gauss point
      vector < adept::adouble > gradSolVig (dim, 0.); // gradient of solution U in the gauss point

      for (unsigned i = 0; i < nDofsV; i++) {
        solVig += phiV[i] * solV[i];

        for (unsigned j = 0; j < dim; j++) {
          gradSolVig[j] += phiV_x[i * dim + j] * solV[i];
        }
      }

      double nu = 1.;

      // *** phiU_i loop ***
      for (unsigned i = 0; i < nDofsU; i++) {
        adept::adouble LaplaceU = 0.;

        for (unsigned j = 0; j < dim; j++) {
          LaplaceU -=  nu * phi_x[i * dim + j] * gradSolUig[j];
        }

        aResU[i] += (phi[i] - LaplaceU) * weight;

      } // end phiU_i loop

      for (unsigned i = 0; i < nDofsV; i++) {
        adept::adouble LaplaceV = 0.;

        for (unsigned j = 0; j < dim; j++) {
          LaplaceV -=  nu * phiV_x[i * dim + j] * gradSolVig[j];
        }

        aResV[i] += (phiV[i] * solUig - LaplaceV) * weight;

      } // end phiV_i loop

    } // end gauss point loop




    // } // endif single element not refined or fine grid loop

    //--------------------------------------------------------------------------------------------------------
    // Add the local Matrix/Vector into the global Matrix/Vector



    //copy the value of the adept::adoube aRes in double Res and store them in RES
    Res.resize (nDofsU + nDofsV);   //resize

    for (int i = 0; i < nDofsU; i++) {
      Res[i] = -aResU[i].value();
    }

    for (int i = 0; i < nDofsV; i++) {
      Res[i + nDofsU] = -aResV[i].value();
    }

    RES->add_vector_blocked (Res, sysDof);

    //Extarct and store the Jacobian

    Jac.resize ( (nDofsU + nDofsV) * (nDofsU + nDofsV));
    // define the dependent variables
    s.dependent (&aResU[0], nDofsU);
    s.dependent (&aResV[0], nDofsV);

    // define the independent variables
    s.independent (&solU[0], nDofsU);
    s.independent (&solV[0], nDofsV);
    // get the and store jacobian matrix (row-major)
    s.jacobian (&Jac[0] , true);
    KK->add_matrix_blocked (Jac, sysDof, sysDof);

    s.clear_independents();
    s.clear_dependents();

  } //end element loop for each process

  RES->close();

  KK->close();

  // ***************** END ASSEMBLY *******************
}
Beispiel #5
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

  //  extract pointers to the several objects that we are going to use
  NonLinearImplicitSystem* mlPdeSys   = &ml_prob.get_system<NonLinearImplicitSystem> ("NS");   // pointer to the linear implicit system named "Poisson"
  const unsigned level = mlPdeSys->GetLevelToAssemble();

  Mesh*           msh         = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
  elem*           el          = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution*   mlSol         = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution*   sol         = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object


  LinearEquationSolver* pdeSys        = mlPdeSys->_LinSolver[level];  // pointer to the equation (level) object

  bool assembleMatrix = mlPdeSys->GetAssembleMatrix();
  // call the adept stack object
  adept::Stack& s = FemusInit::_adeptStack;

  if(assembleMatrix) s.continue_recording();
  else s.pause_recording();

  SparseMatrix*   KK          = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector*  RES         = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
  unsigned dim2 = (3 * (dim - 1) + !(dim - 1));        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

  // reserve memory for the local standar vectors
  const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27

  //solution variable
  unsigned solTIndex;
  solTIndex = mlSol->GetIndex("T");    // get the position of "T" in the ml_sol object
  unsigned solTType = mlSol->GetSolutionType(solTIndex);    // get the finite element type for "T"

  vector < unsigned > solVIndex(dim);
  solVIndex[0] = mlSol->GetIndex("U");    // get the position of "U" in the ml_sol object
  solVIndex[1] = mlSol->GetIndex("V");    // get the position of "V" in the ml_sol object

  if(dim == 3) solVIndex[2] = mlSol->GetIndex("W");       // get the position of "V" in the ml_sol object

  unsigned solVType = mlSol->GetSolutionType(solVIndex[0]);    // get the finite element type for "u"

  unsigned solPIndex;
  solPIndex = mlSol->GetIndex("P");    // get the position of "P" in the ml_sol object
  unsigned solPType = mlSol->GetSolutionType(solPIndex);    // get the finite element type for "u"

  unsigned solTPdeIndex;
  solTPdeIndex = mlPdeSys->GetSolPdeIndex("T");    // get the position of "T" in the pdeSys object

  // std::cout << solTIndex <<" "<<solTPdeIndex<<std::endl;


  vector < unsigned > solVPdeIndex(dim);
  solVPdeIndex[0] = mlPdeSys->GetSolPdeIndex("U");    // get the position of "U" in the pdeSys object
  solVPdeIndex[1] = mlPdeSys->GetSolPdeIndex("V");    // get the position of "V" in the pdeSys object

  if(dim == 3) solVPdeIndex[2] = mlPdeSys->GetSolPdeIndex("W");

  unsigned solPPdeIndex;
  solPPdeIndex = mlPdeSys->GetSolPdeIndex("P");    // get the position of "P" in the pdeSys object

  vector < adept::adouble >  solT; // local solution
  vector < vector < adept::adouble > >  solV(dim);    // local solution
  vector < adept::adouble >  solP; // local solution

  vector< adept::adouble > aResT; // local redidual vector
  vector< vector < adept::adouble > > aResV(dim);    // local redidual vector
  vector< adept::adouble > aResP; // local redidual vector

  vector < vector < double > > coordX(dim);    // local coordinates
  unsigned coordXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  solT.reserve(maxSize);
  aResT.reserve(maxSize);

  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);

  vector <double> phiT;  // local test function
  vector <double> phiT_x; // local test function first order partial derivatives
  vector <double> phiT_xx; // local test function second order partial derivatives

  phiT.reserve(maxSize);
  phiT_x.reserve(maxSize * dim);
  phiT_xx.reserve(maxSize * dim2);

  double* phiP;
  double weight; // gauss point weight

  vector< int > sysDof; // local to global pdeSys dofs
  sysDof.reserve((dim + 2) *maxSize);

  vector< double > Res; // local redidual vector
  Res.reserve((dim + 2) *maxSize);

  vector < double > Jac;
  Jac.reserve((dim + 2) *maxSize * (dim + 2) *maxSize);

  if(assembleMatrix)
    KK->zero(); // Set to zero all the entries of the Global Matrix

  // element loop: each process loops only on the elements that owns
  for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    // element geometry type
    short unsigned ielGeom = msh->GetElementType(iel);

    unsigned nDofsT = msh->GetElementDofNumber(iel, solTType);    // number of solution element dofs
    unsigned nDofsV = msh->GetElementDofNumber(iel, solVType);    // number of solution element dofs
    unsigned nDofsP = msh->GetElementDofNumber(iel, solPType);    // number of solution element dofs
    unsigned nDofsX = msh->GetElementDofNumber(iel, coordXType);    // number of coordinate element dofs

    unsigned nDofsTVP = nDofsT + dim * nDofsV + nDofsP;
    // resize local arrays
    sysDof.resize(nDofsTVP);

    solT.resize(nDofsV);

    for(unsigned  k = 0; k < dim; k++) {
      solV[k].resize(nDofsV);
      coordX[k].resize(nDofsX);
    }

    solP.resize(nDofsP);

    aResT.resize(nDofsT);    //resize
    std::fill(aResT.begin(), aResT.end(), 0);    //set aRes to zero

    for(unsigned  k = 0; k < dim; k++) {
      aResV[k].resize(nDofsV);    //resize
      std::fill(aResV[k].begin(), aResV[k].end(), 0);    //set aRes to zero
    }

    aResP.resize(nDofsP);    //resize
    std::fill(aResP.begin(), aResP.end(), 0);    //set aRes to zero

    // local storage of global mapping and solution
    for(unsigned i = 0; i < nDofsT; i++) {
      unsigned solTDof = msh->GetSolutionDof(i, iel, solTType);    // global to global mapping between solution node and solution dof
      solT[i] = (*sol->_Sol[solTIndex])(solTDof);      // global extraction and local storage for the solution
      sysDof[i] = pdeSys->GetSystemDof(solTIndex, solTPdeIndex, i, iel);    // global to global mapping between solution node and pdeSys dofs
    }

    // local storage of global mapping and solution
    for(unsigned i = 0; i < nDofsV; i++) {
      unsigned solVDof = msh->GetSolutionDof(i, iel, solVType);    // global to global mapping between solution node and solution dof

      for(unsigned  k = 0; k < dim; k++) {
        solV[k][i] = (*sol->_Sol[solVIndex[k]])(solVDof);      // global extraction and local storage for the solution
        sysDof[i + nDofsT + k * nDofsV] = pdeSys->GetSystemDof(solVIndex[k], solVPdeIndex[k], i, iel);    // global to global mapping between solution node and pdeSys dof
      }
    }

    for(unsigned i = 0; i < nDofsP; i++) {
      unsigned solPDof = msh->GetSolutionDof(i, iel, solPType);    // global to global mapping between solution node and solution dof
      solP[i] = (*sol->_Sol[solPIndex])(solPDof);      // global extraction and local storage for the solution
      sysDof[i + nDofsT + dim * nDofsV] = pdeSys->GetSystemDof(solPIndex, solPPdeIndex, i, iel);    // global to global mapping between solution node and pdeSys dof
    }

    // local storage of coordinates
    for(unsigned i = 0; i < nDofsX; i++) {
      unsigned coordXDof  = msh->GetSolutionDof(i, iel, coordXType);    // global to global mapping between coordinates node and coordinate dof

      for(unsigned k = 0; k < dim; k++) {
        coordX[k][i] = (*msh->_topology->_Sol[k])(coordXDof);      // global extraction and local storage for the element coordinates
      }
    }


    // start a new recording of all the operations involving adept::adouble variables
    if(assembleMatrix) s.new_recording();

    // *** Gauss point loop ***
    for(unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solVType]->GetGaussPointNumber(); ig++) {
      // *** get gauss point weight, test function and test function partial derivatives ***
      msh->_finiteElement[ielGeom][solTType]->Jacobian(coordX, ig, weight, phiT, phiT_x, phiT_xx);
      msh->_finiteElement[ielGeom][solVType]->Jacobian(coordX, ig, weight, phiV, phiV_x, phiV_xx);
      phiP = msh->_finiteElement[ielGeom][solPType]->GetPhi(ig);

      // evaluate the solution, the solution derivatives and the coordinates in the gauss point
      adept::adouble solT_gss = 0;
      vector < adept::adouble > gradSolT_gss(dim, 0.);

      for(unsigned i = 0; i < nDofsT; i++) {
        solT_gss += phiT[i] * solT[i];

        for(unsigned j = 0; j < dim; j++) {
          gradSolT_gss[j] += phiT_x[i * dim + j] * solT[i];
        }
      }

      vector < 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 alpha = 1.;
      double beta = 1.;//40000.;


      double Pr = 1. / 10;
      double Ra = 10000;

      // *** phiT_i loop ***
      for(unsigned i = 0; i < nDofsT; i++) {
        adept::adouble Temp = 0.;

        for(unsigned j = 0; j < dim; j++) {
          Temp +=  1. / sqrt(Ra * Pr) * alpha * phiT_x[i * dim + j] * gradSolT_gss[j];
          Temp +=  phiT[i] * (solV_gss[j] * gradSolT_gss[j]);
        }

        aResT[i] += - Temp * weight;
      } // end phiT_i loop


      // *** 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]   +=  sqrt(Pr / Ra) * phiV_x[i * dim + j] * (gradSolV_gss[k][j] + gradSolV_gss[j][k]);
            NSV[k]   +=  phiV[i] * (solV_gss[j] * gradSolV_gss[k][j]);
          }
        }

        for(unsigned  k = 0; k < dim; k++) {
          NSV[k] += -solP_gss * phiV_x[i * dim + k];
        }

        NSV[1] += -beta * solT_gss * phiV[i];

        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

    //--------------------------------------------------------------------------------------------------------
    // Add the local Matrix/Vector into the global Matrix/Vector

    //copy the value of the adept::adoube aRes in double Res and store them in RES
    Res.resize(nDofsTVP);    //resize

    for(int i = 0; i < nDofsT; i++) {
      Res[i] = -aResT[i].value();
    }

    for(int i = 0; i < nDofsV; i++) {
      for(unsigned  k = 0; k < dim; k++) {
        Res[ i + nDofsT + k * nDofsV ] = -aResV[k][i].value();
      }
    }

    for(int i = 0; i < nDofsP; i++) {
      Res[ i + nDofsT + dim * nDofsV ] = -aResP[i].value();
    }

    RES->add_vector_blocked(Res, sysDof);

    //Extarct and store the Jacobian
    if(assembleMatrix) {
      Jac.resize(nDofsTVP * nDofsTVP);
      // define the dependent variables
      s.dependent(&aResT[0], nDofsT);

      for(unsigned  k = 0; k < dim; k++) {
        s.dependent(&aResV[k][0], nDofsV);
      }

      s.dependent(&aResP[0], nDofsP);

      // define the independent variables
      s.independent(&solT[0], nDofsT);

      for(unsigned  k = 0; k < dim; k++) {
        s.independent(&solV[k][0], nDofsV);
      }

      s.independent(&solP[0], nDofsP);

      // get the and store jacobian matrix (row-major)
      s.jacobian(&Jac[0] , true);
      KK->add_matrix_blocked(Jac, sysDof, sysDof);

      s.clear_independents();
      s.clear_dependents();
    }
  } //end element loop for each process

  RES->close();

  if(assembleMatrix) {
    KK->close();
  }

  // ***************** END ASSEMBLY *******************
}
Beispiel #6
0
void AssembleBoussinesqAppoximation(MultiLevelProblem& ml_prob) {
  //  ml_prob is the global object from/to where get/set all the data
  //  level is the level of the PDE system to be assembled
  //  levelMax is the Maximum level of the MultiLevelProblem
  //  assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled

  //  extract pointers to the several objects that we are going to use
  NonLinearImplicitSystem* mlPdeSys   = &ml_prob.get_system<NonLinearImplicitSystem> ("NS");   // pointer to the linear implicit system named "Poisson"
  const unsigned level = mlPdeSys->GetLevelToAssemble();

  Mesh*           msh         = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
  elem*           el          = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution*   mlSol         = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution*   sol         = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object


  LinearEquationSolver* pdeSys        = mlPdeSys->_LinSolver[level];  // pointer to the equation (level) object

  bool assembleMatrix = mlPdeSys->GetAssembleMatrix();
  // call the adept stack object

  SparseMatrix*   KK          = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector*  RES         = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
  unsigned dim2 = (3 * (dim - 1) + !(dim - 1));        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

  // reserve memory for the local standar vectors
  const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27

  //solution variable
  unsigned solTIndex;
  solTIndex = mlSol->GetIndex("T");    // get the position of "T" in the ml_sol object
  unsigned solTType = mlSol->GetSolutionType(solTIndex);    // get the finite element type for "T"

  vector < unsigned > solVIndex(dim);
  solVIndex[0] = mlSol->GetIndex("U");    // get the position of "U" in the ml_sol object
  solVIndex[1] = mlSol->GetIndex("V");    // get the position of "V" in the ml_sol object

  if(dim == 3) solVIndex[2] = mlSol->GetIndex("W");       // get the position of "V" in the ml_sol object

  unsigned solVType = mlSol->GetSolutionType(solVIndex[0]);    // get the finite element type for "u"

  unsigned solPIndex;
  solPIndex = mlSol->GetIndex("P");    // get the position of "P" in the ml_sol object
  unsigned solPType = mlSol->GetSolutionType(solPIndex);    // get the finite element type for "u"

  unsigned solTPdeIndex;
  solTPdeIndex = mlPdeSys->GetSolPdeIndex("T");    // get the position of "T" in the pdeSys object

  // std::cout << solTIndex <<" "<<solTPdeIndex<<std::endl;


  vector < unsigned > solVPdeIndex(dim);
  solVPdeIndex[0] = mlPdeSys->GetSolPdeIndex("U");    // get the position of "U" in the pdeSys object
  solVPdeIndex[1] = mlPdeSys->GetSolPdeIndex("V");    // get the position of "V" in the pdeSys object

  if(dim == 3) solVPdeIndex[2] = mlPdeSys->GetSolPdeIndex("W");

  unsigned solPPdeIndex;
  solPPdeIndex = mlPdeSys->GetSolPdeIndex("P");    // get the position of "P" in the pdeSys object

  vector < double >  solT; // local solution
  vector < vector < double > >  solV(dim);    // local solution
  vector < double >  solP; // local solution

  vector < vector < double > > coordX(dim);    // local coordinates
  unsigned coordXType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  solT.reserve(maxSize);

  for(unsigned  k = 0; k < dim; k++) {
    solV[k].reserve(maxSize);
    coordX[k].reserve(maxSize);
  }

  solP.reserve(maxSize);

  vector <double> phiV;  // local test function
  vector <double> phiV_x; // local test function first order partial derivatives
  vector <double> phiV_xx; // local test function second order partial derivatives

  phiV.reserve(maxSize);
  phiV_x.reserve(maxSize * dim);
  phiV_xx.reserve(maxSize * dim2);

  vector <double> phiT;  // local test function
  vector <double> phiT_x; // local test function first order partial derivatives
  vector <double> phiT_xx; // local test function second order partial derivatives

  phiT.reserve(maxSize);
  phiT_x.reserve(maxSize * dim);
  phiT_xx.reserve(maxSize * dim2);

  double* phiP;
  double weight; // gauss point weight

  vector< int > sysDof; // local to global pdeSys dofs
  sysDof.reserve((dim + 2) *maxSize);

  vector< double > Res; // local redidual vector
  Res.reserve((dim + 2) *maxSize);

  vector < double > Jac;
  Jac.reserve((dim + 2) *maxSize * (dim + 2) *maxSize);

  if(assembleMatrix)
    KK->zero(); // Set to zero all the entries of the Global Matrix

  //BEGIN element loop
  for(int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    //BEGIN local dof number extraction
    unsigned nDofsT = msh->GetElementDofNumber(iel, solTType);  //temperature
    unsigned nDofsV = msh->GetElementDofNumber(iel, solVType);  //velocity
    unsigned nDofsP = msh->GetElementDofNumber(iel, solPType);  //pressure
    unsigned nDofsX = msh->GetElementDofNumber(iel, coordXType); // coordinates
    unsigned nDofsTVP = nDofsT + dim * nDofsV + nDofsP; // all solutions
    //END local dof number extraction

    //BEGIN memory allocation
    Res.resize(nDofsTVP);
    std::fill(Res.begin(), Res.end(), 0);
    Jac.resize(nDofsTVP * nDofsTVP);
    std::fill(Jac.begin(), Jac.end(), 0);
    sysDof.resize(nDofsTVP);

    solT.resize(nDofsV);

    for(unsigned  k = 0; k < dim; k++) {
      solV[k].resize(nDofsV);
      coordX[k].resize(nDofsX);
    }

    solP.resize(nDofsP);
    //END memory allocation

    //BEGIN global to local extraction
    for(unsigned i = 0; i < nDofsT; i++) { //temperature
      unsigned solTDof = msh->GetSolutionDof(i, iel, solTType);  //local to global solution dof
      solT[i] = (*sol->_Sol[solTIndex])(solTDof);  //global to local solution value
      sysDof[i] = pdeSys->GetSystemDof(solTIndex, solTPdeIndex, i, iel);  //local to global system dof
    }

    for(unsigned i = 0; i < nDofsV; i++) { //velocity
      unsigned solVDof = msh->GetSolutionDof(i, iel, solVType);  //local to global solution dof

      for(unsigned  k = 0; k < dim; k++) {
        solV[k][i] = (*sol->_Sol[solVIndex[k]])(solVDof);  //global to local solution value
        sysDof[i + nDofsT + k * nDofsV] = pdeSys->GetSystemDof(solVIndex[k], solVPdeIndex[k], i, iel);  //local to global system dof
      }
    }

    for(unsigned i = 0; i < nDofsP; i++) { //pressure
      unsigned solPDof = msh->GetSolutionDof(i, iel, solPType);  //local to global solution dof
      solP[i] = (*sol->_Sol[solPIndex])(solPDof);  //global to local solution value
      sysDof[i + nDofsT + dim * nDofsV] = pdeSys->GetSystemDof(solPIndex, solPPdeIndex, i, iel);  //local to global system dof
    }

    for(unsigned i = 0; i < nDofsX; i++) { //coordinates
      unsigned coordXDof  = msh->GetSolutionDof(i, iel, coordXType);  //local to global coordinate dof

      for(unsigned k = 0; k < dim; k++) {
        coordX[k][i] = (*msh->_topology->_Sol[k])(coordXDof);  //global to local coordinate value
      }
    }

    //END global to local extraction

    //BEGIN Gauss point loop
    short unsigned ielGeom = msh->GetElementType(iel);

    for(unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solVType]->GetGaussPointNumber(); ig++) {
      // *** get gauss point weight, test function and test function partial derivatives ***
      msh->_finiteElement[ielGeom][solTType]->Jacobian(coordX, ig, weight, phiT, phiT_x, phiT_xx);
      msh->_finiteElement[ielGeom][solVType]->Jacobian(coordX, ig, weight, phiV, phiV_x, phiV_xx);
      phiP = msh->_finiteElement[ielGeom][solPType]->GetPhi(ig);

      // evaluate the solution, the solution derivatives and the coordinates in the gauss point
      double solT_gss = 0;
      vector < double > gradSolT_gss(dim, 0.);

      for(unsigned i = 0; i < nDofsT; i++) {
        solT_gss += phiT[i] * solT[i];

        for(unsigned j = 0; j < dim; j++) {
          gradSolT_gss[j] += phiT_x[i * dim + j] * solT[i];
        }
      }

      vector < double > solV_gss(dim, 0);
      vector < vector < double > > gradSolV_gss(dim);

      for(unsigned  k = 0; k < dim; k++) {
        gradSolV_gss[k].resize(dim);
        std::fill(gradSolV_gss[k].begin(), gradSolV_gss[k].end(), 0);
      }

      for(unsigned i = 0; i < nDofsV; i++) {
        for(unsigned  k = 0; k < dim; k++) {
          solV_gss[k] += phiV[i] * solV[k][i];
        }

        for(unsigned j = 0; j < dim; j++) {
          for(unsigned  k = 0; k < dim; k++) {
            gradSolV_gss[k][j] += phiV_x[i * dim + j] * solV[k][i];
          }
        }
      }

      double solP_gss = 0;

      for(unsigned i = 0; i < nDofsP; i++) {
        solP_gss += phiP[i] * solP[i];
      }


      double alpha = 1.;
      double beta = 1.;//40000.;


      double Pr = Prandtl;
      double Ra = Rayleigh;

      //BEGIN phiT_i loop: Energy balance
      for(unsigned i = 0; i < nDofsT; i++) {
        unsigned irow = i;

        for(unsigned k = 0; k < dim; k++) {
          Res[irow] +=  -alpha / sqrt(Ra * Pr) * phiT_x[i * dim + k] * gradSolT_gss[k] * weight;
          Res[irow] +=  -phiT[i] * solV_gss[k] * gradSolT_gss[k] * weight;

          if(assembleMatrix) {
            unsigned irowMat = irow * nDofsTVP;

            for(unsigned j = 0; j < nDofsT; j++) {
              Jac[ irowMat + j ] +=  alpha / sqrt(Ra * Pr) * phiT_x[i * dim + k] * phiT_x[j * dim + k] * weight;
              Jac[ irowMat + j ] +=  phiT[i] * solV_gss[k] * phiT_x[j * dim + k] * weight;
            }

            for(unsigned j = 0; j < nDofsV; j++) {
              unsigned jcol = nDofsT + k * nDofsV + j;
              Jac[ irowMat + jcol ] += phiT[i] * phiV[j] * gradSolT_gss[k] * weight;
            }
          }

        }
      }

      //END phiT_i loop

      //BEGIN phiV_i loop: Momentum balance
      for(unsigned i = 0; i < nDofsV; i++) {

        for(unsigned k = 0; k < dim; k++) {
          unsigned irow = nDofsT + k * nDofsV + i;

          for(unsigned l = 0; l < dim; l++) {
            Res[irow] +=  -sqrt(Pr / Ra) * phiV_x[i * dim + l] * (gradSolV_gss[k][l] + gradSolV_gss[l][k]) * weight;
            Res[irow] +=  -phiV[i] * solV_gss[l] * gradSolV_gss[k][l] * weight;
          }

          Res[irow] += solP_gss * phiV_x[i * dim + k] * weight;

          if(k == 1) {
            Res[irow] += beta * solT_gss * phiV[i] * weight;
          }

          if(assembleMatrix) {
            unsigned irowMat = nDofsTVP * irow;

            for(unsigned l = 0; l < dim; l++) {
              for(unsigned j = 0; j < nDofsV; j++) {
                unsigned jcol1 = (nDofsT + k * nDofsV + j);
                unsigned jcol2 = (nDofsT + l * nDofsV + j);
                Jac[ irowMat + jcol1] += sqrt(Pr / Ra) * phiV_x[i * dim + l] * phiV_x[j * dim + l] * weight;
                Jac[ irowMat + jcol2] += sqrt(Pr / Ra) * phiV_x[i * dim + l] * phiV_x[j * dim + k] * weight;
                Jac[ irowMat + jcol1] += phiV[i] * solV_gss[l] * phiV_x[j * dim + l] * weight;
                Jac[ irowMat + jcol2] += phiV[i] * phiV[j] * gradSolV_gss[k][l] * weight;
              }
            }

            for(unsigned j = 0; j < nDofsP; j++) {
              unsigned jcol = (nDofsT + dim * nDofsV) + j;
              Jac[ irowMat + jcol] += - phiV_x[i * dim + k] * phiP[j] * weight;
            }

            if(k == 1) {
              for(unsigned j = 0; j < nDofsT; j++) {
                Jac[ irowMat + j ] += -beta * phiV[i] * phiT[j] * weight;
              }
            }
          }

        }
      }

      //END phiV_i loop

      //BEGIN phiP_i loop: mass balance
      for(unsigned i = 0; i < nDofsP; i++) {
        unsigned irow = nDofsT + dim * nDofsV + i;

        for(int k = 0; k < dim; k++) {
          Res[irow] += (gradSolV_gss[k][k]) * phiP[i]  * weight;

          if(assembleMatrix) {
            unsigned irowMat = nDofsTVP * irow;

            for(unsigned j = 0; j < nDofsV; j++) {
              unsigned jcol = (nDofsT + k * nDofsV + j);
              Jac[ irowMat + jcol ] += - phiP[i] * phiV_x[j * dim + k] * weight;
            }
          }

        }
      }

      //END phiP_i loop

    }

    //END Gauss point loop

    //BEGIN local to global Matrix/Vector assembly
    RES->add_vector_blocked(Res, sysDof);

    if(assembleMatrix) {
      KK->add_matrix_blocked(Jac, sysDof, sysDof);
    }

    //END local to global Matrix/Vector assembly

  }

  //END element loop

  RES->close();

  if(assembleMatrix) {
    KK->close();
  }

  // ***************** END ASSEMBLY *******************
}
Beispiel #7
0
//------------------------------------------------------------------------------------------------------------
void AssemblePoissonMatrixandRhs(MultiLevelProblem& ml_prob) {

  //pointers and references

  LinearImplicitSystem& mylin_impl_sys = ml_prob.get_system<LinearImplicitSystem>("Poisson");
  const unsigned level = mylin_impl_sys.GetLevelToAssemble();
  //bool assemble_matrix = mylin_impl_sys.GetAssembleMatrix();

  Solution*      mysolution	       = ml_prob._ml_sol->GetSolutionLevel(level);
  LinearEquationSolver*  mylsyspde     = mylin_impl_sys._LinSolver[level];
  Mesh*          mymsh		       = ml_prob._ml_msh->GetLevel(level);
  elem*          myel		       = mymsh->el;
  SparseMatrix*  myKK		       = mylsyspde->_KK;
  NumericVector* myRES		       = mylsyspde->_RES;
  MultiLevelSolution* ml_sol           = ml_prob._ml_sol;

  //data
  const unsigned	dim	= mymsh->GetDimension();
  unsigned 		nel	= mymsh->GetNumberOfElements();
  unsigned 		igrid	= mymsh->GetLevel();
  unsigned 		iproc	= mymsh->processor_id();

  //solution variable
  unsigned SolIndex;
  unsigned SolPdeIndex;
  SolIndex = ml_sol->GetIndex("Sol");
  SolPdeIndex = mylin_impl_sys.GetSolPdeIndex("Sol");
  //solution order
  unsigned order_ind = ml_sol->GetSolutionType(SolIndex);
  //coordinates
  vector< vector < double> > coordinates(dim);

  // declare
  vector< int > metis_node;
  vector< int > KK_dof;
  vector <double> phi;
  vector <double> gradphi;
  vector <double> nablaphi;
  double weight;
  vector< double > F;
  vector< double > B;
  vector<double> normal(3.0);
  double src_term = 0.;
  vector<double> xyzt(4, 0.);
  ParsedFunction* bdcfunc = NULL;

  // reserve
  const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim)));
  metis_node.reserve(max_size);
  KK_dof.reserve(max_size);

  for (int i = 0; i < dim; i++)
    coordinates[i].reserve(max_size);

  phi.reserve(max_size);
  gradphi.reserve(max_size * dim);
  unsigned nabla_dim = (3 * (dim - 1) + !(dim - 1));
  nablaphi.reserve(max_size * nabla_dim);
  F.reserve(max_size);
  B.reserve(max_size * max_size);


  // Set to zeto all the entries of the Global Matrix
  myKK->zero();


  // *** element loop ***
  for (int iel = mymsh->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielt = mymsh->GetElementType(iel);
    unsigned nve = mymsh->GetElementDofNumber(iel, order_ind);
    unsigned nve2 = mymsh->GetElementDofNumber(iel, 2);
    // resize
    metis_node.resize(nve);
    KK_dof.resize(nve);

    for (int i = 0; i < dim; i++) {
      coordinates[i].resize(nve);
    }

    // set to zero all the entries of the FE matrices
    F.resize(nve);
    memset(&F[0], 0, nve * sizeof(double));

    B.assign(nve * nve, 0.);

    // get local to global mappings
    for (unsigned i = 0; i < nve2; i++) {
      unsigned inode_coord_metis = mymsh->GetSolutionDof(i, iel, 2);

      for (unsigned ivar = 0; ivar < dim; ivar++) {
        coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
      }

      if (i < nve) {
        metis_node[i] = mymsh->GetSolutionDof(i, iel, order_ind);
        KK_dof[i] = mylsyspde->GetSystemDof(SolIndex, SolPdeIndex, i, iel);
      }

    }




    // *** Gauss point loop ***

    // Supg stabilization tau evaluation
    double V[3] = {0., 0., 0.};
    double nu = 1.;

    if (dim == 1) {
      V[0] = 1.;
      nu = 0.01;
    }
    else if (dim == 2) {
// 	nu=0.0001;
// 	V[0]=sqrt(2)/2;
// 	V[1]=-sqrt(2)/2;
      nu = 1.;
      V[0] = 0.;
      V[1] = 0.;
    }
    else if (dim == 3) {
      nu = 1.;
      V[0] = V[1] = V[2] = 0.;
    }

    double barNu = 0.;
    double vL2Norm2 = 0.;

    for (int i = 0; i < dim; i++) {
      vL2Norm2 += V[i] * V[i];
      unsigned ip = referenceElementDirection[ielt][i][1];
      unsigned im = referenceElementDirection[ielt][i][0];
      double VxiHxi = 0.;

      for (int j = 0; j < dim; j++) {
        VxiHxi += (coordinates[j][ip] - coordinates[j][im]) * V[j];
      }

      double PeXi = VxiHxi / (2.*nu);
      double barXi = (fabs(PeXi) < 1.0e-10) ? 0. : 1. / tanh(PeXi) - 1. / PeXi;
      barNu += barXi * VxiHxi / 2.;
    }

    double supgTau = (vL2Norm2 > 1.0e-15) ? barNu / vL2Norm2 : 0.;
    // End Stabilization stabilization tau evaluation

    for (unsigned ig = 0; ig < mymsh->_finiteElement[ielt][order_ind]->GetGaussPointNumber(); ig++) {
      // *** get Jacobian and test function and test function derivatives ***
      mymsh->_finiteElement[ielt][order_ind]->Jacobian(coordinates, ig, weight, phi, gradphi, nablaphi);
      //current solution
      double SolT = 0;
      vector < double > gradSolT(dim, 0.);
      vector < double > NablaSolT(dim, 0.);

      xyzt.assign(4, 0.);
      unsigned SolType = ml_sol->GetSolutionType("Sol");

      for (unsigned i = 0; i < nve; i++) {
        double soli = (*mysolution->_Sol[SolIndex])(metis_node[i]);

        for (unsigned ivar = 0; ivar < dim; ivar++) {
          xyzt[ivar] += coordinates[ivar][i] * phi[i];
        }

        SolT += phi[i] * soli;

        for (unsigned ivar2 = 0; ivar2 < dim; ivar2++) {
          gradSolT[ivar2] += gradphi[i * dim + ivar2] * soli;
          NablaSolT[ivar2] += nablaphi[i * nabla_dim + ivar2] * soli;
        }
      }

      // *** phi_i loop ***
      for (unsigned i = 0; i < nve; i++) {
        //BEGIN RESIDUALS A block ===========================
        double advRhs = 0.;
        double lapRhs = 0.;
        double resRhs = 0.;
        double supgPhi = 0.;

        for (unsigned ivar = 0; ivar < dim; ivar++) {
          lapRhs   +=  nu * gradphi[i * dim + ivar] * gradSolT[ivar];
          advRhs   +=  V[ivar] * gradSolT[ivar] * phi[i];
          resRhs   += -nu * NablaSolT[ivar] + V[ivar] * gradSolT[ivar];
          supgPhi  += (V[ivar] * gradphi[i * dim + ivar] + nu * nablaphi[i * nabla_dim + ivar]) * supgTau;
        }

        src_term = fpsource(&xyzt[0]);

        F[i] += (src_term * phi[i] - lapRhs - advRhs
                 + (src_term - resRhs) * supgPhi) * weight;

        //END RESIDUALS A block ===========================

        // *** phi_j loop ***
        for (unsigned j = 0; j < nve; j++) {
          double lap = 0;
          double adv = 0;

          for (unsigned ivar = 0; ivar < dim; ivar++) {
            lap += nu * (gradphi[i * dim + ivar] * gradphi[j * dim + ivar]
                         - nablaphi[j * nabla_dim + ivar] * supgPhi) * weight;
            adv += V[ivar] * gradphi[j * dim + ivar] * (phi[i] + supgPhi) * weight;
          }

          B[i * nve + j] += lap + adv ;
        } // end phij loop
      } // end phii loop
    } // end gauss point loop

    if (ml_prob._ml_sol->_useParsedBCFunction) {

      //number of faces for each type of element
      unsigned nfaces = mymsh->GetElementFaceNumber(iel);

      // loop on faces
      for (unsigned jface = 0; jface < nfaces; jface++) {
        // look for boundary faces
        if (myel->GetBoundaryIndex(iel, jface) > 0) {
          unsigned int faceIndex =  myel->GetBoundaryIndex(iel, jface);

          if (ml_sol->GetBoundaryCondition("Sol", faceIndex - 1u) == NEUMANN && !ml_sol->Ishomogeneous("Sol", faceIndex - 1u)) {
            bdcfunc = (ParsedFunction*)(ml_sol->GetBdcFunction("Sol", faceIndex - 1u));
            unsigned nve = mymsh->GetElementFaceDofNumber(iel, jface, order_ind);
            const unsigned felt = mymsh->GetElementFaceType(iel, jface);

            for (unsigned i = 0; i < nve; i++) {
              unsigned ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i);
              unsigned inode_coord_metis = mymsh->GetSolutionDof(ilocal, iel, 2);

              for (unsigned ivar = 0; ivar < dim; ivar++) {
                coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
              }
            }

            if (felt != 6) {
              for (unsigned igs = 0; igs < mymsh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) {
                mymsh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal);

                xyzt.assign(4, 0.);

                for (unsigned i = 0; i < nve; i++) {
                  for (unsigned ivar = 0; ivar < dim; ivar++) {
                    xyzt[ivar] += coordinates[ivar][i] * phi[i];
                  }
                }

                // *** phi_i loop ***
                for (unsigned i = 0; i < nve; i++) {
                  double surfterm_g = (*bdcfunc)(&xyzt[0]);
                  double bdintegral = phi[i] * surfterm_g * weight;
                  unsigned int ilocalnode = mymsh->GetLocalFaceVertexIndex(iel, jface, i);
                  F[ilocalnode] += bdintegral;
                }
              }
            }
            else { // 1D : the side elems are points and does not still exist the point elem
              // in 1D it is only one point
              xyzt[0] = coordinates[0][0];
              xyzt[1] = 0.;
              xyzt[2] = 0.;
              xyzt[3] = 0.;

              double bdintegral = (*bdcfunc)(&xyzt[0]);
              unsigned int ilocalnode = mymsh->GetLocalFaceVertexIndex(iel, jface, 0);
              F[ilocalnode] += bdintegral;
            }
          }
        }
      }
    }
    else {
      double tau = 0.;
      std::vector< double > xx(dim, 0.);
      vector < double > normal(dim, 0);

      // loop on faces
      for (unsigned jface = 0; jface < mymsh->GetElementFaceNumber(iel); jface++) {
        // look for boundary faces
        if (myel->GetFaceElementIndex(iel, jface) < 0) {
          unsigned int faceIndex =  myel->GetBoundaryIndex(iel, jface);

          if (!ml_sol->GetBdcFunction()(xx, "Sol", tau, faceIndex, 0.) && tau != 0.) {
            unsigned nve = mymsh->GetElementFaceDofNumber(iel, jface, order_ind);
            const unsigned felt = mymsh->GetElementFaceType(iel, jface);

            for (unsigned i = 0; i < nve; i++) {
              unsigned int ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i);
              unsigned inode = mymsh->GetSolutionDof(ilocal, iel, 2);

              for (unsigned idim = 0; idim < dim; idim++) {
                coordinates[idim][i] = (*mymsh->_topology->_Sol[idim])(inode);
              }
            }

            for (unsigned igs = 0; igs < mymsh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) {
              mymsh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal);

              // *** phi_i loop ***
              for (unsigned i = 0; i < nve; i++) {
                double value = phi[i] * tau * weight;
                unsigned int ilocal = mymsh->GetLocalFaceVertexIndex(iel, jface, i);
                F[ilocal]   += value;
              }
            }
          }
        }
      }
    }

    //--------------------------------------------------------------------------------------------------------
    //Sum the local matrices/vectors into the global Matrix/vector

    myRES->add_vector_blocked(F, KK_dof);

    myKK->add_matrix_blocked(B, KK_dof, KK_dof);
  } //end list of elements loop for each subdomain

  myRES->close();
  myKK->close();

  // ***************** END ASSEMBLY *******************

}
Beispiel #8
0
void AssembleProblem(MultiLevelProblem& ml_prob) {

  // ************** J dx = f - J x_old ******************  
  //  level is the level of the PDE system to be assembled
  //  levelMax is the Maximum level of the MultiLevelProblem
  //  assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled


  NonLinearImplicitSystemWithPrimalDualActiveSetMethod* mlPdeSys  = &ml_prob.get_system<NonLinearImplicitSystemWithPrimalDualActiveSetMethod> ("OptSys");
  const unsigned          level      = mlPdeSys->GetLevelToAssemble();
  const bool          assembleMatrix = mlPdeSys->GetAssembleMatrix();

  Mesh*                          msh = ml_prob._ml_msh->GetLevel(level);

  MultiLevelSolution*         ml_sol = ml_prob._ml_sol;
  Solution*                      sol = ml_prob._ml_sol->GetSolutionLevel(level);

  LinearEquationSolver*       pdeSys = mlPdeSys->_LinSolver[level];
  SparseMatrix*                   KK = pdeSys->_KK;
  NumericVector*                 RES = pdeSys->_RES;

  const unsigned                 dim = msh->GetDimension();                                 // get the domain dimension of the problem
  const unsigned                dim2 = (3 * (dim - 1) + !(dim - 1));                        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  const unsigned            max_size = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27

  const unsigned               iproc = msh->processor_id(); 


 //************** geometry (at dofs) *************************************  
  vector < vector < double > > coords_at_dofs(dim);
  vector < unsigned int >      SolFEType_domain(dim);
    for (unsigned  d = 0; d < dim; d++) SolFEType_domain[d] = BIQUADR_FE;
    
    for (unsigned i = 0; i < coords_at_dofs.size(); i++)    coords_at_dofs[i].reserve(max_size);

 //************** geometry (at quadrature points) *************************************  
  vector < double > coord_at_qp(dim);
  

 //************** geometry phi **************************
  vector < vector < double > > phi_fe_qp_domain(dim);
  vector < vector < double > > phi_x_fe_qp_domain(dim);
  vector < vector < double > > phi_xx_fe_qp_domain(dim);
 
  for(int fe = 0; fe < dim; fe++) {
        phi_fe_qp_domain[fe].reserve(max_size);
      phi_x_fe_qp_domain[fe].reserve(max_size * dim);
     phi_xx_fe_qp_domain[fe].reserve(max_size * dim2);
   }

 //***************************************************  
 //********* WHOLE SET OF VARIABLES ****************** 
 //***************************************************  
  const unsigned int n_unknowns = mlPdeSys->GetSolPdeIndex().size();
  
  enum Sol_pos{pos_state = 0, pos_ctrl, pos_adj, pos_mu};  //these are known at compile-time 
  //right now this is the same as Sol_pos = SolPdeIndex, but now I want to have flexible rows and columns
  // the ROW index corresponds to the EQUATION we want to solve
  // the COLUMN index corresponds to the column variables 
  
  // Now, first of all we have to make sure that the Sparsity pattern is correctly built...
  // This means that we should write the Sparsity pattern with COLUMNS independent of ROWS!
  // But that implies that the BOUNDARY CONDITIONS will be enforced in OFF-DIAGONAL BLOCKS!
  // In fact, having the row order be different from the column order implies that the diagonal blocks would be RECTANGULAR.  
  // Although this is in principle possible, I would avoid doing that for now.
  
//   const unsigned int pos_state = mlPdeSys->GetSolPdeIndex("state");   //these are known at run-time, so they are slower
//   const unsigned int pos_ctrl  = mlPdeSys->GetSolPdeIndex("control"); //these are known at run-time, so they are slower
//   const unsigned int pos_adj   = mlPdeSys->GetSolPdeIndex("adjoint"); //these are known at run-time, so they are slower
//   const unsigned int pos_mu    = mlPdeSys->GetSolPdeIndex("mu");      //these are known at run-time, so they are slower
  
  assert(pos_state == mlPdeSys->GetSolPdeIndex("state"));
  assert(pos_ctrl  == mlPdeSys->GetSolPdeIndex("control"));
  assert(pos_adj   == mlPdeSys->GetSolPdeIndex("adjoint"));
  assert(pos_mu    == mlPdeSys->GetSolPdeIndex("mu"));
 //***************************************************  
  
  const int solFEType_max = BIQUADR_FE;  //biquadratic

  vector < std::string > Solname(n_unknowns);
  Solname[pos_state] = "state";
  Solname[pos_ctrl]  = "control";
  Solname[pos_adj]   = "adjoint";
  Solname[pos_mu]    = "mu";
  
  //***************************************************  
  vector < unsigned int > SolPdeIndex(n_unknowns);  //index as in the row/column of the matrix (diagonal blocks are square)
  vector < unsigned int > SolIndex(n_unknowns);     //index as in the MultilevelSolution vector
  vector < unsigned int > SolFEType(n_unknowns);    //FEtype of each MultilevelSolution       
  vector < unsigned int > Sol_n_el_dofs(n_unknowns); //number of element dofs
  std::fill(Sol_n_el_dofs.begin(), Sol_n_el_dofs.end(), 0);

  for(unsigned ivar=0; ivar < n_unknowns; ivar++) {
    SolPdeIndex[ivar] = mlPdeSys->GetSolPdeIndex(  Solname[ivar].c_str() );
    assert(ivar == SolPdeIndex[ivar]); 
    SolIndex[ivar] = ml_sol->GetIndex         (  Solname[ivar].c_str() );
    SolFEType[ivar] = ml_sol->GetSolutionType  ( SolIndex[ivar]);
  }
  
 //************* shape functions (at dofs and quadrature points) **************************************  
  double weight_qp;
  
  vector < vector < double > > phi_fe_qp(n_unknowns);
  vector < vector < double > > phi_x_fe_qp(n_unknowns);
  vector < vector < double > > phi_xx_fe_qp(n_unknowns);
  vector < vector < vector < double > > > phi_x_fe_qp_vec(n_unknowns);
 
  for(int fe = 0; fe < n_unknowns; fe++) {
        phi_fe_qp[fe].reserve(max_size);
      phi_x_fe_qp[fe].reserve(max_size * dim);
     phi_xx_fe_qp[fe].reserve(max_size * dim2);
  phi_x_fe_qp_vec[fe].resize(dim);
  for(int d = 0; d < dim; d++) {
  phi_x_fe_qp_vec[fe][d].reserve(max_size);
}
      
}
   
 
   
  //----------- quantities (at dof objects) ------------------------------
  vector < vector < double > >     sol_eldofs(n_unknowns);
  for(int k=0; k<n_unknowns; k++)  sol_eldofs[k].reserve(max_size);
  
//************** act flag (at dof objects) **************************** 
   std::string act_flag_name = "act_flag";
   unsigned int solIndex_act_flag = ml_sol->GetIndex(act_flag_name.c_str());
   unsigned int solFEType_act_flag = ml_sol->GetSolutionType(solIndex_act_flag); 
      if(sol->GetSolutionTimeOrder(solIndex_act_flag) == 2) {
        *(sol->_SolOld[solIndex_act_flag]) = *(sol->_Sol[solIndex_act_flag]);
      }

  //********* variables for ineq constraints (at dof objects) *****************
  const int ineq_flag = INEQ_FLAG;
  const double c_compl = C_COMPL;
  vector < double/*int*/ >  sol_actflag;   sol_actflag.reserve(max_size); //flag for active set
  vector < double >          ctrl_lower;    ctrl_lower.reserve(max_size);
  vector < double >          ctrl_upper;    ctrl_upper.reserve(max_size);
      
  //------------ quantities (at quadrature points) ---------------------
            vector<double>        sol_qp(n_unknowns);
    vector< vector<double> > sol_grad_qp(n_unknowns);
    
      std::fill(sol_qp.begin(), sol_qp.end(), 0.);
    for (unsigned  k = 0; k < n_unknowns; k++) {
        sol_grad_qp[k].resize(dim);
        std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.);
    }

      
  //******* EQUATION RELATED STUFF ********************************************  
  
 int m_b_f[n_unknowns][n_unknowns];
     m_b_f[pos_state][pos_state] = 1; //nonzero
     m_b_f[pos_state][pos_ctrl]  = 0; //THIS IS ZERO IN NON-LIFTING APPROACHES (there are also pieces that go on top on blocks that are already meant to be different from zero)
     m_b_f[pos_state][pos_adj]   = 1; //nonzero
     m_b_f[pos_state][pos_mu]    = 0;  //this is zero without state constraints
     
     m_b_f[pos_ctrl][pos_state]  = 0;//THIS IS ZERO IN NON-LIFTING APPROACHES
     m_b_f[pos_ctrl][pos_ctrl]   = 1;//nonzero
     m_b_f[pos_ctrl][pos_adj]    = 1;//nonzero
     m_b_f[pos_ctrl][pos_mu]     = 1;//nonzero
     
     m_b_f[pos_adj][pos_state]  = 1; //nonzero
     m_b_f[pos_adj][pos_ctrl]   = 1; //nonzero
     m_b_f[pos_adj][pos_adj]    = 0; //this must always be zero 
     m_b_f[pos_adj][pos_mu]     = 0; //this must always be zero 
     
     m_b_f[pos_mu][pos_state]  = 0; //this is zero without state constraints
     m_b_f[pos_mu][pos_ctrl]   = 1; //nonzero
     m_b_f[pos_mu][pos_adj]    = 0; //this must always be zero 
     m_b_f[pos_mu][pos_mu]     = 1; //nonzero
 
  //***************************************************  
  vector < vector < int > > L2G_dofmap(n_unknowns);     for(int i = 0; i < n_unknowns; i++) { L2G_dofmap[i].reserve(max_size); }
            vector< int >   L2G_dofmap_AllVars; L2G_dofmap_AllVars.reserve( n_unknowns*max_size );
            vector< double >         Res;                      Res.reserve( n_unknowns*max_size );
            vector< double >         Jac;                      Jac.reserve( n_unknowns*max_size * n_unknowns*max_size);
  //***************************************************  
    
    
  //********************* DATA ************************ 
  double alpha = ALPHA_CTRL_VOL;
  double beta  = BETA_CTRL_VOL;
  double penalty_strong = 10e+14;
 //***************************************************  

  RES->zero();
  if (assembleMatrix)  KK->zero();
    
  // element loop: each process loops only on the elements that it owns
  for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielGeom = msh->GetElementType(iel);    // element geometry type

 //******************** GEOMETRY ********************* 
      for (unsigned jdim = 0; jdim < dim; jdim++) {
    unsigned nDofx = msh->GetElementDofNumber(iel, SolFEType_domain[jdim]);
    coords_at_dofs[jdim].resize(nDofx);
    // local storage of coordinates
    for (unsigned i = 0; i < coords_at_dofs[jdim].size(); i++) {
      unsigned xDof  = msh->GetSolutionDof(i, iel, SolFEType_domain[jdim]);  // global to global mapping between coordinates node and coordinate dof
        coords_at_dofs[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof);      // global extraction and local storage for the element coordinates
      }
    }

   // elem average point 
    vector < double > elem_center(dim);   
    for (unsigned j = 0; j < dim; j++) {  elem_center[j] = 0.;  }
    for (unsigned j = 0; j < dim; j++) {  
      for (unsigned i = 0; i < coords_at_dofs[j].size(); i++) {
         elem_center[j] += coords_at_dofs[j][i];
       }
    }
    
   for (unsigned j = 0; j < dim; j++) { elem_center[j] = elem_center[j]/coords_at_dofs[j].size(); }
 //***************************************************  
  
 //****** set target domain flag ********************* 
   int target_flag = 0;
   target_flag = ElementTargetFlag(elem_center);
 //*************************************************** 
   
   //all vars###################################################################  
  for (unsigned  k = 0; k < n_unknowns; k++) {
    unsigned  ndofs_unk = msh->GetElementDofNumber(iel, SolFEType[k]);
	   Sol_n_el_dofs[k] = ndofs_unk;
          sol_eldofs[k].resize(ndofs_unk);
          L2G_dofmap[k].resize(ndofs_unk); 
    for (unsigned i = 0; i < ndofs_unk; i++) {
           unsigned solDof = msh->GetSolutionDof(i, iel, SolFEType[k]);                        // global to global mapping between solution node and solution dof // via local to global solution node
           sol_eldofs[k][i] = (*sol->_Sol[SolIndex[k]])(solDof);                            // global extraction and local storage for the solution
           L2G_dofmap[k][i] = pdeSys->GetSystemDof(SolIndex[k], SolPdeIndex[k], i, iel);    // global to global mapping between solution node and pdeSys dof
      }
    }
  //all vars###################################################################

  for (unsigned  k = 0; k < n_unknowns; k++) {
     for(int d = 0; d < dim; d++) {
          phi_x_fe_qp_vec[k][d].resize(Sol_n_el_dofs[k]);
     }
  }
  
    
 //************** update active set flag for current nonlinear iteration **************************** 
 // 0: inactive; 1: active_a; 2: active_b
   assert(Sol_n_el_dofs[pos_mu] == Sol_n_el_dofs[pos_ctrl]);
   sol_actflag.resize(Sol_n_el_dofs[pos_mu]);
   ctrl_lower.resize(Sol_n_el_dofs[pos_mu]);
   ctrl_upper.resize(Sol_n_el_dofs[pos_mu]);
     std::fill(sol_actflag.begin(), sol_actflag.end(), 0);
     std::fill(ctrl_lower.begin(), ctrl_lower.end(), 0.);
     std::fill(ctrl_upper.begin(), ctrl_upper.end(), 0.);
   
    for (unsigned i = 0; i < sol_actflag.size(); i++) {
        std::vector<double> node_coords_i(dim,0.);
        for (unsigned d = 0; d < dim; d++) node_coords_i[d] = coords_at_dofs[d][i];
        ctrl_lower[i] = InequalityConstraint(node_coords_i,false);
        ctrl_upper[i] = InequalityConstraint(node_coords_i,true);
        
    if      ( (sol_eldofs[pos_mu][i] + c_compl * (sol_eldofs[pos_ctrl][i] - ctrl_lower[i] )) < 0 )  sol_actflag[i] = 1;
    else if ( (sol_eldofs[pos_mu][i] + c_compl * (sol_eldofs[pos_ctrl][i] - ctrl_upper[i] )) > 0 )  sol_actflag[i] = 2;
    }
 
 //************** act flag **************************** 
    unsigned nDof_act_flag  = msh->GetElementDofNumber(iel, solFEType_act_flag);    // number of solution element dofs
    
    for (unsigned i = 0; i < nDof_act_flag; i++) {
      unsigned solDof_mu = msh->GetSolutionDof(i, iel, solFEType_act_flag); 
      (sol->_Sol[solIndex_act_flag])->set(solDof_mu,sol_actflag[i]);     
    }    

    //******************** ALL VARS ********************* 
    unsigned nDof_AllVars = 0;
    for (unsigned  k = 0; k < n_unknowns; k++) { nDof_AllVars += Sol_n_el_dofs[k]; }
 // TODO COMPUTE MAXIMUM maximum number of element dofs for one scalar variable
    int nDof_max    =  0;   
      for (unsigned  k = 0; k < n_unknowns; k++)     {
          if(Sol_n_el_dofs[k] > nDof_max)    nDof_max = Sol_n_el_dofs[k];
      }
  
    Res.resize(nDof_AllVars);                   std::fill(Res.begin(), Res.end(), 0.);
    Jac.resize(nDof_AllVars * nDof_AllVars);    std::fill(Jac.begin(), Jac.end(), 0.);
    
    L2G_dofmap_AllVars.resize(0);
      for (unsigned  k = 0; k < n_unknowns; k++)     L2G_dofmap_AllVars.insert(L2G_dofmap_AllVars.end(),L2G_dofmap[k].begin(),L2G_dofmap[k].end());
 //*************************************************** 


 //***** set control flag ****************************
  int control_el_flag = 0;
      control_el_flag = ControlDomainFlag_internal_restriction(elem_center);
  std::vector<int> control_node_flag(Sol_n_el_dofs[pos_ctrl],0);
  if (control_el_flag == 1) std::fill(control_node_flag.begin(), control_node_flag.end(), 1);
 //*************************************************** 
  



      // *** Gauss point loop ***
      for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solFEType_max]->GetGaussPointNumber(); ig++) {
	
      // *** get gauss point weight, test function and test function partial derivatives ***
      for(unsigned int k = 0; k < n_unknowns; k++) {
         msh->_finiteElement[ielGeom][SolFEType[k]]->Jacobian(coords_at_dofs, ig, weight_qp, phi_fe_qp[k], phi_x_fe_qp[k], phi_xx_fe_qp[k]);
      }
      
   for (unsigned  k = 0; k < n_unknowns; k++) {
      for(unsigned int d = 0; d < dim; d++) {
        for(unsigned int i = 0; i < Sol_n_el_dofs[k]; i++) {
          phi_x_fe_qp_vec[k][d][i] =  phi_x_fe_qp[k][i * dim + d];
       }
     }
   }
      
      
   //HAVE TO RECALL IT TO HAVE BIQUADRATIC JACOBIAN
    for (unsigned int d = 0; d < dim; d++) {
         msh->_finiteElement[ielGeom][SolFEType_domain[d]]->Jacobian(coords_at_dofs, ig, weight_qp, phi_fe_qp_domain[d], phi_x_fe_qp_domain[d], phi_xx_fe_qp_domain[d]);
      }
      
 //========= fill gauss value xyz ==================   
   std::fill(coord_at_qp.begin(), coord_at_qp.end(), 0.);
    for (unsigned  d = 0; d < dim; d++) {
        	for (unsigned i = 0; i < coords_at_dofs[d].size(); i++) {
               coord_at_qp[d] += coords_at_dofs[d][i] * phi_fe_qp_domain[d][i];
            }
    }
  //========= fill gauss value xyz ==================   

 //========= fill gauss value quantities ==================   
   std::fill(sol_qp.begin(), sol_qp.end(), 0.);
   for (unsigned  k = 0; k < n_unknowns; k++) { std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); }
    
    for (unsigned  k = 0; k < n_unknowns; k++) {
	for (unsigned i = 0; i < Sol_n_el_dofs[k]; i++) {
	                                                         sol_qp[k]    += sol_eldofs[k][i] *   phi_fe_qp[k][i];
                   for (unsigned d = 0; d < dim; d++)   sol_grad_qp[k][d] += sol_eldofs[k][i] * phi_x_fe_qp[k][i * dim + d];
       }        
    }
 //========= fill gauss value quantities ==================   

 
//==========FILLING THE EQUATIONS ===========
        for (unsigned i = 0; i < nDof_max; i++) {
	  
//======================Residuals=======================
          // ===============
        Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_state,i) ] += - weight_qp * (target_flag * phi_fe_qp[pos_state][i] * (
                                                                                              m_b_f[pos_state][pos_state] * sol_qp[pos_state] 
                                                                                            - DesiredTarget(coord_at_qp) ) 
                                                                                          + m_b_f[pos_state][pos_adj]   * ( assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_state, pos_adj, i, dim)  
                                                                                                                            - sol_qp[pos_adj] *  nonlin_term_derivative(phi_fe_qp[pos_state][i]) *  sol_qp[pos_ctrl]) );
        
          

          // ==============
	     if ( control_el_flag == 1)        Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_ctrl,i) ] +=  /*(control_node_flag[i]) **/ - weight_qp * (
                                                                                  + m_b_f[pos_ctrl][pos_ctrl] * alpha * phi_fe_qp[pos_ctrl][i] * sol_qp[pos_ctrl]
		                                                                          + m_b_f[pos_ctrl][pos_ctrl] *  beta * assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_ctrl, pos_ctrl, i, dim) 
		                                                                          - m_b_f[pos_ctrl][pos_adj]  *         phi_fe_qp[pos_ctrl][i] * sol_qp[pos_adj] * nonlin_term_function(sol_qp[pos_state])
                                                                                                                         );
	      else if ( control_el_flag == 0)  Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_ctrl,i) ] +=  /*(1 - control_node_flag[i]) **/ m_b_f[pos_ctrl][pos_ctrl] * (- penalty_strong) * (sol_eldofs[pos_ctrl][i]);

          // =============
        Res[ assemble_jacobian<double,double>::res_row_index(Sol_n_el_dofs,pos_adj,i) ] += - weight_qp *  ( + m_b_f[pos_adj][pos_state] * assemble_jacobian<double,double>::laplacian_row(phi_x_fe_qp_vec, sol_grad_qp, pos_adj, pos_state, i, dim) 
                                                                          - m_b_f[pos_adj][pos_ctrl]  * phi_fe_qp[pos_adj][i] * sol_qp[pos_ctrl] * nonlin_term_function(sol_qp[pos_state]) 
                                                                        );

//======================End Residuals=======================
	      
          if (assembleMatrix) {
	    
            // *** phi_j loop ***
            for (unsigned j = 0; j < nDof_max; j++) {
                
              //============ delta_state row ============================
		Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_state, pos_state, i, j) ]  += 
                                                      m_b_f[pos_state][pos_state] * weight_qp * target_flag * phi_fe_qp[pos_state][j] *  phi_fe_qp[pos_state][i];
              
		Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_state, pos_adj, i, j)  ]  +=
		                                              m_b_f[pos_state][pos_adj] * weight_qp * (
                                                                          assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_state, pos_adj, i, j, dim)
                                                                                                       - phi_fe_qp[pos_adj][j] *
                                                                                                         nonlin_term_derivative(phi_fe_qp[pos_state][i]) * 
                                                                                                         sol_qp[pos_ctrl]
                                                                                              );
              
	      //=========== delta_control row ===========================     
	      if ( control_el_flag == 1)  {
		Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_ctrl, i, j) ]  += 
		                                              m_b_f[pos_ctrl][pos_ctrl] * ( control_node_flag[i]) * weight_qp * (
                                                                                  beta * control_el_flag  * assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_ctrl, pos_ctrl, i, j, dim) 
                                                                               + alpha * control_el_flag  * phi_fe_qp[pos_ctrl][i] * phi_fe_qp[pos_ctrl][j] 
		                                                                                    );
              
		Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_adj, i, j) ]  += m_b_f[pos_ctrl][pos_adj] * control_node_flag[i] * weight_qp * (
                                                                                                                                      - phi_fe_qp[pos_ctrl][i] * 
                                                                                                                                        phi_fe_qp[pos_adj][j] * 
                                                                                                                                        nonlin_term_function(sol_qp[pos_state])
                                                                                                    );
	        }
	      
	      else if ( control_el_flag == 0 && i == j)  {  
        Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_ctrl, pos_ctrl, i, j) ]  += m_b_f[pos_ctrl][pos_ctrl] * (1 - control_node_flag[i]) * penalty_strong;
	      }
	      
	      //=========== delta_adjoint row ===========================
		Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_adj, pos_state, i, j) ]  += m_b_f[pos_adj][pos_state] * weight_qp * (
                                                                                                                                      assemble_jacobian<double,double>::laplacian_row_col(phi_x_fe_qp_vec,phi_x_fe_qp_vec, pos_adj, pos_state, i, j, dim)
                                                                                                                                      - phi_fe_qp[pos_adj][i] *
                                                                                                                                        nonlin_term_derivative(phi_fe_qp[pos_state][j]) * 
                                                                                                                                        sol_qp[pos_ctrl]
                                                                                                                                    );

        Jac[ assemble_jacobian<double,double>::jac_row_col_index(Sol_n_el_dofs, nDof_AllVars, pos_adj, pos_ctrl, i, j)  ]  += m_b_f[pos_adj][pos_ctrl] * weight_qp * ( 
                                                                                                                                      - phi_fe_qp[pos_adj][i] * 
                                                                                                                                        phi_fe_qp[pos_ctrl][j] * 
                                                                                                                                        nonlin_term_function(sol_qp[pos_state])
                                                                                                                                   ); 
		     
	      
            } // end phi_j loop
          } // endif assemble_matrix

        } // end phi_i loop
        
      } // end gauss point loop

      
      
    //std::vector<double> Res_ctrl (Sol_n_el_dofs[pos_ctrl]); std::fill(Res_ctrl.begin(),Res_ctrl.end(), 0.);
    for (unsigned i = 0; i < sol_eldofs[pos_ctrl].size(); i++) {
       unsigned n_els_that_node = 1;
     if ( control_el_flag == 1) {
// 	Res[Sol_n_el_dofs[pos_state] + i] += - ( + n_els_that_node * ineq_flag * sol_eldofs[pos_mu][i] /*- ( 0.4 + sin(M_PI * x[0][i]) * sin(M_PI * x[1][i]) )*/ );
// 	Res_ctrl[i] =  Res[Sol_n_el_dofs[pos_state] + i];
      }
    }
    

 //========== end of integral-based part

                          RES->add_vector_blocked(Res, L2G_dofmap_AllVars);
      if (assembleMatrix)  KK->add_matrix_blocked(Jac, L2G_dofmap_AllVars, L2G_dofmap_AllVars);
    
    
 //========== dof-based part, without summation
 
 //============= delta_mu row ===============================
      std::vector<double> Res_mu (Sol_n_el_dofs[pos_mu]); std::fill(Res_mu.begin(),Res_mu.end(), 0.);
      
    for (unsigned i = 0; i < sol_actflag.size(); i++) {
      if (sol_actflag[i] == 0) {  //inactive
         Res_mu [i] = (- ineq_flag) * ( 1. * sol_eldofs[pos_mu][i] ); 
// 	 Res_mu [i] = Res[res_row_index(Sol_n_el_dofs,pos_mu,i)]; 
      }
      else if (sol_actflag[i] == 1) {  //active_a 
	     Res_mu [i] = (- ineq_flag) * c_compl * ( sol_eldofs[pos_ctrl][i] - ctrl_lower[i]);
      }
      else if (sol_actflag[i] == 2) {  //active_b 
	     Res_mu [i] = (- ineq_flag) * c_compl * ( sol_eldofs[pos_ctrl][i] - ctrl_upper[i]);
      }
    }
    
    RES->insert(Res_mu, L2G_dofmap[pos_mu]);
    
 //============= delta_ctrl - mu ===============================
 KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_ctrl], L2G_dofmap[pos_mu], m_b_f[pos_ctrl][pos_mu] * ineq_flag * 1.);
  
 //============= delta_mu - ctrl row ===============================
 for (unsigned i = 0; i < sol_actflag.size(); i++) if (sol_actflag[i] != 0 ) sol_actflag[i] = m_b_f[pos_mu][pos_ctrl] * ineq_flag * c_compl;    
  
 KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_mu], L2G_dofmap[pos_ctrl], sol_actflag);

 //============= delta_mu - mu row ===============================
  for (unsigned i = 0; i < sol_actflag.size(); i++) sol_actflag[i] =  m_b_f[pos_mu][pos_mu] * ( ineq_flag * (1 - sol_actflag[i]/c_compl)  + (1-ineq_flag) * 1. ); //can do better to avoid division, maybe use modulo operator 

  KK->matrix_set_off_diagonal_values_blocked(L2G_dofmap[pos_mu], L2G_dofmap[pos_mu], sol_actflag );
  
  } //end element loop for each process
  
  RES->close();

  if (assembleMatrix) KK->close();
//  std::ostringstream mat_out; mat_out << ml_prob.GetFilesHandler()->GetOutputPath() << "/" << "jacobian" << mlPdeSys->GetNonlinearIt()  << ".txt";
//   KK->print_matlab(mat_out.str(),"ascii"); 
//    KK->print();
  
  // ***************** END ASSEMBLY *******************
  
  unsigned int global_ctrl_size = pdeSys->KKoffset[pos_ctrl+1][iproc] - pdeSys->KKoffset[pos_ctrl][iproc];
  
  std::vector<double>  one_times_mu(global_ctrl_size, 0.);
  std::vector<int>        positions(global_ctrl_size);
//  double position_mu_i;
  for (unsigned i = 0; i < positions.size(); i++) {
    positions[i] = pdeSys->KKoffset[pos_ctrl][iproc] + i;
//     position_mu_i = pdeSys->KKoffset[pos_mu][iproc] + i;
//     std::cout << position_mu_i << std::endl;
    one_times_mu[i] =  m_b_f[pos_ctrl][pos_mu] * ineq_flag * 1. * (*sol->_Sol[SolIndex[pos_mu]])(i/*position_mu_i*/) ;
  }
    RES->add_vector_blocked(one_times_mu, positions);
//     RES->print();
    
  return;
}
Beispiel #9
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->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc+1]; iel++) {

      unsigned kel        = mymsh->IS_Mts2Gmt_elem[iel]; 
      short unsigned kelt = mymsh->GetElementType(kel);
      unsigned nve2       = mymsh->GetElementDofNumber(kel,SolType2);
      unsigned nve1       = mymsh->GetElementDofNumber(kel,SolType1);
      unsigned nveVx      = mymsh->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->GetSolutionDof(inode,SolTypeVx);	
	for(int j=0; j<dim; j++) {
	  //coordinates
	  vx[j][i]=  (*mymsh->_topology->_Sol[j])(inode_Metis); 
	}
      }
      
      // Velocity
      for (unsigned i=0;i<nve2;i++) {
	unsigned inode=myel->GetMeshDof(kel,i,SolType2);
	unsigned inode_Metis=mymsh->GetSolutionDof(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->GetSystemDof(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->GetSolutionDof(inode,SolType1);
	Soli[indexVAR[dim]][i] = (*mysolution->_Sol[indVAR[dim]])(inode_Metis);
	dofsVAR[dim][i]=myLinEqSolver->GetSystemDof(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 *******************

  }  
Beispiel #10
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();

  Mesh*                    msh = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
  elem*                     el = msh->el;  // pointer to the elem object in msh (level)

  MultiLevelSolution*    mlSol = ml_prob._ml_sol;  // pointer to the multilevel solution object
  Solution*                sol = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object

  LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object
  SparseMatrix*             KK = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
  NumericVector*           RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

  const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
  unsigned dim2 = (3 * (dim - 1) + !(dim - 1));        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
  const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27

  unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

  //solution variable
  unsigned soluIndex;
  soluIndex = mlSol->GetIndex("u");    // get the position of "u" in the ml_sol object
  unsigned soluType = mlSol->GetSolutionType(soluIndex);    // get the finite element type for "u"

  unsigned soluPdeIndex;
  soluPdeIndex = mlPdeSys->GetSolPdeIndex("u");    // get the position of "u" in the pdeSys object

  vector < adept::adouble >  solu; // local solution
  solu.reserve(maxSize);

  vector < vector < double > > x(dim);    // local coordinates
  unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

  for (unsigned i = 0; i < dim; i++) {
    x[i].reserve(maxSize);
  }

  vector <double> phi;  // local test function
  vector <double> phi_x; // local test function first order partial derivatives
  vector <double> phi_xx; // local test function second order partial derivatives
  double weight; // gauss point weight

  phi.reserve(maxSize);
  phi_x.reserve(maxSize * dim);
  phi_xx.reserve(maxSize * dim2);

  vector< adept::adouble > aRes; // local redidual vector
  aRes.reserve(maxSize);

  vector< int > l2GMap; // local to global mapping
  l2GMap.reserve(maxSize);
  vector< double > Res; // local redidual vector
  Res.reserve(maxSize);
  vector < double > Jac;
  Jac.reserve(maxSize * maxSize);

  KK->zero(); // Set to zero all the entries of the Global Matrix

  // element loop: each process loops only on the elements that owns
  for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {
     
    short unsigned ielGeom = msh->GetElementType(iel);
    unsigned nDofu  = msh->GetElementDofNumber(iel, soluType);    // number of solution element dofs
    unsigned nDofx = msh->GetElementDofNumber(iel, xType);    // number of coordinate element dofs

    // resize local arrays
    l2GMap.resize(nDofu);
    solu.resize(nDofu);

    for (int i = 0; i < dim; i++) {
      x[i].resize(nDofx);
    }

    aRes.resize(nDofu);    //resize
    std::fill(aRes.begin(), aRes.end(), 0);    //set aRes to zero

    // local storage of global mapping and solution
    for (unsigned i = 0; i < nDofu; i++) {
      unsigned solDof = msh->GetSolutionDof(i, iel, soluType);    // global to global mapping between solution node and solution dof
      solu[i] = (*sol->_Sol[soluIndex])(solDof);      // global extraction and local storage for the solution
      l2GMap[i] = pdeSys->GetSystemDof(soluIndex, soluPdeIndex, i, iel);    // global to global mapping between solution node and pdeSys dof
    }

    // local storage of coordinates
    for (unsigned i = 0; i < nDofx; i++) {
      unsigned xDof  = msh->GetSolutionDof(i, iel, xType);    // global to global mapping between coordinates node and coordinate dof

      for (unsigned jdim = 0; jdim < dim; jdim++) {
        x[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof);      // global extraction and local storage for the element coordinates
      }
    }


    // start a new recording of all the operations involving adept::adouble variables
    s.new_recording();

    // *** Gauss point loop ***
    for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][soluType]->GetGaussPointNumber(); ig++) {
      // *** get gauss point weight, test function and test function partial derivatives ***
      msh->_finiteElement[ielGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx);

      // evaluate the solution, the solution derivatives and the coordinates in the gauss point
      adept::adouble solu_gss = 0;
      vector < adept::adouble > gradSolu_gss(dim, 0.);
      vector < double > x_gss(dim, 0.);

      for (unsigned i = 0; i < nDofu; i++) {
        solu_gss += phi[i] * solu[i];

        for (unsigned jdim = 0; jdim < dim; jdim++) {
          gradSolu_gss[jdim] += phi_x[i * dim + jdim] * solu[i];
          x_gss[jdim] += x[jdim][i] * phi[i];
        }
      }

      // *** phi_i loop ***
      for (unsigned i = 0; i < nDofu; i++) {

        adept::adouble laplace = 0.;

        for (unsigned jdim = 0; jdim < dim; jdim++) {
          laplace   +=  phi_x[i * dim + jdim] * gradSolu_gss[jdim];
        }

        double srcTerm = - GetExactSolutionLaplace(x_gss);
        aRes[i] += (srcTerm * phi[i] - laplace) * weight;

      } // end phi_i loop
    } // end gauss point loop

    //--------------------------------------------------------------------------------------------------------
    // Add the local Matrix/Vector into the global Matrix/Vector

    //copy the value of the adept::adoube aRes in double Res and store
    Res.resize(nDofu);    //resize

    for (int i = 0; i < nDofu; i++) {
      Res[i] = - aRes[i].value();
    }

    RES->add_vector_blocked(Res, l2GMap);



    // define the dependent variables
    s.dependent(&aRes[0], nDofu);

    // define the independent variables
    s.independent(&solu[0], nDofu);

    // get the jacobian matrix (ordered by row major )
    Jac.resize(nDofu * nDofu);    //resize
    s.jacobian(&Jac[0], true);

    //store K in the global matrix KK
    KK->add_matrix_blocked(Jac, l2GMap, l2GMap);

    s.clear_independents();
    s.clear_dependents();

  } //end element loop for each process

  RES->close();

  KK->close();

  // ***************** END ASSEMBLY *******************
}
Beispiel #11
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);
  //unsigned end_ind   = order_ind;
  
  //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->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc+1]; iel++) {

    unsigned kel = mymsh->IS_Mts2Gmt_elem[iel];
    short unsigned kelt=mymsh->GetElementType(kel);
    unsigned nve=mymsh->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_coord_metis=mymsh->GetSolutionDof(inode,2);
      metis_node[i]=mymsh->GetSolutionDof(inode,order_ind);
      for(unsigned ivar=0; ivar<dim; ivar++) {
	coordinates[ivar][i]=(*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
      }
      KK_dof[i]=mylsyspde->GetSystemDof(SolIndex,SolPdeIndex,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 ivar=0; ivar<dim; ivar++) gradSolT[ivar] += gradphi[i*dim+ivar]*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 *******************
  
}
Beispiel #12
0
void AssembleWillmoreFlow_AD(MultiLevelProblem& ml_prob) {
    //  ml_prob is the global object from/to where get/set all the data
    //  level is the level of the PDE system to be assembled
    //  levelMax is the Maximum level of the MultiLevelProblem
    //  assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled

    // call the adept stack object
    adept::Stack& s = FemusInit::_adeptStack;

    //  extract pointers to the several objects that we are going to use
    TransientNonlinearImplicitSystem* mlPdeSys   = &ml_prob.get_system<TransientNonlinearImplicitSystem> ("Willmore");   // pointer to the linear implicit system named "Poisson"

    const unsigned level = mlPdeSys->GetLevelToAssemble();

    Mesh*          msh        = ml_prob._ml_msh->GetLevel(level);    // pointer to the mesh (level) object
    elem*          el         = msh->el;  // pointer to the elem object in msh (level)

    MultiLevelSolution*  mlSol        = ml_prob._ml_sol;  // pointer to the multilevel solution object
    Solution*    sol        = ml_prob._ml_sol->GetSolutionLevel(level);    // pointer to the solution (level) object

    LinearEquationSolver* pdeSys        = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object
    SparseMatrix*    KK         = pdeSys->_KK;  // pointer to the global stifness matrix object in pdeSys (level)
    NumericVector*   RES          = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level)

    const unsigned  dim = msh->GetDimension(); // get the domain dimension of the problem
    unsigned    iproc = msh->processor_id(); // get the process_id (for parallel computation)

    //solution variable
    unsigned solRIndex[3];
    solRIndex[0] = mlSol->GetIndex("X");    // get the position of "X" in the ml_sol object
    solRIndex[1] = mlSol->GetIndex("Y");    // get the position of "Y" in the ml_sol object
    solRIndex[2] = mlSol->GetIndex("Z");    // get the position of "Z" in the ml_sol object
    unsigned solRType[3];
    solRType[0] = mlSol->GetSolutionType(solRIndex[0]);   // get the finite element type for "R"
    solRType[1] = mlSol->GetSolutionType(solRIndex[1]);   // get the finite element type for "R"
    solRType[2] = mlSol->GetSolutionType(solRIndex[2]);   // get the finite element type for "R"

    unsigned solRPdeIndex[3];
    solRPdeIndex[0] = mlPdeSys->GetSolPdeIndex("X");    // get the position of "X" in the pdeSys object
    solRPdeIndex[1] = mlPdeSys->GetSolPdeIndex("Y");    // get the position of "Y" in the pdeSys object
    solRPdeIndex[2] = mlPdeSys->GetSolPdeIndex("Z");    // get the position of "Z" in the pdeSys object

    vector < adept::adouble >  solR[3]; // local solution
    vector < double > solR_old[3];


    unsigned solHIndex;
    solHIndex = mlSol->GetIndex("H");    // get the position of "H" in the ml_sol object
    unsigned solHType = mlSol->GetSolutionType(solHIndex);    // get the finite element type for "H"

    unsigned solHPdeIndex;
    solHPdeIndex = mlPdeSys->GetSolPdeIndex("H");    // get the position of "H" in the pdeSys object

    vector < adept::adouble >  solH; // local solution

    vector < vector < double > > x(dim);    // local coordinates
    unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC)

    vector< int > sysDof; // local to global pdeSys dofs
    vector <double> phi;  // local test function
    vector <double> phi_x; // local test function first order partial derivatives
    vector <double> phi_xx; // local test function second order partial derivatives
    double weight; // gauss point weight

    vector< double > Res; // local redidual vector
    vector< adept::adouble > aResR[3]; // local redidual vector
    vector< adept::adouble > aResH; // local redidual vector


    // reserve memory for the local standar vectors
    const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27

    for (int i = 0; i < 3; i++) {
        solR[i].reserve(maxSize);
        solR_old[i].reserve(maxSize);
    }

    solH.reserve(maxSize);

    for (unsigned i = 0; i < dim; i++)
        x[i].reserve(maxSize);

    sysDof.reserve(4 * maxSize);
    phi.reserve(maxSize);
    phi_x.reserve(maxSize * dim);
    unsigned dim2 = (3 * (dim - 1) + !(dim - 1));        // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension)
    phi_xx.reserve(maxSize * dim2);

    Res.reserve(4 * maxSize);

    for (int i = 0; i < 3; i++) {
        aResR[i].reserve(maxSize);
    }

    aResH.reserve(maxSize);

    vector < double > Jac; // local Jacobian matrix (ordered by column, adept)
    Jac.reserve(4 * maxSize * 4 * maxSize);


    KK->zero(); // Set to zero all the entries of the Global Matrix

    // element loop: each process loops only on the elements that owns
    for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) {

        short unsigned ielGeom = msh->GetElementType(iel);
        unsigned nDofs  = msh->GetElementDofNumber(iel, solHType);    // number of solution element dofs
        unsigned nDofs2 = msh->GetElementDofNumber(iel, xType);    // number of coordinate element dofs

        // resize local arrays
        sysDof.resize(4 * nDofs);

        for (int i = 0; i < 3; i++) {
            solR[i].resize(nDofs);
            solR_old[i].resize(nDofs);
        }

        solH.resize(nDofs);

        for (int i = 0; i < dim; i++) {
            x[i].resize(nDofs2);
        }

        Res.resize(4 * nDofs);    //resize

        for (int i = 0; i < 3; i++) {
            aResR[i].resize(nDofs);    //resize
        }

        aResH.resize(nDofs);    //resize

        for (int i = 0; i < 3; i++) {
            std::fill(aResR[i].begin(), aResR[i].end(), 0);    //set aRes to zero
        }

        std::fill(aResH.begin(), aResH.end(), 0);    //set aRes to zero

        // local storage of global mapping and solution
        for (unsigned i = 0; i < nDofs; i++) {
            unsigned solDof = msh->GetSolutionDof(i, iel, solHType);    // global to global mapping between solution node and solution dof

            for (int k = 0; k < 3; k++) {
                solR[k][i] = (*sol->_Sol[solRIndex[k]])(solDof);      // global extraction and local storage for the solution
                solR_old[k][i] = (*sol->_SolOld[solRIndex[k]])(solDof);      // global extraction and local storage for the solution

            }

            solH[i] = (*sol->_Sol[solHIndex])(solDof);      // global extraction and local storage for the solution

            for (int k = 0; k < 3; k++) {
                sysDof[k * nDofs + i] = pdeSys->GetSystemDof(solRIndex[k], solRPdeIndex[k], i, iel);  // global to global mapping between solution node and pdeSys dof
            }

            sysDof[3 * nDofs + i] = pdeSys->GetSystemDof(solHIndex, solHPdeIndex, i, iel);  // global to global mapping between solution node and pdeSys dof
        }

        // local storage of coordinates
        for (unsigned i = 0; i < nDofs2; i++) {
            unsigned xDof  = msh->GetSolutionDof(i, iel, xType);    // global to global mapping between coordinates node and coordinate dof

            for (unsigned idim = 0; idim < dim; idim++) {
                x[idim][i] = (*msh->_topology->_Sol[idim])(xDof);      // global extraction and local storage for the element coordinates
            }
        }


        // start a new recording of all the operations involving adept::adouble variables
        s.new_recording();


        // *** Gauss point loop ***
        for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][solHType]->GetGaussPointNumber(); ig++) {
            // *** get gauss point weight, test function and test function partial derivatives ***
            msh->_finiteElement[ielGeom][solHType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx);

            // evaluate the solution, the solution derivatives and the coordinates in the gauss point
            adept::adouble solRGauss[3];
            double solRGaussOld[3];
            adept::adouble solRGauss_x[3][2];
            adept::adouble solRGauss_xx[3][2][2];

            adept::adouble sol_x[2];
            sol_x[0] = sol_x[1] = 0.;

            for (int k = 0; k < 3; k++) {
                solRGauss[k] = 0.;
                solRGaussOld[k] = 0.;

                for (int i = 0; i < dim; i++) {
                    solRGauss_x[k][i] = 0.;

                    for (int j = 0; j < dim; j++) {
                        solRGauss_xx[k][i][j] = 0.;
                    }
                }
            }

            adept::adouble solHGauss = 0;
            adept::adouble solHGauss_x[2] = {0., 0.};

            for (unsigned i = 0; i < nDofs; i++) {
                for (int k = 0; k < 3; k++) {
                    solRGauss[k] += phi[i] * solR[k][i];
                    solRGaussOld[k] += phi[i] * solR_old[k][i];
                }

                solHGauss += phi[i] * solH[i];

                for (unsigned u = 0; u < dim; u++) {
                    sol_x[u] += phi[i] * x[u][i];
                }

                for (unsigned u = 0; u < dim; u++) { // gradient
                    for (int k = 0; k < 3; k++) {
                        solRGauss_x[k][u] += phi_x[i * dim + u] * solR[k][i];
                    }

                    solHGauss_x[u] += phi_x[i * dim + u] * solH[i];
                }

                for (unsigned u = 0; u < dim; u++) {  // hessian
                    for (unsigned v = 0; v < dim; v++) {
                        unsigned uvindex = 0; //_uu

                        if (u != v) uvindex = 2;  //_uv or _vu
                        else if (u == 1) uvindex = 1;  //_vv

                        for (int k = 0; k < 3; k++) {
                            solRGauss_xx[k][u][v] += phi_xx[i * dim2 + uvindex] * solR[k][i];
                        }
                    }
                }
            }

            adept::adouble g[2][2];


            g[0][0] = g[0][1] = g[1][0] = g[1][1] = 0.;

            for (int k = 0; k < 3; k++) {
                for (int u = 0; u < dim; u++) {
                    for (int v = 0; v < dim; v++) {
                        g[u][v] += solRGauss_x[k][u] * solRGauss_x[k][v];
                    }
                }
            }

            adept::adouble detg = g[0][0] * g[1][1] - g[0][1] * g[1][0];

            adept::adouble  A = sqrt(detg);

            adept::adouble gI[2][2];

            gI[0][0] =  g[1][1] / detg;
            gI[0][1] = -g[0][1] / detg;
            gI[1][0] = -g[1][0] / detg;
            gI[1][1] =  g[0][0] / detg;

            adept::adouble N[3];

            N[0] = (solRGauss_x[1][0] * solRGauss_x[2][1] - solRGauss_x[1][1] * solRGauss_x[2][0]) / A;
            N[1] = (solRGauss_x[2][0] * solRGauss_x[0][1] - solRGauss_x[2][1] * solRGauss_x[0][0]) / A;
            N[2] = (solRGauss_x[0][0] * solRGauss_x[1][1] - solRGauss_x[0][1] * solRGauss_x[1][0]) / A;

            adept::adouble h[2][2];

            h[0][0] = h[0][1] = h[1][0] = h[1][1] = 0.;

            for (int k = 0; k < 3; k++) {
                for (int u = 0; u < dim; u++) {
                    for (int v = 0; v < dim; v++) {
                        h[u][v] += solRGauss_xx[k][u][v] * N[k];

                    }
                }
            }

            //adept::adouble K = cos(sol_x[0])/(a+cos(sol_x[0]));//(h[0][0]*h[1][1]-h[0][1]*h[1][0])/detg;

            adept::adouble K = (h[0][0] * h[1][1] - h[0][1] * h[1][0]) / detg;

            adept::adouble H_exact = 0.5 * (1. + cos(sol_x[0]) / (a + cos(sol_x[0])));

            // *** phi_i loop ***
            for (unsigned i = 0; i < nDofs; i++) {

                for (int k = 0; k < 3; k++) {
                    for (int u = 0; u < dim; u++) {
                        adept::adouble AgIgradRgradPhi = 0;

                        for (int v = 0; v < dim; v++) {
                            AgIgradRgradPhi += A * gI[u][v].value() * solRGauss_x[k][v];
                        }

                        aResR[k][i] += AgIgradRgradPhi * phi_x[i * dim + u] * weight;
                    }

                    aResR[k][i] += 2.* A * solHGauss.value() * N[k] * phi[i] * weight;
                }


                for (int u = 0; u < dim; u++) {
                    adept::adouble AgIgradHgradPhi = 0;

                    for (int v = 0; v < dim; v++) {
                        AgIgradHgradPhi += A * gI[u][v].value() * solHGauss_x[v];
                    }

                    aResH[i] -= AgIgradHgradPhi * phi_x[i * dim + u] * weight;
                }

                aResH[i] += A * (-0 * (solRGauss[0] - solRGaussOld[0]) * N[0].value()
                                 - 0 * (solRGauss[1] - solRGaussOld[1]) * N[1].value()
                                 - 0 * (solRGauss[2] - solRGaussOld[2]) * N[2].value()
                                 + 2. * solHGauss * (solHGauss * solHGauss  - K.value())) * phi[i] * weight;

            } // end phi_i loop
        } // end gauss point loop

        //--------------------------------------------------------------------------------------------------------
        // Add the local Matrix/Vector into the global Matrix/Vector

        //copy the value of the adept::adoube aRes in double Res and store
        for (int i = 0; i < nDofs; i++) {
            for (int k = 0; k < 3; k++) {
                Res[ k * nDofs + i] = -aResR[k][i].value();
            }

            Res[ 3 * nDofs + i] = -aResH[i].value();
        }

        RES->add_vector_blocked(Res, sysDof);


        Jac.resize((4 * nDofs) * (4 * nDofs));

        // define the dependent variables
        for (int k = 0; k < 3; k++) {
            s.dependent(&aResR[k][0], nDofs);
        }

        s.dependent(&aResH[0], nDofs);

        // define the independent variables
        for (int k = 0; k < 3; k++) {
            s.independent(&solR[k][0], nDofs);
        }

        s.independent(&solH[0], nDofs);
        // get the jacobian matrix (ordered by row)
        s.jacobian(&Jac[0], true);

        KK->add_matrix_blocked(Jac, sysDof, sysDof);

        s.clear_independents();
        s.clear_dependents();

    } //end element loop for each process

    RES->close();

    KK->close();

    // ***************** END ASSEMBLY *******************
}
Beispiel #13
0
void AssembleMatrixResSteadyStokes(MultiLevelProblem &ml_prob){
     
  //pointers
  LinearImplicitSystem& my_lin_impl_sys    = ml_prob.get_system<LinearImplicitSystem>("Stokes");
  const unsigned level = my_lin_impl_sys.GetLevelToAssemble();
  const unsigned gridn = my_lin_impl_sys.GetLevelMax();
  bool assemble_matrix = my_lin_impl_sys.GetAssembleMatrix(); 
   
  Solution*	 mysolution  	             = ml_prob._ml_sol->GetSolutionLevel(level);
  LinearEquationSolver*  mylsyspde	     = my_lin_impl_sys._LinSolver[level];   
  const char* pdename                        = my_lin_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; 
  const bool symm_mat = false;
  
  // solution and coordinate variables
  const char Solname[4][2] = {"U","V","W","P"};
  vector < unsigned > SolPdeIndex(dim+1);
  vector < unsigned > SolIndex(dim+1);  

  vector< vector < double> > coordinates(dim);
  
  for(unsigned ivar=0; ivar<dim; ivar++) {
    SolPdeIndex[ivar]=my_lin_impl_sys.GetSolPdeIndex(&Solname[ivar][0]);
    SolIndex[ivar]=ml_sol->GetIndex(&Solname[ivar][0]);
  }
  SolPdeIndex[dim]=my_lin_impl_sys.GetSolPdeIndex(&Solname[3][0]);
  SolIndex[dim]=ml_sol->GetIndex(&Solname[3][0]);       
  //solution order
  unsigned order_ind_vel = ml_sol->GetSolutionType(SolIndex[0]);
  unsigned order_ind_p = ml_sol->GetSolutionType(SolIndex[dim]);
  
  double alpha = 0.;
  if(order_ind_p == order_ind_vel && order_ind_vel == 0) // if pressure and velocity are both linear, we need stabilization 
  {
    alpha = 0.013333; 
  }
  
  // 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->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc+1]; iel++) {

    unsigned kel = mymsh->IS_Mts2Gmt_elem[iel];
    short unsigned kelt=myel->GetElementType(kel);
    unsigned nve2=myel->GetElementDofNumber(kel,order_ind_vel);
    unsigned nve1=myel->GetElementDofNumber(kel,order_ind_p);
    
    //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*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_coord_metis=mymsh->GetSolutionDof(inode,2);
      metis_node2[i]=mymsh->GetSolutionDof(inode,order_ind_vel);
      for(unsigned ivar=0; ivar<dim; ivar++) {
	coordinates[ivar][i]=(*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
	KK_dof[ivar][i]=mylsyspde->GetSystemDof(SolIndex[ivar],SolPdeIndex[ivar],inode);
      }
    }
    
    double hk = sqrt( (coordinates[0][2] - coordinates[0][0])*(coordinates[0][2] - coordinates[0][0]) + 
      (coordinates[1][2] - coordinates[1][0])*(coordinates[1][2] - coordinates[1][0]) );
    
    for(unsigned i=0;i<nve1;i++) {
      unsigned inode=(order_ind_p<dim)?(myel->GetElementVertexIndex(kel,i)-1u):(kel+i*nel);
      node1[i]=inode;
      KK_dof[dim][i]=mylsyspde->GetSystemDof(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_ind_vel]->GetGaussPointNumber(); ig++) {
	// *** get Jacobian and test function and test function derivatives ***
	ml_prob._ml_msh->_finiteElement[kelt][order_ind_vel]->Jacobian(coordinates,ig,Weight2,phi2,gradphi2,nablaphi2);
	phi1=ml_prob._ml_msh->_finiteElement[kelt][order_ind_p]->GetPhi(ig);

	double GradSolP[3] = {0.,0.,0.};
	//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->GetSolutionDof(node1[i],SolType);
	  double soli = (*mysolution->_Sol[SolIndex])(sol_dof);
	  SolVAR[dim]+=phi1[i]*soli;
	  for(unsigned ivar2=0; ivar2<dim; ivar2++){
	    GradSolP[ivar2] += gradphi2[i*dim+ivar2]*soli;
	  }
	}

// 	std::cout << "   0: " << GradSolP[0] << "    1: " << GradSolP[1] << std::endl;
	
	// *** phi_i loop ***
	for(unsigned i=0; i<nve2; i++){
	
	  //BEGIN RESIDUALS A block ===========================
	  for(unsigned ivar=0; ivar<dim; ivar++) {
	    double Lap_rhs=0;
	    for(unsigned ivar2=0; ivar2<dim; ivar2++) {
	      Lap_rhs += gradphi2[i*dim+ivar2]*gradSolVAR[ivar][ivar2];
	    }
	    F[SolPdeIndex[ivar]][i]+= (-IRe*Lap_rhs + 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;
	      for(unsigned ivar=0; ivar<dim; ivar++) {
		// Laplacian
		Lap  += gradphi2[i*dim+ivar]*gradphi2[j*dim+ivar]*Weight2;
	      }

	      for(unsigned ivar=0; ivar<dim; ivar++) {    
		B[SolPdeIndex[ivar]][SolPdeIndex[ivar]][i*nve2+j] += IRe*Lap;
	      }
  	    } //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]*/ 
	                             + 0.*((hk*hk)/(4.*IRe))*alpha*(GradSolP[0]*gradphi2[i*dim + 0] + GradSolP[1]*gradphi2[i*dim + 1]) )*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;
	      for(unsigned ivar=0; ivar<dim; ivar++) {
	        B[SolPdeIndex[dim]][SolPdeIndex[dim]][i*nve1+j] -= ((hk*hk)/(4.*IRe))*alpha*(gradphi2[i*dim + ivar]*gradphi2[j*dim + ivar])*Weight2; 
	      }
	    }
	  }
	}   //end if penalty
      }  // end gauss point loop
      
      //--------------------------------------------------------------------------------------------------------
      // Boundary Integral --> to be added
      //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]);
      }
    }
    //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 *******************
}
Beispiel #14
0
//------------------------------------------------------------------------------------------------------------
void AssembleMatrixRes_VC(MultiLevelProblem &ml_prob) {

  TransientNonlinearImplicitSystem* mlPdeSys = & ml_prob.get_system<TransientNonlinearImplicitSystem>("Timedep");
  const unsigned level = mlPdeSys->GetLevelToAssemble();

  MultiLevelSolution *ml_sol			      = ml_prob._ml_sol;
  Solution*	 sol  	                          = ml_sol->GetSolutionLevel(level);
  LinearEquationSolver*  pdeSys	              = mlPdeSys->_LinSolver[level];
  const char* pdename                         = mlPdeSys->name().c_str();

  Mesh*		 msh    	   = ml_prob._ml_msh->GetLevel(level);
  elem*		 myel		   = msh->el;
  SparseMatrix*	 JAC	   = pdeSys->_KK;
  NumericVector* RES 	   = pdeSys->_RES;

  // data
  const unsigned dim = msh->GetDimension();
  const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim)));          // conservative: based on line3, quad9, hex27
  unsigned nel = msh->GetNumberOfElements();
  unsigned igrid = msh->GetLevel();
  unsigned iproc = msh->processor_id();
  
  // time dep data
  double dt = mlPdeSys->GetIntervalTime();
//   double theta = 0.5;

  //************** geometry (at dofs and quadrature points) *************************************  
  vector < vector < double > > coords_at_dofs(dim);
  unsigned coords_fe_type = BIQUADR_FE; // get the finite element type for "x", it is always 2 (LAGRANGE BIQUADRATIC)
  for (unsigned i = 0; i < coords_at_dofs.size(); i++)    coords_at_dofs[i].reserve(max_size);

  vector < double > coord_at_qp(dim);
  
  //************* shape functions (at dofs and quadrature points) **************************************  
  const int solType_max = BIQUADR_FE;  //biquadratic

  double weight_qp; // gauss point weight
  
  vector < vector < double > > phi_fe_qp(NFE_FAMS);
  vector < vector < double > > phi_x_fe_qp(NFE_FAMS);
  vector < vector < double > > phi_xx_fe_qp(NFE_FAMS);
 
  for(int fe=0; fe < NFE_FAMS; fe++) {  
        phi_fe_qp[fe].reserve(max_size);
      phi_x_fe_qp[fe].reserve(max_size*dim);
     phi_xx_fe_qp[fe].reserve(max_size*(3*(dim-1)));
   }

  
  //***************************************************  
  //********* WHOLE SET OF VARIABLES ****************** 
  //***************************************************  
  const unsigned int n_unknowns = mlPdeSys->GetSolPdeIndex().size();

  vector < std::string > Solname(n_unknowns);     Solname[0] = "u";
  vector < unsigned > SolPdeIndex(n_unknowns);
  vector < unsigned > SolIndex(n_unknowns);
  vector < unsigned int > SolFEType(n_unknowns);     //FEtype of each MultilevelSolution       
  vector < unsigned int > Sol_n_el_dofs(n_unknowns); //number of element dofs

  std::fill(Sol_n_el_dofs.begin(), Sol_n_el_dofs.end(), 0);

  for(unsigned ivar=0; ivar < n_unknowns; ivar++) {
    SolPdeIndex[ivar] = mlPdeSys->GetSolPdeIndex(  Solname[ivar].c_str() );
       SolIndex[ivar] = ml_sol->GetIndex         ( Solname[ivar].c_str() );
      SolFEType[ivar] = ml_sol->GetSolutionType  ( SolIndex[ivar]);
  }
  
  //------------ quantities (at quadrature points) ---------------------
          vector<double>        sol_qp(n_unknowns);
          vector<double>    sol_old_qp(n_unknowns);
  vector< vector<double> > sol_grad_qp(n_unknowns);
  vector< vector<double> > sol_old_grad_qp(n_unknowns);
    
  std::fill(sol_qp.begin(), sol_qp.end(), 0.);
  std::fill(sol_old_qp.begin(), sol_old_qp.end(), 0.);
  for (unsigned  k = 0; k < n_unknowns; k++) {
        sol_grad_qp[k].resize(dim);
        std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.);
        sol_old_grad_qp[k].resize(dim);
        std::fill(sol_old_grad_qp[k].begin(), sol_old_grad_qp[k].end(), 0.);
    }

  //----------- quantities (at dof objects) ------------------------------
  vector < vector < double > >     sol_eldofs(n_unknowns);
  vector < vector < double > >     sol_old_eldofs(n_unknowns);
  for(int k=0; k<n_unknowns; k++) { sol_eldofs[k].reserve(max_size);
                                sol_old_eldofs[k].reserve(max_size);
   }
  
  //******** linear system *******************************************  
  vector < vector < int > > L2G_dofmap(n_unknowns);     for(int i = 0; i < n_unknowns; i++) { L2G_dofmap[i].reserve(max_size); }
            vector< int >   L2G_dofmap_AllVars; L2G_dofmap_AllVars.reserve( n_unknowns*max_size );
          
  vector< vector< double > > Res_el(n_unknowns);
  vector< vector< vector< double > > > Jac_el(n_unknowns);

   for(int i = 0; i < n_unknowns; i++) Res_el[i].reserve(max_size);

   for(int i = 0; i < n_unknowns; i++) {
     Jac_el[i].resize(n_unknowns);
     for(int j = 0; j < n_unknowns; j++) {
        Jac_el[i][j].reserve(max_size*max_size);
     }
   }
  
  // Set to zero all the entries of the matrix
  RES->zero();
  JAC->zero();
  
  
  const double deltat_term = 1.;
  const double lapl_term = 1.;
  const double delta_g_term = 1.;

  
  // *** element loop ***
  for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc+1]; iel++) {

    short unsigned ielGeom = msh->GetElementType(iel);    // element geometry type
    
    //******************** GEOMETRY ********************* 
    unsigned nDofx = msh->GetElementDofNumber(iel, coords_fe_type);       // number of coordinate element dofs
    for (int i = 0; i < dim; i++)  coords_at_dofs[i].resize(nDofx);
    // local storage of coordinates
    for (unsigned i = 0; i < nDofx; i++) {
      unsigned xDof  = msh->GetSolutionDof(i, iel, coords_fe_type);       // global to global mapping between coordinates node and coordinate dof

      for (unsigned jdim = 0; jdim < dim; jdim++) {
        coords_at_dofs[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof);    // global extraction and local storage for the element coordinates
      }
    }
  //***************************************************  
    
  //all vars###################################################################  
  for (unsigned  k = 0; k < n_unknowns; k++) {
    unsigned  ndofs_unk = msh->GetElementDofNumber(iel, SolFEType[k]);
	   Sol_n_el_dofs[k] = ndofs_unk;
          sol_eldofs[k].resize(ndofs_unk);
      sol_old_eldofs[k].resize(ndofs_unk);
          L2G_dofmap[k].resize(ndofs_unk); 
    for (unsigned i = 0; i < ndofs_unk; i++) {
            unsigned solDof = msh->GetSolutionDof(i, iel, SolFEType[k]);                    // global to global mapping between solution node and solution dof 
                                                                                            // via local to global solution node
           sol_eldofs[k][i] = (*sol->_Sol[SolIndex[k]])(solDof);                            // global extraction and local storage for the solution
       sol_old_eldofs[k][i] = (*sol->_SolOld[SolIndex[k]])(solDof);                         // This is OLD in TIME, not in nonlinear loop
           L2G_dofmap[k][i] = pdeSys->GetSystemDof(SolIndex[k], SolPdeIndex[k], i, iel);    // global to global mapping between solution node and pdeSys dof
      }
    }
    
    
    unsigned nDof_AllVars = 0;
    for (unsigned  k = 0; k < n_unknowns; k++) { nDof_AllVars += Sol_n_el_dofs[k]; }
    // TODO COMPUTE MAXIMUM maximum number of element dofs for one scalar variable
    int nDof_max    =  0;   
      for (unsigned  k = 0; k < n_unknowns; k++)     {
          if(Sol_n_el_dofs[k] > nDof_max)    nDof_max = Sol_n_el_dofs[k];
       }
    
      for(int k = 0; k < n_unknowns; k++) {
      L2G_dofmap[k].resize(Sol_n_el_dofs[k]);

      Res_el[SolPdeIndex[k]].resize(Sol_n_el_dofs[k]);
      memset(& Res_el[SolPdeIndex[k]][0], 0., Sol_n_el_dofs[k] * sizeof(double) );


      Jac_el[SolPdeIndex[k]][SolPdeIndex[k]].resize(Sol_n_el_dofs[k] * Sol_n_el_dofs[k]);
      memset(& Jac_el[SolPdeIndex[k]][SolPdeIndex[k]][0], 0., Sol_n_el_dofs[k] * Sol_n_el_dofs[k] * sizeof(double));
    }

  //all vars###################################################################    

      // *** quadrature loop ***
      for(unsigned ig = 0; ig < ml_prob.GetQuadratureRule(ielGeom).GetGaussPointsNumber(); ig++) {
          
      // *** get gauss point weight, test function and test function partial derivatives ***
      for(int fe=0; fe < NFE_FAMS; fe++) {
         msh->_finiteElement[ielGeom][fe]->Jacobian(coords_at_dofs,ig,weight_qp,phi_fe_qp[fe],phi_x_fe_qp[fe],phi_xx_fe_qp[fe]);
      }
      //HAVE TO RECALL IT TO HAVE BIQUADRATIC JACOBIAN
         msh->_finiteElement[ielGeom][coords_fe_type]->Jacobian(coords_at_dofs,ig,weight_qp,phi_fe_qp[coords_fe_type],phi_x_fe_qp[coords_fe_type],phi_xx_fe_qp[coords_fe_type]);

   //========= fill gauss value quantities ==================   
   std::fill(sol_qp.begin(), sol_qp.end(), 0.);
   std::fill(sol_old_qp.begin(), sol_old_qp.end(), 0.);
   for (unsigned  k = 0; k < n_unknowns; k++) { std::fill(sol_grad_qp[k].begin(), sol_grad_qp[k].end(), 0.); 
                                                std::fill(sol_old_grad_qp[k].begin(), sol_old_grad_qp[k].end(), 0.);
                                            }
    
    for (unsigned  k = 0; k < n_unknowns; k++) {
	for (unsigned i = 0; i < Sol_n_el_dofs[k]; i++) {
	                                                         sol_qp[k]    +=     sol_eldofs[k][i] *   phi_fe_qp[SolFEType[k]][i];
	                                                     sol_old_qp[k]    += sol_old_eldofs[k][i] *   phi_fe_qp[SolFEType[k]][i];
                   for (unsigned d = 0; d < dim; d++) {      sol_grad_qp[k][d] +=     sol_eldofs[k][i] * phi_x_fe_qp[SolFEType[k]][i * dim + d]; 
                                                         sol_old_grad_qp[k][d] += sol_old_eldofs[k][i] * phi_x_fe_qp[SolFEType[k]][i * dim + d]; 
                                     }
       }        
    }
 
  //========= fill gauss value quantities ==================
         
	// *** phi_i loop ***
	for(unsigned i = 0; i < nDof_max; i++) {

    //BEGIN RESIDUALS A block ===========================
	    double Lap_rhs_i = 0.;
	    double Lap_old_rhs_i = 0.;
	    for(unsigned d = 0;  d < dim;  d++) {
	      Lap_rhs_i     += phi_x_fe_qp[SolFEType[0]][i * dim + d] *     sol_grad_qp[0][d];
	      Lap_old_rhs_i += phi_x_fe_qp[SolFEType[0]][i * dim + d] * sol_old_grad_qp[0][d];
	    }
	    Res_el[SolPdeIndex[0]][i] +=  - weight_qp * ( 
                       delta_g_term * Singularity::function(sol_qp[0]) * Singularity::g_vc(sol_qp[0])     * phi_fe_qp[ SolFEType[0] ][i]
                     - delta_g_term * Singularity::function(sol_qp[0]) * Singularity::g_vc(sol_old_qp[0]) * phi_fe_qp[ SolFEType[0] ][i]
                     + deltat_term * Singularity::function(sol_qp[0]) * dt                               * phi_fe_qp[ SolFEType[0] ][i]
                     + lapl_term *  dt * Lap_rhs_i
            );
    //END RESIDUALS A block ===========================


	    // *** phi_j loop ***
	    for(unsigned j = 0; j<nDof_max; j++) {
            
          double Lap_mat_i_j = 0.;
          for(unsigned d = 0; d < dim; d++) Lap_mat_i_j += phi_x_fe_qp[SolFEType[0]][i * dim + d] *
                                                           phi_x_fe_qp[SolFEType[0]][j * dim + d];


          Jac_el[SolPdeIndex[0]][SolPdeIndex[0]][i * Sol_n_el_dofs[0] + j] += weight_qp * (
                    + delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative(  phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * Singularity::g_vc( phi_fe_qp[ SolFEType[0] ][j] ) 
                    + delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::function  (  phi_fe_qp[ SolFEType[0] ][j] ) * Singularity::g_vc_derivative( phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] 
                    
                    - delta_g_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative(  phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * Singularity::g_vc( sol_old_qp[0] ) 
                    
                    + deltat_term * phi_fe_qp[ SolFEType[0] ][i] * Singularity::derivative(  phi_fe_qp[ SolFEType[0] ][j] ) * phi_fe_qp[ SolFEType[0] ][j] * dt 
                    + lapl_term * dt * Lap_mat_i_j  
                                                                                          );
	      
  	    }    //end phij loop

        
    }        //end phii loop
    
  }          // end gauss point loop

//--------------------------------------------------------------------------------------------------------
    //Sum the local matrices/vectors into the Global Matrix/Vector
    for(unsigned ivar=0; ivar < n_unknowns; ivar++) {
      RES->add_vector_blocked(Res_el[SolPdeIndex[ivar]],L2G_dofmap[ivar]);
      JAC->add_matrix_blocked(Jac_el[SolPdeIndex[ivar]][SolPdeIndex[ivar]],L2G_dofmap[ivar],L2G_dofmap[ivar]);
    }
    //--------------------------------------------------------------------------------------------------------
  } //end list of elements loop for each subdomain

  JAC->close();
  RES->close();
  // ***************** END ASSEMBLY *******************
}
Beispiel #15
0
//------------------------------------------------------------------------------------------------------------
void AssemblePoissonMatrixandRhs(MultiLevelProblem& ml_prob) {

  //pointers and references
  LinearImplicitSystem& mylin_impl_sys = ml_prob.get_system<LinearImplicitSystem>("Poisson");
  const unsigned level = mylin_impl_sys.GetLevelToAssemble();

  Solution*      mysolution	       = ml_prob._ml_sol->GetSolutionLevel(level);
  LinearEquationSolver*  mylsyspde     = mylin_impl_sys._LinSolver[level];
  Mesh*          mymsh		       = ml_prob._ml_msh->GetLevel(level);
  elem*          myel		       = mymsh->el;
  SparseMatrix*  myKK		       = mylsyspde->_KK;
  NumericVector* myRES		       = mylsyspde->_RES;
  MultiLevelSolution* ml_sol           = ml_prob._ml_sol;

  //data
  const unsigned	dim	= mymsh->GetDimension();
  unsigned 		nel	= mymsh->GetNumberOfElements();
  unsigned 		igrid	= mymsh->GetLevel();
  unsigned 		iproc	= mymsh->processor_id();

  //solution variable
  unsigned SolIndex;
  unsigned SolPdeIndex;
  SolIndex = ml_sol->GetIndex("Sol");
  SolPdeIndex = mylin_impl_sys.GetSolPdeIndex("Sol");
  //solution order
  unsigned order_ind = ml_sol->GetSolutionType(SolIndex);


  //coordinates
  vector< vector < double> > coordinates(dim);

  // declare
  vector< int > metis_node;
  vector< int > KK_dof;
  vector <double> phi;
  vector <double> gradphi;
  vector <double> nablaphi;
  double weight;
  vector< double > F;
  vector< double > B;
  vector<double> normal(3.0);
  double src_term = 0.;
  vector<double> xyzt(4, 0.);
  ParsedFunction* bdcfunc = NULL;

  // reserve
  const unsigned max_size = static_cast< unsigned >(ceil(pow(3, dim)));
  metis_node.reserve(max_size);
  KK_dof.reserve(max_size);

  for (int i = 0; i < dim; i++)
    coordinates[i].reserve(max_size);

  phi.reserve(max_size);
  gradphi.reserve(max_size * dim);
  nablaphi.reserve(max_size * (3 * (dim - 1) + !(dim - 1)));
  F.reserve(max_size);
  B.reserve(max_size * max_size);

  // Set to zeto all the entries of the Global Matrix
  myKK->zero();

  // *** element loop ***
  for (int iel = mymsh->_elementOffset[iproc]; iel < mymsh->_elementOffset[iproc + 1]; iel++) {

    short unsigned ielt = myel->GetElementType(iel);
    unsigned nve = myel->GetElementDofNumber(iel, order_ind);

    // resize
    metis_node.resize(nve);
    KK_dof.resize(nve);
    phi.resize(nve);
    gradphi.resize(nve * dim);
    nablaphi.resize(nve * (3 * (dim - 1) + !(dim - 1)));

    for (int i = 0; i < dim; i++) {
      coordinates[i].resize(nve);
    }

    // set to zero all the entries of the FE matrices
    F.resize(nve);
    memset(&F[0], 0, nve * sizeof(double));
    B.resize(nve * nve);
    memset(&B[0], 0, nve * nve * sizeof(double));


    // get local to global mappings
    for (unsigned i = 0; i < nve; i++) {
      unsigned inode_coord_metis = mymsh->GetSolutionDof(i, iel, 2);
      metis_node[i] = mymsh->GetSolutionDof(i, iel, order_ind);

      for (unsigned ivar = 0; ivar < dim; ivar++) {
        coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
      }

      KK_dof[i] = mylsyspde->GetSystemDof(SolIndex, SolPdeIndex, i, iel);
    }


    // *** Gauss poit loop ***
    for (unsigned ig = 0; ig < ml_prob._ml_msh->_finiteElement[ielt][order_ind]->GetGaussPointNumber(); ig++) {
      // *** get Jacobian and test function and test function derivatives ***
      ml_prob._ml_msh->_finiteElement[ielt][order_ind]->Jacobian(coordinates, ig, weight, phi, gradphi, nablaphi);
      //current solution
      double SolT = 0;
      vector < double > gradSolT(dim, 0.);

      for (unsigned ivar = 0; ivar < dim; ivar++) {
        gradSolT[ivar] = 0;
      }

      xyzt.assign(4, 0.);
      unsigned SolType = ml_sol->GetSolutionType("Sol");

      for (unsigned i = 0; i < nve; i++) {
        double soli = (*mysolution->_Sol[SolIndex])(metis_node[i]);

        for (unsigned ivar = 0; ivar < dim; ivar++) {
          xyzt[ivar] += coordinates[ivar][i] * phi[i];
        }

        SolT += phi[i] * soli;

        for (unsigned ivar2 = 0; ivar2 < dim; ivar2++) gradSolT[ivar2] += gradphi[i * dim + ivar2] * soli;
      }

      // *** phi_i loop ***
      for (unsigned i = 0; i < nve; i++) {
        //BEGIN RESIDUALS A block ===========================
        double Adv_rhs = 0;
        double Lap_rhs = 0;

        for (unsigned ivar = 0; ivar < dim; ivar++) {
          Lap_rhs += gradphi[i * dim + ivar] * gradSolT[ivar];
        }


        //src_term = Source(xyzt);
#ifdef HAVE_FPARSER
        //src_term = fpsource.Eval(xyzt);
        src_term = fpsource(&xyzt[0]);
#endif

        F[i] += (-Lap_rhs + src_term * phi[i]) * weight;

        //END RESIDUALS A block ===========================
        // *** phi_j loop ***
        for (unsigned j = 0; j < nve; j++) {
          double Lap = 0;
          double Adv1 = 0;

          for (unsigned ivar = 0; ivar < dim; ivar++) {
            // Laplacian
            Lap  += gradphi[i * dim + ivar] * gradphi[j * dim + ivar] * weight;
          }

          B[i * nve + j] += Lap;
        } // end phij loop

      } // endif assemble_matrix
    } // end gauss point loop

    //number of faces for each type of element
    //number of faces for each type of element
    unsigned nfaces = myel->GetElementFaceNumber(iel);

    // loop on faces
    for (unsigned jface = 0; jface < nfaces; jface++) {

      // look for boundary faces
      if (myel->GetBoundaryIndex(iel, jface) > 0) {

        unsigned int faceIndex =  myel->GetBoundaryIndex(iel, jface) - 1u;

        if (ml_sol->GetBoundaryCondition("Sol", faceIndex) == NEUMANN && !ml_sol->Ishomogeneous("Sol", faceIndex)) {

          bdcfunc = (ParsedFunction*)(ml_sol->GetBdcFunction("Sol", faceIndex));
          unsigned nve = mymsh->el->GetElementFaceDofNumber(iel, jface, order_ind);
          const unsigned felt = mymsh->el->GetElementFaceType(iel, jface);

          for (unsigned i = 0; i < nve; i++) {
            unsigned ilocal = mymsh->el->GetLocalFaceVertexIndex(iel, jface, i);
            unsigned inode_coord_metis = mymsh->GetSolutionDof(ilocal, iel, 2);

            for (unsigned ivar = 0; ivar < dim; ivar++) {
              coordinates[ivar][i] = (*mymsh->_topology->_Sol[ivar])(inode_coord_metis);
            }
          }

          if (felt != 6)
          {
            for (unsigned igs = 0; igs < ml_prob._ml_msh->_finiteElement[felt][order_ind]->GetGaussPointNumber(); igs++) {
              ml_prob._ml_msh->_finiteElement[felt][order_ind]->JacobianSur(coordinates, igs, weight, phi, gradphi, normal);

              xyzt.assign(4, 0.);

              for (unsigned i = 0; i < nve; i++) {
                for (unsigned ivar = 0; ivar < dim; ivar++) {
                  xyzt[ivar] += coordinates[ivar][i] * phi[i];
                }
              }

              // *** phi_i loop ***
              for (unsigned i = 0; i < nve; i++) {
                double surfterm_g = (*bdcfunc)(&xyzt[0]);
                double bdintegral = phi[i] * surfterm_g * weight;
                unsigned int ilocalnode = mymsh->el->GetLocalFaceVertexIndex(iel, jface, i);
                F[ilocalnode] += bdintegral;
              }
            }
          }
          else // 1D : the side elems are points and does not still exist the point elem
          {
            // in 1D it is only one point
            xyzt[0] = coordinates[0][0];
            xyzt[1] = 0.;
            xyzt[2] = 0.;
            xyzt[3] = 0.;

            double bdintegral = (*bdcfunc)(&xyzt[0]);
            unsigned int ilocalnode = mymsh->el->GetLocalFaceVertexIndex(iel, jface, 0);
            F[ilocalnode] += bdintegral;
          }
        }
      }
    }


    //--------------------------------------------------------------------------------------------------------
    //Sum the local matrices/vectors into the global Matrix/vector

    myRES->add_vector_blocked(F, KK_dof);
    myKK->add_matrix_blocked(B, KK_dof, KK_dof);
  } //end list of elements loop for each subdomain

  myRES->close();
  myKK->close();

  // ***************** END ASSEMBLY *******************

}