///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2020- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RigFemPartResultCalculatorSurfaceAngles.h" #include "RiaOffshoreSphericalCoords.h" #include "RigFemPart.h" #include "RigFemPartCollection.h" #include "RigFemPartResultsCollection.h" #include "RigFemResultAddress.h" #include "RigFemScalarResultFrames.h" #include "cafProgressInfo.h" #include "cvfGeometryTools.h" #include "cvfMath.h" #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFemPartResultCalculatorSurfaceAngles::RigFemPartResultCalculatorSurfaceAngles( RigFemPartResultsCollection& collection ) : RigFemPartResultCalculator( collection ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFemPartResultCalculatorSurfaceAngles::~RigFemPartResultCalculatorSurfaceAngles() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigFemPartResultCalculatorSurfaceAngles::isMatching( const RigFemResultAddress& resVarAddr ) const { return ( ( resVarAddr.resultPosType == RIG_ELEMENT_NODAL_FACE ) && ( resVarAddr.componentName == "Pazi" || resVarAddr.componentName == "Pinc" ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFemScalarResultFrames* RigFemPartResultCalculatorSurfaceAngles::calculate( int partIndex, const RigFemResultAddress& resVarAddr ) { CVF_ASSERT( resVarAddr.componentName == "Pazi" || resVarAddr.componentName == "Pinc" ); caf::ProgressInfo stepCountProgress( m_resultCollection->timeStepCount() * 1, "" ); stepCountProgress.setProgressDescription( "Calculating " + QString::fromStdString( resVarAddr.fieldName + ": " + resVarAddr.componentName ) ); RigFemScalarResultFrames* PaziFrames = m_resultCollection->createScalarResult( partIndex, RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "Pazi" ) ); RigFemScalarResultFrames* PincFrames = m_resultCollection->createScalarResult( partIndex, RigFemResultAddress( resVarAddr.resultPosType, resVarAddr.fieldName, "Pinc" ) ); const RigFemPart* femPart = m_resultCollection->parts()->part( partIndex ); const std::vector& nodeCoordinates = femPart->nodes().coordinates; // HACK ! Todo : make it robust against other elements than Hex8 size_t valCount = femPart->elementCount() * 24; // Number of Elm Node Face results 24 = 4 * num faces = 3* // numElmNodes const int timeSteps = m_resultCollection->timeStepCount(); for ( int stepIdx = 0; stepIdx < timeSteps; stepIdx++ ) { const int frameCount = m_resultCollection->frameCount( stepIdx ); for ( int fIdx = 0; fIdx < frameCount; fIdx++ ) { std::vector& Pazi = PaziFrames->frameData( stepIdx, fIdx ); std::vector& Pinc = PincFrames->frameData( stepIdx, fIdx ); Pazi.resize( valCount ); Pinc.resize( valCount ); int elementCount = femPart->elementCount(); #pragma omp parallel for for ( int elmIdx = 0; elmIdx < elementCount; ++elmIdx ) { RigElementType elmType = femPart->elementType( elmIdx ); int faceCount = RigFemTypes::elementFaceCount( elmType ); const int* elmNodeIndices = femPart->connectivities( elmIdx ); int elmNodFaceResIdxElmStart = elmIdx * 24; // HACK should get from part for ( int lfIdx = 0; lfIdx < faceCount; ++lfIdx ) { int faceNodeCount = 0; const int* localElmNodeIndicesForFace = RigFemTypes::localElmNodeIndicesForFace( elmType, lfIdx, &faceNodeCount ); if ( faceNodeCount == 4 ) { int elmNodFaceResIdxFaceStart = elmNodFaceResIdxElmStart + lfIdx * 4; // HACK cvf::Vec3f quadVxs[4]; quadVxs[0] = ( nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[0]]] ); quadVxs[1] = ( nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[1]]] ); quadVxs[2] = ( nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[2]]] ); quadVxs[3] = ( nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[3]]] ); cvf::Mat3f rotMx = cvf::GeometryTools::computePlaneHorizontalRotationMx( quadVxs[2] - quadVxs[0], quadVxs[3] - quadVxs[1] ); RiaOffshoreSphericalCoords sphCoord( cvf::Vec3f( rotMx.rowCol( 2, 0 ), rotMx.rowCol( 2, 1 ), rotMx.rowCol( 2, 2 ) ) ); // Use Ez // from the // matrix // as plane // normal for ( int qIdx = 0; qIdx < 4; ++qIdx ) { int elmNodFaceResIdx = elmNodFaceResIdxFaceStart + qIdx; Pazi[elmNodFaceResIdx] = cvf::Math::toDegrees( sphCoord.azi() ); Pinc[elmNodFaceResIdx] = cvf::Math::toDegrees( sphCoord.inc() ); } } } } } stepCountProgress.incrementProgress(); } RigFemScalarResultFrames* requestedPlaneAngle = m_resultCollection->findOrLoadScalarResult( partIndex, resVarAddr ); return requestedPlaneAngle; }