You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmPebiGridViewDataBuilder.cpp

261 lines
8.8 KiB
C++

#include "nmPebiGridViewDataBuilder.h"
#include "nmPebiGridViewData.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataHorizontalFracturedWell.h"
#include "nmDataNumericalAnalysisCase.h"
#include "nmDataVerticalFracturedWell.h"
#include "nmDataWellBase.h"
#include <QCoreApplication>
#include <QSet>
#include <QThread>
#include <cmath>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkMath.h>
#include <vtkUnstructuredGrid.h>
namespace {
QString builderText(const char* pText)
{
return QCoreApplication::translate("nmPebiGridViewDataBuilder", pText);
}
bool isBuilderGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == NULL ||
pApplication->thread() == QThread::currentThread();
}
bool isFinitePoint(const QPointF& oPoint)
{
return vtkMath::IsFinite(oPoint.x()) &&
vtkMath::IsFinite(oPoint.y());
}
bool appendWellData(nmDataWellBase* pWell,
nmPebiGridWellViewData* pWellData,
QString* pError)
{
if(pWell == NULL || pWellData == NULL) {
if(pError != NULL) {
*pError = builderText("The well data is incomplete.");
}
return false;
}
pWellData->m_sWellCode = pWell->getWellCode().trimmed();
pWellData->m_sWellName = pWell->getWellName();
pWellData->m_eWellType = pWell->getWellType();
pWellData->m_oPosition = QPointF(
pWell->getX().getValue().toDouble(),
pWell->getY().getValue().toDouble());
if(pWellData->m_sWellCode.isEmpty()) {
if(pError != NULL) {
*pError = builderText("A well has no stable code.");
}
return false;
}
if(!isFinitePoint(pWellData->m_oPosition)) {
if(pError != NULL) {
*pError = builderText("A well contains an invalid position.");
}
return false;
}
nmDataHorizontalFracturedWell* pHorizontalWell =
dynamic_cast<nmDataHorizontalFracturedWell*>(pWell);
nmDataVerticalFracturedWell* pVerticalFracturedWell =
dynamic_cast<nmDataVerticalFracturedWell*>(pWell);
if(pHorizontalWell != NULL) {
const double dLength = pHorizontalWell->getWellLength()
.getValue().toDouble();
const double dAngle = pHorizontalWell->getDrainAngle()
.getValue().toDouble();
if(!vtkMath::IsFinite(dLength) || dLength < 0.0 ||
!vtkMath::IsFinite(dAngle)) {
if(pError != NULL) {
*pError = builderText(
"A horizontal well contains invalid geometry.");
}
return false;
}
const double dRadians = dAngle * 3.14159265358979323846 / 180.0;
const QPointF oEndPoint(
pWellData->m_oPosition.x() + dLength * std::cos(dRadians),
pWellData->m_oPosition.y() + dLength * std::sin(dRadians));
if(!isFinitePoint(oEndPoint)) {
if(pError != NULL) {
*pError = builderText(
"A horizontal well contains invalid geometry.");
}
return false;
}
pWellData->m_vecWellSegments.append(
QLineF(pWellData->m_oPosition, oEndPoint));
const QVector<QPair<QPointF, QPointF> > vecFractures =
pHorizontalWell->getFracs();
for(int nIndex = 0; nIndex < vecFractures.size(); ++nIndex) {
const QPointF& oStart = vecFractures[nIndex].first;
const QPointF& oEnd = vecFractures[nIndex].second;
if(!isFinitePoint(oStart) || !isFinitePoint(oEnd)) {
if(pError != NULL) {
*pError = builderText(
"A well contains invalid fracture geometry.");
}
return false;
}
pWellData->m_vecFractureSegments.append(QLineF(oStart, oEnd));
}
} else if(pVerticalFracturedWell != NULL) {
const QVector<QPointF> vecFractures =
pVerticalFracturedWell->getFracs();
if(vecFractures.size() != 2 ||
!isFinitePoint(vecFractures[0]) ||
!isFinitePoint(vecFractures[1])) {
if(pError != NULL) {
*pError = builderText(
"A well contains invalid fracture geometry.");
}
return false;
}
pWellData->m_vecFractureSegments.append(
QLineF(vecFractures[0], vecFractures[1]));
} else if(pWellData->m_eWellType != Vertical_Well) {
if(pError != NULL) {
*pError = builderText("The well type is not supported by this view.");
}
return false;
}
return true;
}
}
bool nmPebiGridViewDataBuilder::build(
nmDataAnalyzeManager* pDataManager,
nmPebiGridViewData* pViewData,
QString* pError)
{
Q_ASSERT(isBuilderGuiThread());
if(pError != NULL) {
pError->clear();
}
if(!isBuilderGuiThread()) {
if(pError != NULL) {
*pError = builderText(
"Grid preview data must be built in the GUI thread.");
}
return false;
}
if(pDataManager == NULL || pViewData == NULL) {
if(pError != NULL) {
*pError = builderText("The grid data source is unavailable.");
}
return false;
}
if(pDataManager->thread() != QThread::currentThread()) {
if(pError != NULL) {
*pError = builderText(
"Grid preview data must be built in the GUI thread.");
}
return false;
}
if(!pDataManager->isPebiGridValid()) {
if(pError != NULL) {
*pError = builderText("The PEBI grid has not been committed.");
}
return false;
}
if(pDataManager->getGridType() != NM_Grid_PEBI) {
if(pError != NULL) {
*pError = builderText("The committed grid is not a PEBI grid.");
}
return false;
}
vtkSmartPointer<vtkUnstructuredGrid> pGrid =
pDataManager->getUnstructuredGrid();
if(pGrid == NULL || pGrid->GetNumberOfPoints() <= 0 ||
pGrid->GetNumberOfCells() <= 0) {
if(pError != NULL) {
*pError = builderText("The committed PEBI grid is empty.");
}
return false;
}
const nmDataNumericalAnalysisCase* pAnalysisCase =
pDataManager->getNumericalAnalysisCase();
if(pAnalysisCase == NULL) {
if(pError != NULL) {
*pError = builderText("The grid version is unavailable.");
}
return false;
}
// 先在局部对象中收集完整快照,任何井数据错误都不会覆盖调用方旧数据。
nmPebiGridViewData oCandidate;
oCandidate.m_pGrid = pGrid;
oCandidate.m_eGridType = NM_Grid_PEBI;
oCandidate.m_nGridInputRevision =
pAnalysisCase->getGridInputRevision();
oCandidate.m_nValidCellCount = pGrid->GetNumberOfCells();
// Material 只认可 CellData 中与 VTK 单元一一对应的数组。
vtkCellData* pCellData = pGrid->GetCellData();
vtkDataArray* pMaterialArray = pCellData != NULL
? pCellData->GetArray("Material") : NULL;
oCandidate.m_bHasMaterial = pMaterialArray != NULL &&
pMaterialArray->GetNumberOfTuples() == pGrid->GetNumberOfCells();
// 井显示必须与本次已提交网格使用的求解器槽位一致,不能遍历 Map 中
// 未参与建网的井。手工裂缝槽位只维持 DLL 下标,不对应真实井 Actor。
const QVector<nmSolverWellRef> vecSolverWellOrder =
pDataManager->getSolverWellOrder();
QSet<QString> setWellCodes;
oCandidate.m_vecWells.reserve(vecSolverWellOrder.size());
for(int nIndex = 0; nIndex < vecSolverWellOrder.size(); ++nIndex) {
const nmSolverWellRef& oWellRef = vecSolverWellOrder[nIndex];
if(oWellRef.m_eEntryKind != NM_SolverEntry_Well) {
continue;
}
const QString sWellCode = oWellRef.m_sWellCode.trimmed();
nmDataWellBase* pWell = pDataManager->findWellByCode(sWellCode);
if(sWellCode.isEmpty() || pWell == NULL) {
if(pError != NULL) {
*pError = builderText(
"The committed grid references a missing well.");
}
return false;
}
nmPebiGridWellViewData oWellData;
if(!appendWellData(pWell, &oWellData, pError)) {
return false;
}
if(setWellCodes.contains(oWellData.m_sWellCode)) {
if(pError != NULL) {
*pError = builderText("The grid contains duplicate well codes.");
}
return false;
}
setWellCodes.insert(oWellData.m_sWellCode);
oCandidate.m_vecWells.append(oWellData);
}
*pViewData = oCandidate;
return true;
}