From 1d7de266f0bb60642a44cf11eac1449de0d4aca7 Mon Sep 17 00:00:00 2001 From: Abiy Melaku Date: Fri, 13 Sep 2024 16:23:42 -0700 Subject: [PATCH 1/4] abiy - wind direction, json file read/write updated --- EVENTS/EmptyDomainCFD/EmptyDomainCFD.cpp | 47 +++- .../EmptyDomainCFD/EmptyResultMonitoring.cpp | 4 +- EVENTS/EmptyDomainCFD/EmptyResultMonitoring.h | 6 +- .../GeometricInputWidget.cpp | 27 +- .../IsolatedBuildingCFD.cpp | 53 +++- .../IsolatedBuildingCFD/IsolatedBuildingCFD.h | 6 + .../ResultMonitoringWidget.cpp | 243 +++++++++++++++++- .../ResultMonitoringWidget.h | 14 + .../SnappyHexMeshWidget.cpp | 40 +-- .../SurroundedBuildingCFD.cpp | 15 +- WorkflowAppWE.cpp | 2 + 11 files changed, 405 insertions(+), 52 deletions(-) diff --git a/EVENTS/EmptyDomainCFD/EmptyDomainCFD.cpp b/EVENTS/EmptyDomainCFD/EmptyDomainCFD.cpp index 0d33333..58dea2f 100644 --- a/EVENTS/EmptyDomainCFD/EmptyDomainCFD.cpp +++ b/EVENTS/EmptyDomainCFD/EmptyDomainCFD.cpp @@ -533,7 +533,37 @@ bool EmptyDomainCFD::inputFromJSON(QJsonObject &jsonObject) { this->clear(); - caseDirectoryPathWidget->setText(jsonObject["caseDirectoryPath"].toString()); + QString foamPath = jsonObject["caseDirectoryPath"].toString(); + + QDir foamDir(foamPath); + + if (!foamDir.exists(foamPath)) + { + QDir workingDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); + + QString workingDirPath = workingDir.filePath(QCoreApplication::applicationName() + QDir::separator() + + "LocalWorkDir" + QDir::separator() + + "EmptyDomainCFD"); + workingDir.mkpath(workingDirPath); + + caseDirectoryPathWidget->setText(workingDirPath); + + if(!isCaseConfigured()) + { + setupCase(); + } + + if (!isMeshed()) + { + snappyHexMesh->onRunBlockMeshClicked(); + } + } + else + { + caseDirectoryPathWidget->setText(jsonObject["caseDirectoryPath"].toString()); + } + + openFoamVersion->setCurrentText(jsonObject["OpenFoamVersion"].toString()); geometry->inputFromJSON(jsonObject); @@ -626,7 +656,16 @@ bool EmptyDomainCFD::copyFiles(QString &destDir) { QString caseName = "EmptyDomainCFD"; - bool result = this->copyPath(caseDir(), destDir + QDir::separator() + caseName, false); + //Copy each directory in the OF case directory + QStringList foamDirs = {"constant", "system", "0"}; + + bool copyResults = true; + + for(QString dir:foamDirs) + { + qDebug() << "Copying " << dir; + copyResults *= this->copyPath(caseDir() + QDir::separator() + dir, destDir + QDir::separator() + caseName + QDir::separator() + dir, false); + } //Remove the 'constant/polyMesh' directory // Makes it slow to transfer the mesh to DesignSafe @@ -634,13 +673,13 @@ bool EmptyDomainCFD::copyFiles(QString &destDir) { QDir polyMeshDir(destDir + QDir::separator() + caseName + QDir::separator() + "constant" + QDir::separator() + "polyMesh"); polyMeshDir.removeRecursively(); - if (result == false) { + if (copyResults == false) { QString errorMessage; errorMessage = "EmptyDomainCFD - failed to copy file: " + caseDir() + " to: " + destDir; emit sendFatalMessage(errorMessage); qDebug() << errorMessage; } - return result; + return copyResults; } bool EmptyDomainCFD::cleanCase() diff --git a/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.cpp b/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.cpp index 21e33ed..facf42c 100644 --- a/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.cpp +++ b/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.cpp @@ -615,13 +615,11 @@ void EmptyResultMonitoring::initializeVTKTable(int numRows) { vtkSampleTable->setColumnWidth(i, vtkSampleTable->size().width()/(vtkNumCols + 0.25)); - for (int j=0; j < numRows; j++) + for(int j=0; j < numRows; j++) { vtkSampleTable->setItem(j, i, new QTableWidgetItem("")); } } - - } diff --git a/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.h b/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.h index 6fd4d9f..4fdf704 100644 --- a/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.h +++ b/EVENTS/EmptyDomainCFD/EmptyResultMonitoring.h @@ -80,11 +80,11 @@ public slots: void onAddProfileClicked(); void onRemoveProfileClicked(); void onShowProfilesClicked(); - void onAddPlaneClicked(); - void onRemovePlaneClicked(); void onMonitorProfileChecked(int); - void onMonitorPlaneChecked(int); + void onMonitorPlaneChecked(int); + void onAddPlaneClicked(); + void onRemovePlaneClicked(); private: diff --git a/EVENTS/IsolatedBuildingCFD/GeometricInputWidget.cpp b/EVENTS/IsolatedBuildingCFD/GeometricInputWidget.cpp index 6e25cf2..dca05ff 100644 --- a/EVENTS/IsolatedBuildingCFD/GeometricInputWidget.cpp +++ b/EVENTS/IsolatedBuildingCFD/GeometricInputWidget.cpp @@ -136,7 +136,7 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. QLabel *windDirectionLabel = new QLabel("Wind Direction:"); windDirectionWidget = new QSpinBox; - windDirectionWidget->setRange(0, 90); + windDirectionWidget->setRange(0, 360); windDirectionWidget->setSingleStep(10); windDirectionWidget->setValue(0); @@ -450,13 +450,11 @@ void GeometricInputWidget::buildingShapeChanged(const QString &arg) { importSTLButton->setEnabled(false); importSTLLabel->setEnabled(false); - generateBuildingSTL->setEnabled(true); } else if(arg == "Complex") { importSTLButton->setEnabled(true); importSTLLabel->setEnabled(true); - generateBuildingSTL->setEnabled(false); } } @@ -741,9 +739,19 @@ void GeometricInputWidget::onSTLImportButtonClicked() double depth = (yMax-yMin)*scale; double height = (zMax-zMin)*scale; - theGI->setLengthUnit("m"); - theGI->setNumStoriesAndHeight(mainModel->numberOfFloors(), height); - theGI->setBuildingDimensions(width, depth, width*depth); + if(mainModel->isLaunchedAsTool) + { + buildingWidthWidget->setText(QString::number(width)); + buildingDepthWidget->setText(QString::number(depth)); + buildingHeightWidget->setText(QString::number(height)); + } + + else + { + theGI->setLengthUnit("m"); + theGI->setNumStoriesAndHeight(mainModel->numberOfFloors(), height); + theGI->setBuildingDimensions(width, depth, width*depth); + } mainModel->writeOpenFoamFiles(); } @@ -766,9 +774,6 @@ void GeometricInputWidget::onSTLCancelButtonClicked() void GeometricInputWidget::onGenerateBuildingSTL() { - if(buildingShape->currentText() == "Simple") - { - mainModel->writeOpenFoamFiles(); - mainModel->reloadMesh(); - } + mainModel->writeOpenFoamFiles(); + mainModel->reloadMesh(); } diff --git a/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.cpp b/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.cpp index 925b227..31e3840 100644 --- a/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.cpp +++ b/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.cpp @@ -104,7 +104,7 @@ bool IsolatedBuildingCFD::initialize() visWindowLayout = new QVBoxLayout(); visWindowGroup = new QGroupBox(); - QTabWidget *inputTab = new QTabWidget(this); + inputTab = new QTabWidget(this); QWidget *generalWidget = new QWidget(); QWidget *geometryWidget = new QWidget(); @@ -813,11 +813,22 @@ bool IsolatedBuildingCFD::inputAppDataFromJSON(QJsonObject &jsonObject) { bool IsolatedBuildingCFD::copyFiles(QString &destDir) { - writeOpenFoamFiles(); + writeOpenFoamFiles(); + + QString caseName = "IsolatedBuildingCFD"; + + + //Copy each directory in the OF case directory + QStringList foamDirs = {"constant", "system", "0"}; - QString caseName = "IsolatedBuildingCFD"; + bool copyResults = true; + + for(QString dir:foamDirs) + { + qDebug() << "Copying " << dir; + copyResults *= this->copyPath(caseDir() + QDir::separator() + dir, destDir + QDir::separator() + caseName + QDir::separator() + dir, false); + } - bool result = this->copyPath(caseDir(), destDir + QDir::separator() + caseName, false); //Remove the 'constant/polyMesh' directory // Makes it slow to transfer the mesh to DesignSafe @@ -825,13 +836,13 @@ bool IsolatedBuildingCFD::copyFiles(QString &destDir) { QDir polyMeshDir(destDir + QDir::separator() + caseName + QDir::separator() + "constant" + QDir::separator() + "polyMesh"); polyMeshDir.removeRecursively(); - if (result == false) { + if (copyResults == false) { QString errorMessage; errorMessage = "IsolatedBuildingCFD - failed to copy file: " + caseDir() + " to: " + destDir; emit sendFatalMessage(errorMessage); qDebug() << errorMessage; } - return result; + return copyResults; } bool IsolatedBuildingCFD::cleanCase() @@ -1024,6 +1035,23 @@ int IsolatedBuildingCFD::numberOfFloors() } + +double IsolatedBuildingCFD::buildingWidthModelScale() +{ + return buildingWidth()/geometricScale(); +} + +double IsolatedBuildingCFD::buildingDepthModelScale() +{ + return buildingDepth()/geometricScale(); +} + +double IsolatedBuildingCFD::buildingHeightModelScale() +{ + return buildingHeight()/geometricScale();; +} + + double IsolatedBuildingCFD::geometricScale() { return geometry->geometricScaleWidget->text().toDouble(); @@ -1147,6 +1175,19 @@ vtkPolyData* IsolatedBuildingCFD::getBldgBlock() return visWidget->getBldgBlock(); } +double IsolatedBuildingCFD::getDuration() +{ + return numericalSetup->duration->text().toDouble(); +} + + +SC_ResultsWidget* IsolatedBuildingCFD::getResultsWidget(QWidget *parent) +{ + inputTab->setCurrentIndex(6); + statusMessage("Isolated building CFD results downloaded! Now processing..."); + return resultDisplay; +} + void IsolatedBuildingCFD::onSaveMeshClicked() { statusMessage("Writing OpenFOAM dictionary files ... "); diff --git a/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.h b/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.h index 5d28553..b4543f7 100644 --- a/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.h +++ b/EVENTS/IsolatedBuildingCFD/IsolatedBuildingCFD.h @@ -111,6 +111,9 @@ class IsolatedBuildingCFD : public SimCenterAppWidget double buildingWidth(); double buildingDepth(); double buildingHeight(); + double buildingWidthModelScale(); + double buildingDepthModelScale(); + double buildingHeightModelScale(); int numberOfFloors(); double geometricScale(); @@ -132,6 +135,8 @@ class IsolatedBuildingCFD : public SimCenterAppWidget double getTimeStep(); vtkPolyData* getBldgBlock(); + SC_ResultsWidget* getResultsWidget(QWidget *parent); + double getDuration(); bool isLaunchedAsTool = false; @@ -176,6 +181,7 @@ public slots: QGridLayout *openFoamVersionLayout; QComboBox *openFoamVersion; + QTabWidget *inputTab; GeometricInputWidget *geometry; SnappyHexMeshWidget *snappyHexMesh; SimCenterVTKRenderingWidget *visWidget; diff --git a/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.cpp b/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.cpp index 4286f25..520cf43 100644 --- a/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.cpp +++ b/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.cpp @@ -135,6 +135,10 @@ ResultMonitoringWidget::ResultMonitoringWidget( IsolatedBuildingCFD *parent) monitorPressureLayout = new QGridLayout(); monitorPressureGroup->setLayout(monitorPressureLayout); + vtkSampleGroup = new QGroupBox("VTK Planes"); + vtkSampleLayout = new QGridLayout(); + vtkSampleGroup->setLayout(vtkSampleLayout); + pressureMonitoringPointsGroup = new QGroupBox(""); pressureMonitoringPointsLayout = new QGridLayout(); pressureMonitoringPointsGroup->setLayout(pressureMonitoringPointsLayout); @@ -300,8 +304,94 @@ ResultMonitoringWidget::ResultMonitoringWidget( IsolatedBuildingCFD *parent) pressureMonitoringPointsGroup->setEnabled(monitorSurfacePressure->isChecked()); + + + //================================================================== + // Sample On Plane + //================================================================== + + monitorVTKPlane = new QCheckBox("Sample Flow Field"); + monitorVTKPlane->setChecked(true); + monitorVTKPlane->setToolTip("If checked, monitors flow field on plane i.e. using VTK"); + + const int vtkNumCols = 8; + const int vtkNumRows = 2; + + vtkSampleTable = new QTableWidget(vtkNumRows, vtkNumCols); + + initializeVTKTable(vtkNumRows); + + for (int i=0; i < vtkNumRows; i++) + { + vtkSampleTable->item(i, 0)->setText(tr("Plane%1").arg(i + 1)); + } + + for (int j=0; j < vtkNumRows; j++) + { + QComboBox* axisName = new QComboBox(); + axisName->addItem("X"); + axisName->addItem("Y"); + axisName->addItem("Z"); + axisName->setToolTip("Axis normal to the plane."); + + vtkSampleTable->setCellWidget(j, 1, axisName); + + if(j == 0) + { + axisName->setCurrentIndex(1); + } + else + { + axisName->setCurrentIndex(2); + } + } + + for (int j=0; j < vtkNumRows; j++) + { + QComboBox* fieldName = new QComboBox(); + fieldName->addItem("Velocity"); + fieldName->addItem("Pressure"); + fieldName->setToolTip("Name of the field to monitor, e.g., velocity or pressure field."); + + vtkSampleTable->setCellWidget(j, vtkNumCols-1, fieldName); + } + + QLabel* vtkWriteIntervalLabel = new QLabel("Flow Write Interval: "); + vtkWriteInterval = new QSpinBox(); + vtkWriteInterval->setSingleStep(10); + vtkWriteInterval->setMinimum(1); + vtkWriteInterval->setValue(10); + vtkWriteInterval->setMaximum(10000); + vtkWriteInterval->setEnabled(true); + vtkWriteInterval->setToolTip("Writing interval as a multiple of time step for flow field"); + vtkWriteInterval->setMinimumWidth(100); + + addPlane = new QPushButton("Add Plane"); + removePlane = new QPushButton("Remove Plane"); + showPlane = new QPushButton("Show Plane"); + + + vtkSampleLayout->addWidget(monitorVTKPlane, 0, 0); + vtkSampleLayout->addWidget(addPlane, 0, 1); + vtkSampleLayout->addWidget(removePlane, 0, 2); + vtkSampleLayout->addWidget(showPlane, 0, 3); + vtkSampleLayout->addWidget(vtkSampleTable, 1, 0, 1, 4); + vtkSampleLayout->addWidget(vtkWriteIntervalLabel, 2, 0); + vtkSampleLayout->addWidget(vtkWriteInterval, 2, 1, Qt::AlignLeft); + + + connect(addPlane,SIGNAL(clicked()), this, SLOT(onAddPlaneClicked())); + connect(removePlane,SIGNAL(clicked()), this, SLOT(onRemovePlaneClicked())); + connect(showPlane,SIGNAL(clicked()), this, SLOT(onShowPlaneClicked())); + connect(monitorVTKPlane, SIGNAL(stateChanged(int)), this, SLOT(onMonitorPlaneChecked(int))); + + + + + layout->addWidget(monitorPressureGroup); - + layout->addWidget(vtkSampleGroup); + // layout->addWidget(resultMonitoringGroup); this->setLayout(layout); @@ -757,7 +847,6 @@ QList ResultMonitoringWidget::createSamplingPoints() bool ResultMonitoringWidget::outputToJSON(QJsonObject &jsonObject) { // Writes wind load monitoring options JSON file. - QJsonObject resMonitoringJson = QJsonObject(); resMonitoringJson["numStories"] = numStories->value(); @@ -800,6 +889,35 @@ bool ResultMonitoringWidget::outputToJSON(QJsonObject &jsonObject) resMonitoringJson["generatedPressureSamplingPoints"] = generatedPointsJson; resMonitoringJson["importedPressureSamplingPoints"] = importedPointsJson; + + resMonitoringJson["monitorVTKPlane"] = monitorVTKPlane->isChecked(); + + QJsonArray vtkPlanes; + for(int row=0; row < vtkSampleTable->rowCount(); row++) + { + QJsonObject vtkPlane = QJsonObject(); + + vtkPlane["name"] = vtkSampleTable->item(row, 0)->text(); + + QComboBox* axisName = dynamic_cast(vtkSampleTable->cellWidget(row, 1)); + vtkPlane["normalAxis"] = axisName->currentText(); + + vtkPlane["pointX"] = vtkSampleTable->item(row, 2)->text().toDouble(); + vtkPlane["pointY"] = vtkSampleTable->item(row, 3)->text().toDouble(); + vtkPlane["pointZ"] = vtkSampleTable->item(row, 4)->text().toDouble(); + vtkPlane["startTime"] = vtkSampleTable->item(row, 5)->text().toDouble(); + vtkPlane["endTime"] = vtkSampleTable->item(row, 6)->text().toDouble(); + + QComboBox* fieldName = dynamic_cast(vtkSampleTable->cellWidget(row, 7)); + vtkPlane["field"] = fieldName->currentText(); + + vtkPlanes.append(vtkPlane); + } + resMonitoringJson["vtkPlanes"] = vtkPlanes; + + resMonitoringJson["vtkWriteInterval"] = vtkWriteInterval->value(); + + jsonObject["resultMonitoring"] = resMonitoringJson; return true; @@ -838,6 +956,48 @@ bool ResultMonitoringWidget::inputFromJSON(QJsonObject &jsonObject) generatedPoints = createSamplingPoints(); importedPoints = importSamplingPointsCSV(); + + //Set vtk planes + QJsonArray vtkPlanes = resMonitoringJson["vtkPlanes"].toArray(); + monitorVTKPlane->setChecked(resMonitoringJson["monitorVTKPlane"].toBool()); + vtkWriteInterval->setValue(resMonitoringJson["vtkWriteInterval"].toInt()); + + initializeVTKTable(vtkPlanes.size()); + + + for (int pi = 0; pi < vtkPlanes.size(); pi++) + { + QJsonObject vtkPlane = vtkPlanes[pi].toObject(); + + vtkSampleTable->item(pi, 0)->setText(vtkPlane["name"].toString()); + + QComboBox* axisName = new QComboBox(); + axisName->addItem("X"); + axisName->addItem("Y"); + axisName->addItem("Z"); + axisName->setToolTip("Axis normal to the plane."); + axisName->setCurrentText(vtkPlane["normalAxis"].toString()); + + vtkSampleTable->setCellWidget(pi, 1, axisName); + + + vtkSampleTable->item(pi, 2)->setText(QString::number(vtkPlane["pointX"].toDouble())); + vtkSampleTable->item(pi, 3)->setText(QString::number(vtkPlane["pointY"].toDouble())); + vtkSampleTable->item(pi, 4)->setText(QString::number(vtkPlane["pointZ"].toDouble())); + vtkSampleTable->item(pi, 5)->setText(QString::number(vtkPlane["startTime"].toDouble())); + vtkSampleTable->item(pi, 6)->setText(QString::number(vtkPlane["endTime"].toDouble())); + + QComboBox* fieldName = new QComboBox(); + fieldName->addItem("Velocity"); + fieldName->addItem("Pressure"); + fieldName->setToolTip("Name of the field to monitor, e.g., velocity or pressure field."); + + fieldName->setCurrentText(vtkPlane["feild"].toString()); + + vtkSampleTable->setCellWidget(pi, 7, fieldName); + } + + return true; } @@ -923,3 +1083,82 @@ QList ResultMonitoringWidget::importSamplingPointsCSV() return points; } + +void ResultMonitoringWidget::initializeVTKTable(int numRows) +{ + const int vtkNumCols = 8; + + vtkSampleTable->setRowCount(numRows); + + vtkSampleTable->setMaximumHeight(150); + + QStringList vtkTitles = {"Name", "Normal", "point-X", "point-Y", "point-Z", "Start Time", "End Time", "Field"}; + + vtkSampleTable->setHorizontalHeaderLabels(vtkTitles); + + for (int i=0; i < vtkNumCols; i++) + { + vtkSampleTable->setColumnWidth(i, vtkSampleTable->size().width()/(vtkNumCols + 0.25)); + + for (int j=0; j < numRows; j++) + { + vtkSampleTable->setItem(j, i, new QTableWidgetItem("")); + } + } +} + + + +void ResultMonitoringWidget::onAddPlaneClicked() +{ + + int rowIndx = vtkSampleTable->rowCount(); + + vtkSampleTable->insertRow(rowIndx); + + QComboBox* axisName = new QComboBox(); + axisName->addItem("X"); + axisName->addItem("Y"); + axisName->addItem("Z"); + axisName->setToolTip("Axis normal to the plane."); + axisName->setCurrentIndex(2); + + QComboBox* fieldName = new QComboBox(); + fieldName->addItem("Velocity"); + fieldName->addItem("Pressure"); + fieldName->setToolTip("Name of the field to monitor, e.g., velocity or pressure field."); + + //Add VTK plane + vtkSampleTable->setItem(rowIndx, 0, new QTableWidgetItem(tr("Plane%1").arg(rowIndx + 1))); + vtkSampleTable->setCellWidget(rowIndx, 1, axisName); + vtkSampleTable->setItem(rowIndx, 2, new QTableWidgetItem("0.0")); + vtkSampleTable->setItem(rowIndx, 3, new QTableWidgetItem("0.0")); + vtkSampleTable->setItem(rowIndx, 4, new QTableWidgetItem(QString::number(mainModel->buildingHeightModelScale()*(2.0/3.0)))); + vtkSampleTable->setItem(rowIndx, 5, new QTableWidgetItem(QString::number(mainModel->getDuration()*0.10))); + vtkSampleTable->setItem(rowIndx, 6, new QTableWidgetItem(QString::number(mainModel->getDuration()*0.20))); + vtkSampleTable->setCellWidget(rowIndx, 7, fieldName); + +} + +void ResultMonitoringWidget::onRemovePlaneClicked() +{ + QItemSelectionModel *selected = vtkSampleTable->selectionModel(); + + if(selected->hasSelection()) + { + for (int i = 0; i selectedRows().size(); i++) + { + vtkSampleTable->removeRow(selected->selectedRows()[i].row()); + } + } +} + + +void ResultMonitoringWidget::onMonitorPlaneChecked(int state) +{ + vtkSampleTable->setEnabled(monitorVTKPlane->isChecked()); + vtkWriteInterval->setEnabled(monitorVTKPlane->isChecked()); + addPlane->setEnabled(monitorVTKPlane->isChecked()); + removePlane->setEnabled(monitorVTKPlane->isChecked()); + showPlane->setEnabled(monitorVTKPlane->isChecked()); +} diff --git a/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.h b/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.h index fad5f6e..a57f874 100644 --- a/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.h +++ b/EVENTS/IsolatedBuildingCFD/ResultMonitoringWidget.h @@ -83,6 +83,9 @@ public slots: void onCreatePressurePointsToggled(bool); void onShowCoordinateOfPointsClicked(); void onOpenCSVFileClicked(); + void onAddPlaneClicked(); + void onRemovePlaneClicked(); + void onMonitorPlaneChecked(int); private: @@ -135,6 +138,16 @@ public slots: QPushButton *openCSVFile; QPushButton *showCoordinateOfPoints; + + QGroupBox *vtkSampleGroup; + QGridLayout *vtkSampleLayout; + QTableWidget *vtkSampleTable; + QSpinBox *vtkWriteInterval; + QCheckBox *monitorVTKPlane; + QPushButton *addPlane; + QPushButton *removePlane; + QPushButton *showPlane; + QString importedPointsPath; QList createSamplingPoints(); @@ -147,6 +160,7 @@ public slots: //Read a block from mesh template Type* findBlock(vtkMultiBlockDataSet* mb, const char* blockName); + void initializeVTKTable(int nVtk); public: diff --git a/EVENTS/IsolatedBuildingCFD/SnappyHexMeshWidget.cpp b/EVENTS/IsolatedBuildingCFD/SnappyHexMeshWidget.cpp index 3550165..5c785c5 100644 --- a/EVENTS/IsolatedBuildingCFD/SnappyHexMeshWidget.cpp +++ b/EVENTS/IsolatedBuildingCFD/SnappyHexMeshWidget.cpp @@ -683,26 +683,26 @@ bool SnappyHexMeshWidget::runExtractSurfaceFeaturesCommand() QString localFoamPath = "/home/openfoam"; QString dockerImage = "openfoam/openfoam10-paraview510"; - QDir homeDir(QDir::homePath()); - QString sourceBash(""); - if (homeDir.exists(".bash_profile")) { - sourceBash = QString("source $HOME/.bash_profile; "); - } else if (homeDir.exists(".bashrc")) { - sourceBash = QString("source $HOME/.bashrc; "); - } else if (homeDir.exists(".zprofile")) { - sourceBash = QString("source $HOME/.zprofile; "); - } else if (homeDir.exists(".zshrc")) { - sourceBash = QString("source $HOME/.zshrc; "); - } else - this->errorMessage( "No .bash_profile, .bashrc, .zprofile or .zshrc file found. This may not find Dakota or OpenSees"); - - commands = sourceBash + " docker run --rm --entrypoint /bin/bash" + QString(" --platform linux/amd64 -v ") + mainModel->caseDir() + QString(":") - +localFoamPath + QString(" ") + dockerImage + QString(" -c \"source /opt/openfoam10/etc/bashrc; surfaceFeatures > log.surfaceFeatures; exit\""); - - qDebug() << commands; - - //Actual command on the terminal - //docker run --rm --entrypoint /bin/bash --platform linux/amd64 -v $HOME/Documents/WE-UQ/LocalWorkdir/openfoam:/home/openfoam openfoam/openfoam9-paraview56 -c "source /opt/openfoam9/etc/bashrc; surfaceFeatures > log.surfaceFeatures; exit" + QDir homeDir(QDir::homePath()); + QString sourceBash(""); + if (homeDir.exists(".bash_profile")) { + sourceBash = QString("source $HOME/.bash_profile; "); + } else if (homeDir.exists(".bashrc")) { + sourceBash = QString("source $HOME/.bashrc; "); + } else if (homeDir.exists(".zprofile")) { + sourceBash = QString("source $HOME/.zprofile; "); + } else if (homeDir.exists(".zshrc")) { + sourceBash = QString("source $HOME/.zshrc; "); + } else + this->errorMessage( "No .bash_profile, .bashrc, .zprofile or .zshrc file found. This may not find Dakota or OpenSees"); + + commands = sourceBash + " docker run --rm --entrypoint /bin/bash" + QString(" --platform linux/amd64 -v ") + mainModel->caseDir() + QString(":") + +localFoamPath + QString(" ") + dockerImage + QString(" -c \"source /opt/openfoam10/etc/bashrc; surfaceFeatures > log.surfaceFeatures; exit\""); + + qDebug() << commands; + + //Actual command on the terminal + //docker run --rm --entrypoint /bin/bash --platform linux/amd64 -v $HOME/Documents/WE-UQ/LocalWorkdir/openfoam:/home/openfoam openfoam/openfoam9-paraview56 -c "source /opt/openfoam9/etc/bashrc; surfaceFeatures > log.surfaceFeatures; exit" #else diff --git a/EVENTS/SurroundedBuildingCFD/SurroundedBuildingCFD.cpp b/EVENTS/SurroundedBuildingCFD/SurroundedBuildingCFD.cpp index a5d85eb..35f121a 100644 --- a/EVENTS/SurroundedBuildingCFD/SurroundedBuildingCFD.cpp +++ b/EVENTS/SurroundedBuildingCFD/SurroundedBuildingCFD.cpp @@ -622,7 +622,16 @@ bool SurroundedBuildingCFD::copyFiles(QString &destDir) { QString caseName = "SurroundedBuildingCFD"; - bool result = this->copyPath(caseDir(), destDir + QDir::separator() + caseName, false); + //Copy each directory in the OF case directory + QStringList foamDirs = {"constant", "system", "0"}; + + bool copyResults = true; + + for(QString dir:foamDirs) + { + qDebug() << "Copying " << dir; + copyResults *= this->copyPath(caseDir() + QDir::separator() + dir, destDir + QDir::separator() + caseName + QDir::separator() + dir, false); + } //Remove the 'constant/polyMesh' directory // Makes it slow to transfer the mesh to DesignSafe @@ -630,13 +639,13 @@ bool SurroundedBuildingCFD::copyFiles(QString &destDir) { QDir polyMeshDir(destDir + QDir::separator() + caseName + QDir::separator() + "constant" + QDir::separator() + "polyMesh"); polyMeshDir.removeRecursively(); - if (result == false) { + if (copyResults == false) { QString errorMessage; errorMessage = "SurroundedBuildingCFD - failed to copy file: " + caseDir() + " to: " + destDir; emit sendFatalMessage(errorMessage); qDebug() << errorMessage; } - return result; + return copyResults; } bool SurroundedBuildingCFD::cleanCase() diff --git a/WorkflowAppWE.cpp b/WorkflowAppWE.cpp index 0f4c8ce..9622d18 100644 --- a/WorkflowAppWE.cpp +++ b/WorkflowAppWE.cpp @@ -227,6 +227,7 @@ WorkflowAppWE::setMainWindow(MainWindowWorkflowApp* window) { EmptyDomainCFD *theEmptyDomain = new EmptyDomainCFD(theRVs); +// QString appName = "simcenter-weuq-openfoam-frontera"; QString appName = "simcenter-weuq-cfd-frontera"; QString appVersion = "1.0.0"; QString machine = "frontera"; @@ -257,6 +258,7 @@ WorkflowAppWE::setMainWindow(MainWindowWorkflowApp* window) { // Add Isolated Building CFD Model Tools // IsolatedBuildingCFD *theIsoBldg = new IsolatedBuildingCFD(theRVs,true); +// QString isoAppName = "simcenter-weuq-openfoam-frontera"; QString isoAppName = "simcenter-weuq-cfd-frontera"; QString isoAppVersion = "1.0.0"; QString isoMachine = "frontera"; From 06ebe4a7c6355f77485d413e6a984817d08a9b49 Mon Sep 17 00:00:00 2001 From: abiyfantaye Date: Mon, 23 Sep 2024 15:55:49 -0700 Subject: [PATCH 2/4] abiy - updates to surrounded building examples --- Examples/weuq-0017/README.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Examples/weuq-0017/README.rst b/Examples/weuq-0017/README.rst index 0364fa3..2e655d0 100644 --- a/Examples/weuq-0017/README.rst +++ b/Examples/weuq-0017/README.rst @@ -334,6 +334,20 @@ Visualizing the CFD Output ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The simulated case directory can be directly accessed on the *DesignSafe* data depot and visualized remotely using Paraview. The following plots show sample visualization of the instantaneous flow field. + +.. raw:: html + +
+ +
+ +.. raw:: html + +
+ +
+ + In :numref:`fig-we17-CFD-result1`, the streamlines of the approaching flow, as it passes around the building, are shown. On the building surface, the calculated pressure coefficients are displayed. It also shows the inside view of the mesh underlying. .. _fig-we17-CFD-result1: From 8197d7d24731ce05d77bb2610411f8387dd10162 Mon Sep 17 00:00:00 2001 From: abiyfantaye Date: Sun, 29 Sep 2024 01:03:55 -0700 Subject: [PATCH 3/4] abiy - updated the json index for surrounded building figures --- Examples/index.json | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Examples/index.json b/Examples/index.json index 800eb4e..a1f8736 100644 --- a/Examples/index.json +++ b/Examples/index.json @@ -308,6 +308,44 @@ }, "tags": [ ] + }, + "weuq-0017": { + "id": "weuq-0017", + "base": "weuq-0017", + "title": "Digital Wind Tunnel III: Wind Loads on a Building with Surroundings", + "doc": [ + "weuq-0017/figures/we17_surrounded_building_demo.png", + "weuq-0017/README.rst", + "weuq-0017/figures/we17_EDP_panel.svg", + "weuq-0017/figures/we17_EVT_BoundaryConditions.svg", + "weuq-0017/figures/we17_EVT_Geometry_tab.svg", + "weuq-0017/figures/we17_EVT_Mesh_EdgeRefinement_tab.svg", + "weuq-0017/figures/we17_EVT_Mesh_RegionalRefinement_tab.svg", + "weuq-0017/figures/we17_EVT_Mesh_Run.svg", + "weuq-0017/figures/we17_EVT_Mesh_SurfaceRefinement_tab.svg", + "weuq-0017/figures/we17_EVT_Mesh_View.svg", + "weuq-0017/figures/we17_EVT_Mesh_tab.svg", + "weuq-0017/figures/we17_EVT_Monitoring.svg", + "weuq-0017/figures/we17_EVT_NumericalSetup.svg", + "weuq-0017/figures/we17_EVT_Start_tab.svg", + "weuq-0017/figures/we17_FEM_panel.svg", + "weuq-0017/figures/we17_GI_panel.svg", + "weuq-0017/figures/we17_MonitorJob.svg", + "weuq-0017/figures/we17_RV_panel.svg", + "weuq-0017/figures/we17_RunJob.svg", + "weuq-0017/figures/we17_SIM_panel.svg", + "weuq-0017/figures/we17_UQ_panel.svg" + ], + "entry_point": "weuq-0017/./input.json", + "summary": "This example demonstrates application of CFD for simulating wind loads on a building with surroundings and estimating the resulting structural responses.", + "logo": "we17_surrounded_building_demo.png", + "published": "2023-09-12T21:30:53.946381-08:00\"", + "categories": { + "Difficulty": "0", + "Simulation": "OpenSees-Simulation" + }, + "tags": [ + ] } }, "categories": { From a43c3b8ac1f61eb00983c7c309f767f630a29d70 Mon Sep 17 00:00:00 2001 From: abiyfantaye Date: Sun, 29 Sep 2024 01:31:23 -0700 Subject: [PATCH 4/4] abiy - updated the numerical example --- Examples/index.json | 2 +- Examples/weuq-0017/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/index.json b/Examples/index.json index a1f8736..98b4412 100644 --- a/Examples/index.json +++ b/Examples/index.json @@ -315,7 +315,7 @@ "title": "Digital Wind Tunnel III: Wind Loads on a Building with Surroundings", "doc": [ "weuq-0017/figures/we17_surrounded_building_demo.png", - "weuq-0017/README.rst", + "weuq-0017/README.rst", "weuq-0017/figures/we17_EDP_panel.svg", "weuq-0017/figures/we17_EVT_BoundaryConditions.svg", "weuq-0017/figures/we17_EVT_Geometry_tab.svg", diff --git a/Examples/weuq-0017/meta.yaml b/Examples/weuq-0017/meta.yaml index cdca5ef..2dc6807 100644 --- a/Examples/weuq-0017/meta.yaml +++ b/Examples/weuq-0017/meta.yaml @@ -1,2 +1,2 @@ -summary: "This example demonstrates the application of a Computational Fluid Dynamics (CFD) based wind load generator using a building with simple box type geometry. The workflow uses a transient CFD-solver for simulation wind loads and evaluates the response the building with uncertainty in the structural properties" +summary: "This example demonstrates a feature that uses Computational Fluid Dynamics (CFD) to simulate transient wind load on a building with idealized surroundings. The workflow uses a transient CFD-solver for simulation wind loads and evaluates the response the building with uncertainty in structural damping" difficulty: 1