//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanElementColorSurfacePart(const RimEclipseView& activeView) { CVF_ASSERT(m_rimFracture); RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast<RimStimPlanFractureTemplate*>(m_rimFracture->fractureTemplate()); CVF_ASSERT(stimPlanFracTemplate); if (!stimPlanFracTemplate->fractureGrid()) return nullptr; auto displayCoordTransform = activeView.displayCoordTransform(); if (displayCoordTransform.isNull()) return nullptr; std::vector<cvf::Vec3f> stimPlanMeshVertices; cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray; const cvf::ScalarMapper* scalarMapper = nullptr; { std::vector<RigFractureCell> stimPlanCells = stimPlanFracTemplate->fractureGrid()->fractureCells(); RimRegularLegendConfig* legendConfig = nullptr; if (activeView.fractureColors() && activeView.fractureColors()->isChecked() && activeView.fractureColors()->activeLegend()) { legendConfig = activeView.fractureColors()->activeLegend(); scalarMapper = legendConfig->scalarMapper(); QString resultNameFromColors = activeView.fractureColors()->uiResultName(); QString resultUnitFromColors = activeView.fractureColors()->unit(); std::vector<double> prCellResults = stimPlanFracTemplate->fractureGridResults( resultNameFromColors, resultUnitFromColors, stimPlanFracTemplate->activeTimeStepIndex()); textureCoords->reserve(prCellResults.size() * 4); for (size_t cIdx = 0; cIdx < stimPlanCells.size(); ++cIdx) { if (prCellResults[cIdx] > 1e-7) { const RigFractureCell& stimPlanCell = stimPlanCells[cIdx]; std::vector<cvf::Vec3d> stimPlanCellPolygon = stimPlanCell.getPolygon(); for (const cvf::Vec3d& cellCorner : stimPlanCellPolygon) { stimPlanMeshVertices.push_back(static_cast<cvf::Vec3f>(cellCorner)); textureCoords->add(scalarMapper->mapToTextureCoord(prCellResults[cIdx])); } } } textureCoords->squeeze(); } else { for (const auto& stimPlanCell : stimPlanCells) { for (const auto& cellCorner : stimPlanCell.getPolygon()) { stimPlanMeshVertices.push_back(static_cast<cvf::Vec3f>(cellCorner)); } } } } if (stimPlanMeshVertices.empty()) { return nullptr; } cvf::Mat4d fractureXf = m_rimFracture->transformMatrix(); std::vector<cvf::Vec3f> nodeDisplayCoords = transformToFractureDisplayCoords(stimPlanMeshVertices, fractureXf, *displayCoordTransform); std::vector<cvf::uint> triIndicesToInclude; size_t cellCount = stimPlanMeshVertices.size() / 4; for (cvf::uint i = 0; i < cellCount; i++) { triIndicesToInclude.push_back(i * 4 + 0); triIndicesToInclude.push_back(i * 4 + 1); triIndicesToInclude.push_back(i * 4 + 2); triIndicesToInclude.push_back(i * 4 + 0); triIndicesToInclude.push_back(i * 4 + 2); triIndicesToInclude.push_back(i * 4 + 3); } // Show selected result on the surface geometry and filter out triangles that have result values near 0 if (scalarMapper) { if (triIndicesToInclude.empty()) { return nullptr; } cvf::ref<cvf::DrawableGeo> geo = buildDrawableGeoFromTriangles(triIndicesToInclude, nodeDisplayCoords); geo->setTextureCoordArray(textureCoords.p()); cvf::ref<cvf::Part> surfacePart = createScalarMapperPart(geo.p(), scalarMapper, m_rimFracture, activeView.isLightingDisabled()); return surfacePart; } else { // No result is mapped, show the entire StimPlan surface with default color return createSingleColorSurfacePart(triIndicesToInclude, nodeDisplayCoords, activeView.fractureColors()->defaultColor()); } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivFaultPartMgr::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) { CVF_ASSERT(cellResultColors); updateNNCColors(cellResultColors); RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); RimEclipseView* eclipseView = cellResultColors->reservoirView(); RigCaseData* eclipseCase = eclipseView->eclipseCase()->reservoirData(); // Faults if (m_nativeFaultFaces.notNull()) { if (cellResultColors->isTernarySaturationSelected()) { RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), timeStepIndex, m_grid->gridIndex(), m_nativeFaultGenerator->quadToCellFaceMapper()); texturer.createTextureCoords(m_nativeFaultFacesTextureCoords.p()); const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_nativeFaultFaces.p(), m_nativeFaultFacesTextureCoords.p(), mapper, m_opacityLevel, this->faceCullingMode(), eclipseView->isLightingDisabled()); } else { RivTextureCoordsCreator texturer(cellResultColors, timeStepIndex, m_grid->gridIndex(), m_nativeFaultGenerator->quadToCellFaceMapper()); if (!texturer.isValid()) { return; } texturer.createTextureCoords(m_nativeFaultFacesTextureCoords.p()); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); RivScalarMapperUtils::applyTextureResultsToPart(m_nativeFaultFaces.p(), m_nativeFaultFacesTextureCoords.p(), mapper, m_opacityLevel, this->faceCullingMode(), eclipseView->isLightingDisabled()); } } if (m_oppositeFaultFaces.notNull()) { if (cellResultColors->isTernarySaturationSelected()) { RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), timeStepIndex, m_grid->gridIndex(), m_oppositeFaultGenerator->quadToCellFaceMapper()); texturer.createTextureCoords(m_oppositeFaultFacesTextureCoords.p()); const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_oppositeFaultFaces.p(), m_oppositeFaultFacesTextureCoords.p(), mapper, m_opacityLevel, this->faceCullingMode(), eclipseView->isLightingDisabled()); } else { RivTextureCoordsCreator texturer(cellResultColors, timeStepIndex, m_grid->gridIndex(), m_oppositeFaultGenerator->quadToCellFaceMapper()); if (!texturer.isValid()) { return; } texturer.createTextureCoords(m_oppositeFaultFacesTextureCoords.p()); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); RivScalarMapperUtils::applyTextureResultsToPart(m_oppositeFaultFaces.p(), m_oppositeFaultFacesTextureCoords.p(), mapper, m_opacityLevel, this->faceCullingMode(), eclipseView->isLightingDisabled()); } } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref<cvf::Part> RivWellFracturePartMgr::createStimPlanColorInterpolatedSurfacePart(const RimEclipseView& activeView) { CVF_ASSERT(m_rimFracture); RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast<RimStimPlanFractureTemplate*>(m_rimFracture->fractureTemplate()); CVF_ASSERT(stimPlanFracTemplate); auto displayCoordTransform = activeView.displayCoordTransform(); if (displayCoordTransform.isNull()) return nullptr; // Note that the filtering and result mapping code below couples closely to the triangulation and vertex layout returned by // triangleGeometry() If this ever changes, the entire code must be revisited std::vector<cvf::uint> triangleIndices; std::vector<cvf::Vec3f> nodeDisplayCoords; { std::vector<cvf::Vec3f> nodeCoords; stimPlanFracTemplate->fractureTriangleGeometry(&nodeCoords, &triangleIndices); if (triangleIndices.empty() || nodeCoords.empty()) { return nullptr; } cvf::Mat4d fractureXf = m_rimFracture->transformMatrix(); nodeDisplayCoords = transformToFractureDisplayCoords(nodeCoords, fractureXf, *displayCoordTransform); } RimRegularLegendConfig* legendConfig = nullptr; if (activeView.fractureColors() && activeView.fractureColors()->isChecked()) { legendConfig = activeView.fractureColors()->activeLegend(); } // Show selected result on the surface geometry and filter out triangles that have result values near 0 if (legendConfig) { // Construct array with per node result values that correspond to the node coordinates of the triangle mesh // Since some time steps don't have result vales, we initialize the array to well known values before populating it std::vector<double> perNodeResultValues(nodeDisplayCoords.size(), HUGE_VAL); { size_t idx = 0; const std::vector<std::vector<double>> dataToPlot = stimPlanFracTemplate->resultValues(activeView.fractureColors()->uiResultName(), activeView.fractureColors()->unit(), stimPlanFracTemplate->activeTimeStepIndex()); for (const std::vector<double>& dataAtY : dataToPlot) { for (double val : dataAtY) { perNodeResultValues[idx++] = val; } } } CVF_ASSERT(perNodeResultValues.size() == nodeDisplayCoords.size()); std::vector<cvf::uint> triIndicesToInclude; for (size_t i = 0; i < triangleIndices.size(); i += 6) { // Include all triangles where at least one of the vertices in the triangle pair has a value above threshold bool includeThisTrianglePair = false; for (size_t j = 0; j < 6; j++) { if (perNodeResultValues[triangleIndices[i + j]] > 1e-7) { includeThisTrianglePair = true; } } if (includeThisTrianglePair) { for (size_t j = 0; j < 6; j++) { triIndicesToInclude.push_back(triangleIndices[i + j]); } } } if (triIndicesToInclude.empty()) { return nullptr; } cvf::ref<cvf::DrawableGeo> geo = buildDrawableGeoFromTriangles(triIndicesToInclude, nodeDisplayCoords); const cvf::ScalarMapper* scalarMapper = legendConfig->scalarMapper(); CVF_ASSERT(scalarMapper); cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray(nodeDisplayCoords.size()); textureCoords->setAll(cvf::Vec2f(0.5f, 1.0f)); for (size_t i = 0; i < perNodeResultValues.size(); i++) { const double val = perNodeResultValues[i]; if (val < HUGE_VAL && val == val) { textureCoords->set(i, scalarMapper->mapToTextureCoord(val)); } } geo->setTextureCoordArray(textureCoords.p()); cvf::ref<cvf::Part> surfacePart = createScalarMapperPart(geo.p(), scalarMapper, m_rimFracture, activeView.isLightingDisabled()); return surfacePart; } else { // No result is mapped, show the entire StimPlan surface with default color return createSingleColorSurfacePart(triangleIndices, nodeDisplayCoords, activeView.fractureColors()->defaultColor()); } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) { if (m_crossSectionGenerator.isNull()) return; if (!m_crossSectionGenerator->isAnyGeometryPresent()) return; RimEclipseView* eclipseView; m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); if (eclipseView) { RimEclipseCellColors* cellResultColors = eclipseView->cellResult(); CVF_ASSERT(cellResultColors); RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); RigCaseData* eclipseCase = eclipseView->eclipseCase()->reservoirData(); // CrossSections if (m_crossSectionFaces.notNull()) { if (cellResultColors->isTernarySaturationSelected()) { RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), timeStepIndex); texturer.createTextureCoords(m_crossSectionFacesTextureCoords.p(), m_crossSectionGenerator->triangleToCellIndex()); const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_crossSectionFaces.p(), m_crossSectionFacesTextureCoords.p(), mapper, 1.0, caf::FC_NONE, eclipseView->isLightingDisabled()); } else { CVF_ASSERT(m_crossSectionGenerator.notNull()); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); cvf::ref<RigResultAccessor> resultAccessor; if (RimDefines::isPerCellFaceResult(cellResultColors->resultVariable())) { resultAccessor = new RigHugeValResultAccessor; } else { resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), 0, timeStepIndex, cellResultColors); } RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), m_crossSectionGenerator->triangleToCellIndex(), resultAccessor.p(), mapper); RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), m_crossSectionFacesTextureCoords.p(), mapper, 1.0, caf::FC_NONE, eclipseView->isLightingDisabled()); } } } RimGeoMechView* geoView; m_rimCrossSection->firstAnchestorOrThisOfType(geoView); if (geoView) { RimGeoMechCellColors* cellResultColors = geoView->cellResult(); RigGeoMechCaseData* caseData = cellResultColors->ownerCaseData(); if (!caseData) return; RigFemResultAddress resVarAddress = cellResultColors->resultAddress(); // Do a "Hack" to show elm nodal and not nodal POR results if (resVarAddress.resultPosType == RIG_NODAL && resVarAddress.fieldName == "POR-Bar") resVarAddress.resultPosType = RIG_ELEMENT_NODAL; const std::vector<RivVertexWeights> &vertexWeights = m_crossSectionGenerator->triangleVxToCellCornerInterpolationWeights(); const std::vector<float>& resultValues = caseData->femPartResults()->resultValues(resVarAddress, 0, (int)timeStepIndex); bool isElementNodalResult = !(resVarAddress.resultPosType == RIG_NODAL); RigFemPart* femPart = caseData->femParts()->part(0); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); RivCrossSectionPartMgr::calculateGeoMechTextureCoords(m_crossSectionFacesTextureCoords.p(), vertexWeights, resultValues, isElementNodalResult, femPart, mapper); RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), m_crossSectionFacesTextureCoords.p(), mapper, 1.0, caf::FC_NONE, geoView->isLightingDisabled()); } }