// display the field on screen void DisplayField(Field* f){ //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; printf("Display field...\n"); for(int ie=0;ie<f->macromesh.nbelems;ie++){ printf("elem %d\n",ie); for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double xref[3],wpg; ref_pg_vol(f->interp_param+1,ipg,xref,&wpg,NULL); printf("Gauss point %d %f %f %f \n",ipg,xref[0],xref[1],xref[2]); printf("dtw= "); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); printf("%f ",f->dtwn[imem]); } printf("\n"); printf("w= "); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); printf("%f ",f->wn[imem]); } printf("\n"); } } };
int TestFieldDG(void){ int test = (1==1); Field f; f.model.m=1; // only one conservative variable f.model.NumFlux=TransportNumFlux; f.model.BoundaryFlux=TestTransportBoundaryFlux; f.model.InitData=TestTransportInitData; f.model.ImposedData=TestTransportImposedData; f.varindex=GenericVarindex; f.interp.interp_param[0]=1; // _M f.interp.interp_param[1]=2; // x direction degree f.interp.interp_param[2]=2; // y direction degree f.interp.interp_param[3]=2; // z direction degree f.interp.interp_param[4]=1; // x direction refinement f.interp.interp_param[5]=1; // y direction refinement f.interp.interp_param[6]=1; // z direction refinement ReadMacroMesh(&(f.macromesh),"test/testcube.msh"); BuildConnectivity(&(f.macromesh)); PrintMacroMesh(&(f.macromesh)); //AffineMapMacroMesh(&(f.macromesh)); PrintMacroMesh(&(f.macromesh)); InitField(&f); CheckMacroMesh(&(f.macromesh),f.interp.interp_param+1); dtField(&f); DisplayField(&f); int yes_compare = 1; int no_compare = 0; PlotField(0,no_compare,&f,"visu.msh"); PlotField(0,yes_compare,&f,"error.msh"); // test the time derivative with the exact solution for(int i=0;i<f.model.m * f.macromesh.nbelems * NPG(f.interp.interp_param+1);i++){ test = test && fabs(4*f.wn[i]-pow(f.dtwn[i],2))<1e-2; assert(test); } return test; };
int TestfieldDG() { int test = true; field f; init_empty_field(&f); f.model.cfl = 0.05; f.model.m = 1; // only one conservative variable f.model.NumFlux = TransNumFlux; f.model.BoundaryFlux = TestTransBoundaryFlux; f.model.InitData = TestTransInitData; f.model.ImposedData = TestTransImposedData; f.model.Source = NULL; f.varindex = GenericVarindex; f.interp.interp_param[0] = 1; // _M f.interp.interp_param[1] = 2; // x direction degree f.interp.interp_param[2] = 2; // y direction degree f.interp.interp_param[3] = 2; // z direction degree f.interp.interp_param[4] = 2; // x direction refinement f.interp.interp_param[5] = 2; // y direction refinement f.interp.interp_param[6] = 2; // z direction refinement ReadMacroMesh(&(f.macromesh), "../test/testcube2.msh"); //ReadMacroMesh(&(f.macromesh),"test/testmacromesh.msh"); BuildConnectivity(&(f.macromesh)); PrintMacroMesh(&(f.macromesh)); //AffineMapMacroMesh(&(f.macromesh)); PrintMacroMesh(&(f.macromesh)); real tnow = 0.0; Initfield(&f); CheckMacroMesh(&(f.macromesh), f.interp.interp_param + 1); dtfield(&f, tnow, f.wn, f.dtwn); Displayfield(&f); /* Plotfield(0, false, &f, NULL, "visu.msh"); */ /* Plotfield(0, true, &f, "error", "error.msh"); */ // Test the time derivative with the exact solution int *raf = f.interp.interp_param + 4; int *deg = f.interp.interp_param + 1; for(int i = 0; i < f.model.m * f.macromesh.nbelems * NPG(raf, deg); i++){ test = test && fabs(4 * f.wn[i] - pow(f.dtwn[i], 2)) < 1e-2; printf("i=%d err=%f \n",i,4 * f.wn[i] - pow(f.dtwn[i], 2)); assert(test); } return test; };
void RK2StVenantLin(Field* f,double tmax){ printf("RK2StVenantLin\n"); double vmax=sqrt(const_g*H0); // to be changed for another model !!!!!!!!! double cfl=0.2/vmax; double dt = cfl * f->hmin / vmax; int itermax=tmax/dt; int freq=(1 >= itermax/10)? 1 : itermax/10; //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; int sizew=f->macromesh.nbelems * f->model.m * NPG(f->interp_param+1); int iter=0; while(f->tnow<tmax){ if (iter%freq==0) printf("t=%f iter=%d/%d dt=%f\n",f->tnow,iter,itermax,dt); // predictor dtField(f); #ifdef _OPENMP #pragma omp parallel for #endif for(int iw=0;iw<sizew;iw++){ f->wnp1[iw]=f->wn[iw]+ dt/2 * f->dtwn[iw]; } //exchange the field pointers double *temp; temp=f->wnp1; f->wnp1=f->wn; f->wn=temp; // corrector f->tnow+=dt/2; dtField(f); #ifdef _OPENMP #pragma omp parallel for #endif for(int iw=0;iw<sizew;iw++){ f->wnp1[iw]+=dt*f->dtwn[iw]; } f->tnow+=dt/2; iter++; //exchange the field pointers temp=f->wnp1; f->wnp1=f->wn; f->wn=temp; } printf("t=%f iter=%d/%d dt=%f\n",f->tnow,iter,itermax,dt); }
// TODO: do not store all diagnotics for all time, but instead just // append to the output file. void Energies(field *f, real *w, real k_energy, real e_energy, real t_energy) { k_energy = 0; e_energy = 0; t_energy = 0; for (int ie = 0; ie < f->macromesh.nbelems; ie++){ // get the physical nodes of element ie real physnode[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++){ int ino = f->macromesh.elem2node[20 * ie + inoloc]; physnode[inoloc][0] = f->macromesh.node[3 * ino + 0]; physnode[inoloc][1] = f->macromesh.node[3 * ino + 1]; physnode[inoloc][2] = f->macromesh.node[3 * ino + 2]; } // loop on the glops (for numerical integration) for(int ipg = 0; ipg < NPG(f->interp_param + 1); ipg++){ real xpgref[3], xphy[3], wpg; real dtau[3][3], codtau[3][3];//,xpg[3]; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param + 1, ipg, xpgref, &wpg, NULL); Ref2Phy(physnode, // phys. nodes xpgref, // xref NULL,-1, // dpsiref,ifa xphy,dtau, // xphy,dtau codtau,NULL,NULL); // codtau,dpsi,vnds real det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; real wn[f->model.m]; for(int iv = 0; iv < _INDEX_MAX + 1; iv++){ int imem = f->varindex(f->interp_param, ie, ipg, iv); wn[iv] = w[imem]; } // get the exact value k_energy += local_kinetic_energy(f, xphy, wn) * wpg * det; e_energy += wn[_MV+1] * wn[_MV+1] * wpg * det; } } t_energy = 0.5 * (e_energy + k_energy); f->Diagnostics[f->iter_time] = 0.5 * k_energy; f->Diagnostics[f->iter_time + f->itermax] = 0.5 * e_energy; f->Diagnostics[f->iter_time + 2 * f->itermax] = t_energy; }
// compute the normalized L2 distance with the imposed data double L2error(Field* f){ //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; double error=0; double moy=0; // mean value //#pragma omp parallel for for (int ie=0;ie<f->macromesh.nbelems;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // loop on the glops (for numerical integration) for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double xpgref[3],xphy[3],wpg; double dtau[3][3],codtau[3][3];//,xpg[3]; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param+1,ipg,xpgref,&wpg,NULL); Ref2Phy(physnode, // phys. nodes xpgref, // xref NULL,-1, // dpsiref,ifa xphy,dtau, // xphy,dtau codtau,NULL,NULL); // codtau,dpsi,vnds double det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; double w[f->model.m],wex[f->model.m]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); w[iv]=f->wn[imem]; } // get the exact value f->model.ImposedData(xphy,f->tnow,wex); for(int iv=0;iv<f->model.m;iv++){ error+=pow(w[iv]-wex[iv],2)*wpg*det; moy+=pow(w[iv],2)*wpg*det; } } } return sqrt(error)/sqrt(moy); }
// apply division by the mass matrix void* DGMass(void* mc){ MacroCell* mcell = (MacroCell*) mc; Field* f= mcell->field; // loop on the elements for (int ie=mcell->first_cell;ie<mcell->last_cell_p1;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++) { int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double dtau[3][3],codtau[3][3],xpgref[3],wpg; ref_pg_vol(f->interp_param+1,ipg,xpgref,&wpg,NULL); Ref2Phy(physnode, // phys. nodes xpgref, // xref NULL,-1, // dpsiref,ifa NULL,dtau, // xphy,dtau codtau,NULL,NULL); // codtau,dpsi,vnds double det = dtau[0][0]*codtau[0][0] + dtau[0][1]*codtau[0][1] + dtau[0][2]*codtau[0][2]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); f->dtwn[imem]/=(wpg*det); } } } return NULL; }
// time integration by a second order Runge-Kutta algorithm // with memory copy instead of pointers exchange void RK2Copy(Field* f,double tmax){ double vmax=1; // to be changed for another model !!!!!!!!! double cfl=0.05; double dt = cfl * f->hmin / vmax; //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; int sizew=f->macromesh.nbelems * f->model.m * NPG(f->interp_param+1); int iter=0; while(f->tnow<tmax){ printf("t=%f iter=%d dt=%f\n",f->tnow,iter,dt); // predictor dtField(f); for(int iw=0;iw<sizew;iw++){ f->wnp1[iw]=f->wn[iw]+ dt/2 * f->dtwn[iw]; } //exchange the field pointers for(int iw=0;iw<sizew;iw++){ double temp=f->wn[iw]; f->wn[iw]=f->wnp1[iw]; f->wnp1[iw]=temp; } // corrector f->tnow+=dt/2; dtField(f); for(int iw=0;iw<sizew;iw++){ f->wnp1[iw]+=dt*f->dtwn[iw]; } f->tnow+=dt/2; iter++; //exchange the field pointers for(int iw=0;iw<sizew;iw++){ f->wn[iw]=f->wnp1[iw]; } } }
real L2_Kinetic_error(field* f){ real error = 0; for (int ie = 0; ie < f->macromesh.nbelems; ie++){ // get the physical nodes of element ie real physnode[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++){ int ino = f->macromesh.elem2node[20 * ie + inoloc]; physnode[inoloc][0] = f->macromesh.node[3 * ino + 0]; physnode[inoloc][1] = f->macromesh.node[3 * ino + 1]; physnode[inoloc][2] = f->macromesh.node[3 * ino + 2]; } // loop on the glops (for numerical integration) for(int ipg = 0; ipg < NPG(f->interp_param + 1); ipg++){ real xpgref[3], xphy[3], wpg; real dtau[3][3], codtau[3][3];//,xpg[3]; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param + 1, ipg, xpgref, &wpg, NULL); Ref2Phy(physnode, // phys. nodes xpgref, // xref NULL, -1, // dpsiref,ifa xphy, dtau, // xphy,dtau codtau, NULL, NULL); // codtau,dpsi,vnds real det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; real w[f->model.m]; for(int iv = 0;iv < f->model.m; iv++){ int imem = f->varindex(f->interp_param, ie, ipg, iv); w[iv] = f->wn[imem]; } // get the exact value error += L2VelError(f, xphy, w) * wpg * det; } } return sqrt(error); }
void AccumulateParticles(void *fv, real *w) { field *f = fv; PIC *pic = f->pic; int *raf = f->interp_param + 4; int *deg = f->interp_param + 1; int npg = NPG(raf, deg); for(int ie = 0; ie < f->macromesh.nbelems; ie++){ MacroCell *mcell = f->mcell + ie; for(int ipg = 0; ipg < npg; ipg++){ int iv = 4; int imem = f->varindex(f->interp_param, ipg, iv) + mcell->woffset; f->wn[imem]=0; iv = 5; imem = f->varindex(f->interp_param, ipg, iv) + mcell->woffset; f->wn[imem]=0; iv = 6; imem = f->varindex(f->interp_param, ipg, iv) + mcell->woffset; f->wn[imem]=0; } } for(int i=0;i<pic->nbparts;i++) { int ie=pic->old_cell_id[i]; // https://xkcd.com/292/ // FIXME: remove goto if (ie < 0) goto nexti; MacroCell *mcell = f->mcell + ie; int npg=NPG(raf, deg); real physnode[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++) { int ino = f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0] = f->macromesh.node[3 * ino + 0]; physnode[inoloc][1] = f->macromesh.node[3 * ino + 1]; physnode[inoloc][2] = f->macromesh.node[3 * ino + 2]; } real dtau[3][3], codtau[3][3]; Ref2Phy(physnode, // phys. nodes pic->xv + 6 * i, // xref NULL, -1, // dpsiref, ifa NULL, dtau, // xphy, dtau codtau, NULL, NULL); // codtau, dpsi, vnds real det = dot_product(dtau[0], codtau[0]); for(int ib=0;ib < npg;ib++){ real wpg; int *raf = f->interp_param + 4; int *deg = f->interp_param + 1; ref_pg_vol(raf, deg, ib, NULL, &wpg, NULL); //printf("det=%f wpg=%f \n", det, wpg); wpg *= det; real psi; psi_ref(f->interp_param+1,ib,pic->xv + 6*i,&psi,NULL); int iv = 6; // rho index int imem = f->varindex(f->interp_param, ib, iv) + mcell->woffset; w[imem] += psi / wpg * pic->weight; iv = 4; // j1 index imem = f->varindex(f->interp_param, ib, iv) + mcell->woffset; w[imem] += pic->xv[6 * i + 3] * psi / wpg * pic->weight; iv = 5; // j2 index imem = f->varindex(f->interp_param, ib, iv) + mcell->woffset; w[imem] += pic->xv[6 * i + 4] * psi / wpg * pic->weight; } nexti: assert(1==1); } }
void CheckMacroMesh(MacroMesh *m, int *param) { Geom g; real face_centers[6][3]={ {0.5,0.0,0.5}, {1.0,0.5,0.5}, {0.5,1.0,0.5}, {0.0,0.5,0.5}, {0.5,0.5,1.0}, {0.5,0.5,0.0} }; //real *bounds = malloc(6 * sizeof(real)); //macromesh_bounds(m, bounds); /* real refnormal[6][3]={{0,-1,0},{1,0,0}, */ /* {0,1,0},{-1,0,0}, */ /* {0,0,1},{0,0,-1}}; */ assert(m->connec_ok); for(int ie = 0; ie < m->nbelems; ie++) { // Load geometry for macro element ie: for(int inoloc = 0; inoloc < 20; inoloc++) { int ino = m->elem2node[20 * ie + inoloc]; g.physnode[inoloc][0] = m->node[3 * ino + 0]; g.physnode[inoloc][1] = m->node[3 * ino + 1]; g.physnode[inoloc][2] = m->node[3 * ino + 2]; } // Test that the ref_ipg function is compatible with ref_pg_vol //int param[7]={_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; for(int ipg = 0; ipg < NPG(param); ipg++) { real xref1[3], xref_in[3]; real wpg; ref_pg_vol(param, ipg, xref1, &wpg, xref_in); memcpy(g.xref, xref1, sizeof(g.xref)); g.ifa = 0; GeomRef2Phy(&g); GeomPhy2Ref(&g); // if(param[4]==1 && param[5]==1 && param[6]==1) { //printf("ipg %d ipg2 %d xref %f %f %f\n",ipg, // ref_ipg(param,xref_in),xref_in[0],xref_in[1],xref_in[2]); // Ensure that the physical coordinates give the same point: assert(ipg == ref_ipg(param, xref_in)); //} } // middle of the element g.xref[0] = 0.5; g.xref[1] = 0.5; g.xref[2] = 0.5; GeomRef2Phy(&g); real xphym[3]; memcpy(xphym, g.xphy, sizeof(xphym)); for(int ifa = 0; ifa < 6; ifa++) { // Middle of the face memcpy(g.xref, face_centers[ifa], sizeof(g.xref)); g.ifa = ifa; GeomRef2Phy(&g); // Check volume orientation assert(g.det > 0); real vec[3] = {g.xphy[0] - xphym[0], g.xphy[1] - xphym[1], g.xphy[2] - xphym[2]}; // Check face orientation assert(0 < dot_product(g.vnds, vec)); // Check compatibility between face and volume numbering for(int ipgf = 0; ipgf < NPGF(param, ifa); ipgf++) { // Get the coordinates of the Gauss point real xpgref[3]; { real wpg; ref_pg_face(param, ifa, ipgf, xpgref, &wpg, NULL); } // Recover the volume gauss point from the face index int ipgv = param[6]; real xpgref2[3]; { real wpg2; ref_pg_vol(param, ipgv, xpgref2, &wpg2, NULL); } if(m->is2d) { // in 2D do not check upper and lower face if(ifa < 4) assert(Dist(xpgref, xpgref2) < 1e-11); } else if (m->is1d){ if (ifa==1 || ifa==3) { assert(Dist(xpgref,xpgref2)<1e-11); } } // in 3D check all faces else { // in 3D check all faces if(Dist(xpgref, xpgref2) >= 1e-11) { printf("ERROR: face and vol indices give different rev points:\n"); printf("ipgv: %d\n", ipgv); printf("ipgf: %d\n", ipgf); printf("ifa: %d\n", ifa); printf("xpgref:%f %f %f\n", xpgref[0], xpgref[1], xpgref[2]); printf("xpgref2:%f %f %f\n", xpgref2[0], xpgref2[1], xpgref2[2]); } assert(Dist(xpgref, xpgref2) < 1e-11); } } } } // Check that the faces are defined by the same mapping with // opposite normals for (int ie = 0; ie < m->nbelems; ie++) { // int param[8]={1,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; // Get the geometry for the macro element ie real physnode[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++) { int ino = m->elem2node[20 * ie + inoloc]; physnode[inoloc][0] = m->node[3 * ino + 0]; physnode[inoloc][1] = m->node[3 * ino + 1]; physnode[inoloc][2] = m->node[3 * ino + 2]; } // Loop on the 6 faces for(int ifa = 0; ifa < 6; ifa++) { // Loop on the glops (numerical integration) of the face ifa for(int ipgf = 0; ipgf < NPGF(param, ifa); ipgf++) { // Get the right elem or the boundary id int ieR = m->elem2elem[6 * ie + ifa]; // If the right element exists and is not // the left element (may arrive in periodic cases) if(ieR >= 0 && ieR != ie) { // Get the coordinates of the Gauss point from the // face-local point index and the point slightly inside the // macrocell. real xpgref[3], xpgref_in[3]; ref_pg_face(param, ifa, ipgf, xpgref, NULL, xpgref_in); //ref_pg_face(param, ifa, ipgf, xpgref, NULL, NULL); int ipg=param[6]; /* #ifdef _PERIOD */ /* assert(m->is1d); // TODO: generalize to 2d */ /* if (xpgref_in[0] > _PERIOD) xpgref_in[0] -= _PERIOD; */ /* if (xpgref_in[0] < 0) xpgref_in[0] += _PERIOD; */ /* #endif */ // Compute the position of the point and the face normal. real xpg[3], vnds[3]; { real dtau[3][3]; real codtau[3][3]; Ref2Phy(physnode, xpgref, NULL, ifa, // dpsiref,ifa xpg, dtau, codtau, NULL, vnds); // codtau,dpsi,vnds } // Compute the "slightly inside" position real xpg_in[3]; Ref2Phy(physnode, xpgref_in, NULL, ifa, // dpsiref,ifa xpg_in, NULL, NULL, NULL, NULL); // codtau,dpsi,vnds PeriodicCorrection(xpg_in,m->period); // Load the geometry of the right macrocell real physnodeR[20][3]; for(int inoloc = 0; inoloc < 20; inoloc++) { int ino = m->elem2node[20 * ieR + inoloc]; physnodeR[inoloc][0] = m->node[3 * ino + 0]; physnodeR[inoloc][1] = m->node[3 * ino + 1]; physnodeR[inoloc][2] = m->node[3 * ino + 2]; } // Find the corresponding point in the right elem real xpgrefR_in[3];//,xpgrefR[3]; Phy2Ref(physnodeR, xpg_in, xpgrefR_in); //Phy2Ref(physnodeR, xpg, xpgrefR); int ipgR = ref_ipg(param, xpgrefR_in); // search the id of the face in the right elem // special treatment if the mesh is periodic // and contains only one elem (then ie==ieR) int neighb_count=0; for(int ifaR=0;ifaR<6;ifaR++){ if (m->elem2elem[6*ieR+ifaR] == ie) { for(int ipgfR = 0; ipgfR < NPGF(param, ifaR); ipgfR++) { real xpgrefR[3]; ref_pg_face(param, ifaR, ipgfR, xpgrefR, NULL, NULL); if (param[6] == ipgR){ real xpgR[3]; real vndsR[3]; { ref_pg_vol(param, ipgR, xpgrefR, NULL, NULL); real dtauR[3][3], codtauR[3][3]; Ref2Phy(physnodeR, xpgrefR, NULL, ifaR, // dphiref, ifa xpgR, dtauR, codtauR, NULL, vndsR); // codtau, dphi, vnds } // Ensure that the normals are opposite // if xpg and xpgR are close /* printf("xpg:%f %f %f\n", xpg_in[0], xpg_in[1], xpg_in[2]); */ /* printf("vnds: %f %f %f vndsR: %f %f %f \n", */ /* vnds[0],vnds[1],vnds[2], */ /* vndsR[0],vndsR[1],vndsR[2]); */ /* printf("xpgR:%f %f %f\n", xpgR[0], xpgR[1], xpgR[2]); */ assert(fabs(vnds[0] + vndsR[0]) < 1e-8); assert(fabs(vnds[1] + vndsR[1]) < 1e-8); assert(fabs(vnds[2] + vndsR[2]) < 1e-8); neighb_count++; } } } } //printf("neighb=%d\n",neighb_count); assert(neighb_count == 1); } } } } //free(bounds); }
// compute the Discontinuous Galerkin volume terms // slow version void DGVolumeSlow(Field* f){ // assembly of the volume terms // loop on the elements //#pragma omp parallel for for (int ie=0;ie<f->macromesh.nbelems;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // mass matrix double masspg[NPG(f->interp_param+1)]; // loop on the glops (for numerical integration) for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double xpgref[3],wpg; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param+1,ipg,xpgref,&wpg,NULL); // get the value of w at the gauss point double w[f->model.m]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); w[iv]=f->wn[imem]; } // loop on the basis functions for(int ib=0;ib<NPG(f->interp_param+1);ib++){ // gradient of psi_ib at gauss point ipg double dpsiref[3],dpsi[3]; double dtau[3][3],codtau[3][3];//,xpg[3]; grad_psi_pg(f->interp_param+1,ib,ipg,dpsiref); Ref2Phy(physnode, // phys. nodes xpgref, // xref dpsiref,-1, // dpsiref,ifa NULL,dtau, // xphy,dtau codtau,dpsi,NULL); // codtau,dpsi,vnds // remember the diagonal mass term if (ib == ipg){ double det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; masspg[ipg]=wpg*det; } // int_L F(w,w,grad phi_ib ) double flux[f->model.m]; f->model.NumFlux(w,w,dpsi,flux); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ib,iv); f->dtwn[imem]+=flux[iv]*wpg; } } } for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ // apply the inverse of the diagonal mass matrix for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); (f->dtwn[imem])/=masspg[ipg]; } } } }
void InitField(Field* f){ //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; double w[f->model.m]; double xpg[3]; double xref[3],omega; double physnode[20][3]; f->is2d = false; // a copy for avoiding too much "->" for(int ip=0;ip<8;ip++){ f->interp_param[ip]=f->interp.interp_param[ip]; } int nmem=f->model.m * f->macromesh.nbelems * NPG(f->interp_param+1); printf("allocate %d doubles\n",nmem); f->wn=malloc(nmem * sizeof(double)); assert(f->wn); f->wnp1=malloc(nmem * sizeof(double)); assert(f->wnp1); f->dtwn=malloc(nmem * sizeof(double)); assert(f->dtwn); f->tnow=0; for(int ie=0;ie<f->macromesh.nbelems;ie++){ for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ ref_pg_vol(f->interp_param+1, ipg, xref, &omega,NULL); double dtau[3][3]; Ref2Phy(physnode, xref, 0,-1, // dphiref,ifa xpg,dtau, NULL,NULL,NULL); // codtau,dphi,vnds // check the reverse transform at all the GLOPS double xref2[3]; Phy2Ref(physnode,xpg,xref2); assert(Dist(xref,xref2) < 1e-8); f->model.InitData(xpg,w); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); f->wn[imem]=w[iv]; } } } // compute cfl parameter min_i vol_i/surf_i f->hmin=1e10; for (int ie=0;ie<f->macromesh.nbelems;ie++){ double vol=0,surf=0; // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // loop on the glops (for numerical integration) for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double xpgref[3],wpg; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param+1,ipg,xpgref,&wpg,NULL); double codtau[3][3],dtau[3][3]; Ref2Phy(physnode, // phys. nodes xpgref, // xref NULL,-1, // dpsiref,ifa NULL,dtau, // xphy,dtau codtau,NULL,NULL); // codtau,dpsi,vnds double det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; vol+=wpg*det; } for(int ifa=0;ifa<6;ifa++){ // loop on the faces for(int ipgf=0;ipgf<NPGF(f->interp_param+1,ifa);ipgf++){ double xpgref[3],wpg; //double xpgref2[3],wpg2; // get the coordinates of the Gauss point ref_pg_face(f->interp_param+1,ifa,ipgf,xpgref,&wpg,NULL); double vnds[3]; double codtau[3][3],dtau[3][3]; Ref2Phy(physnode, xpgref, NULL,ifa, // dpsiref,ifa NULL,dtau, codtau,NULL,vnds); // codtau,dpsi,vnds surf+=sqrt(vnds[0]*vnds[0]+vnds[1]*vnds[1]+vnds[2]*vnds[2])*wpg; } } f->hmin = f->hmin < vol/surf ? f->hmin : vol/surf; } // now take into account the polynomial degree and the refinement int maxd=f->interp_param[1]; maxd = maxd > f->interp_param[2] ? maxd : f->interp_param[2]; maxd = maxd > f->interp_param[3] ? maxd : f->interp_param[3]; f->hmin/=((maxd+1)*f->interp_param[4]); printf("hmin=%f\n",f->hmin); };
// save the results in the gmsh format // typplot: index of the plotted variable // int compare == true -> compare with the exact value void PlotField(int typplot,int compare,Field* f,char* filename){ const int hexa64ref[3*64]={ 0,0,3, 3,0,3, 3,3,3, 0,3,3, 0,0,0,3,0,0,3,3,0,0,3,0, 1,0,3,2,0,3,0,1,3,0,2,3,0,0,2,0,0,1,3,1,3,3,2,3, 3,0,2,3,0,1,2,3,3,1,3,3,3,3,2,3,3,1,0,3,2,0,3,1, 1,0,0,2,0,0,0,1,0,0,2,0,3,1,0,3,2,0,2,3,0,1,3,0, 1,1,3,1,2,3,2,2,3,2,1,3,1,0,2,2,0,2,2,0,1,1,0,1, 0,1,2,0,1,1,0,2,1,0,2,2,3,1,2,3,2,2,3,2,1,3,1,1, 2,3,2,1,3,2,1,3,1,2,3,1,1,1,0,2,1,0,2,2,0,1,2,0, 1,1,2,2,1,2,2,2,2,1,2,2,1,1,1,2,1,1,2,2,1,1,2,1}; int* elem2nodes = f->macromesh.elem2node; double* node = f->macromesh.node; FILE * gmshfile; gmshfile = fopen( filename, "w" ); // data plots //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; int nraf[3]={f->interp_param[4],f->interp_param[5],f->interp_param[6]}; // refinement size in each direction double hh[3]={1./nraf[0],1./nraf[1],1./nraf[2]}; int npgv = NPG(f->interp_param+1); int nnodes = 20; double physnode[nnodes][3]; double Xr[3]; double Xphy[3]; // header fprintf(gmshfile,"$MeshFormat\n2.2 0 %d\n",(int) sizeof(double)); //int one=1; //fwrite((char*) &one,sizeof(int),1,gmshfile); fprintf(gmshfile,"$EndMeshFormat\n$Nodes\n%d\n", f->macromesh.nbelems*nraf[0]*nraf[1]*nraf[2]*64); int nb_plotnodes=f->macromesh.nbelems*nraf[0]*nraf[1]*nraf[2]*64; double* value=malloc(nb_plotnodes*sizeof(double)); assert(value); int nodecount=0; // nodes for(int i=0;i<f->macromesh.nbelems;i++){ // get the nodes of element L for(int ino=0;ino<nnodes;ino++){ int numnoe=elem2nodes[nnodes*i+ino]; for(int ii=0;ii<3;ii++){ physnode[ino][ii]=node[3*numnoe+ii]; } } // loop on the macro elem subcells int icL[3]; // loop on the subcells for(icL[0]=0;icL[0]<nraf[0];icL[0]++){ for(icL[1]=0;icL[1]<nraf[1];icL[1]++){ for(icL[2]=0;icL[2]<nraf[2];icL[2]++){ // get the left subcell id // first glop index in the subcell //int offsetL=(deg[0]+1)*(deg[1]+1)*(deg[2]+1)*ncL; for(int ino=0;ino<64;ino++){ Xr[0]=(double) (hexa64ref[3*ino+0]) / 3; Xr[1]=(double) (hexa64ref[3*ino+1]) / 3; Xr[2]=(double) (hexa64ref[3*ino+2]) / 3; Xr[0] = icL[0]*hh[0]+ Xr[0] * hh[0]; Xr[1] = icL[1]*hh[1]+ Xr[1] * hh[1]; Xr[2] = icL[2]*hh[2]+ Xr[2] * hh[2]; for(int ii=0;ii<3;ii++){ assert(Xr[ii]<1+1e-10 && Xr[ii]>-1e-10); } Ref2Phy(physnode, Xr, NULL, -1, Xphy, NULL, NULL, NULL, NULL); double Xplot[3]; Xplot[0]=Xphy[0]; Xplot[1]=Xphy[1]; Xplot[2]=Xphy[2]; value[nodecount]=0; double testpsi=0; for(int ib=0;ib<npgv;ib++){ double psi; psi_ref_subcell(f->interp_param+1,icL, ib, Xr, &psi, NULL); testpsi+=psi; int vi = f->varindex(f->interp_param, i, ib, typplot); value[nodecount] += psi * f->wn[vi]; } assert(fabs(testpsi-1)<1e-10); // compare with an // exact solution if (compare){ double wex[f->model.m]; f->model.ImposedData(Xphy,f->tnow,wex); value[nodecount] -= wex[typplot]; } nodecount++; // fwrite((char*) &nnoe,sizeof(int),1,gmshfile); // fwrite((char*) &(Xplot[0]),sizeof(double),1,gmshfile); // fwrite((char*) &(Xplot[1]),sizeof(double),1,gmshfile); // fwrite((char*) &(Xplot[2]),sizeof(double),1,gmshfile); fprintf(gmshfile,"%d %f %f %f\n",nodecount,Xplot[0],Xplot[1],Xplot[2]); } } } } } fprintf(gmshfile,"$EndNodes\n"); // elements fprintf(gmshfile,"$Elements\n"); fprintf(gmshfile,"%d\n",f->macromesh.nbelems*nraf[0]*nraf[1]*nraf[2]); int elm_type=92; //int num_elm_follow=f->macromesh.nbelems; int num_tags=0; // fwrite((char*) &elm_type,sizeof(int),1,gmshfile); // fwrite((char*) &num_elm_follow,sizeof(int),1,gmshfile); // fwrite((char*) &num_tags,sizeof(int),1,gmshfile); for(int i=0;i<f->macromesh.nbelems;i++){ // loop on the macro elem subcells int icL[3]; // loop on the subcells for(icL[0]=0;icL[0]<nraf[0];icL[0]++){ for(icL[1]=0;icL[1]<nraf[1];icL[1]++){ for(icL[2]=0;icL[2]<nraf[2];icL[2]++){ // get the subcell id int ncL=icL[0]+nraf[0]*(icL[1]+nraf[1]*icL[2]); // first glop index in the subcell //int offsetL=(deg[0]+1)*(deg[1]+1)*(deg[2]+1)*ncL; // global subcell id int numelem=ncL+i*nraf[0]*nraf[1]*nraf[2]+1; //fwrite((char*) &numelem,sizeof(int),1,gmshfile); fprintf(gmshfile,"%d ",numelem); fprintf(gmshfile,"%d ",elm_type); fprintf(gmshfile,"%d ",num_tags); for(int ii=0;ii<64;ii++){ int numnoe=64*(i*nraf[0]*nraf[1]*nraf[2]+ncL) + ii +1; //fwrite((char*) &numnoe,sizeof(int),1,gmshfile); fprintf(gmshfile,"%d ",numnoe); } fprintf(gmshfile,"\n"); } } } } fprintf(gmshfile,"$EndElements\n"); // now display data fprintf(gmshfile,"$NodeData\n"); fprintf(gmshfile,"1\n"); fprintf(gmshfile,"\"Field %d\"\n",typplot); double t = 0; fprintf(gmshfile,"1\n%f\n3\n0\n1\n",t); fprintf(gmshfile,"%d\n",nb_plotnodes); for(int ino=0;ino<nb_plotnodes;ino++){ //fwrite(const void *ptr, size_t size_of_elements, // size_t number_of_elements, FILE *a_file); //fwrite((char*) &nodenumber, sizeof(int),1,gmshfile); //fwrite((char*) &value, sizeof(double),1,gmshfile); //fprintf(gmshfile,"%d %f\n",nodenumber,value); fprintf(gmshfile,"%d %f\n",ino+1,value[ino]); } /* for(int i=0;i<f->macromesh.nbelems;i++){ */ /* for(int ino=0;ino<20;ino++){ */ /* int numnoe=elem2nodes[nnodes*i+ino]; */ /* for(int ii=0;ii<3;ii++){ */ /* physnode[ino][ii]=node[3*numnoe+ii]; */ /* } */ /* } */ /* // data at the eight nodes */ /* for(int ii=0;ii<64;ii++){ */ /* int nodenumber=64*i + ii +1; */ /* Xr[0]=(double) (hexa64ref[3*ii+0]) / 3; */ /* Xr[1]=(double) (hexa64ref[3*ii+1]) / 3; */ /* Xr[2]=(double) (hexa64ref[3*ii+2]) / 3; */ /* Ref2Phy(physnode, */ /* Xr, */ /* NULL, */ /* -1, */ /* Xphy, */ /* NULL, */ /* NULL, */ /* NULL, */ /* NULL); */ /* double value=0; */ /* for(int ib=0;ib<npgv;ib++){ */ /* double psi; */ /* psi_ref(f->interp_param+1, ib, Xr, &psi, NULL); */ /* int vi = f->varindex(f->interp_param, i, ib, typplot); */ /* value += psi * f->wn[vi]; */ /* } */ /* // compare with an */ /* // exact solution */ /* if (compare){ */ /* double wex[f->model.m]; */ /* f->model.ImposedData(Xphy,f->tnow,wex); */ /* value -= wex[typplot]; */ /* } */ /* //fwrite(const void *ptr, size_t size_of_elements, */ /* // size_t number_of_elements, FILE *a_file); */ /* //fwrite((char*) &nodenumber, sizeof(int),1,gmshfile); */ /* //fwrite((char*) &value, sizeof(double),1,gmshfile); */ /* //fprintf(gmshfile,"%d %f\n",nodenumber,value); */ /* fprintf(gmshfile,"%d %f\n",nodenumber,value); */ /* } */ /* } */ fprintf(gmshfile,"\n$EndNodeData\n"); fclose(gmshfile); free(value); }
// apply the Discontinuous Galerkin approximation for computing // the time derivative of the field void dtFieldSlow(Field* f){ // interpolation params // warning: this is ugly, but the last // parameter is used for computing the volume // GLOP index from the face GLOP index... // ugly too: the first parameter is not used by all // utilities. we have sometimes to jump over : pass param+1 // instead of param... //int param[8]={f->model.m,_DEGX,_DEGY,_DEGZ,_RAFX,_RAFY,_RAFZ,0}; // init to zero the time derivative int sizew=0; //#pragma omp parallel for for(int ie=0;ie<f->macromesh.nbelems;ie++){ for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); f->dtwn[imem]=0; sizew++; } } } assert(sizew==f->macromesh.nbelems * f->model.m * NPG(f->interp_param+1)); // assembly of the surface terms // loop on the elements //#pragma omp parallel for for (int ie=0;ie<f->macromesh.nbelems;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // loop on the 6 faces // or four faces for 2d computations int nbfa=6; if (f->is2d) nbfa=4; for(int ifa=0;ifa<nbfa;ifa++){ // get the right elem or the boundary id int ieR=f->macromesh.elem2elem[6*ie+ifa]; double physnodeR[20][3]; if (ieR >= 0) { for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ieR+inoloc]; physnodeR[inoloc][0]=f->macromesh.node[3*ino+0]; physnodeR[inoloc][1]=f->macromesh.node[3*ino+1]; physnodeR[inoloc][2]=f->macromesh.node[3*ino+2]; } } // loop on the glops (numerical integration) // of the face ifa for(int ipgf=0;ipgf<NPGF(f->interp_param+1,ifa);ipgf++){ double xpgref[3],xpgref_in[3],wpg; //double xpgref2[3],wpg2; // get the coordinates of the Gauss point // and coordinates of a point slightly inside the // opposite element in xref_in ref_pg_face(f->interp_param+1,ifa,ipgf,xpgref,&wpg,xpgref_in); // recover the volume gauss point from // the face index int ipg=f->interp_param[7]; // get the left value of w at the gauss point double wL[f->model.m],wR[f->model.m]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); wL[iv]=f->wn[imem]; } // the basis functions is also the gauss point index int ib=ipg; // normal vector at gauss point ipg double dtau[3][3],codtau[3][3],xpg[3]; double vnds[3]; Ref2Phy(physnode, xpgref, NULL,ifa, // dpsiref,ifa xpg,dtau, codtau,NULL,vnds); // codtau,dpsi,vnds double flux[f->model.m]; if (ieR >=0) { // the right element exists // find the corresponding point in the right elem double xpg_in[3]; Ref2Phy(physnode, xpgref_in, NULL,ifa, // dpsiref,ifa xpg_in,dtau, codtau,NULL,vnds); // codtau,dpsi,vnds double xref[3]; Phy2Ref(physnodeR,xpg_in,xref); int ipgR=ref_ipg(f->interp_param+1,xref); double xpgR[3],xrefR[3],wpgR; ref_pg_vol(f->interp_param+1, ipgR, xrefR, &wpgR,NULL); Ref2Phy(physnodeR, xrefR, NULL,-1, // dphiref,ifa xpgR,NULL, NULL,NULL,NULL); // codtau,dphi,vnds assert(Dist(xpgR,xpg)<1e-10); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ieR,ipgR,iv); wR[iv]=f->wn[imem]; } // int_dL F(wL,wR,grad phi_ib ) f->model.NumFlux(wL,wR,vnds,flux); } else { //the right element does not exist f->model.BoundaryFlux(xpg,f->tnow,wL,vnds,flux); } for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ib,iv); f->dtwn[imem]-=flux[iv]*wpg; } } } } // assembly of the volume terms // loop on the elements //#pragma omp parallel for for (int ie=0;ie<f->macromesh.nbelems;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // mass matrix double masspg[NPG(f->interp_param+1)]; // loop on the glops (for numerical integration) for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ double xpgref[3],wpg; // get the coordinates of the Gauss point ref_pg_vol(f->interp_param+1,ipg,xpgref,&wpg,NULL); // get the value of w at the gauss point double w[f->model.m]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); w[iv]=f->wn[imem]; } // loop on the basis functions for(int ib=0;ib<NPG(f->interp_param+1);ib++){ // gradient of psi_ib at gauss point ipg double dpsiref[3],dpsi[3]; double dtau[3][3],codtau[3][3];//,xpg[3]; grad_psi_pg(f->interp_param+1,ib,ipg,dpsiref); Ref2Phy(physnode, // phys. nodes xpgref, // xref dpsiref,-1, // dpsiref,ifa NULL,dtau, // xphy,dtau codtau,dpsi,NULL); // codtau,dpsi,vnds // remember the diagonal mass term if (ib == ipg){ double det = dtau[0][0] * codtau[0][0] + dtau[0][1] * codtau[0][1] + dtau[0][2] * codtau[0][2]; masspg[ipg]=wpg*det; } // int_L F(w,w,grad phi_ib ) double flux[f->model.m]; f->model.NumFlux(w,w,dpsi,flux); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ib,iv); f->dtwn[imem]+=flux[iv]*wpg; } } } for(int ipg=0;ipg<NPG(f->interp_param+1);ipg++){ // apply the inverse of the diagonal mass matrix for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(f->interp_param,ie,ipg,iv); (f->dtwn[imem])/=masspg[ipg]; } } } };
int TestfieldSubCellDGVol() { int test = true; field f; init_empty_field(&f); f.model.cfl = 0.05; f.model.m = 1; // only one conservative variable f.model.NumFlux = TransNumFlux; f.model.BoundaryFlux = TestTransBoundaryFlux; f.model.InitData = TestTransInitData; f.model.ImposedData = TestTransImposedData; f.varindex = GenericVarindex; f.interp.interp_param[0] = 1; // _M f.interp.interp_param[1] = 2; // x direction degree f.interp.interp_param[2] = 2; // y direction degree f.interp.interp_param[3] = 2; // z direction degree f.interp.interp_param[4] = 2; // x direction refinement f.interp.interp_param[5] = 2; // y direction refinement f.interp.interp_param[6] = 1; // z direction refinement ReadMacroMesh(&f.macromesh, "../test/testcube.msh"); //ReadMacroMesh(&f.macromesh,"test/testdisque.msh"); BuildConnectivity(&f.macromesh); PrintMacroMesh(&f.macromesh); //AffineMapMacroMesh(&f.macromesh); PrintMacroMesh(&f.macromesh); Initfield(&f); CheckMacroMesh(&f.macromesh, f.interp.interp_param + 1); real tnow = 0.0; for(int ie = 0;ie < f.macromesh.nbelems; ie++) DGMacroCellInterfaceSlow((void*) (f.mcell+ie), &f, f.wn, f.dtwn); for(int ie = 0; ie < f.macromesh.nbelems; ie++) { DGSubCellInterface((void*) (f.mcell+ie), &f, f.wn, f.dtwn); DGVolume((void*) (f.mcell+ie), &f, f.wn, f.dtwn); DGMass((void*) (f.mcell+ie), &f, f.dtwn); DGSource((void*) (f.mcell+ie), &f, tnow, f.wn, f.dtwn); } /* DGMacroCellInterfaceSlow(&f); */ /* DGSubCellInterface(&f); */ /* DGVolume(&f); */ /* DGMass(&f); */ Displayfield(&f); /* Plotfield(0, false, &f, NULL, "visu.msh"); */ /* Plotfield(0, true, &f, "error", "error.msh"); */ // test the time derivative with the exact solution int *raf = f.interp.interp_param + 4; int *deg = f.interp.interp_param + 1; for(int i=0; i < f.model.m * f.macromesh.nbelems * NPG(raf, deg); i++) { test = test && fabs(4 * f.wn[i] - pow(f.dtwn[i] , 2)) < 1e-2; assert(test); } return test; }
int TestPoisson(void) { bool test = true; field f; init_empty_field(&f); int vec=1; // num of conservative variables f(vi) for each vi, phi, E, rho, u, // p, e (ou T) f.model.m=_MV+6; f.vmax = _VMAX; // maximal wave speed f.model.NumFlux = VlasovP_Lagrangian_NumFlux; f.model.Source = VlasovP_Lagrangian_Source; //f.model.Source = NULL; f.model.BoundaryFlux = TestPoisson_BoundaryFlux; f.model.InitData = TestPoisson_InitData; f.model.ImposedData = TestPoisson_ImposedData; f.varindex = GenericVarindex; f.pre_dtfield = NULL; f.update_after_rk = NULL; f.interp.interp_param[0] = f.model.m; // _M f.interp.interp_param[1] = 3; // x direction degree f.interp.interp_param[2] = 0; // y direction degree f.interp.interp_param[3] = 0; // z direction degree f.interp.interp_param[4] = 32; // x direction refinement f.interp.interp_param[5] = 1; // y direction refinement f.interp.interp_param[6] = 1; // z direction refinement // read the gmsh file ReadMacroMesh(&(f.macromesh),"../test/testcube.msh"); // try to detect a 2d mesh //bool is1d=Detect1DMacroMesh(&(f.macromesh)); Detect1DMacroMesh(&(f.macromesh)); bool is1d=f.macromesh.is1d; assert(is1d); // mesh preparation BuildConnectivity(&(f.macromesh)); PrintMacroMesh(&(f.macromesh)); //assert(1==2); //AffineMapMacroMesh(&(f.macromesh)); // prepare the initial fields Initfield(&f); f.nb_diags=0; // prudence... CheckMacroMesh(&(f.macromesh),f.interp.interp_param+1); printf("cfl param =%f\n",f.hmin); // time derivative //dtField(&f); //DisplayField(&f); //assert(1==2); // apply the DG scheme // time integration by RK2 scheme // up to final time = 1. /*Compute_electric_field(&f); // check the gradient on every glop for(int ie=0;ie<f.macromesh.nbelems;ie++){ printf("elem %d\n",ie); for(int ipg=0;ipg<NPG(f.interp_param+1);ipg++){ real xref[3],wpg; ref_pg_vol(f.interp_param+1,ipg,xref,&wpg,NULL); printf("Gauss point %d %f %f %f \n",ipg,xref[0],xref[1],xref[2]); int imem=f.varindex(f.interp_param,ie,ipg,_MV+1); printf("gradphi exact=%f gradphinum=%f\n",1-2*xref[0],f.wn[imem]); test=test && (fabs(f.wn[imem]-(1-2*xref[0]))<1e-10); } }*/ //Computation_charge_density(f); SolvePoisson1D(&f,f.wn,1,0.0,0.0,LU,NONE); // check the gradient given by the poisson solver for(int ie=0;ie<f.macromesh.nbelems;ie++){ MacroCell *mcell = f.mcell + ie; for(int ipg=0;ipg<NPG(mcell->raf, mcell->deg);ipg++){ real xref[3],wpg; int *raf = f.interp_param+4; int *deg = f.interp_param+1; ref_pg_vol(raf, deg, ipg, xref, &wpg, NULL); //printf("Gauss point %d %f %f %f \n",ipg,xref[0],xref[1],xref[2]); int imem=f.varindex(f.interp_param, ipg, _MV + 1) + mcell->woffset; // printf("gradphi exact=%f gradphinum=%f rap=%f\n", //1-2*xref[0],f.wn[imem],(1-2*xref[0])/f.wn[imem]); real tolerance; if(sizeof(real) == sizeof(double)) tolerance = 1e-8; else tolerance = 1e-4; test=test && (fabs(f.wn[imem]-(-1+2*xref[0])) < tolerance); } } return test; }
// compute the Discontinuous Galerkin inter-macrocells boundary terms void* DGMacroCellInterface(void* mc){ MacroCell* mcell = (MacroCell*) mc; Field* f= mcell->field; int iparam[8]; for(int ip=0;ip<8;ip++) iparam[ip]=f->interp_param[ip]; // init to zero the time derivative for (int ie=mcell->first_cell;ie<mcell->last_cell_p1;ie++){ for(int ipg=0;ipg<NPG(iparam+1);ipg++){ for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(iparam,ie,ipg,iv); f->dtwn[imem]=0; } } } //assert(sizew==f->macromesh.nbelems * f->model.m * NPG(iparam+1)); // assembly of the surface terms // loop on the elements for (int ie=mcell->first_cell;ie<mcell->last_cell_p1;ie++){ // get the physical nodes of element ie double physnode[20][3]; for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ie+inoloc]; physnode[inoloc][0]=f->macromesh.node[3*ino+0]; physnode[inoloc][1]=f->macromesh.node[3*ino+1]; physnode[inoloc][2]=f->macromesh.node[3*ino+2]; } // loop on the 6 faces // or four faces for 2d computations int nbfa=6; if (f->is2d) nbfa=4; for(int ifa=0;ifa<nbfa;ifa++){ // get the right elem or the boundary id int ieR=f->macromesh.elem2elem[6*ie+ifa]; double physnodeR[20][3]; if (ieR >= 0) { for(int inoloc=0;inoloc<20;inoloc++){ int ino=f->macromesh.elem2node[20*ieR+inoloc]; physnodeR[inoloc][0]=f->macromesh.node[3*ino+0]; physnodeR[inoloc][1]=f->macromesh.node[3*ino+1]; physnodeR[inoloc][2]=f->macromesh.node[3*ino+2]; } } // loop on the glops (numerical integration) // of the face ifa for(int ipgf=0;ipgf<NPGF(f->interp_param+1,ifa);ipgf++){ // for(int ipgf=0;ipgf<NPGF(iparam+1,ifa);ipgf++){ // FIXME? double xpgref[3],xpgref_in[3],wpg; //double xpgref2[3],wpg2; // get the coordinates of the Gauss point // and coordinates of a point slightly inside the // opposite element in xref_in ref_pg_face(iparam+1,ifa,ipgf,xpgref,&wpg,xpgref_in); // recover the volume gauss point from // the face index int ipg=iparam[7]; // get the left value of w at the gauss point double wL[f->model.m],wR[f->model.m]; for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(iparam,ie,ipg,iv); wL[iv]=f->wn[imem]; } // the basis functions is also the gauss point index int ib=ipg; // normal vector at gauss point ipg double dtau[3][3],codtau[3][3],xpg[3]; double vnds[3]; Ref2Phy(physnode, xpgref, NULL,ifa, // dpsiref,ifa xpg,dtau, codtau,NULL,vnds); // codtau,dpsi,vnds double flux[f->model.m]; if (ieR >=0) { // the right element exists // find the corresponding point in the right elem double xpg_in[3]; Ref2Phy(physnode, xpgref_in, NULL,ifa, // dpsiref,ifa xpg_in,dtau, codtau,NULL,vnds); // codtau,dpsi,vnds double xref[3]; Phy2Ref(physnodeR,xpg_in,xref); int ipgR=ref_ipg(iparam+1,xref); double xpgR[3],xrefR[3],wpgR; ref_pg_vol(iparam+1, ipgR, xrefR, &wpgR,NULL); Ref2Phy(physnodeR, xrefR, NULL,-1, // dphiref,ifa xpgR,NULL, NULL,NULL,NULL); // codtau,dphi,vnds assert(Dist(xpgR,xpg)<1e-10); for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(iparam,ieR,ipgR,iv); wR[iv]=f->wn[imem]; } // int_dL F(wL,wR,grad phi_ib ) f->model.NumFlux(wL,wR,vnds,flux); } else { //the right element does not exist f->model.BoundaryFlux(xpg,f->tnow,wL,vnds,flux); } for(int iv=0;iv<f->model.m;iv++){ int imem=f->varindex(iparam,ie,ib,iv); f->dtwn[imem]-=flux[iv]*wpg; } } } } return NULL; }