int fluxRegTest() { #ifdef CH_USE_HDF5 writeLevel(NULL); #endif int retflag = 0; int nref; Vector<Box> fineboxes; Vector<Box> coarboxes; Box domf, domc; //set coarse and fine grid boxes setDefaults(nref, coarboxes, fineboxes, domc, domf); { // first do nonperiodic test Interval interv(0,0); //set up coarse and fine grids DisjointBoxLayout dblFineCell,dblCoarCell; Vector<int> procAssignCoar(coarboxes.size(), 0); Vector<int> procAssignFine(fineboxes.size(), 0); LoadBalance(procAssignCoar, coarboxes); LoadBalance(procAssignFine, fineboxes); dblCoarCell.define(coarboxes, procAssignCoar); dblFineCell.define(fineboxes, procAssignFine); dblCoarCell.close(); dblFineCell.close(); LevelData<FArrayBox> coarData(dblCoarCell, 1); LevelData<FArrayBox> fineData(dblFineCell, 1); DataIterator coarIt = coarData.dataIterator(); DataIterator fineIt = fineData.dataIterator(); LevelFluxRegister fluxReg(dblFineCell, dblCoarCell, domf, nref, 1); //set data and flux registers to zero for (coarIt.reset(); coarIt.ok(); ++coarIt) coarData[coarIt()].setVal(0.); fluxReg.setToZero(); //increment and decrement //flux registers with equal size fluxes Real scale = 1.0; Real fluxVal = 4.77; for (coarIt.reset(); coarIt.ok(); ++coarIt) { const Box& cellBoxCoar = dblCoarCell.get(coarIt()); for (int idir = 0; idir < SpaceDim; idir++) { Box edgeBoxCoar = surroundingNodes(cellBoxCoar, idir); FArrayBox edgeFlux(edgeBoxCoar,1); edgeFlux.setVal(fluxVal); DataIndex dataIndGlo = coarIt(); fluxReg.incrementCoarse(edgeFlux, scale, dataIndGlo, interv, interv, idir); } } for (fineIt.reset(); fineIt.ok(); ++fineIt) { const Box& cellBoxFine = dblFineCell.get(fineIt()); for (int idir = 0; idir < SpaceDim; idir++) { Box edgeBoxFine = surroundingNodes(cellBoxFine, idir); FArrayBox edgeFlux(edgeBoxFine,1); edgeFlux.setVal(fluxVal); SideIterator sit; DataIndex dataIndGlo = fineIt(); for (sit.reset(); sit.ok(); ++sit) { fluxReg.incrementFine(edgeFlux, scale, dataIndGlo, interv, interv, idir, sit()); } } } //reflux what ought to be zero into zero and the result should be zero fluxReg.reflux(coarData, scale); DataIterator datIt = coarData.dataIterator(); for (datIt.reset(); datIt.ok(); ++datIt) { const FArrayBox& data = coarData[datIt()]; Real rmax = Abs(data.max()); Real rmin = Abs(data.min()); if ((rmax > 1.0e-10)||(rmin > 1.0e-10)) { pout() << indent << pgmname << ": fluxRegister failed the nonperiodic conservation test = " << endl; retflag = 1; } } } // end non-periodic test // now do the same thing all over again, this time with a periodic domain { ProblemDomain coarseDomain(domc); ProblemDomain fineDomain(domf); for (int dir=0; dir<SpaceDim; dir++) { coarseDomain.setPeriodic(dir, true); fineDomain.setPeriodic(dir, true); } Interval interv(0,0); //set up coarse and fine grids DisjointBoxLayout dblFineCell,dblCoarCell; Vector<int> procAssignCoar(coarboxes.size(), 0); Vector<int> procAssignFine(fineboxes.size(), 0); LoadBalance(procAssignCoar, coarboxes); LoadBalance(procAssignFine, fineboxes); dblCoarCell.define(coarboxes, procAssignCoar, coarseDomain); dblFineCell.define(fineboxes, procAssignFine, fineDomain); dblCoarCell.close(); dblFineCell.close(); LevelData<FArrayBox> coarData(dblCoarCell, 1); LevelData<FArrayBox> fineData(dblFineCell, 1); DataIterator coarIt = coarData.dataIterator(); DataIterator fineIt = fineData.dataIterator(); LevelFluxRegister fluxReg(dblFineCell, dblCoarCell, fineDomain, nref, 1); //set data and flux registers to zero for (coarIt.reset(); coarIt.ok(); ++coarIt) coarData[coarIt()].setVal(0.); fluxReg.setToZero(); //increment and decrement //flux registers with equal size fluxes Real scale = 1.0; Real fluxVal = 4.77; for (coarIt.reset(); coarIt.ok(); ++coarIt) { const Box& cellBoxCoar = dblCoarCell.get(coarIt()); for (int idir = 0; idir < SpaceDim; idir++) { Box edgeBoxCoar = surroundingNodes(cellBoxCoar, idir); FArrayBox edgeFlux(edgeBoxCoar,1); edgeFlux.setVal(fluxVal); DataIndex dataIndGlo = coarIt(); fluxReg.incrementCoarse(edgeFlux, scale, dataIndGlo, interv, interv, idir); } } for (fineIt.reset(); fineIt.ok(); ++fineIt) { const Box& cellBoxFine = dblFineCell.get(fineIt()); for (int idir = 0; idir < SpaceDim; idir++) { Box edgeBoxFine = surroundingNodes(cellBoxFine, idir); FArrayBox edgeFlux(edgeBoxFine,1); edgeFlux.setVal(fluxVal); SideIterator sit; DataIndex dataIndGlo = fineIt(); for (sit.reset(); sit.ok(); ++sit) { fluxReg.incrementFine(edgeFlux, scale, dataIndGlo, interv, interv, idir, sit()); } } } //reflux what ought to be zero into zero and the result should be zero fluxReg.reflux(coarData, scale); DataIterator datIt = coarData.dataIterator(); for (datIt.reset(); datIt.ok(); ++datIt) { const FArrayBox& data = coarData[datIt()]; Real rmax = Abs(data.max()); Real rmin = Abs(data.min()); if ((rmax > 1.0e-10)||(rmin > 1.0e-10)) { pout() << indent << pgmname << ": fluxRegister failed the periodic conservation test " << endl; retflag += 2; } } } // end periodic test return retflag; }
// this function averages down the fine solution to the valid // regions of the computed solution, then subtracts ir from // the computed solution. (error is exact-computed) void computeAMRError(Vector<LevelData<FArrayBox>* >& a_error, const Vector<string>& a_errorVars, const Vector<LevelData<FArrayBox>* >& a_computedSoln, const Vector<string>& a_computedVars, const Vector<DisjointBoxLayout>& a_computedGrids, const Real a_computedDx, const Vector<int>& a_computedRefRatio, const Vector<LevelData<FArrayBox>* >& a_exactSoln, const Vector<string>& a_exactVars, const Real a_exactDx, Real a_bogus_value, bool a_HOaverage, bool a_computeRelativeError) { int numLevels = a_computedSoln.size(); CH_assert(a_exactSoln.size() == 1); CH_assert(a_error.size() == numLevels); CH_assert(a_exactDx <= a_computedDx); CH_assert(a_computedRefRatio.size() >= numLevels - 1); if (a_exactDx == a_computedDx) { cerr << "Exact dx and computed dx are equal." << endl; } // check whether input file selects "sum all variables" bool sumAll = false; ParmParse pp; pp.query("sumAll",sumAll); // const DisjointBoxLayout& exactGrids = a_exactSoln[0]->getBoxes(); Real dxLevel = a_computedDx; // do a bit of sleight-of-hand in the case where there are no // ghost cells in the exact solution -- allocate a temporary which // _has_ ghost cells, and do a copyTo LevelData<FArrayBox>* exactSolnPtr = NULL; bool allocatedMemory = false; if (a_exactSoln[0]->ghostVect() == IntVect::Zero) { exactSolnPtr = new LevelData<FArrayBox>(a_exactSoln[0]->getBoxes(), a_exactSoln[0]->nComp(), IntVect::Unit); a_exactSoln[0]->copyTo(*exactSolnPtr); allocatedMemory = true; } else { // if there are ghost cells, we can use the exactSoln as-is exactSolnPtr = a_exactSoln[0]; } LevelData<FArrayBox>& exactSolnRef = *exactSolnPtr; // first need to set boundary conditions on exactsoln // this is for the Laplacian which is needed in AverageHO DataIterator ditFine = exactSolnRef.dataIterator(); DomainGhostBC exactBC; Interval exactComps(0, a_exactVars.size() - 1); for (int dir = 0; dir < SpaceDim; dir++) { SideIterator sit; for (sit.reset(); sit.ok(); ++sit) { // use HO extrapolation at physical boundaries HOExtrapBC thisBC(dir, sit(), exactComps); exactBC.setBoxGhostBC(thisBC); } } for (ditFine.begin(); ditFine.ok(); ++ditFine) { FArrayBox& thisFineSoln = exactSolnRef[ditFine()]; const Box& fineBox = exactSolnRef.getBoxes()[ditFine()]; exactBC.applyInhomogeneousBCs(thisFineSoln, fineBox, a_exactDx); } exactSolnRef.exchange(exactComps); // outer loop is over levels for (int level = 0; level < numLevels; level++) { LevelData<FArrayBox>& thisLevelError = *a_error[level]; LevelData<FArrayBox>& thisLevelComputed = *a_computedSoln[level]; // compute refinement ratio between solution at this level // and exact solution Real nRefTemp = (dxLevel / a_exactDx); int nRefExact = (int) nRefTemp; // this is to do rounding properly if necessary if (nRefTemp - nRefExact > 0.5) nRefExact += 1; // make sure it's not zero if (nRefExact == 0) nRefExact =1; const DisjointBoxLayout levelGrids = a_error[level]->getBoxes(); const DisjointBoxLayout fineGrids = a_exactSoln[0]->getBoxes(); DisjointBoxLayout coarsenedFineGrids; // petermc, 14 Jan 2014: Replace this because fineGrids might // not be coarsenable by nRefExact. // coarsen(coarsenedFineGrids, fineGrids, nRefExact); int nCoarsenExact = nRefExact; while ( !fineGrids.coarsenable(nCoarsenExact) && (nCoarsenExact > 0) ) { // Divide nCoarsenExact by 2 until fineGrids is coarsenable by it. nCoarsenExact /= 2; } if (nCoarsenExact == 0) { nCoarsenExact = 1; } coarsen(coarsenedFineGrids, fineGrids, nCoarsenExact); int numExact = a_exactVars.size(); LevelData<FArrayBox> averagedExact(coarsenedFineGrids, numExact); Box fineRefBox(IntVect::Zero, (nCoarsenExact-1)*IntVect::Unit); // average fine solution down to coarsened-fine level // loop over grids and do HO averaging down //DataIterator crseExactDit = coarsenedFineGrids.dataIterator(); for (ditFine.reset(); ditFine.ok(); ++ditFine) { const Box fineBox = exactSolnRef.getBoxes()[ditFine()]; FArrayBox fineTemp(fineBox, 1); Box coarsenedFineBox(fineBox); coarsenedFineBox.coarsen(nCoarsenExact); if (a_exactDx < a_computedDx) { // loop over components for (int comp = 0; comp < numExact; comp++) { Box coarseBox(coarsenedFineGrids.get(ditFine())); coarseBox &= coarsenedFineBox; if (!coarseBox.isEmpty()) { // for now, this is a quick and dirty way to avoid // stepping out of bounds if there are no ghost cells. // LapBox will be the box over which we are // able to compute the Laplacian. Box LapBox = exactSolnRef[ditFine()].box(); LapBox.grow(-1); LapBox &= fineBox; fineTemp.setVal(0.0); int doHO = 0; if (a_HOaverage) { doHO = 1; } // average by default int doAverage = 1; if (sumAll || sumVar(a_exactVars[comp])) { doAverage = 0; } // average or sum, based on booleans FORT_AVERAGEHO(CHF_FRA1(averagedExact[ditFine], comp), CHF_CONST_FRA1(exactSolnRef[ditFine], comp), CHF_FRA1(fineTemp, 0), CHF_BOX(coarseBox), CHF_BOX(LapBox), CHF_CONST_INT(nCoarsenExact), CHF_BOX(fineRefBox), CHF_INT(doHO), CHF_INT(doAverage)); } // end if crseBox not empty } // end loop over comps } else { // if cell sizes are the same, then copy averagedExact[ditFine].copy(exactSolnRef[ditFine]); } } // end loop over exact solution boxes int nRefineComputed = nRefExact / nCoarsenExact; LevelData<FArrayBox>* thisLevelComputedRefinedPtr = &thisLevelComputed; LevelData<FArrayBox>* thisLevelErrorRefinedPtr = &thisLevelError; if (nRefineComputed > 1) { // Do piecewise constant interpolation (replication) by nRefineComputed // on thisLevelComputed. DisjointBoxLayout levelRefinedGrids; refine(levelRefinedGrids, levelGrids, nRefineComputed); int nCompComputed = thisLevelComputed.nComp(); IntVect ghostVectComputed = nRefineComputed * thisLevelComputed.ghostVect(); thisLevelComputedRefinedPtr = new LevelData<FArrayBox>(levelRefinedGrids, nCompComputed, ghostVectComputed); ProblemDomain levelDomain = levelRefinedGrids.physDomain(); FineInterp interpolator(levelRefinedGrids, nCompComputed, nRefineComputed, levelDomain); interpolator.pwcinterpToFine(*thisLevelComputedRefinedPtr, thisLevelComputed); int nCompErr = thisLevelError.nComp(); IntVect ghostVectErr = nRefineComputed * thisLevelError.ghostVect(); thisLevelErrorRefinedPtr = new LevelData<FArrayBox>(levelRefinedGrids, nCompErr, ghostVectErr); } // initialize error to 0 // also initialize error to a bogus value DataIterator levelDit = thisLevelError.dataIterator(); for (levelDit.begin(); levelDit.ok(); ++levelDit) { (*thisLevelErrorRefinedPtr)[levelDit].setVal(a_bogus_value); } Box refComputedBox(IntVect::Zero, (nRefineComputed-1)*IntVect::Unit); // loop over variables for (int nErr = 0; nErr < a_errorVars.size(); nErr++) { string thisErrVar = a_errorVars[nErr]; bool done = false; // first loop over exact variables for (int exactComp = 0; exactComp < a_exactVars.size(); exactComp++) { string thisExactVar = a_exactVars[exactComp]; // check if this exact variable is "the one" if ((thisExactVar == thisErrVar) || nonAverageVar(thisErrVar)) { int computedComp = 0; // now loop over computed variables while (!done && (computedComp < a_computedVars.size())) { if (a_computedVars[computedComp] == thisErrVar) { if (!nonAverageVar(thisErrVar)) { // copy averaged exact solution -> error // and then subtract computed solution Interval exactInterval(exactComp, exactComp); Interval errorInterval(nErr, nErr); averagedExact.copyTo(exactInterval, *thisLevelErrorRefinedPtr, errorInterval); } DataIterator levelDit = thisLevelError.dataIterator(); for (levelDit.reset(); levelDit.ok(); ++levelDit) { FArrayBox& thisComputedRefined = (*thisLevelComputedRefinedPtr)[levelDit]; FArrayBox& thisErrorRefined = (*thisLevelErrorRefinedPtr)[levelDit]; if (a_computeRelativeError) { // do this a little strangely -- relative // error is one - computed/exact. thisErrorRefined.divide(thisComputedRefined, computedComp, nErr, 1); thisErrorRefined.invert(-1.0, nErr, 1); thisErrorRefined.plus(1.0, nErr, 1); } else { thisErrorRefined.minus(thisComputedRefined, computedComp, nErr, 1); } if (nRefineComputed > 1) { FArrayBox& thisError = thisLevelError[levelDit]; Box coarseBox = thisError.box(); // Average thisErrorRefined to thisError. int doHO = 0; if (a_HOaverage) { doHO = 1; } CH_assert(doHO == 0); // for now, this is a quick and dirty way to avoid // stepping out of bounds if there are no ghost cells. // LapBox will be the box over which we are // able to compute the Laplacian. Box LapBox = thisErrorRefined.box(); LapBox.grow(-1); // LapBox &= fineBox; FArrayBox fineTemp(thisErrorRefined.box(), 1); fineTemp.setVal(0.0); // average by default int doAverage = 1; // average or sum, based on booleans FORT_AVERAGEHO(CHF_FRA1(thisError, nErr), CHF_CONST_FRA1(thisErrorRefined, nErr), CHF_FRA1(fineTemp, 0), CHF_BOX(coarseBox), CHF_BOX(LapBox), CHF_CONST_INT(nRefineComputed), CHF_BOX(refComputedBox), CHF_INT(doHO), CHF_INT(doAverage)); } } // end loop over coarse grids done = true; } // if computedVar is a_errorVar computedComp += 1; } // end loop over a_computedVars if (!done) { pout() << "Variable " << thisErrVar << " not found!!!" << endl; MayDay::Error(); } } // end if this exactVar is correct } // end loop over exact variables } // end loop over errors if (nRefineComputed > 1) { delete thisLevelComputedRefinedPtr; delete thisLevelErrorRefinedPtr; } // now need to set covered regions to 0 if (level < numLevels - 1) { // will need to loop over all boxes in finer level, not just // those on this processor... const BoxLayout& finerGrids = a_computedSoln[level + 1]->boxLayout(); LayoutIterator fineLit = finerGrids.layoutIterator(); // outer loop over this level's grids, since there are fewer of them DataIterator levelDit = thisLevelError.dataIterator(); for (levelDit.reset(); levelDit.ok(); ++levelDit) { const Box& coarseBox = levelGrids[levelDit()]; FArrayBox& thisError = thisLevelError[levelDit()]; int numError = thisError.nComp(); for (fineLit.reset(); fineLit.ok(); ++fineLit) { Box fineBox(finerGrids[fineLit()]); // now coarsen box down to this level fineBox.coarsen(a_computedRefRatio[level]); // if coarsened fine box intersects error's box, set // overlap to 0 fineBox &= coarseBox; if (!fineBox.isEmpty()) { thisError.setVal(0.0, fineBox, 0, numError); } } // end loop over finer-level grids } // end loop over this-level grids // this is a good place to update dx as well dxLevel = dxLevel / a_computedRefRatio[level]; } // end if there is a finer level thisLevelError.exchange(); } // end loop over levels // clean up if we need to if (allocatedMemory) { delete exactSolnPtr; exactSolnPtr = NULL; } }