//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCellRangeFilter::setDefaultValues() { CVF_ASSERT(m_parentContainer); RigMainGrid* mainGrid = m_parentContainer->mainGrid(); if (mainGrid) { cvf::Vec3st min, max; mainGrid->matrixModelActiveCellsBoundingBox(min, max); // Adjust to Eclipse indexing min.x() = min.x() + 1; min.y() = min.y() + 1; min.z() = min.z() + 1; max.x() = max.x() + 1; max.y() = max.y() + 1; max.z() = max.z() + 1; startIndexI = static_cast<int>(min.x()); startIndexJ = static_cast<int>(min.y()); startIndexK = static_cast<int>(min.z()); cellCountI = static_cast<int>(max.x() - min.x() + 1); cellCountJ = static_cast<int>(max.y() - min.y() + 1); cellCountK = static_cast<int>(max.z() - min.z() + 1); } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList<caf::PdmOptionItemInfo> RimCellRangeFilter::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) { QList<caf::PdmOptionItemInfo> options; if (useOptionsOnly) (*useOptionsOnly) = true; if (&gridIndex == fieldNeedingOptions) { RigMainGrid * mainGrid = NULL; if (parentContainer() && parentContainer()->reservoirView() && parentContainer()->reservoirView()->eclipseCase() && parentContainer()->reservoirView()->eclipseCase()->reservoirData()) mainGrid = parentContainer()->reservoirView()->eclipseCase()->reservoirData()->mainGrid(); for (size_t gIdx = 0; gIdx < mainGrid->gridCount(); ++gIdx) { RigGridBase* grid = mainGrid->gridByIndex(gIdx); QString gridName; gridName += grid->gridName().c_str(); if (gIdx == 0) { if (gridName.isEmpty()) gridName += "Main Grid"; else gridName += " (Main Grid)"; } caf::PdmOptionItemInfo item(gridName, (int)gIdx); options.push_back(item); } } return options; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const cvf::StructGridInterface* RimCellRangeFilterCollection::gridByIndex(int gridIndex) const { RigMainGrid* mnGrid = mainGrid(); RigFemPartCollection* femPartColl = this->femPartColl(); if (mnGrid) { RigGridBase* grid = NULL; grid = mnGrid->gridByIndex(gridIndex); CVF_ASSERT(grid); return grid; } else if (femPartColl) { if (gridIndex < femPartColl->partCount()) return femPartColl->part(gridIndex)->structGrid(); else return NULL; } return NULL; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigGridBase* RimCellRangeFilter::selectedGrid() { RigMainGrid* mainGrid = m_parentContainer->mainGrid(); CVF_ASSERT(mainGrid); RigGridBase* grid = NULL; if (static_cast<size_t>(gridIndex()) >= mainGrid->gridCount()) { gridIndex = 0; } grid = mainGrid->gridByIndex(gridIndex()); CVF_ASSERT(grid); return grid; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimCellRangeFilterCollection::gridName(int gridIndex) const { RigMainGrid* mnGrid = mainGrid(); RigFemPartCollection* femPartColl = this->femPartColl(); if (mnGrid) { return mnGrid->gridByIndex(gridIndex)->gridName().c_str(); } else if (femPartColl) { return QString::number(gridIndex); } return ""; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimCellRangeFilterCollection::gridCount() const { RigMainGrid* mnGrid = mainGrid(); RigFemPartCollection* femPartColl = this->femPartColl(); if (mnGrid) { return (int)mnGrid->gridCount(); } else if (femPartColl) { return femPartColl->partCount(); } return 0; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCellRangeFilter::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute * attribute) { caf::PdmUiSliderEditorAttribute* myAttr = static_cast<caf::PdmUiSliderEditorAttribute*>(attribute); if (!myAttr || !m_parentContainer) { return; } RigMainGrid* mainGrid = m_parentContainer->mainGrid(); if (mainGrid) { cvf::Vec3st min, max; mainGrid->matrixModelActiveCellsBoundingBox(min, max); // Adjust to Eclipse indexing min.x() = min.x() + 1; min.y() = min.y() + 1; min.z() = min.z() + 1; max.x() = max.x() + 1; max.y() = max.y() + 1; max.z() = max.z() + 1; startIndexI.setUiName(QString("I Start (%1)").arg(min.x())); startIndexJ.setUiName(QString("J Start (%1)").arg(min.y())); startIndexK.setUiName(QString("K Start (%1)").arg(min.z())); cellCountI.setUiName(QString(" Width (%1)").arg(max.x() - min.x() + 1)); cellCountJ.setUiName(QString(" Width (%1)").arg(max.y() - min.y() + 1)); cellCountK.setUiName(QString(" Width (%1)").arg(max.z() - min.z() + 1)); if (field == &startIndexI || field == &cellCountI) { myAttr->m_minimum = 1; myAttr->m_maximum = static_cast<int>(mainGrid->cellCountI()); } else if (field == &startIndexJ || field == &cellCountJ) { myAttr->m_minimum = 1; myAttr->m_maximum = static_cast<int>(mainGrid->cellCountJ()); } else if (field == &startIndexK || field == &cellCountK) { myAttr->m_minimum = 1; myAttr->m_maximum = static_cast<int>(mainGrid->cellCountK()); } } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCellRangeFilter::computeAndSetValidValues() { CVF_ASSERT(m_parentContainer); RigMainGrid* mainGrid = m_parentContainer->mainGrid(); if (mainGrid && mainGrid->cellCount() > 0 ) { cellCountI = cvf::Math::clamp(cellCountI.v(), 1, static_cast<int>(mainGrid->cellCountI())); startIndexI = cvf::Math::clamp(startIndexI.v(), 1, static_cast<int>(mainGrid->cellCountI())); cellCountJ = cvf::Math::clamp(cellCountJ.v(), 1, static_cast<int>(mainGrid->cellCountJ())); startIndexJ = cvf::Math::clamp(startIndexJ.v(), 1, static_cast<int>(mainGrid->cellCountJ())); cellCountK = cvf::Math::clamp(cellCountK.v(), 1, static_cast<int>(mainGrid->cellCountK())); startIndexK = cvf::Math::clamp(startIndexK.v(), 1, static_cast<int>(mainGrid->cellCountK())); } this->updateIconState(); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigNNCData::processConnections(const RigMainGrid& mainGrid) { //cvf::Trace::show("NNC: Total number: " + cvf::String((int)m_connections.size())); for (size_t cnIdx = 0; cnIdx < m_connections.size(); ++cnIdx) { const RigCell& c1 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c1GlobIdx]; const RigCell& c2 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c2GlobIdx]; bool foundAnyOverlap = false; std::vector<size_t> connectionPolygon; std::vector<cvf::Vec3d> connectionIntersections; cvf::StructGridInterface::FaceType connectionFace = cvf::StructGridInterface::NO_FACE; connectionFace = calculateCellFaceOverlap(c1, c2, mainGrid, &connectionPolygon, &connectionIntersections); if (connectionFace != cvf::StructGridInterface::NO_FACE) { foundAnyOverlap = true; // Found an overlap polygon. Store data about connection m_connections[cnIdx].m_c1Face = connectionFace; for (size_t pIdx = 0; pIdx < connectionPolygon.size(); ++pIdx) { if (connectionPolygon[pIdx] < mainGrid.nodes().size()) m_connections[cnIdx].m_polygon.push_back(mainGrid.nodes()[connectionPolygon[pIdx]]); else m_connections[cnIdx].m_polygon.push_back(connectionIntersections[connectionPolygon[pIdx] - mainGrid.nodes().size()]); } // Add to search map, possibly not needed //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][connectionFace].push_back(cnIdx); //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::oppositeFace(connectionFace].push_back(cnIdx); } else { //cvf::Trace::show("NNC: No overlap found for : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + "C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx)); } } }
//-------------------------------------------------------------------------------------------------- /// Create mask for the parts outside the grid cells of the reservoir //-------------------------------------------------------------------------------------------------- cvf::ref<cvf::Part> RivWellFracturePartMgr::createMaskOfFractureOutsideGrid(const RimEclipseView& activeView) { cvf::Mat4d frMx = m_rimFracture->transformMatrix(); std::vector<cvf::Vec3f> maskTriangles; auto displCoordTrans = activeView.displayCoordTransform(); for (const auto& visibleFracturePolygon : m_visibleFracturePolygons) { std::vector<cvf::Vec3d> borderOfFractureCellPolygonLocalCsd; cvf::BoundingBox frBBox; for (const auto& pv : visibleFracturePolygon) { cvf::Vec3d pvd(pv); borderOfFractureCellPolygonLocalCsd.push_back(pvd); pvd.transformPoint(frMx); frBBox.add(pvd); } std::vector<std::vector<cvf::Vec3d>> clippedPolygons; std::vector<size_t> cellCandidates; activeView.mainGrid()->findIntersectingCells(frBBox, &cellCandidates); if (cellCandidates.empty()) { clippedPolygons.push_back(borderOfFractureCellPolygonLocalCsd); } else { // Check if fracture polygon is fully inside the grid bool allPointsInsideGrid = true; for (const auto& v : borderOfFractureCellPolygonLocalCsd) { auto pointInDomainCoords = v.getTransformedPoint(frMx); bool pointInsideGrid = false; RigMainGrid* mainGrid = activeView.mainGrid(); std::array<cvf::Vec3d, 8> corners; for (size_t cellIndex : cellCandidates) { mainGrid->cellCornerVertices(cellIndex, corners.data()); if (RigHexIntersectionTools::isPointInCell(pointInDomainCoords, corners.data())) { pointInsideGrid = true; break; } } if (!pointInsideGrid) { allPointsInsideGrid = false; break; } } if (!allPointsInsideGrid) { std::vector<std::vector<cvf::Vec3d>> allEclCellPolygons; for (size_t resCellIdx : cellCandidates) { // Calculate Eclipse cell intersection with fracture plane std::array<cvf::Vec3d, 8> corners; activeView.mainGrid()->cellCornerVertices(resCellIdx, corners.data()); std::vector<std::vector<cvf::Vec3d>> eclCellPolygons; bool hasIntersection = RigHexIntersectionTools::planeHexIntersectionPolygons(corners, frMx, eclCellPolygons); if (!hasIntersection || eclCellPolygons.empty()) continue; // Transform eclCell - plane intersection onto fracture cvf::Mat4d invertedTransformMatrix = frMx.getInverted(); for (std::vector<cvf::Vec3d>& eclCellPolygon : eclCellPolygons) { for (cvf::Vec3d& v : eclCellPolygon) { v.transformPoint(invertedTransformMatrix); } allEclCellPolygons.push_back(eclCellPolygon); } } { std::vector<std::vector<cvf::Vec3d>> polys = RigCellGeometryTools::subtractPolygons(borderOfFractureCellPolygonLocalCsd, allEclCellPolygons); for (const auto& polygon : polys) { clippedPolygons.push_back(polygon); } } } } for (auto& clippedPolygon : clippedPolygons) { for (auto& point : clippedPolygon) { point.transformPoint(frMx); } } // Create triangles from the clipped polygons cvf::Vec3d fractureNormal = cvf::Vec3d(frMx.col(2)); for (const auto& clippedPolygon : clippedPolygons) { cvf::EarClipTesselator tess; tess.setNormal(fractureNormal); cvf::Vec3dArray cvfNodes(clippedPolygon); tess.setGlobalNodeArray(cvfNodes); std::vector<size_t> polyIndexes; for (size_t idx = 0; idx < clippedPolygon.size(); ++idx) polyIndexes.push_back(idx); tess.setPolygonIndices(polyIndexes); std::vector<size_t> triangleIndices; tess.calculateTriangles(&triangleIndices); for (size_t idx : triangleIndices) { maskTriangles.push_back(cvf::Vec3f(displCoordTrans->transformToDisplayCoord(clippedPolygon[idx]))); } } } if (maskTriangles.size() >= 3) { cvf::ref<cvf::DrawableGeo> maskTriangleGeo = new cvf::DrawableGeo; maskTriangleGeo->setVertexArray(new cvf::Vec3fArray(maskTriangles)); cvf::ref<cvf::PrimitiveSetDirect> primitives = new cvf::PrimitiveSetDirect(cvf::PT_TRIANGLES); primitives->setIndexCount(maskTriangles.size()); maskTriangleGeo->addPrimitiveSet(primitives.p()); maskTriangleGeo->computeNormals(); cvf::ref<cvf::Part> containmentMaskPart = new cvf::Part(0, "FractureContainmentMaskPart"); containmentMaskPart->setDrawable(maskTriangleGeo.p()); containmentMaskPart->setSourceInfo(new RivObjectSourceInfo(m_rimFracture)); cvf::Color4f maskColor = cvf::Color4f(cvf::Color3f(cvf::Color3::GRAY)); caf::SurfaceEffectGenerator surfaceGen(maskColor, caf::PO_NONE); cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect(); containmentMaskPart->setEffect(eff.p()); return containmentMaskPart; } return nullptr; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::StructGridInterface::FaceType RigNNCData::calculateCellFaceOverlap(const RigCell &c1, const RigCell &c2, const RigMainGrid &mainGrid, std::vector<size_t>* connectionPolygon, std::vector<cvf::Vec3d>* connectionIntersections) { // Try to find the shared face bool isPossibleNeighborInDirection[6]={ true, true, true, true, true, true }; if ( c1.hostGrid() == c2.hostGrid() ) { char hasNeighbourInAnyDirection = 0; size_t i1, j1, k1; c1.hostGrid()->ijkFromCellIndex(c1.gridLocalCellIndex(), &i1, &j1, &k1); size_t i2, j2, k2; c2.hostGrid()->ijkFromCellIndex(c2.gridLocalCellIndex(), &i2, &j2, &k2); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] = ((i1 + 1) == i2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] = ((i2 + 1) == i1); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] = ((j1 + 1) == j2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] = ((j2 + 1) == j1); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] = ((k1 + 1) == k2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K] = ((k2 + 1) == k1); hasNeighbourInAnyDirection = isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] + isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] + isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K]; // If cell 2 is not adjancent with respect to any of the six ijk directions, // assume that we have no overlapping area. if ( !hasNeighbourInAnyDirection ) { // Add to search map //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx); //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx); //cvf::Trace::show("NNC: No direct neighbors : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + " C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx)); return cvf::StructGridInterface::NO_FACE; } } #if 0 // Possibly do some testing to avoid unneccesary overlap calculations cvf::Vec3d normal; for ( char fIdx = 0; fIdx < 6; ++fIdx ) { if ( isPossibleNeighborInDirection[fIdx] ) { cvf::Vec3d fc1 = c1.faceCenter((cvf::StructGridInterface::FaceType)(fIdx)); cvf::Vec3d fc2 = c2.faceCenter(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx))); cvf::Vec3d fc1ToFc2 = fc2 - fc1; normal = c1.faceNormalWithAreaLenght((cvf::StructGridInterface::FaceType)(fIdx)); normal.normalize(); // Check that face centers are approx in the face plane if ( normal.dot(fc1ToFc2) < 0.01*fc1ToFc2.length() ) { } } } #endif for ( unsigned char fIdx = 0; fIdx < 6; ++fIdx ) { if ( !isPossibleNeighborInDirection[fIdx] ) { continue; } // Calculate connection polygon std::vector<size_t> polygon; std::vector<cvf::Vec3d> intersections; caf::SizeTArray4 face1; caf::SizeTArray4 face2; c1.faceIndices((cvf::StructGridInterface::FaceType)(fIdx), &face1); c2.faceIndices(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx)), &face2); bool foundOverlap = cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( &polygon, &intersections, (cvf::EdgeIntersectStorage<size_t>*)nullptr, cvf::wrapArrayConst(&mainGrid.nodes()), face1.data(), face2.data(), 1e-6); if ( foundOverlap ) { if (connectionPolygon)(*connectionPolygon) = polygon; if (connectionIntersections) (*connectionIntersections) = intersections; return (cvf::StructGridInterface::FaceType)(fIdx); } } return cvf::StructGridInterface::NO_FACE; }
bool interpretCommand(RiaSocketServer* server, const QList<QByteArray>& args, QDataStream& socketStream) override { RimEclipseCase* rimCase = RiaSocketTools::findCaseFromArgs(server, args); QString porosityModelName; porosityModelName = args[2]; RiaDefines::PorosityModelType porosityModelEnum = RiaDefines::MATRIX_MODEL; if (porosityModelName.toUpper() == "FRACTURE") { porosityModelEnum = RiaDefines::FRACTURE_MODEL; } if (!rimCase || !rimCase->eclipseCaseData() ) { // No data available socketStream << (quint64)0 << (quint64)0 ; return true; } RigActiveCellInfo* actCellInfo = rimCase->eclipseCaseData()->activeCellInfo(porosityModelEnum); RigMainGrid* mainGrid = rimCase->eclipseCaseData()->mainGrid(); size_t activeCellCount = actCellInfo->reservoirActiveCellCount(); size_t doubleValueCount = activeCellCount * 3 * 8; socketStream << (quint64)activeCellCount; quint64 byteCount = doubleValueCount * sizeof(double); socketStream << byteCount; // This structure is supposed to be received by Octave using a NDArray. The ordering of this loop is // defined by the ordering of the receiving NDArray // // See riGetCellCorners // // dim_vector dv; // dv.resize(3); // dv(0) = coordCount; // dv(1) = 8; // dv(2) = 3; cvf::Vec3d cornerVerts[8]; size_t blockByteCount = activeCellCount * sizeof(double); std::vector<double> doubleValues(blockByteCount); for (int coordIdx = 0; coordIdx < 3; coordIdx++) { for (size_t cornerIdx = 0; cornerIdx < 8; cornerIdx++) { size_t cornerIndexMapping = cellCornerMappingEclipse[cornerIdx]; quint64 valueIndex = 0; for (size_t reservoirCellIndex = 0; reservoirCellIndex < mainGrid->globalCellArray().size(); reservoirCellIndex++) { if (!actCellInfo->isActive(reservoirCellIndex)) continue; mainGrid->cellCornerVertices(reservoirCellIndex, cornerVerts); doubleValues[valueIndex++] = getCellCornerWithPositiveDepth(cornerVerts, cornerIndexMapping, coordIdx); } CVF_ASSERT(valueIndex == activeCellCount); RiaSocketTools::writeBlockData(server, server->currentClient(), (const char *)doubleValues.data(), blockByteCount); } } return true; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivReservoirFaultsPartMgr::appendPartsToModel(cvf::ModelBasicList* model) { CVF_ASSERT(model != NULL); RimFaultCollection* faultCollection = m_reservoirView->faultCollection(); if (!faultCollection) return; bool isShowingGrid = faultCollection->isGridVisualizationMode(); if (!faultCollection->showFaultCollection() && !isShowingGrid) return; // Check match between model fault count and fault parts CVF_ASSERT(faultCollection->faults.size() == m_faultParts.size()); cvf::ModelBasicList parts; for (size_t i = 0; i < faultCollection->faults.size(); i++) { const RimFault* rimFault = faultCollection->faults[i]; cvf::ref<RivFaultPartMgr> rivFaultPart = m_faultParts[i]; CVF_ASSERT(rivFaultPart.notNull()); // Parts that is overridden by the grid settings bool forceDisplayOfFault = false; if (!faultCollection->showFaultsOutsideFilters()) { forceDisplayOfFault = isShowingGrid; } if (m_forceVisibility && isShowingGrid) { forceDisplayOfFault = true; } if ( (faultCollection->showFaultCollection() && rimFault->showFault()) || forceDisplayOfFault) { if (faultCollection->showFaultFaces() || forceDisplayOfFault) { rivFaultPart->appendNativeFaultFacesToModel(&parts); } if (faultCollection->showOppositeFaultFaces() || forceDisplayOfFault) { rivFaultPart->appendOppositeFaultFacesToModel(&parts); } if (faultCollection->showFaultFaces() || faultCollection->showOppositeFaultFaces() || faultCollection->showNNCs() || forceDisplayOfFault) { rivFaultPart->appendMeshLinePartsToModel(&parts); } } // Parts that is not overridden by the grid settings RimEclipseFaultColors* faultResultColors = m_reservoirView->faultResultSettings(); RimEclipseCellColors* cellResultColors = m_reservoirView->cellResult(); if (rimFault->showFault() && faultCollection->showFaultCollection()) { if (faultCollection->showNNCs()) { bool showNncs = true; if (faultCollection->hideNncsWhenNoResultIsAvailable()) { size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; if (faultResultColors->showCustomFaultResult()) { scalarResultIndex = faultResultColors->customFaultResult()->scalarResultIndex(); } else { scalarResultIndex = cellResultColors->scalarResultIndex(); } RigMainGrid* mainGrid = m_reservoirView->eclipseCase()->reservoirData()->mainGrid(); if (!(mainGrid && mainGrid->nncData()->hasScalarValues(scalarResultIndex))) { showNncs = false; } } if (showNncs) { rivFaultPart->appendNNCFacesToModel(&parts); } } } } for (size_t i = 0; i < parts.partCount(); i++) { cvf::Part* part = parts.part(i); part->setTransform(m_scaleTransform.p()); model->addPart(part); } }
//-------------------------------------------------------------------------------------------------- /// Read geometry from file given by name into given reservoir object //-------------------------------------------------------------------------------------------------- bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, RigReservoir* reservoir) { CVF_ASSERT(reservoir); if (!mainEclGrid) { // Some error return false; } RigMainGrid* mainGrid = reservoir->mainGrid(); { cvf::Vec3st gridPointDim(0,0,0); gridPointDim.x() = ecl_grid_get_nx(mainEclGrid) + 1; gridPointDim.y() = ecl_grid_get_ny(mainEclGrid) + 1; gridPointDim.z() = ecl_grid_get_nz(mainEclGrid) + 1; mainGrid->setGridPointDimensions(gridPointDim); } // Get and set grid and lgr metadata size_t totalCellCount = static_cast<size_t>(ecl_grid_get_global_size(mainEclGrid)); int numLGRs = ecl_grid_get_num_lgr(mainEclGrid); int lgrIdx; for (lgrIdx = 0; lgrIdx < numLGRs; ++lgrIdx) { ecl_grid_type* localEclGrid = ecl_grid_iget_lgr(mainEclGrid, lgrIdx); std::string lgrName = ecl_grid_get_name(localEclGrid); cvf::Vec3st gridPointDim(0,0,0); gridPointDim.x() = ecl_grid_get_nx(localEclGrid) + 1; gridPointDim.y() = ecl_grid_get_ny(localEclGrid) + 1; gridPointDim.z() = ecl_grid_get_nz(localEclGrid) + 1; RigLocalGrid* localGrid = new RigLocalGrid(mainGrid); mainGrid->addLocalGrid(localGrid); localGrid->setIndexToStartOfCells(totalCellCount); localGrid->setGridName(lgrName); localGrid->setGridPointDimensions(gridPointDim); totalCellCount += ecl_grid_get_global_size(localEclGrid); } // Reserve room for the cells and nodes and fill them with data mainGrid->cells().reserve(totalCellCount); mainGrid->nodes().reserve(8*totalCellCount); caf::ProgressInfo progInfo(3 + numLGRs, ""); progInfo.setProgressDescription("Main Grid"); progInfo.setNextProgressIncrement(3); transferGridCellData(mainGrid, mainGrid, mainEclGrid, 0, 0); progInfo.setProgress(3); size_t globalMatrixActiveSize = ecl_grid_get_nactive(mainEclGrid); size_t globalFractureActiveSize = ecl_grid_get_nactive_fracture(mainEclGrid); mainGrid->setMatrixModelActiveCellCount(globalMatrixActiveSize); mainGrid->setFractureModelActiveCellCount(globalFractureActiveSize); for (lgrIdx = 0; lgrIdx < numLGRs; ++lgrIdx) { progInfo.setProgressDescription("LGR number " + QString::number(lgrIdx+1)); ecl_grid_type* localEclGrid = ecl_grid_iget_lgr(mainEclGrid, lgrIdx); RigLocalGrid* localGrid = static_cast<RigLocalGrid*>(mainGrid->gridByIndex(lgrIdx+1)); transferGridCellData(mainGrid, localGrid, localEclGrid, globalMatrixActiveSize, globalFractureActiveSize); int activeCellCount = ecl_grid_get_nactive(localEclGrid); localGrid->setMatrixModelActiveCellCount(activeCellCount); globalMatrixActiveSize += activeCellCount; activeCellCount = ecl_grid_get_nactive_fracture(localEclGrid); localGrid->setFractureModelActiveCellCount(activeCellCount); globalFractureActiveSize += activeCellCount; progInfo.setProgress(3 + lgrIdx); } mainGrid->setGlobalMatrixModelActiveCellCount(globalMatrixActiveSize); mainGrid->setGlobalFractureModelActiveCellCount(globalFractureActiveSize); return true; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseCaseData* eclipseCase, bool readFaultData) { CVF_ASSERT(eclipseCase); std::vector< RifKeywordAndFilePos > keywordsAndFilePos; findKeywordsOnFile(fileName, &keywordsAndFilePos); qint64 coordPos = -1; qint64 zcornPos = -1; qint64 specgridPos = -1; qint64 actnumPos = -1; qint64 mapaxesPos = -1; findGridKeywordPositions(keywordsAndFilePos, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos); if (coordPos < 0 || zcornPos < 0 || specgridPos < 0) { QString errorText = QString("Failed to import grid file '%1'\n").arg(fileName); if (coordPos < 0) { errorText += " Missing required keyword COORD"; } if (zcornPos < 0) { errorText += " Missing required keyword ZCORN"; } if (specgridPos < 0) { errorText += " Missing required keyword SPECGRID"; } RiaLogging::error(errorText); return false; } FILE* gridFilePointer = util_fopen(fileName.toLatin1().data(), "r"); if (!gridFilePointer) return false; // Main grid dimensions // SPECGRID - This is whats normally available, but not really the input to Eclipse. // DIMENS - Is what Eclipse expects and uses, but is not defined in the GRID section and is not (?) available normally // ZCORN, COORD, ACTNUM, MAPAXES //ecl_kw_type * ecl_kw_fscanf_alloc_grdecl_dynamic__( FILE * stream , const char * kw , bool strict , ecl_type_enum ecl_type); //ecl_grid_type * ecl_grid_alloc_GRDECL_kw( int nx, int ny , int nz , const ecl_kw_type * zcorn_kw , const ecl_kw_type * coord_kw , const ecl_kw_type * actnum_kw , const ecl_kw_type * mapaxes_kw ); ecl_kw_type* specGridKw = nullptr; ecl_kw_type* zCornKw = nullptr; ecl_kw_type* coordKw = nullptr; ecl_kw_type* actNumKw = nullptr; ecl_kw_type* mapAxesKw = nullptr; // Try to read all the needed keywords. Early exit if some are not found caf::ProgressInfo progress(8, "Read Grid from Eclipse Input file"); bool allKwReadOk = true; fseek(gridFilePointer, specgridPos, SEEK_SET); allKwReadOk = allKwReadOk && nullptr != (specGridKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_INT_TYPE))); progress.setProgress(1); fseek(gridFilePointer, zcornPos, SEEK_SET); allKwReadOk = allKwReadOk && nullptr != (zCornKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE))); progress.setProgress(2); fseek(gridFilePointer, coordPos, SEEK_SET); allKwReadOk = allKwReadOk && nullptr != (coordKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE))); progress.setProgress(3); // If ACTNUM is not defined, this pointer will be NULL, which is a valid condition if (actnumPos >= 0) { fseek(gridFilePointer, actnumPos, SEEK_SET); allKwReadOk = allKwReadOk && nullptr != (actNumKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_INT_TYPE))); progress.setProgress(4); } // If MAPAXES is not defined, this pointer will be NULL, which is a valid condition if (mapaxesPos >= 0) { fseek(gridFilePointer, mapaxesPos, SEEK_SET); mapAxesKw = ecl_kw_fscanf_alloc_current_grdecl__( gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE)); } if (!allKwReadOk) { if(specGridKw) ecl_kw_free(specGridKw); if(zCornKw) ecl_kw_free(zCornKw); if(coordKw) ecl_kw_free(coordKw); if(actNumKw) ecl_kw_free(actNumKw); if(mapAxesKw) ecl_kw_free(mapAxesKw); return false; } progress.setProgress(5); int nx = ecl_kw_iget_int(specGridKw, 0); int ny = ecl_kw_iget_int(specGridKw, 1); int nz = ecl_kw_iget_int(specGridKw, 2); ecl_grid_type* inputGrid = ecl_grid_alloc_GRDECL_kw( nx, ny, nz, zCornKw, coordKw, actNumKw, mapAxesKw ); progress.setProgress(6); RifReaderEclipseOutput::transferGeometry(inputGrid, eclipseCase); progress.setProgress(7); progress.setProgressDescription("Read faults ..."); if (readFaultData) { cvf::Collection<RigFault> faults; RifEclipseInputFileTools::readFaults(fileName, keywordsAndFilePos, &faults); RigMainGrid* mainGrid = eclipseCase->mainGrid(); mainGrid->setFaults(faults); } progress.setProgress(8); progress.setProgressDescription("Cleaning up ..."); ecl_kw_free(specGridKw); ecl_kw_free(zCornKw); ecl_kw_free(coordKw); if (actNumKw) ecl_kw_free(actNumKw); if (mapAxesKw) ecl_kw_free(mapAxesKw); ecl_grid_free(inputGrid); util_fclose(gridFilePointer); return true; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigReservoirBuilderMock::addFaults(RigEclipseCaseData* eclipseCase) { if (!eclipseCase) return; RigMainGrid* grid = eclipseCase->mainGrid(); if (!grid) return; cvf::Collection<RigFault> faults; { cvf::ref<RigFault> fault = new RigFault; fault->setName("Fault A"); cvf::Vec3st min = cvf::Vec3st::ZERO; cvf::Vec3st max(0, 0, cellDimension().z() - 2); if (cellDimension().x() > 5) { min.x() = cellDimension().x() / 2; max.x() = min.x() + 2; } if (cellDimension().y() > 5) { min.y() = cellDimension().y() / 2; max.y() = cellDimension().y() / 2; } cvf::CellRange cellRange(min, max); fault->addCellRangeForFace(cvf::StructGridInterface::POS_I, cellRange); faults.push_back(fault.p()); } grid->setFaults(faults); // NNCs std::vector<RigConnection>& nncConnections = grid->nncData()->connections(); { size_t i1 = 2; size_t j1 = 2; size_t k1 = 3; size_t i2 = 2; size_t j2 = 3; size_t k2 = 4; addNnc(grid, i1, j1, k1, i2, j2, k2, nncConnections); } { size_t i1 = 2; size_t j1 = 2; size_t k1 = 3; size_t i2 = 2; size_t j2 = 1; size_t k2 = 4; addNnc(grid, i1, j1, k1, i2, j2, k2, nncConnections); } std::vector<double>& tranVals = grid->nncData()->makeStaticConnectionScalarResult(RigNNCData::propertyNameCombTrans()); for (size_t cIdx = 0; cIdx < tranVals.size(); ++cIdx) { tranVals[cIdx] = 0.2; } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigNNCData::processConnections(const RigMainGrid& mainGrid) { //cvf::Trace::show("NNC: Total number: " + cvf::String((int)m_connections.size())); for (size_t cnIdx = 0; cnIdx < m_connections.size(); ++cnIdx) { const RigCell& c1 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c1GlobIdx]; const RigCell& c2 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c2GlobIdx]; // Try to find the shared face char hasNeighbourInAnyDirection = 0; bool isPossibleNeighborInDirection[6]= {true, true, true, true, true, true}; if (c1.hostGrid() == c2.hostGrid()) { size_t i1, j1, k1; c1.hostGrid()->ijkFromCellIndex(c1.gridLocalCellIndex(), &i1, &j1, &k1); size_t i2, j2, k2; c2.hostGrid()->ijkFromCellIndex(c2.gridLocalCellIndex(), &i2, &j2, &k2); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] = ((i1 + 1) == i2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] = ((i2 + 1) == i1); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] = ((j1 + 1) == j2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] = ((j2 + 1) == j1); isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] = ((k1 + 1) == k2); isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K] = ((k2 + 1) == k1); hasNeighbourInAnyDirection = isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] + isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] + isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] + isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K]; // If cell 2 is not adjancent with respect to any of the six ijk directions, // assume that we have no overlapping area. if (!hasNeighbourInAnyDirection) { // Add to search map //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx); //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx); //cvf::Trace::show("NNC: No direct neighbors : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + " C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx)); continue; // to next connection } } // Possibly do some testing to avoid unneccesary overlap calculations cvf::Vec3d normal; for (char fIdx = 0; fIdx < 6; ++fIdx) { if (isPossibleNeighborInDirection[fIdx]) { cvf::Vec3d fc1 = c1.faceCenter((cvf::StructGridInterface::FaceType)(fIdx)); cvf::Vec3d fc2 = c2.faceCenter(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx))); cvf::Vec3d fc1ToFc2 = fc2 - fc1; normal = c1.faceNormalWithAreaLenght((cvf::StructGridInterface::FaceType)(fIdx)); normal.normalize(); // Check that face centers are approx in the face plane if (normal.dot(fc1ToFc2) < 0.01*fc1ToFc2.length()) { } } } bool foundAnyOverlap = false; for (char fIdx = 0; fIdx < 6; ++fIdx) { if (!isPossibleNeighborInDirection[fIdx]) { continue; } // Calculate connection polygon std::vector<size_t> polygon; std::vector<cvf::Vec3d> intersections; caf::SizeTArray4 face1; caf::SizeTArray4 face2; c1.faceIndices((cvf::StructGridInterface::FaceType)(fIdx), &face1); c2.faceIndices(cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx)), &face2); bool foundOverlap = cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( &polygon, &intersections, (cvf::EdgeIntersectStorage<size_t>*)NULL, cvf::wrapArrayConst(&mainGrid.nodes()), face1.data(), face2.data(), 1e-6); if (foundOverlap) { foundAnyOverlap = true; // Found an overlap polygon. Store data about connection m_connections[cnIdx].m_c1Face = (cvf::StructGridInterface::FaceType)fIdx; for (size_t pIdx = 0; pIdx < polygon.size(); ++pIdx) { if (polygon[pIdx] < mainGrid.nodes().size()) m_connections[cnIdx].m_polygon.push_back(mainGrid.nodes()[polygon[pIdx]]); else m_connections[cnIdx].m_polygon.push_back(intersections[polygon[pIdx] - mainGrid.nodes().size()]); } // Add to search map, possibly not needed //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][fIdx].push_back(cnIdx); //m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::oppositeFace((cvf::StructGridInterface::FaceType)(fIdx))].push_back(cnIdx); break; // The connection face is found. Stop looping over the cell faces. Jump to next connection } } if (!foundAnyOverlap) { //cvf::Trace::show("NNC: No overlap found for : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) + "C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx)); } } }