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(); } }
/** * This function assemble the stiffnes matrix KK and the residual vector Res * Using automatic differentiation for Newton iterative scheme * J(u0) w = - F(u0) , * with u = u0 + w * - F = f(x) - J u = Res * J = \grad_u F * * thus * J w = f(x) - J u0 **/ void AssemblePoissonProblem_AD(MultiLevelProblem& ml_prob) { // ml_prob is the global object from/to where get/set all the data // level is the level of the PDE system to be assembled // levelMax is the Maximum level of the MultiLevelProblem // assembleMatrix is a flag that tells if only the residual or also the matrix should be assembled // call the adept stack object adept::Stack& s = FemusInit::_adeptStack; // extract pointers to the several objects that we are going to use LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned soluIndex; soluIndex = mlSol->GetIndex("u"); // get the position of "u" in the ml_sol object unsigned soluType = mlSol->GetSolutionType(soluIndex); // get the finite element type for "u" unsigned soluPdeIndex; soluPdeIndex = mlPdeSys->GetSolPdeIndex("u"); // get the position of "u" in the pdeSys object vector < adept::adouble > solu; // local solution solu.reserve(maxSize); vector < vector < double > > x(dim); // local coordinates unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) for (unsigned i = 0; i < dim; i++) { x[i].reserve(maxSize); } vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives vector <double> phi_xx; // local test function second order partial derivatives double weight; // gauss point weight phi.reserve(maxSize); phi_x.reserve(maxSize * dim); phi_xx.reserve(maxSize * dim2); vector< adept::adouble > aRes; // local redidual vector aRes.reserve(maxSize); vector< int > l2GMap; // local to global mapping l2GMap.reserve(maxSize); vector< double > Res; // local redidual vector Res.reserve(maxSize); vector < double > Jac; Jac.reserve(maxSize * maxSize); KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++) { short unsigned ielGeom = msh->GetElementType(iel); unsigned nDofu = msh->GetElementDofNumber(iel, soluType); // number of solution element dofs unsigned nDofx = msh->GetElementDofNumber(iel, xType); // number of coordinate element dofs // resize local arrays l2GMap.resize(nDofu); solu.resize(nDofu); for (int i = 0; i < dim; i++) { x[i].resize(nDofx); } aRes.resize(nDofu); //resize std::fill(aRes.begin(), aRes.end(), 0); //set aRes to zero // local storage of global mapping and solution for (unsigned i = 0; i < nDofu; i++) { unsigned solDof = msh->GetSolutionDof(i, iel, soluType); // global to global mapping between solution node and solution dof solu[i] = (*sol->_Sol[soluIndex])(solDof); // global extraction and local storage for the solution l2GMap[i] = pdeSys->GetSystemDof(soluIndex, soluPdeIndex, i, iel); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofx; i++) { unsigned xDof = msh->GetSolutionDof(i, iel, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_topology->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } // start a new recording of all the operations involving adept::adouble variables s.new_recording(); // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[ielGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[ielGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point adept::adouble solu_gss = 0; vector < adept::adouble > gradSolu_gss(dim, 0.); vector < double > x_gss(dim, 0.); for (unsigned i = 0; i < nDofu; i++) { solu_gss += phi[i] * solu[i]; for (unsigned jdim = 0; jdim < dim; jdim++) { gradSolu_gss[jdim] += phi_x[i * dim + jdim] * solu[i]; x_gss[jdim] += x[jdim][i] * phi[i]; } } // *** phi_i loop *** for (unsigned i = 0; i < nDofu; i++) { adept::adouble laplace = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { laplace += phi_x[i * dim + jdim] * gradSolu_gss[jdim]; } double srcTerm = - GetExactSolutionLaplace(x_gss); aRes[i] += (srcTerm * phi[i] - laplace) * weight; } // end phi_i loop } // end gauss point loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store Res.resize(nDofu); //resize for (int i = 0; i < nDofu; i++) { Res[i] = - aRes[i].value(); } RES->add_vector_blocked(Res, l2GMap); // define the dependent variables s.dependent(&aRes[0], nDofu); // define the independent variables s.independent(&solu[0], nDofu); // get the jacobian matrix (ordered by row major ) Jac.resize(nDofu * nDofu); //resize s.jacobian(&Jac[0], true); //store K in the global matrix KK KK->add_matrix_blocked(Jac, l2GMap, l2GMap); s.clear_independents(); s.clear_dependents(); } //end element loop for each process RES->close(); KK->close(); // ***************** END ASSEMBLY ******************* }
void GetL2Norm ( MultiLevelProblem& ml_prob, MultiLevelProblem& ml_prob2 ) { LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ( "NonLocal" ); const unsigned level = mlPdeSys->GetLevelToAssemble(); Mesh* msh = ml_prob._ml_msh->GetLevel ( level ); elem* el = msh->el; MultiLevelSolution* mlSol = ml_prob._ml_sol; Solution* sol = ml_prob._ml_sol->GetSolutionLevel ( level ); LinearImplicitSystem* mlPdeSys2 = &ml_prob2.get_system<LinearImplicitSystem> ( "Local" ); MultiLevelSolution* mlSol2 = ml_prob2._ml_sol; Solution* sol2 = ml_prob2._ml_sol->GetSolutionLevel ( level ); const unsigned dim = msh->GetDimension(); unsigned xType = 2; // get the finite element type for "x", it is always 2 (LAGRANGE QUADRATIC) double error_solExact_norm2 = 0.; double error_solExact_local_norm2 = 0.; double error_solLocal_norm2 = 0.; double solNonlocal_norm2 = 0.; double solLocal_norm2 = 0.; double sol_exact_norm2 = 0.; unsigned soluIndex; soluIndex = mlSol->GetIndex ( "u" ); unsigned soluType = mlSol->GetSolutionType ( soluIndex ); unsigned soluIndexLocal; soluIndexLocal = mlSol2->GetIndex ( "u_local" ); unsigned iproc = msh->processor_id(); unsigned nprocs = msh->n_processors(); for ( int iel = msh->_elementOffset[iproc]; iel < msh->_elementOffset[iproc + 1]; iel++ ) { short unsigned ielGeom = msh->GetElementType ( iel ); unsigned nDofu = msh->GetElementDofNumber ( iel, soluType ); unsigned nDofx = msh->GetElementDofNumber ( iel, xType ); vector < vector < double > > x1 ( dim ); for ( int i = 0; i < dim; i++ ) { x1[i].resize ( nDofx ); } vector < double > soluNonLoc ( nDofu ); vector < double > soluLoc ( nDofu ); for ( unsigned i = 0; i < nDofu; i++ ) { unsigned solDof = msh->GetSolutionDof ( i, iel, soluType ); soluNonLoc[i] = ( *sol->_Sol[soluIndex] ) ( solDof ); soluLoc[i] = ( *sol2->_Sol[soluIndexLocal] ) ( solDof ); } for ( unsigned i = 0; i < nDofx; i++ ) { unsigned xDof = msh->GetSolutionDof ( i, iel, xType ); for ( unsigned jdim = 0; jdim < dim; jdim++ ) { x1[jdim][i] = ( *msh->_topology->_Sol[jdim] ) ( xDof ); } } vector <double> phi; // local test function vector <double> phi_x; // local test function first order partial derivatives double weight; // gauss point weight // *** 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 ( x1, ig, weight, phi, phi_x ); double soluNonLoc_gss = 0.; double soluLoc_gss = 0.; double exactSol_gss_x = 0.; double exactSol_gss_y = 0.; for ( unsigned i = 0; i < nDofu; i++ ) { soluNonLoc_gss += phi[i] * soluNonLoc[i]; soluLoc_gss += phi[i] * soluLoc[i]; exactSol_gss_x += phi[i] * x1[0][i]; // this is x at the Gauss point // exactSol_gss_y += phi[i] * x1[1][i]; // this is y at the Gauss point } exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x + 0.1 * exactSol_gss_x * exactSol_gss_x; // this is x^4 + delta * x^2 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x; // this is x^2 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x; // this is x^3 // exactSol_gss_y = exactSol_gss_y * exactSol_gss_y * exactSol_gss_y; // this is y^3 // exactSol_gss_x = exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x; // this is x^4 // exactSol_gss_x = 2 * exactSol_gss_x + exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x * exactSol_gss_x ; // this is 2x + x^5 error_solExact_norm2 += ( soluNonLoc_gss - exactSol_gss_x ) * ( soluNonLoc_gss - exactSol_gss_x ) * weight; // error_solExact_norm2 += (soluNonLoc_gss - (exactSol_gss_x + exactSol_gss_y)) * (soluNonLoc_gss - (exactSol_gss_x + exactSol_gss_y)) * weight; //error L2 norm of x^3 + y^3 error_solExact_local_norm2 += ( soluLoc_gss - exactSol_gss_x ) * ( soluLoc_gss - exactSol_gss_x ) * weight; error_solLocal_norm2 += ( soluNonLoc_gss - soluLoc_gss ) * ( soluNonLoc_gss - soluLoc_gss ) * weight; solNonlocal_norm2 += soluNonLoc_gss * soluNonLoc_gss * weight; solLocal_norm2 += soluLoc_gss * soluLoc_gss * weight; // sol_exact_norm2 += (exactSol_gss_x + exactSol_gss_y) * (exactSol_gss_x + exactSol_gss_y) * weight; //L2 norm of x^3 + y^3 sol_exact_norm2 += exactSol_gss_x * exactSol_gss_x * weight; } } double norm2 = 0.; MPI_Allreduce ( &error_solExact_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); double norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Nonlocal - exact = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &error_solExact_local_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Local - exact = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &error_solLocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of ERROR: Nonlocal - local = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &solNonlocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of NONLOCAL soln = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &solLocal_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of LOCAL soln = " << norm << std::endl; norm2 = 0.; MPI_Allreduce ( &sol_exact_norm2, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "L2 norm of EXACT soln = " << norm << std::endl; double littleL2norm = 0.; std::vector<double> littleLInfinitynorm ( nprocs, 0. ); for ( unsigned i = msh->_dofOffset[soluType][iproc]; i < msh->_dofOffset[soluType][iproc + 1]; i++ ) { double nonLocalNodalValue = ( *sol->_Sol[soluIndex] ) ( i ); double LocalNodalValue = ( *sol2->_Sol[soluIndexLocal] ) ( i ); double difference = fabs ( nonLocalNodalValue - LocalNodalValue ); if ( difference > littleLInfinitynorm[iproc] ) littleLInfinitynorm[iproc] = difference; littleL2norm += difference * difference; } norm2 = 0.; MPI_Allreduce ( &littleL2norm, &norm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); norm = sqrt ( norm2 ); std::cout.precision ( 14 ); std::cout << "l2 norm of ERROR: Nonlocal - local = " << norm << std::endl; for ( int kproc = 0; kproc < nprocs; kproc++ ) { MPI_Bcast ( &littleLInfinitynorm[iproc], 1, MPI_DOUBLE, kproc, MPI_COMM_WORLD ); } double littleLInfinityNorm = littleLInfinitynorm[0]; for ( unsigned kproc = 0; kproc < nprocs; kproc++ ) { if ( littleLInfinitynorm[kproc] > littleLInfinityNorm ) littleLInfinityNorm = littleLInfinitynorm[kproc]; } std::cout.precision ( 14 ); std::cout << "linfinity norm of ERROR: Nonlocal - local = " << littleLInfinityNorm << std::endl; }
/** * This function assemble the stiffnes matrix Jac and the residual vector Res * such that * Jac w = RES = F - Jac u0, * and consequently * u = u0 + w satisfies Jac u = F **/ void AssemblePoissonProblem(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 LinearImplicitSystem* mlPdeSys = &ml_prob.get_system<LinearImplicitSystem> ("Poisson"); // pointer to the linear implicit system named "Poisson" const unsigned level = mlPdeSys->GetLevelToAssemble(); const unsigned levelMax = mlPdeSys->GetLevelMax(); const bool assembleMatrix = mlPdeSys->GetAssembleMatrix(); Mesh* msh = ml_prob._ml_msh->GetLevel(level); // pointer to the mesh (level) object elem* el = msh->el; // pointer to the elem object in msh (level) MultiLevelSolution* mlSol = ml_prob._ml_sol; // pointer to the multilevel solution object Solution* sol = ml_prob._ml_sol->GetSolutionLevel(level); // pointer to the solution (level) object LinearEquationSolver* pdeSys = mlPdeSys->_LinSolver[level]; // pointer to the equation (level) object SparseMatrix* KK = pdeSys->_KK; // pointer to the global stifness matrix object in pdeSys (level) NumericVector* RES = pdeSys->_RES; // pointer to the global residual vector object in pdeSys (level) const unsigned dim = msh->GetDimension(); // get the domain dimension of the problem unsigned dim2 = (3 * (dim - 1) + !(dim - 1)); // dim2 is the number of second order partial derivatives (1,3,6 depending on the dimension) const unsigned maxSize = static_cast< unsigned >(ceil(pow(3, dim))); // conservative: based on line3, quad9, hex27 unsigned iproc = msh->processor_id(); // get the process_id (for parallel computation) //solution variable unsigned soluIndex; soluIndex = mlSol->GetIndex("u"); // get the position of "u" in the ml_sol object unsigned soluType = mlSol->GetSolutionType(soluIndex); // get the finite element type for "u" unsigned soluPdeIndex; soluPdeIndex = mlPdeSys->GetSolPdeIndex("u"); // get the position of "u" in the pdeSys object vector < double > 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< double > Res; // local redidual vector Res.reserve(maxSize); vector< int > l2GMap; // local to global mapping l2GMap.reserve(maxSize); vector < double > Jac; Jac.reserve(maxSize * maxSize); if (assembleMatrix) KK->zero(); // Set to zero all the entries of the Global Matrix // element loop: each process loops only on the elements that owns for (int iel = msh->IS_Mts2Gmt_elem_offset[iproc]; iel < msh->IS_Mts2Gmt_elem_offset[iproc + 1]; iel++) { unsigned kel = msh->IS_Mts2Gmt_elem[iel]; // mapping between paralell dof and mesh dof short unsigned kelGeom = el->GetElementType(kel); // element geometry type unsigned nDofu = el->GetElementDofNumber(kel, soluType); // number of solution element dofs unsigned nDofx = el->GetElementDofNumber(kel, xType); // number of coordinate element dofs // resize local arrays l2GMap.resize(nDofu); solu.resize(nDofu); for (int i = 0; i < dim; i++) { x[i].resize(nDofx); } Res.resize(nDofu); //resize std::fill(Res.begin(), Res.end(), 0); //set Res to zero Jac.resize(nDofu * nDofu); //resize std::fill(Jac.begin(), Jac.end(), 0); //set Jac to zero // local storage of global mapping and solution for (unsigned i = 0; i < nDofu; i++) { unsigned iNode = el->GetMeshDof(kel, i, soluType); // local to global solution node unsigned solDof = msh->GetMetisDof(iNode, soluType); // global to global mapping between solution node and solution dof solu[i] = (*sol->_Sol[soluIndex])(solDof); // global extraction and local storage for the solution l2GMap[i] = pdeSys->GetKKDof(soluIndex, soluPdeIndex, iNode); // global to global mapping between solution node and pdeSys dof } // local storage of coordinates for (unsigned i = 0; i < nDofx; i++) { unsigned iNode = el->GetMeshDof(kel, i, xType); // local to global coordinates node unsigned xDof = msh->GetMetisDof(iNode, xType); // global to global mapping between coordinates node and coordinate dof for (unsigned jdim = 0; jdim < dim; jdim++) { x[jdim][i] = (*msh->_coordinate->_Sol[jdim])(xDof); // global extraction and local storage for the element coordinates } } if (level == levelMax || !el->GetRefinedElementIndex(kel)) { // do not care about this if now (it is used for the AMR) // *** Gauss point loop *** for (unsigned ig = 0; ig < msh->_finiteElement[kelGeom][soluType]->GetGaussPointNumber(); ig++) { // *** get gauss point weight, test function and test function partial derivatives *** msh->_finiteElement[kelGeom][soluType]->Jacobian(x, ig, weight, phi, phi_x, phi_xx); // evaluate the solution, the solution derivatives and the coordinates in the gauss point double solu_gss = 0; vector < double > 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++) { double laplace = 0.; for (unsigned jdim = 0; jdim < dim; jdim++) { laplace += phi_x[i * dim + jdim] * gradSolu_gss[jdim]; } double srcTerm = - GetExactSolutionLaplace(x_gss); Res[i] += (srcTerm * phi[i] - laplace) * weight; if (assembleMatrix) { // *** phi_j loop *** for (unsigned j = 0; j < nDofu; j++) { laplace = 0.; for (unsigned kdim = 0; kdim < dim; kdim++) { laplace += (phi_x[i * dim + kdim] * phi_x[j * dim + kdim]) * weight; } Jac[i * nDofu + j] += laplace; } // end phi_j loop } // endif assemble_matrix } // end phi_i loop } // end gauss point loop } // endif single element not refined or fine grid loop //-------------------------------------------------------------------------------------------------------- // Add the local Matrix/Vector into the global Matrix/Vector //copy the value of the adept::adoube aRes in double Res and store RES->add_vector_blocked(Res, l2GMap); if (assembleMatrix) { //store K in the global matrix KK KK->add_matrix_blocked(Jac, l2GMap, l2GMap); } } //end element loop for each process RES->close(); if (assembleMatrix) KK->close(); // ***************** END ASSEMBLY ******************* }