void SerialBlockCommunicator2D::copyOverlap ( Overlap2D const& overlap, MultiBlock2D const& fromMultiBlock, MultiBlock2D& toMultiBlock, modif::ModifT whichData ) const { MultiBlockManagement2D const& fromManagement = fromMultiBlock.getMultiBlockManagement(); MultiBlockManagement2D const& toManagement = toMultiBlock.getMultiBlockManagement(); plint fromEnvelopeWidth = fromManagement.getEnvelopeWidth(); plint toEnvelopeWidth = toManagement.getEnvelopeWidth(); SparseBlockStructure2D const& fromSparseBlock = fromManagement.getSparseBlockStructure(); SparseBlockStructure2D const& toSparseBlock = toManagement.getSparseBlockStructure(); plint originalId = overlap.getOriginalId(); plint overlapId = overlap.getOverlapId(); SmartBulk2D originalBulk(fromSparseBlock, fromEnvelopeWidth, originalId); SmartBulk2D overlapBulk(toSparseBlock, toEnvelopeWidth, overlapId); Box2D originalCoords(originalBulk.toLocal(overlap.getOriginalCoordinates())); Box2D overlapCoords(overlapBulk.toLocal(overlap.getOverlapCoordinates())); PLB_PRECONDITION(originalCoords.x1-originalCoords.x0 == overlapCoords.x1-overlapCoords.x0); PLB_PRECONDITION(originalCoords.y1-originalCoords.y0 == overlapCoords.y1-overlapCoords.y0); AtomicBlock2D const* originalBlock = &fromMultiBlock.getComponent(originalId); AtomicBlock2D* overlapBlock = &toMultiBlock.getComponent(overlapId); plint deltaX = originalCoords.x0 - overlapCoords.x0; plint deltaY = originalCoords.y0 - overlapCoords.y0; overlapBlock -> getDataTransfer().attribute(overlapCoords, deltaX, deltaY, *originalBlock, whichData); }
void Parallelizer3D::parallelizeLevel(plint whichLevel, std::vector<std::vector<Box3D> > const& originalBlocks, std::vector<Box3D> const& parallelRegions, std::vector<plint> const& regionIDs ) { PLB_PRECONDITION( parallelRegions.size() == regionIDs.size() ); PLB_PRECONDITION( whichLevel < (plint)originalBlocks.size() ); std::vector<Box3D> newBlocks; // IDs are going to be reattributed at the level whichLevel. if (finalMpiDistribution.size() <= (pluint)whichLevel) { finalMpiDistribution.resize(whichLevel+1); } for (pluint iRegion=0; iRegion<parallelRegions.size(); ++iRegion) { plint currentId = regionIDs[iRegion]; for (pluint iBlock=0; iBlock<originalBlocks[whichLevel].size(); ++iBlock) { Box3D intersection; if ( intersect( originalBlocks[whichLevel][iBlock], parallelRegions[iRegion], intersection ) ) { newBlocks.push_back(intersection); finalMpiDistribution[whichLevel].push_back(currentId); } } } recomputedBlocks[whichLevel].insert( recomputedBlocks[whichLevel].end(),newBlocks.begin(),newBlocks.end() ); }
const char* AtomicBlockSerializer3D::getNextDataBuffer(pluint& bufferSize) const { PLB_PRECONDITION( !isEmpty() ); if (ordering==IndexOrdering::forward || ordering==IndexOrdering::memorySaving) { bufferSize = domain.getNz() * block.getDataTransfer().staticCellSize(); buffer.resize(bufferSize); block.getDataTransfer().send(Box3D(iX,iX,iY,iY, domain.z0, domain.z1), buffer, modif::staticVariables); ++iY; if (iY > domain.y1) { iY = domain.y0; ++iX; } } else { bufferSize = domain.getNx() * block.getDataTransfer().staticCellSize(); buffer.resize(bufferSize); block.getDataTransfer().send(Box3D(domain.x0, domain.x1, iY,iY,iZ,iZ), buffer, modif::staticVariables); ++iY; if (iY > domain.y1) { iY = domain.y0; ++iZ; } } return &buffer[0]; }
void PeriodicitySwitch3D::toggle(plint direction, bool periodic) { PLB_PRECONDITION( direction==0 || direction==1 || direction==2 ); periodicity[direction] = periodic; // Make sure periodic envelope is filled with data, else all // subsequent operations are wrong. block.signalPeriodicity(); block.duplicateOverlaps(modif::dataStructure); }
void AllFlagsTrueFunctional3D::processGenericBlocks ( Box3D domain, std::vector<AtomicBlock3D*> blocks ) { PLB_PRECONDITION( blocks.size()==1 ); if (!blocks[0]->getFlag()) { this->getStatistics().gatherIntSum(numFalseId, 1); } }
void XMLreader::mainProcessorIni( std::vector<TiXmlNode*> pParentVect ) { std::map<plint, TiXmlNode*> parents; for (pluint iParent=0; iParent<pParentVect.size(); ++iParent) { PLB_PRECONDITION( pParentVect[iParent]->Type()==TiXmlNode::DOCUMENT || pParentVect[iParent]->Type()==TiXmlNode::ELEMENT ); TiXmlElement* pParentElement = pParentVect[iParent]->ToElement(); plint id=0; if (pParentElement) { const char* attribute = pParentElement->Attribute("id"); if (attribute) { std::stringstream attributestr(attribute); attributestr >> id; } } parents[id] = pParentVect[iParent]; } plint numId = (plint)parents.size(); global::mpi().bCast(&numId, 1); std::map<plint, TiXmlNode*>::iterator it = parents.begin(); name = it->second->ValueStr(); global::mpi().bCast(name); for (; it != parents.end(); ++it) { plint id = it->first; global::mpi().bCast(&id, 1); TiXmlNode* pParent = it->second; Data& data = data_map[id]; data.text=""; typedef std::map<std::string, std::vector<TiXmlNode*> > ChildMap; ChildMap childMap; TiXmlNode* pChild; for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) { int type = pChild->Type(); if ( type==TiXmlNode::ELEMENT ) { std::string name(pChild->Value()); childMap[name].push_back(pChild); } else if ( type==TiXmlNode::TEXT ) { data.text = pChild->ToText()->ValueStr(); } } global::mpi().bCast(data.text); plint numChildren = (plint) childMap.size(); global::mpi().bCast(&numChildren, 1); for (ChildMap::iterator it = childMap.begin(); it != childMap.end(); ++it) { std::vector<TiXmlNode*> pChildVect = it->second; data.children.push_back( new XMLreader( pChildVect ) ); } } }
char* AtomicBlockUnSerializer3D::getNextDataBuffer(pluint& bufferSize) { PLB_PRECONDITION( !isFull() ); if (ordering==IndexOrdering::forward || ordering==IndexOrdering::memorySaving) { bufferSize = domain.getNz() * block.getDataTransfer().staticCellSize(); } else { bufferSize = domain.getNx() * block.getDataTransfer().staticCellSize(); } buffer.resize(bufferSize); return &buffer[0]; }
void AtomicBlockUnSerializer2D::commitData() { PLB_PRECONDITION( !isFull() ); if (ordering==IndexOrdering::forward || ordering==IndexOrdering::memorySaving) { block.getDataTransfer().receive(Box2D(iX,iX, domain.y0, domain.y1), buffer, modif::staticVariables); ++iX; } else { block.getDataTransfer().receive(Box2D(domain.x0, domain.x1, iY,iY), buffer, modif::staticVariables); ++iY; } }
void ParallellizeBySquares2D::parallelize(){ // we must have the same number of blocks as processors PLB_PRECONDITION(xTiles*yTiles == processorNumber); plint totalCost = computeCost(originalBlocks, finestBoundingBox); plint idealCostPerProcessor = totalCost/processorNumber; pcout << "Total cost of computations = " << totalCost << std::endl; pcout << "We are using " << processorNumber << " processors...\n"; pcout << "Ideal cost per processor = " << idealCostPerProcessor << std::endl; std::vector<plint> totalCosts(processorNumber); plint total = 0; for (plint iProc=0; iProc<processorNumber; ++iProc){ plint blockCost = computeCost(originalBlocks,finestDivision[iProc]); totalCosts[iProc] += blockCost; mpiDistribution[iProc] = iProc; total += blockCost; } pcout << "---- Costs Per Processor ----\n"; for (pluint i=0; i<totalCosts.size(); ++i){ pcout << i << " : " << totalCosts[i] << std::endl; // check if everyone is doing something if (totalCosts[i] == 0){ pcout << "\t >> processor " << i << " does not have work to do. Exiting.....\n"; std::exit(1); } } pcout << "*******************************\n"; pcout << "Sum of all costs = " << total << std::endl; pcout << "*******************************\n"; // convert the original blocks to the new blocks recomputedBlocks.resize(originalBlocks.size()); finalMpiDistribution.resize(originalBlocks.size()); plint finestLevel= (plint)originalBlocks.size()-1; for (plint iLevel=finestLevel; iLevel>=0; --iLevel) { parallelizeLevel(iLevel, originalBlocks,finestDivision, mpiDistribution); // Adapt the regions to the next-coarser level. for (pluint iRegion=0; iRegion<finestDivision.size(); ++iRegion) { finestDivision[iRegion] = finestDivision[iRegion].divideAndFitSmaller(2); } } }
void ParallelBlockCommunicator2D::communicate ( std::vector<Overlap2D> const& overlaps, MultiBlock2D const& originMultiBlock, MultiBlock2D& destinationMultiBlock, modif::ModifT whichData ) const { PLB_PRECONDITION( originMultiBlock.sizeOfCell() == destinationMultiBlock.sizeOfCell() ); CommunicationStructure2D communication ( overlaps, originMultiBlock.getMultiBlockManagement(), destinationMultiBlock.getMultiBlockManagement(), originMultiBlock.sizeOfCell() ); global::profiler().start("mpiCommunication"); communicate(communication, originMultiBlock, destinationMultiBlock, whichData); global::profiler().stop("mpiCommunication"); }
void MultiBlock3D::addModifiedBlocks ( plint level, std::vector<MultiBlock3D*> modifiedBlocks, std::vector<modif::ModifT> typeOfModification, std::vector<std::vector<BlockAndModif> >& multiBlockCollection, bool includesEnvelope ) { PLB_PRECONDITION( modifiedBlocks.size() == typeOfModification.size() ); // Resize vector which collects modified blocks (resize needs to be // done even when no block is added, to avoid memory violations // during read access to the vector). if ((pluint)level >= multiBlockCollection.size()) { multiBlockCollection.resize(level+1); } // Unless envelope is already included in the domain of application of the data // processor, subscribe modified blocks for an update of the envelope. if (!includesEnvelope) { for (pluint iNewBlock=0; iNewBlock<modifiedBlocks.size(); ++iNewBlock) { bool alreadyAdded=false; // Check if the block is already in the collection. // Note: It may seem stupid to use a linear-complexity algorithm to // find existing blocks. However, it would be a mistake to store the data // processors in a sorted structure. Indeed, sorting pointers leads to // an unpredictable order (because the pointers have an unpredictable value). // This is a problem in parallel programs, because different threads may find a // different order, and the communication pattern between processes gets messed up. for (pluint iOriginal=0; iOriginal<multiBlockCollection[level].size(); ++iOriginal) { MultiBlock3D* existingBlock = multiBlockCollection[level][iOriginal].first; if (existingBlock == modifiedBlocks[iNewBlock]) { // If the block already exists, simply update the type of modification // that applies to it. modif::ModifT& existingModif = multiBlockCollection[level][iOriginal].second; existingModif = combine( existingModif, typeOfModification[iNewBlock] ); alreadyAdded = true; } } // If the block is not already in the structure, add it. if (!alreadyAdded) { multiBlockCollection[level].push_back ( BlockAndModif( modifiedBlocks[iNewBlock], typeOfModification[iNewBlock] ) ); } } } }
MultiProcessing3D<OriginalGenerator,MutableGenerator>::MultiProcessing3D ( OriginalGenerator& generator_, std::vector<MultiBlock3D*> multiBlocks_ ) : generator(generator_), multiBlocks(multiBlocks_) { PLB_PRECONDITION( multiBlocks.size()>=1 ); firstMultiBlock = multiBlocks[0]; // Subdivide the original generator into smaller generators which act // on the intersection of all implied blocks. At this stage, all coordinates // are global, thus relative to the multi-block, not to the individual // atomic-blocks. subdivideGenerator(); // Then, convert coordinates from a global representation to a local one, // relative to the atomoic-blocks of the first multi-block. adjustCoordinates(); }
void IterateDynamicsFunctional3D::processGenericBlocks ( Box3D domain, std::vector<AtomicBlock3D*> blocks ) { PLB_PRECONDITION( blocks.size()==1 ); AtomicContainerBlock3D& container = *dynamic_cast<AtomicContainerBlock3D*>(blocks[0]); StoreDynamicsID* storeId = dynamic_cast<StoreDynamicsID*>(container.getData()); std::vector<int> nextIDs(previousMaximum.size()); for (pluint i=0; i<nextIDs.size(); ++i) { nextIDs[i] = -1; } if (!storeId->empty()) { nextIDs = storeId->getCurrent(); util::extendVectorSize(nextIDs, previousMaximum.size()); if (vectorEquals(nextIDs,previousMaximum)) { nextIDs = storeId->iterate(); util::extendVectorSize(nextIDs, previousMaximum.size()); } } for (pluint i=0; i<nextIDs.size(); ++i) { this->getStatistics().gatherMax(maxIds[i], (double)nextIDs[i]); } }
void ParallellizeByCubes3D::parallelize(){ // we must have the same number of blocks as processors PLB_PRECONDITION(xTiles*yTiles*zTiles == processorNumber); plint totalCost = computeCost(originalBlocks, finestBoundingBox); plint idealCostPerProcessor = totalCost/processorNumber; pcout << "Total cost of computations = " << totalCost << std::endl; pcout << "We are using " << processorNumber << " processors...\n"; pcout << "Ideal cost per processor = " << idealCostPerProcessor << std::endl; std::vector<plint> totalCosts(processorNumber); // greedy load balancing part // plint currentProcessor = 0; // bool allAssigned = false; // plint iBlock = 0; // plint maxBlockCost = 0; // while ( (currentProcessor<processorNumber) && !allAssigned) { // plint blockCost = computeCost(originalBlocks, finestDivision[iBlock]); // if (blockCost > maxBlockCost) maxBlockCost = blockCost; // if ( totalCosts[currentProcessor] < idealCostPerProcessor ){ // totalCosts[currentProcessor] += blockCost; // mpiDistribution[iBlock] = currentProcessor; // ++iBlock; // } // else { // currentProcessor++; // } // if (iBlock>=(plint)finestDivision.size()){ // allAssigned = true; // } // } // // if (maxBlockCost > idealCostPerProcessor){ // pcout << "There is a problem : maxBlockCost=" << maxBlockCost << " and ideal cost=" << idealCostPerProcessor // << std::endl; // } plint total = 0; for (plint iProc=0; iProc<processorNumber; ++iProc){ plint blockCost = computeCost(originalBlocks,finestDivision[iProc]); totalCosts[iProc] += blockCost; mpiDistribution[iProc] = iProc; total += blockCost; } pcout << "---- Costs Per Processor ----\n"; for (pluint i=0; i<totalCosts.size(); ++i){ pcout << i << " : " << totalCosts[i] << std::endl; // check if everyone is doing something if (totalCosts[i] == 0){ pcout << "\t >> processor " << i << " does not have work to do. Exiting.....\n"; std::exit(1); } } pcout << "*******************************\n"; pcout << "Sum of all costs = " << total << std::endl; pcout << "*******************************\n"; // convert the original blocks to the new blocks recomputedBlocks.resize(originalBlocks.size()); finalMpiDistribution.resize(originalBlocks.size()); plint finestLevel= (plint)originalBlocks.size()-1; for (plint iLevel=finestLevel; iLevel>=0; --iLevel) { parallelizeLevel(iLevel, originalBlocks,finestDivision, mpiDistribution); // Adapt the regions to the next-coarser level. for (pluint iRegion=0; iRegion<finestDivision.size(); ++iRegion) { finestDivision[iRegion] = finestDivision[iRegion].divideAndFitSmaller(2); } } }
std::vector<Box2D> const& MultiGridManagement2D::getBulks(plint iLevel) const{ PLB_PRECONDITION( iLevel>=0 && iLevel<(plint)bulks.size() ); return bulks[iLevel]; }
void MultiGridManagement2D::coarsen(plint fineLevel, Box2D coarseDomain){ // The coarsest multi-block, at level 0, cannot be further coarsened. PLB_PRECONDITION( fineLevel>=1 && fineLevel<(plint)bulks.size() ); plint coarseLevel = fineLevel-1; // First, trim the domain coarseDomain in case it exceeds the extent of the // multi-block, and determine whether coarseDomain touches one of the boundaries // of the multi-block. This information is needed, because the coarse domain // fully replaces the fine domain on boundaries of the multi-block, and there // is therefore no need to create a coarse-fine coupling. bool touchLeft=false, touchRight=false, touchBottom=false, touchTop=false; trimDomain(coarseLevel, coarseDomain, touchLeft, touchRight, touchBottom, touchTop); // Convert the coarse domain to fine units. Box2D fineDomain(coarseDomain.multiply(2)); // The reduced fine domain is the one which is going to be excluded from // the original fine lattice. Box2D intermediateFineDomain(fineDomain.enlarge(-1)); // The extended coarse domain it the one which is going to be added // to the original coarse lattice. Box2D extendedCoarseDomain(coarseDomain.enlarge(1)); // If the domain in question touches a boundary of the multi-block, // both the reduced fine domain and the extended coarse domain are // identified with the boundary location. if (touchLeft) { intermediateFineDomain.x0 -= 1; extendedCoarseDomain.x0 += 1; } if (touchRight) { intermediateFineDomain.x1 += 1; extendedCoarseDomain.x1 -= 1; } if (touchBottom) { intermediateFineDomain.y0 -= 1; extendedCoarseDomain.y0 += 1; } if (touchTop) { intermediateFineDomain.y1 += 1; extendedCoarseDomain.y1 -= 1; } // Extract reduced fine domain from the original fine multi-block. std::vector<Box2D> exceptedBlocks; for (pluint iBlock=0; iBlock<bulks[fineLevel].size(); ++iBlock) { except(bulks[fineLevel][iBlock], intermediateFineDomain, exceptedBlocks); } exceptedBlocks.swap(bulks[fineLevel]); // Add extended coarse domain to the original coarse multi-block. bulks[coarseLevel].push_back(extendedCoarseDomain); // Define coupling interfaces for all four sides of the refined domain, unless they // touch a boundary of the multi-block. if (!touchLeft) { coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x0, extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) ); fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x0, coarseDomain.y0, coarseDomain.y1 ) ); // it is a left border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,-1)); // it is an right border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,1)); } if (!touchRight) { coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x1, extendedCoarseDomain.x1, extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) ); fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x1, coarseDomain.x1, coarseDomain.y0, coarseDomain.y1 ) ); // it is a right border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,1)); // it is a left border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,-1)); } if (!touchBottom) { coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, extendedCoarseDomain.y0, extendedCoarseDomain.y0 ) ); fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x1, coarseDomain.y0, coarseDomain.y0 ) ); // it is a bottom border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,-1)); //TODO check this!!! // it is a top border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,1)); } if (!touchTop) { coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, extendedCoarseDomain.y1, extendedCoarseDomain.y1 ) ); fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x1, coarseDomain.y1, coarseDomain.y1 ) ); // it is a top border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,1)); // it is an bottom border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,-1)); } }
Box2D MultiGridManagement2D::getBoundingBox(plint level) const { PLB_PRECONDITION(level>=0 && level<(plint)bulks.size()); return boundingBoxes[level]; }
CommunicationStructure2D::CommunicationStructure2D ( std::vector<Overlap2D> const& overlaps, MultiBlockManagement2D const& originManagement, MultiBlockManagement2D const& destinationManagement, plint sizeOfCell ) { plint fromEnvelopeWidth = originManagement.getEnvelopeWidth(); plint toEnvelopeWidth = destinationManagement.getEnvelopeWidth(); SparseBlockStructure2D const& fromSparseBlock = originManagement.getSparseBlockStructure(); SparseBlockStructure2D const& toSparseBlock = destinationManagement.getSparseBlockStructure(); SendRecvPool sendPool, recvPool; for (pluint iOverlap=0; iOverlap<overlaps.size(); ++iOverlap) { Overlap2D const& overlap = overlaps[iOverlap]; CommunicationInfo2D info; info.fromBlockId = overlap.getOriginalId(); info.toBlockId = overlap.getOverlapId(); SmartBulk2D originalBulk(fromSparseBlock, fromEnvelopeWidth, info.fromBlockId); SmartBulk2D overlapBulk(toSparseBlock, toEnvelopeWidth, info.toBlockId); Box2D originalCoordinates(overlap.getOriginalCoordinates()); Box2D overlapCoordinates(overlap.getOverlapCoordinates()); info.fromDomain = originalBulk.toLocal(originalCoordinates); info.toDomain = overlapBulk.toLocal(overlapCoordinates); info.absoluteOffset = Dot2D ( overlapCoordinates.x0 - originalCoordinates.x0, overlapCoordinates.y0 - originalCoordinates.y0 ); plint lx = info.fromDomain.x1-info.fromDomain.x0+1; plint ly = info.fromDomain.y1-info.fromDomain.y0+1; PLB_PRECONDITION(lx == info.toDomain.x1-info.toDomain.x0+1); PLB_PRECONDITION(ly == info.toDomain.y1-info.toDomain.y0+1); plint numberOfCells = lx*ly; ThreadAttribution const& fromAttribution = originManagement.getThreadAttribution(); ThreadAttribution const& toAttribution = destinationManagement.getThreadAttribution(); info.fromProcessId = fromAttribution.getMpiProcess(info.fromBlockId); info.toProcessId = toAttribution.getMpiProcess(info.toBlockId); if ( fromAttribution.isLocal(info.fromBlockId) && toAttribution.isLocal(info.toBlockId)) { sendRecvPackage.push_back(info); } else if (fromAttribution.isLocal(info.fromBlockId)) { sendPackage.push_back(info); sendPool.subscribeMessage(info.toProcessId, numberOfCells*sizeOfCell); } else if (toAttribution.isLocal(info.toBlockId)) { recvPackage.push_back(info); recvPool.subscribeMessage(info.fromProcessId, numberOfCells*sizeOfCell); } } sendComm = SendPoolCommunicator(sendPool); recvComm = RecvPoolCommunicator(recvPool); }
bool PeriodicitySwitch3D::get(plint direction) const { PLB_PRECONDITION( direction==0 || direction==1 || direction==2 ); return periodicity[direction]; }
/// toggle on/off the periodicity in one direction void MultiGridPeriodicitySwitch2D::toggle(int direction, bool periodicity){ PLB_PRECONDITION( direction==0 || direction==1 ); periodicityArray[direction] = periodicity; block->signalPeriodicity(); }
void MultiGridManagement2D::refineMultiGrid(plint coarseLevel, Box2D coarseDomain){ // The finest multi-block, at level bulks.size()-1, cannot be further refined. PLB_PRECONDITION( coarseLevel>=0 && coarseLevel< (plint)bulks.size()-1 ); plint fineLevel = coarseLevel+1; // First, trim the domain coarseDomain in case it exceeds the extent of the // multi-block, and determine whether coarseDomain touches one of the boundaries // of the multi-block. This information is needed, because the coarse domain // fully replaces the fine domain on boundaries of the multi-block, and there // is therefore no need to create a coarse-fine coupling. bool touchLeft=false, touchRight=false, touchBottom=false, touchTop=false; trimDomain(coarseLevel, coarseDomain, touchLeft, touchRight, touchBottom, touchTop); // The reduced coarse domain is the one which is going to be excluded from // the original coarse lattice. Box2D reducedCoarseDomain(coarseDomain.enlarge(-1)); // The extended coarse domain it the one which is going to be added // to the original fine lattice. Box2D extendedCoarseDomain(coarseDomain.enlarge(overlapWidth)); // If the domain in question touches a boundary of the multi-block, // both the reduced and the extended coarse domain are // identified with the boundary location. if (touchLeft) { reducedCoarseDomain.x0 -= 1; extendedCoarseDomain.x0 += overlapWidth; } if (touchRight) { reducedCoarseDomain.x1 += 1; extendedCoarseDomain.x1 -= overlapWidth; } if (touchBottom) { reducedCoarseDomain.y0 -= 1; extendedCoarseDomain.y0 += overlapWidth; } if (touchTop) { reducedCoarseDomain.y1 += 1; extendedCoarseDomain.y1 -= overlapWidth; } // Do not do anything to the coarse domain // Convert the extended coarse domain to fine units, // and add to the original fine multi-block. Box2D extendedFineDomain(extendedCoarseDomain.multiply(2)); bulks[fineLevel].push_back(extendedFineDomain); // Define coupling interfaces for all four sides of the coarsened domain, unless they // touch a boundary of the multi-block. if (!touchLeft) { // it is a right border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,1)); fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x0, extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) ); // it is a left border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,-1)); } if (!touchRight) { // it is a left border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,-1)); fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x1, extendedCoarseDomain.x1, extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) ); // it is a right border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,1)); } if (!touchBottom) { fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, extendedCoarseDomain.y0, extendedCoarseDomain.y0 ) ); // it is an upper border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,1)); // it is a lower border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,-1)); } if (!touchTop) { // it is a lower border in the coarse case coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,-1)); fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, extendedCoarseDomain.y1, extendedCoarseDomain.y1 ) ); // it is an upper border in the fine case fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,1)); } coarseGridInterfaces[coarseLevel].push_back(coarseDomain); }