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(); const unsigned levelMax = mlPdeSys->GetLevelMax(); const bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned 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); 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++) { short unsigned ielGeom = el->GetElementType(iel); // element geometry type unsigned nDofs = el->GetElementDofNumber(iel, solHType); // number of solution element dofs unsigned nDofs2 = el->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 } } if (level == levelMax || !el->GetRefinedElementIndex(iel)) { // do not care about this if now (it is used for the AMR) // start a new recording of all the operations involving adept::adouble variables s.new_recording(); // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[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 } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store for (int i = 0; i < nDofs; i++) { 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); if (assembleMatrix) { 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(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }