From 4a2d7ee79e8a8d645310d7bed7478443185b03c7 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:16:04 -0700 Subject: [PATCH 1/9] azs - move the csv parser function to a shared file that all pelicun classes can use --- PBE.pro | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PBE.pro b/PBE.pro index fe99851..ae21dbe 100644 --- a/PBE.pro +++ b/PBE.pro @@ -78,7 +78,8 @@ SOURCES += main.cpp \ LossModel/LossModelSelection.cpp \ LossModel/HazusGeneralSettingsContainer.cpp \ LossModel/HazusLossModel.cpp \ - LossModel/LossMethod.cpp + LossModel/LossMethod.cpp \ + LossModel/PelicunShared.cpp @@ -104,7 +105,8 @@ HEADERS += \ LossModel/LossModelSelection.h \ LossModel/HazusLossModel.h \ LossModel/HazusGeneralSettingsContainer.h \ - LossModel/LossMethod.h + LossModel/LossMethod.h \ + LossModel/PelicunShared.h RESOURCES += \ images.qrc From c95c82b94dbddc6edd387bbce9679dac36fe8699 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:16:39 -0700 Subject: [PATCH 2/9] azs - extend the list of keywords checked when reading results to accommodate the custom DV feature --- ResultsPelicun.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ResultsPelicun.cpp b/ResultsPelicun.cpp index c4de57f..8625013 100644 --- a/ResultsPelicun.cpp +++ b/ResultsPelicun.cpp @@ -636,13 +636,17 @@ int ResultsPelicun::processResults(QString &inputFileName, resultsToShow.insert("irreparable","Irreparable?"); + resultsToShow.insert("repair_cost","Repair Cost"); resultsToShow.insert("repair_cost-","Repair Cost"); resultsToShow.insert("repair_time","Repair Time"); + resultsToShow.insert("repair_time-","Repair Time"); resultsToShow.insert("repair_time-sequential","Repair Time - sequential"); resultsToShow.insert("repair_time-parallel","Repair Time - parallel"); + resultsToShow.insert("repair_carbon","Embodied Carbon in Repairs"); resultsToShow.insert("repair_carbon-","Embodied Carbon in Repairs"); + resultsToShow.insert("repair_energy","Embodied Energy in Repairs"); resultsToShow.insert("repair_energy-","Embodied Energy in Repairs"); //resultsToShow.insert("injuries/sev1","injuries-1"); @@ -1215,9 +1219,9 @@ QWidget * ResultsPelicun::createSummaryItem2(QString &name, double mean, double stdDev, double logStdDev, double min, double p10, double p50, double p90, double max) { - QStringList probOnly = (QStringList() << "collapsed?" << "red tagged?" << - "irreparable?" << "excessive repair cost?" << - "excessive repair time?"); + QStringList probOnly = (QStringList() << "Collapsed?" << "Red Tagged?" << + "Irreparable?" << "Excessive Repair Cost?" << + "Excessive Repair Time?"); QWidget *item = new QWidget; QHBoxLayout *itemLayout = new QHBoxLayout(); From a1246baf0cb6346cd9c4beb9b764decd75a631e4 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:17:32 -0700 Subject: [PATCH 3/9] azs - remove csv parser function and use the new shared one in the Asset tab --- LossModel/PelicunComponentContainer.cpp | 20 +++++++++++++------- LossModel/PelicunComponentContainer.h | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/LossModel/PelicunComponentContainer.cpp b/LossModel/PelicunComponentContainer.cpp index bba3e64..4af90f2 100644 --- a/LossModel/PelicunComponentContainer.cpp +++ b/LossModel/PelicunComponentContainer.cpp @@ -309,6 +309,7 @@ PelicunComponentContainer::PelicunComponentContainer(QWidget *parent) selectDBLayout->addWidget(databaseCombo, 1); + // export db QPushButton *btnExportDataBase = new QPushButton(); btnExportDataBase->setMinimumWidth(100); btnExportDataBase->setMaximumWidth(100); @@ -683,7 +684,7 @@ PelicunComponentContainer::PelicunComponentContainer(QWidget *parent) //compDetailsFormLayout->addRow(tr("Name: "), compName); */ - // fragility info (temporary location) + // fragility info fragilityViz = new QWebEngineView(); fragilityViz->setMinimumHeight(240); @@ -901,9 +902,9 @@ PelicunComponentContainer::generateFragilityInfo(QString comp_DB_path) QString output_path = workDir + "/resources/fragility_viz/"; - this->statusMessage(python); - this->statusMessage(workDir); - this->statusMessage(output_path); + //this->statusMessage(python); + //this->statusMessage(workDir); + //this->statusMessage(output_path); QProcess proc; QStringList params; @@ -1251,12 +1252,14 @@ int PelicunComponentContainer::updateAvailableComponents(){ QString line = stream.readLine(); QStringList line_list; - this->parseCSVLine(line, line_list); + //this->parseCSVLine(line, line_list); + parseCSVLine(line, line_list, this); QString compName = line_list[0]; if (compName == "ID") { - this->parseCSVLine(line, header); + //this->parseCSVLine(line, header); + parseCSVLine(line, header, this); continue; } @@ -1536,6 +1539,7 @@ PelicunComponentContainer::exportComponentVulnerabilityDB(void) { this->statusMessage(QString("Successfully exported damage and loss database...")); } +/* void PelicunComponentContainer::parseCSVLine(QString &line, QStringList &line_list) { @@ -1585,6 +1589,7 @@ PelicunComponentContainer::parseCSVLine(QString &line, QStringList &line_list) } } } +*/ void PelicunComponentContainer::deleteCompConfig(){ @@ -1666,7 +1671,8 @@ PelicunComponentContainer::loadComponentAssignment(QString filePath) { QString line = stream.readLine(); QStringList line_list; - this->parseCSVLine(line, line_list); + //this->parseCSVLine(line, line_list); + parseCSVLine(line, line_list, this); QString compName = line_list[0]; if (compName == "ID") { diff --git a/LossModel/PelicunComponentContainer.h b/LossModel/PelicunComponentContainer.h index 119e676..d9a1b2c 100644 --- a/LossModel/PelicunComponentContainer.h +++ b/LossModel/PelicunComponentContainer.h @@ -44,6 +44,7 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include #include +#include "PelicunShared.h" #include #include @@ -92,7 +93,7 @@ class PelicunComponentContainer : public SimCenterAppWidget void clearCompGroupWidget(); void retrieveCompGroups(); - void parseCSVLine(QString &line, QStringList &line_list); + //void parseCSVLine(QString &line, QStringList &line_list); public slots: int updateAvailableComponents(); From eac19b27dcc47897d634a8a8c628bab67abc8e5d Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:18:10 -0700 Subject: [PATCH 4/9] azs - use a standard 800 width across all tabs under DL to get a consistent look --- LossModel/PelicunDamageContainer.cpp | 11 ++++++----- LossModel/PelicunDemandContainer.cpp | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/LossModel/PelicunDamageContainer.cpp b/LossModel/PelicunDamageContainer.cpp index 3d76660..e387b4e 100644 --- a/LossModel/PelicunDamageContainer.cpp +++ b/LossModel/PelicunDamageContainer.cpp @@ -58,7 +58,7 @@ PelicunDamageContainer::PelicunDamageContainer(QWidget *parent) : SimCenterAppWidget(parent) { - int maxWidth = 400; + int maxWidth = 800; this->setMaximumWidth(maxWidth); @@ -67,7 +67,7 @@ PelicunDamageContainer::PelicunDamageContainer(QWidget *parent) // Global Vulnerability --------------------------------------------------- QGroupBox *GlobalVulGB = new QGroupBox("Global Vulnerabilities"); - GlobalVulGB->setMaximumWidth(maxWidth); + GlobalVulGB->setMaximumWidth(500); QVBoxLayout *loGV = new QVBoxLayout(GlobalVulGB); @@ -309,7 +309,7 @@ PelicunDamageContainer::PelicunDamageContainer(QWidget *parent) // Data Source ------------------------------------------------------------ QGroupBox *DamageProcessGB = new QGroupBox("Damage Process"); - DamageProcessGB->setMaximumWidth(maxWidth); + //DamageProcessGB->setMaximumWidth(maxWidth); QVBoxLayout *loDP = new QVBoxLayout(DamageProcessGB); @@ -365,8 +365,9 @@ PelicunDamageContainer::PelicunDamageContainer(QWidget *parent) // assemble the widgets --------------------------------------------------- gridLayout->addWidget(GlobalVulGB,0,0); - gridLayout->addWidget(DamageProcessGB,1,0); - gridLayout->setRowStretch(1, 1); + gridLayout->addWidget(DamageProcessGB,0,1); + + gridLayout->setRowStretch(0, 1); this->setLayout(gridLayout); } diff --git a/LossModel/PelicunDemandContainer.cpp b/LossModel/PelicunDemandContainer.cpp index 3fd8305..b035d8c 100644 --- a/LossModel/PelicunDemandContainer.cpp +++ b/LossModel/PelicunDemandContainer.cpp @@ -63,9 +63,9 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PelicunDemandContainer::PelicunDemandContainer(QWidget *parent) : SimCenterAppWidget(parent) { - this->setMaximumWidth(700); + this->setMaximumWidth(800); - int maxWidth = 350; + int maxWidth = 400; collConfig = new QVector* >; truncConfig = new QVector* >; From 31031f2d5dff43463b0983e23a1471bb12dca82b Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:22:15 -0700 Subject: [PATCH 5/9] azs - several updates to the Loss tab (see below) - allow combination of a default database and user defined additional components - allow selection of a subset of decision variables to calculate - display available consequence functions from the default + additional datasets - link replacement consequences to the requested decision variables - only show the appropriate ones in the UI - add a function that initializes the Loss tab UI and variables and apply it every time before a new file is loaded --- LossModel/PelicunLossRepairContainer.cpp | 1060 +++++++++++++++++++--- 1 file changed, 916 insertions(+), 144 deletions(-) diff --git a/LossModel/PelicunLossRepairContainer.cpp b/LossModel/PelicunLossRepairContainer.cpp index a79a449..fbc62d3 100644 --- a/LossModel/PelicunLossRepairContainer.cpp +++ b/LossModel/PelicunLossRepairContainer.cpp @@ -36,6 +36,7 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. // Written: fmckenna, adamzs +#include #include #include #include @@ -49,7 +50,9 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include #include #include +#include #include +#include #include "SimCenterPreferences.h" #include "PelicunLossRepairContainer.h" @@ -57,17 +60,233 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) : SimCenterAppWidget(parent) { + int maxWidth = 800; + this->setMaximumWidth(maxWidth); - int maxWidth = 450; - - this->setMaximumWidth(450); + // initialize the compDB Map + compDB = new QMap* >; gridLayout = new QGridLayout(); + // Loss Database --------------------------------------------------- + + QGroupBox *LossDataGB = new QGroupBox("Component Repair Consequences"); + LossDataGB->setMaximumWidth(500); + + QVBoxLayout *loLDB = new QVBoxLayout(LossDataGB); + + // component data folder + QHBoxLayout *selectDBLayout = new QHBoxLayout(); + + QLabel *lblCDB = new QLabel(); + lblCDB->setText("Database:"); + //lblCDB->setMaximumWidth(150); + //lblCDB->setMinimumWidth(150); + lblCDB->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + selectDBLayout->addWidget(lblCDB); + + // database selection + databaseConseq = new QComboBox(); + databaseConseq->setToolTip(tr("This database defines the component repair consequence functions available for the analysis.")); + databaseConseq->addItem("FEMA P-58",0); + databaseConseq->addItem("Hazus Earthquake",1); + databaseConseq->addItem("None",2); + + databaseConseq->setItemData(0, "Based on the 2nd edition of FEMA P-58", Qt::ToolTipRole); + databaseConseq->setItemData(1, "Based on the Hazus MH 2.1 Earthquake Technical Manual", Qt::ToolTipRole); + databaseConseq->setItemData(2, "None of the built-in databases will be used", Qt::ToolTipRole); + + connect(databaseConseq,SIGNAL(currentIndexChanged(int)),this,SLOT(updateComponentConsequenceDB())); + + selectDBLayout->addWidget(databaseConseq, 1); + + // export db + QPushButton *btnExportDataBase = new QPushButton(); + btnExportDataBase->setMinimumWidth(100); + btnExportDataBase->setMaximumWidth(100); + btnExportDataBase->setText(tr("Export DB")); + connect(btnExportDataBase, SIGNAL(clicked()),this,SLOT(exportConsequenceDB())); + selectDBLayout->addWidget(btnExportDataBase); + + loLDB->addLayout(selectDBLayout); + + // additional component checkbox + + QHBoxLayout *addCompLayout = new QHBoxLayout(); + + addComp = new QCheckBox(); + addComp->setText(""); + QString addCompTT = QString("Complement or replace parts of the database with additional components."); + addComp->setToolTip(addCompTT); + addComp->setChecked(false); + addComp->setTristate(false); + addCompLayout->addWidget(addComp); + + QLabel *lblCompCheck = new QLabel(); + lblCompCheck->setText("Use Additional Components"); + lblCompCheck->setToolTip(addCompTT); + addCompLayout->addWidget(lblCompCheck); + + addCompLayout->addStretch(); + + loLDB->addLayout(addCompLayout); + + // database path + QHBoxLayout *customFolderLayout = new QHBoxLayout(); + + leAdditionalComponentDB = new QLineEdit; + leAdditionalComponentDB->setToolTip(tr("Location of the user-defined component consequence data.")); + customFolderLayout->addWidget(leAdditionalComponentDB, 1); + leAdditionalComponentDB->setVisible(false); + leAdditionalComponentDB->setReadOnly(true); + + btnChooseConsequence = new QPushButton(); + btnChooseConsequence->setMinimumWidth(100); + btnChooseConsequence->setMaximumWidth(100); + btnChooseConsequence->setText(tr("Choose")); + connect(btnChooseConsequence, SIGNAL(clicked()),this,SLOT(chooseConsequenceDataBase())); + customFolderLayout->addWidget(btnChooseConsequence); + btnChooseConsequence->setVisible(false); + + connect(addComp, SIGNAL(stateChanged(int)), this, SLOT(addComponentCheckChanged(int))); + + //connect(databaseConseq, SIGNAL(currentIndexChanged(QString)), this, + // SLOT(DBSelectionChanged(QString))); + + loLDB->addLayout(customFolderLayout); + + loLDB->addStretch(); + + // Consequence type selection ---------------------------------------------- + + QGroupBox *ConseqSelectGB = new QGroupBox(""); + ConseqSelectGB->setMaximumWidth(300); + + QVBoxLayout *loCSel = new QVBoxLayout(ConseqSelectGB); + + QLabel *lblCTypes = new QLabel(); + lblCTypes->setText("Repair Consequence Types"); + lblCTypes->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + loCSel->addWidget(lblCTypes); + + cbCTypeCost = new QCheckBox(); + cbCTypeCost->setText("Repair Cost"); + cbCTypeCost->setChecked(false); + cbCTypeCost->setTristate(false); + cbCTypeCost->setEnabled(false); + loCSel->addWidget(cbCTypeCost); + + cbCTypeTime = new QCheckBox(); + cbCTypeTime->setText("Repair Time"); + cbCTypeTime->setChecked(false); + cbCTypeTime->setTristate(false); + cbCTypeTime->setEnabled(false); + loCSel->addWidget(cbCTypeTime); + + cbCTypeCarbon = new QCheckBox(); + cbCTypeCarbon->setText("Embodied Carbon in Repairs"); + cbCTypeCarbon->setChecked(false); + cbCTypeCarbon->setTristate(false); + cbCTypeCarbon->setEnabled(false); + loCSel->addWidget(cbCTypeCarbon); + + cbCTypeEnergy = new QCheckBox(); + cbCTypeEnergy->setText("Embodied Energy in Repairs"); + cbCTypeEnergy->setChecked(false); + cbCTypeEnergy->setTristate(false); + cbCTypeEnergy->setEnabled(false); + loCSel->addWidget(cbCTypeEnergy); + + loCSel->addStretch(); + + connect(cbCTypeCost, SIGNAL(stateChanged(int)), this, + SLOT(cTypeSetupChanged(int))); + + connect(cbCTypeTime, SIGNAL(stateChanged(int)), this, + SLOT(cTypeSetupChanged(int))); + + connect(cbCTypeCarbon, SIGNAL(stateChanged(int)), this, + SLOT(cTypeSetupChanged(int))); + + connect(cbCTypeEnergy, SIGNAL(stateChanged(int)), this, + SLOT(cTypeSetupChanged(int))); + + // Consequence info ----------------------------------------------------- + + QGroupBox *compDetailsGroupBox = new QGroupBox(""); + + QVBoxLayout *loCDetails = new QVBoxLayout(compDetailsGroupBox); + + QLabel *lblCModels = new QLabel(); + lblCModels->setText("Available Consequence Models"); + lblCModels->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + loCDetails->addWidget(lblCModels); + + // select component and consequence type + QHBoxLayout *selectedCLayout = new QHBoxLayout(); + + QLabel *lblSelectedComp = new QLabel(); + lblSelectedComp->setText("Component:"); + lblSelectedComp->setMaximumWidth(70); + lblSelectedComp->setMinimumWidth(70); + lblSelectedComp->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + selectedCLayout->addWidget(lblSelectedComp); + + selectedCompCombo = new QComboBox(); + selectedCompCombo->setMinimumWidth(150); + selectedCBModel = new QStringListModel(); + selectedCompCombo->setModel(selectedCBModel); + selectedCompCombo->setToolTip(tr("List of available components in the selected databases.")); + connect(selectedCompCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(showSelectedComponent())); + selectedCLayout->addWidget(selectedCompCombo); + + QLabel *lblSelectedCType = new QLabel(); + lblSelectedCType->setText("Consequence Type:"); + lblSelectedCType->setMaximumWidth(150); + lblSelectedCType->setMinimumWidth(150); + lblSelectedCType->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + selectedCLayout->addWidget(lblSelectedCType); + + selectedCType = new QComboBox(); + selectedCType->setMinimumWidth(150); + //selectedCTypeModel = new QStringListModel(); + //selectedCType->setModel(selectedCTypeModel); + selectedCType->setToolTip(tr("List of available consequence types for the selected component.")); + connect(selectedCType,SIGNAL(currentIndexChanged(int)),this,SLOT(showSelectedCType())); + selectedCLayout->addWidget(selectedCType); + + selectedCLayout->addStretch(); + + loCDetails->addLayout(selectedCLayout); + + // Additional info + QHBoxLayout *loCDInfo = new QHBoxLayout(); + + compInfo = new QLabel(); + compInfo->setWordWrap(true); + compInfo->setText(""); + loCDInfo->addWidget(compInfo, 1); + + loCDetails->addLayout(loCDInfo); + + // consequence info + + consequenceViz = new QWebEngineView(); + consequenceViz->setMinimumHeight(320); + consequenceViz->setMaximumHeight(320); + consequenceViz->page()->setBackgroundColor(Qt::transparent); + //consequenceViz->page()->setBackgroundColor(Qt::red); + consequenceViz->setHtml(""); + consequenceViz->setVisible(false); + // sy - **NOTE** QWebEngineView display is VERY SLOW when the app is built in debug mode + // Max size of figure is limited to 2MB + loCDetails->addWidget(consequenceViz, 0); + + // Global Consequences --------------------------------------------- QGroupBox *GlobalCsqGB = new QGroupBox("Global Consequences"); - GlobalCsqGB->setMaximumWidth(maxWidth); + GlobalCsqGB->setMaximumWidth(500); QVBoxLayout *loGC = new QVBoxLayout(GlobalCsqGB); @@ -109,8 +328,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) QLabel *lblReplacementUnit = new QLabel(); lblReplacementUnit->setText("Unit"); - lblReplacementUnit->setMaximumWidth(75); - lblReplacementUnit->setMinimumWidth(75); + lblReplacementUnit->setMaximumWidth(85); + lblReplacementUnit->setMinimumWidth(85); loReplacementHeader->addWidget(lblReplacementUnit); QLabel *lblReplacementMedian = new QLabel(); @@ -142,7 +361,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) // - - - - Cost - QHBoxLayout * loReplacementCostValues = new QHBoxLayout(); + repCostSettings = new QWidget(); + QHBoxLayout * loReplacementCostValues = new QHBoxLayout(repCostSettings); loReplacementCostValues->setMargin(0); QLabel *lblCost = new QLabel(); @@ -157,8 +377,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) "is consistent with the repair cost unit used in the chosen\n" "component loss database.\n" "FEMA P-58 uses \"USD_2011\";\n")); - repCostUnit->setMaximumWidth(75); - repCostUnit->setMinimumWidth(75); + repCostUnit->setMaximumWidth(85); + repCostUnit->setMinimumWidth(85); repCostUnit->setText(""); repCostUnit->setAlignment(Qt::AlignRight); loReplacementCostValues->addWidget(repCostUnit); @@ -200,11 +420,13 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) loReplacementCostValues->setSpacing(10); //loGC->addLayout(loReplacementCostValues); - loRepSetV->addLayout(loReplacementCostValues); + //loRepSetV->addLayout(loReplacementCostValues); + loRepSetV->addWidget(repCostSettings); // - - - - Time - QHBoxLayout * loReplacementTimeValues = new QHBoxLayout(); + repTimeSettings = new QWidget(); + QHBoxLayout * loReplacementTimeValues = new QHBoxLayout(repTimeSettings); loReplacementTimeValues->setMargin(0); QLabel *lblTime = new QLabel(); @@ -219,8 +441,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) "is consistent with the repair time unit used in the chosen\n" "component loss database.\n" "FEMA P-58 uses \"worker_day\";\n")); - repTimeUnit->setMaximumWidth(75); - repTimeUnit->setMinimumWidth(75); + repTimeUnit->setMaximumWidth(85); + repTimeUnit->setMinimumWidth(85); repTimeUnit->setText(""); repTimeUnit->setAlignment(Qt::AlignRight); loReplacementTimeValues->addWidget(repTimeUnit); @@ -262,11 +484,13 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) loReplacementTimeValues->setSpacing(10); //loGC->addLayout(loReplacementTimeValues); - loRepSetV->addLayout(loReplacementTimeValues); + //loRepSetV->addLayout(loReplacementTimeValues); + loRepSetV->addWidget(repTimeSettings); // - - - - Carbon - QHBoxLayout * loReplacementCarbonValues = new QHBoxLayout(); + repCarbonSettings = new QWidget(); + QHBoxLayout * loReplacementCarbonValues = new QHBoxLayout(repCarbonSettings); loReplacementCarbonValues->setMargin(0); QLabel *lblCarbon = new QLabel(); @@ -281,8 +505,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) "Make sure the specified unit is consistent with the one chosen\n" "for repair carbon emissions in the component loss database.\n" "FEMA P-58 uses \"kg\";\n")); - repCarbonUnit->setMaximumWidth(75); - repCarbonUnit->setMinimumWidth(75); + repCarbonUnit->setMaximumWidth(85); + repCarbonUnit->setMinimumWidth(85); repCarbonUnit->setText(""); repCarbonUnit->setAlignment(Qt::AlignRight); loReplacementCarbonValues->addWidget(repCarbonUnit); @@ -323,11 +547,13 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) loReplacementCarbonValues->addStretch(); loReplacementCarbonValues->setSpacing(10); - loRepSetV->addLayout(loReplacementCarbonValues); + //loRepSetV->addLayout(loReplacementCarbonValues); + loRepSetV->addWidget(repCarbonSettings); // - - - - Energy - QHBoxLayout * loReplacementEnergyValues = new QHBoxLayout(); + repEnergySettings = new QWidget(); + QHBoxLayout * loReplacementEnergyValues = new QHBoxLayout(repEnergySettings); loReplacementEnergyValues->setMargin(0); QLabel *lblEnergy = new QLabel(); @@ -342,8 +568,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) "Make sure the specified unit is consistent with the one chosen\n" "for repair embodied energy in the component loss database.\n" "FEMA P-58 uses \"MJ\";\n")); - repEnergyUnit->setMaximumWidth(75); - repEnergyUnit->setMinimumWidth(75); + repEnergyUnit->setMaximumWidth(85); + repEnergyUnit->setMinimumWidth(85); repEnergyUnit->setText(""); repEnergyUnit->setAlignment(Qt::AlignRight); loReplacementEnergyValues->addWidget(repEnergyUnit); @@ -384,78 +610,21 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) loReplacementEnergyValues->addStretch(); loReplacementEnergyValues->setSpacing(10); - loRepSetV->addLayout(loReplacementEnergyValues); + //loRepSetV->addLayout(loReplacementEnergyValues); + loRepSetV->addWidget(repEnergySettings); loGC->addWidget(replacementSettings); + loGC->addStretch(); + connect(replacementCheck, SIGNAL(stateChanged(int)), this, SLOT(replacementCheckChanged(int))); this->replacementCheckChanged(replacementCheck->checkState()); - // Loss Database --------------------------------------------------- - - QGroupBox *LossDataGB = new QGroupBox("Database"); - LossDataGB->setMaximumWidth(maxWidth); - - QVBoxLayout *loLDB = new QVBoxLayout(LossDataGB); - - // component data folder - QHBoxLayout *selectDBLayout = new QHBoxLayout(); - - QLabel *lblCDB = new QLabel(); - lblCDB->setText("Consequence Data:"); - lblCDB->setMaximumWidth(150); - lblCDB->setMinimumWidth(150); - selectDBLayout->addWidget(lblCDB); - - // database selection - databaseConseq = new QComboBox(); - databaseConseq->setToolTip(tr("This database defines the consequence functions available for the analysis.")); - databaseConseq->addItem("FEMA P-58",0); - databaseConseq->addItem("Hazus Earthquake",1); - databaseConseq->addItem("User Defined",2); - - databaseConseq->setItemData(0, "Based on the 2nd edition of FEMA P-58", Qt::ToolTipRole); - databaseConseq->setItemData(1, "Based on the Hazus MH 2.1 Earthquake Technical Manual", Qt::ToolTipRole); - databaseConseq->setItemData(2, "Custom database provided by the user", Qt::ToolTipRole); - - selectDBLayout->addWidget(databaseConseq, 0); - - QPushButton *btnExportDataBase = new QPushButton(); - btnExportDataBase->setMinimumWidth(100); - btnExportDataBase->setMaximumWidth(100); - btnExportDataBase->setText(tr("Export DB")); - connect(btnExportDataBase, SIGNAL(clicked()),this,SLOT(exportConsequenceDB())); - selectDBLayout->addWidget(btnExportDataBase); - - loLDB->addLayout(selectDBLayout); - - // database path - QHBoxLayout *customFolderLayout = new QHBoxLayout(); - - consequenceDataBasePath = new QLineEdit; - consequenceDataBasePath->setToolTip(tr("Location of the user-defined consequence data.")); - customFolderLayout->addWidget(consequenceDataBasePath, 1); - consequenceDataBasePath->setVisible(false); - consequenceDataBasePath->setEnabled(false); - - btnChooseConsequence = new QPushButton(); - btnChooseConsequence->setMinimumWidth(100); - btnChooseConsequence->setMaximumWidth(100); - btnChooseConsequence->setText(tr("Choose")); - connect(btnChooseConsequence, SIGNAL(clicked()),this,SLOT(chooseConsequenceDataBase())); - customFolderLayout->addWidget(btnChooseConsequence); - btnChooseConsequence->setVisible(false); - - connect(databaseConseq, SIGNAL(currentIndexChanged(QString)), this, - SLOT(DBSelectionChanged(QString))); - - loLDB->addLayout(customFolderLayout); - // Loss Mapping --------------------------------------------------- QGroupBox *LossMappingGB = new QGroupBox("Mapping"); - LossMappingGB->setMaximumWidth(maxWidth); + LossMappingGB->setMaximumWidth(300); QVBoxLayout *loMAP = new QVBoxLayout(LossMappingGB); @@ -463,8 +632,8 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) QLabel *lblMAPApproach = new QLabel(); lblMAPApproach->setText("Approach:"); - lblMAPApproach->setMaximumWidth(100); - lblMAPApproach->setMinimumWidth(100); + //lblMAPApproach->setMaximumWidth(100); + //lblMAPApproach->setMinimumWidth(100); selectMAPLayout->addWidget(lblMAPApproach); // approach selection @@ -506,27 +675,44 @@ PelicunLossRepairContainer::PelicunLossRepairContainer(QWidget *parent) // assemble the widgets --------------------------------------------------- - gridLayout->addWidget(GlobalCsqGB,0,0); - gridLayout->addWidget(LossDataGB,1,0); - gridLayout->addWidget(LossMappingGB,2,0); + gridLayout->addWidget(LossDataGB,0,0); + gridLayout->addWidget(ConseqSelectGB,0,1); + gridLayout->addWidget(compDetailsGroupBox,1,0,1,2); + gridLayout->addWidget(GlobalCsqGB,2,0); + gridLayout->addWidget(LossMappingGB,2,1); + + gridLayout->setRowStretch(2, 1); this->setLayout(gridLayout); + this-> updateComponentConsequenceDB(); } PelicunLossRepairContainer::~PelicunLossRepairContainer() {} void -PelicunLossRepairContainer::DBSelectionChanged(const QString &arg1) +PelicunLossRepairContainer::addComponentCheckChanged(int newState) { - if (arg1 == QString("User Defined")) { - consequenceDataBasePath->setVisible(true); + if (newState == 2) { + leAdditionalComponentDB->setVisible(true); btnChooseConsequence->setVisible(true); } else { - consequenceDataBasePath->setVisible(false); + leAdditionalComponentDB->setVisible(false); btnChooseConsequence->setVisible(false); } + + this->updateComponentConsequenceDB(); +} + +int +PelicunLossRepairContainer::setAdditionalComponentDB(QString additionalComponentDB_path){ + + leAdditionalComponentDB->setText(additionalComponentDB_path); + if (addComp->checkState() != 2){ + addComp->setChecked(true); + } + return 0; } void @@ -534,11 +720,511 @@ PelicunLossRepairContainer::chooseConsequenceDataBase(void) { QString appDir = SimCenterPreferences::getInstance()->getAppDir(); - QString consequenceDataBase; - consequenceDataBase = + QString additionalComponentDB_path; + additionalComponentDB_path = QFileDialog::getOpenFileName(this, tr("Select Database CSV File"), appDir); - consequenceDataBasePath->setText(consequenceDataBase); + this->setAdditionalComponentDB(additionalComponentDB_path); + + this->updateComponentConsequenceDB(); +} + +void +PelicunLossRepairContainer::updateComponentConsequenceDB(){ + + bool cmpDataChanged = false; + + // check the component consequence database set in the combo box + QString appDir = SimCenterPreferences::getInstance()->getAppDir(); + + QString cmpConsequenceDB_tmp; + + if (databaseConseq->currentText() == "FEMA P-58") { + + cmpConsequenceDB_tmp = appDir + + "/applications/performDL/pelicun3/pelicun/resources/bldg_repair_DB_FEMA_P58_2nd.csv"; + + } else if (databaseConseq->currentText() == "Hazus Earthquake") { + + cmpConsequenceDB_tmp = appDir + + "/applications/performDL/pelicun3/pelicun/resources/bldg_repair_DB_Hazus_EQ.csv"; + + } else { + + cmpConsequenceDB_tmp = ""; + + } + + // check if the component consequence database has changed + if (cmpConsequenceDB != cmpConsequenceDB_tmp) + { + cmpDataChanged = true; + cmpConsequenceDB = cmpConsequenceDB_tmp; + + if (cmpConsequenceDB != "") + { + this->statusMessage("Updating component consequence list with " + + QString(databaseConseq->currentText()) + + " data from "+ cmpConsequenceDB); + + // load the visualization path too + // (assume that we have a zip file for every bundled DB) + cmpConsequenceDB_viz = cmpConsequenceDB; + cmpConsequenceDB_viz.chop(4); + cmpConsequenceDB_viz = cmpConsequenceDB_viz + QString(".zip"); + + } else { + this->statusMessage("Removing built-in component consequence data from the list."); + + cmpConsequenceDB_viz = cmpConsequenceDB; + } + } + + // check if there is additional component data prescribed in the line edit + QString additionalComponentDB_tmp; + if (addComp->checkState() == 2) + { + additionalComponentDB_tmp = leAdditionalComponentDB->text(); + } else { + additionalComponentDB_tmp = ""; + } + + // check if this additional data is new + if (additionalComponentDB != additionalComponentDB_tmp) + { + cmpDataChanged = true; + additionalComponentDB = additionalComponentDB_tmp; + + if (additionalComponentDB != "") + { + this->statusMessage("Updating component consequence list with data from" + additionalComponentDB); + additionalComponentDB_viz = generateConsequenceInfo(additionalComponentDB); + } else { + this->statusMessage("Removing additional component consequence data from the list."); + additionalComponentDB_viz = ""; + } + } + + if (cmpDataChanged == true) + this->updateAvailableComponents(); +} + +QString +PelicunLossRepairContainer::generateConsequenceInfo(QString comp_DB_path) +{ + + SimCenterPreferences *preferences = SimCenterPreferences::getInstance(); + QString python = preferences->getPython(); + QString workDir = preferences->getLocalWorkDir(); + QString appDir = preferences->getAppDir(); + + QString output_path = workDir + "/resources/consequence_viz/"; + + this->statusMessage(python); + this->statusMessage(workDir); + this->statusMessage(output_path); + + QProcess proc; + QStringList params; + + params << appDir + "/applications/performDL/pelicun3/" + "DL_visuals.py" << "repair" << comp_DB_path << "--output_path" << output_path; + + proc.start(python, params); + proc.waitForFinished(-1); + + this->statusMessage(proc.readAllStandardOutput()); + this->errorMessage(proc.readAllStandardError()); + + return output_path; +} + +void +PelicunLossRepairContainer::deleteCompDB(){ + + qDeleteAll(compDB->begin(), compDB->end()); + compDB->clear(); + delete compDB; +} + +int +PelicunLossRepairContainer::updateAvailableComponents(){ + + this->statusMessage("Updating list of available component consequences..."); + + // initialize component combo + selectedCompCombo->clear(); + + // initialize ctype combo + selectedCType->clear(); + + QString componentDataBase; + QStringList compIDs; + + QStringList availableCTypes; + + QVector qvComp; + + //initialize the component map + deleteCompDB(); + compDB = new QMap* >; + + for (int db_i=0; db_i<2; db_i++) + { + if (db_i==0){ + componentDataBase = cmpConsequenceDB; + } else if (db_i==1) { + componentDataBase = additionalComponentDB; + } + + if (componentDataBase==""){ + continue; + } + + if (componentDataBase.endsWith("csv")) { + + //this->statusMessage("Parsing component consequence data file..."); + + QFile csvFile(componentDataBase); + + componentDataBase.chop(4); + QFile jsonFile(componentDataBase+QString(".json")); + + if (csvFile.open(QIODevice::ReadOnly)) + { + + QStringList header; + + // open the JSON file to get the metadata + QJsonObject metaData; + bool hasMeta = false; + if (jsonFile.open(QFile::ReadOnly | QFile::Text)){ + QString val = jsonFile.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(val.toUtf8()); + metaData = doc.object(); + jsonFile.close(); + hasMeta = true; + } + + // start the CSV stream + QTextStream stream(&csvFile); + + int counter = 0; + while (!stream.atEnd()) { + counter ++; + + QString line = stream.readLine(); + QStringList line_list; + + parseCSVLine(line, line_list, this); + + QString compName = line_list[0]; + + if (compName == "ID") { + parseCSVLine(line, header, this); + continue; + } + + QStringList compNameParts = compName.split(QRegularExpression("-")); + compName = compNameParts[0]; + QString cType = compNameParts[1]; + + QMap* C_info; + if (compIDs.contains(compName)){ + // Get the existing C_info dict from the compDB + C_info = compDB->value(compName); + } + else { + compIDs << compName; + // Create a new C_info dict and add it to the compDB dict + C_info = new QMap; + compDB->insert(compName, C_info); + } + + // Then fill the C_info with the info from the DL DB + for (int i=0; i insert(cType+header[i], line_list[i]); + } + } + + // Store the consequence types available with this component + QStringList cTypeList; + QString cTypes; + if (C_info->contains("cTypes")){ + cTypes = C_info->value("cTypes"); + cTypeList = cTypes.split(QRegularExpression("-")); + } + + if (!cTypeList.contains(cType)){ + cTypeList.append(cType); + cTypes = cTypeList.join(QString("-")); + C_info -> insert("cTypes", cTypes); + + // update available ctypes + if (!availableCTypes.contains(cType)){ + availableCTypes.append(cType); + } + } + + // and add info from metaData + if (hasMeta){ + if (metaData.contains(compName)) { + QJsonObject compMetaData = metaData[compName].toObject(); + + // Description + if (compMetaData.contains("Description")){ + + QString description = compMetaData["Description"].toString(); + + if (compMetaData.contains("Comments")){ + description += "\n" + compMetaData["Comments"].toString(); + } + + C_info -> insert("Description", description); + } else { + C_info -> insert("Description", ""); + } + + // Block size + if (compMetaData.contains("ControllingDemand")){ + QString blockSize = compMetaData["ControllingDemand"].toString(); + C_info -> insert("ControllingDemand", blockSize); + } else { + C_info -> insert("ControllingDemand", QString("N/A")); + } + } + } + + } + + csvFile.close(); + + } else { + this->errorMessage("Cannot open CSV file."); + return 1; + } + + //this->statusMessage("Successfully parsed CSV file."); + + } else { + this->errorMessage("Component data file is not in CSV format."); + return 1; + } + } + + compIDs.sort(); + selectedCompCombo->addItems(compIDs); + + // update ctype checkboxes + // when the availability of a ctype changes, we turn and check the boxes + if (availableCTypes.contains("Cost")){ + + if (!cbCTypeCost->isEnabled()){ + cbCTypeCost->setChecked(true); + cbCTypeCost->setEnabled(true); + } + } else { + + if (cbCTypeCost->isEnabled()){ + cbCTypeCost->setChecked(false); + cbCTypeCost->setEnabled(false); + } + } + + if (availableCTypes.contains("Time")){ + + if (!cbCTypeTime->isEnabled()){ + cbCTypeTime->setChecked(true); + cbCTypeTime->setEnabled(true); + } + } else { + + if (cbCTypeTime->isEnabled()){ + cbCTypeTime->setChecked(false); + cbCTypeTime->setEnabled(false); + } + } + + if (availableCTypes.contains("Carbon")){ + + if (!cbCTypeCarbon->isEnabled()){ + cbCTypeCarbon->setChecked(true); + cbCTypeCarbon->setEnabled(true); + } + } else { + + if (cbCTypeCarbon->isEnabled()){ + cbCTypeCarbon->setChecked(false); + cbCTypeCarbon->setEnabled(false); + } + } + + if (availableCTypes.contains("Energy")){ + + if (!cbCTypeEnergy->isEnabled()){ + cbCTypeEnergy->setChecked(true); + cbCTypeEnergy->setEnabled(true); + } + } else { + + if (cbCTypeEnergy->isEnabled()){ + cbCTypeEnergy->setChecked(false); + cbCTypeEnergy->setEnabled(false); + } + } + + return 0; +} + +void +PelicunLossRepairContainer::showSelectedComponent(){ + + if ((selectedCompCombo->count() > 0) && + (selectedCompCombo->currentText() != "") && + (compDB->contains(selectedCompCombo->currentText()))){ + + selectedCType->clear(); + + QString compID = selectedCompCombo->currentText(); + + QMap* C_info = compDB->value(compID); + + // assign the consequence types to the other combobox + + QString cTypes = C_info->value("cTypes"); + QStringList cTypeList = cTypes.split(QRegularExpression("-")); + + cTypeList.sort(); + selectedCType->addItems(cTypeList); + } + + this->updateComponentInfo(); +} + +void +PelicunLossRepairContainer::showSelectedCType(){ + + this->updateComponentInfo(); +} + +void +PelicunLossRepairContainer::updateComponentInfo(){ + + if ((selectedCompCombo->count() > 0) && + (selectedCompCombo->currentText() != "") && + (compDB->contains(selectedCompCombo->currentText()))){ + + // Start with the metadata + + QString compID = selectedCompCombo->currentText(); + QString cType = selectedCType->currentText(); + + QMap* C_info = compDB->value(compID); + + QString infoString = ""; + infoString += C_info->value("Description"); + infoString += "\nControlling Demand: " + C_info->value("ControllingDemand"); + + if (C_info->value("Incomplete") == "1") { + infoString += "\n\nINCOMPLETE DATA!"; + } + + compInfo->setText(infoString); + + consequenceViz->hide(); + consequenceViz->setVisible(false); // don't worry, we'll set it to true later, if needed + + // Then load the vulnerability model visualization + + QString vizDatabase; + for (int db_i=1; db_i>=0; db_i--) + { + if (db_i==0){ + vizDatabase = cmpConsequenceDB_viz; + } else if (db_i==1) { + vizDatabase = additionalComponentDB_viz; + } + + if (vizDatabase==""){ + continue; + } + + //this->statusMessage("Loading figure from "+vizDatabase); + + QString htmlString; + if (vizDatabase.endsWith("zip")) { + + QuaZip componentDBZip(vizDatabase); + + if (!componentDBZip.open(QuaZip::mdUnzip)) { + this->errorMessage(QString( + "Error while trying to open figure zip file")); + } + + if (!componentDBZip.setCurrentFile(compID+"-"+cType+".html")) { + this->statusMessage(QString("Cannot find figure for component ") + + compID+"-"+cType + " in " + vizDatabase); + continue; // hoping that the component is in the other DB + } + + QuaZipFile inFile(&componentDBZip); + if (!inFile.open(QIODevice::ReadOnly)) { + this->errorMessage(QString( + "Error while trying to open figure for component " + + compID+"-"+cType)); + } else { + QTextStream ts(&inFile); + htmlString = ts.readAll(); + inFile.close(); + } + + componentDBZip.close(); + + } else { + + // we assume that in every other case the viz DB points to a directory + + QFile inFile(vizDatabase + compID+"-"+cType + ".html"); + + if (!inFile.exists()){ + continue; + } + + if (!inFile.open(QIODevice::ReadOnly)) { + this->errorMessage(QString( + "Error while trying to open figure for component " + + compID+"-"+cType)); + } else { + QTextStream ts(&inFile); + htmlString = ts.readAll(); + inFile.close(); + } + } + + consequenceViz->setHtml(htmlString, + QUrl::fromUserInput("/Users/")); + // Zoom factor has a bug in Qt, below is a workaround + QObject::connect( + consequenceViz, &QWebEngineView::loadFinished, + [=](bool arg) { + consequenceViz->setZoomFactor(0.75); + consequenceViz->show(); + consequenceViz->setVisible(true); + }); + + break; // so that we do not check the following databases for the same component + } + + } else { + + // Initialize the description fields and hide them if the combo is empty. + compInfo->setText(""); + + consequenceViz->hide(); + consequenceViz->setVisible(false); + } + + } void @@ -555,7 +1241,7 @@ PelicunLossRepairContainer::exportConsequenceDB(void) { qDebug() << QString("Exporting consequence database..."); // copy the db file(s) to the desired location - QFileInfo fi = consequenceDataBasePath->text(); + QFileInfo fi = leAdditionalComponentDB->text(); // get the filenames QString csvFileName = fi.fileName(); @@ -613,6 +1299,35 @@ PelicunLossRepairContainer::replacementCheckChanged(int newState) } } +void +PelicunLossRepairContainer::cTypeSetupChanged(int newState) +{ + if (cbCTypeCost->isChecked()){ + repCostSettings->show(); + } else { + repCostSettings->hide(); + } + + if (cbCTypeTime->isChecked()){ + repTimeSettings->show(); + } else { + repTimeSettings->hide(); + } + + if (cbCTypeCarbon->isChecked()){ + repCarbonSettings->show(); + } else { + repCarbonSettings->hide(); + } + + if (cbCTypeEnergy->isChecked()){ + repEnergySettings->show(); + } else { + repEnergySettings->hide(); + } + +} + void PelicunLossRepairContainer::chooseMAP(void) { @@ -633,7 +1348,8 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { if (replacementCheck->isChecked()) { - if (repCostMedian->text() != QString("")) { + if ((cbCTypeCost->isChecked()) && + (repCostMedian->text() != QString(""))) { QJsonObject costData; @@ -648,7 +1364,8 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { lossData["ReplacementCost"] = costData; } - if (repTimeMedian->text() != QString("")) { + if ((cbCTypeTime->isChecked()) && + (repTimeMedian->text() != QString(""))) { QJsonObject timeData; @@ -663,7 +1380,8 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { lossData["ReplacementTime"] = timeData; } - if (repCarbonMedian->text() != QString("")) { + if ((cbCTypeCarbon->isChecked()) && + (repCarbonMedian->text() != QString(""))) { QJsonObject CarbonData; @@ -678,7 +1396,8 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { lossData["ReplacementCarbon"] = CarbonData; } - if (repEnergyMedian->text() != QString("")) { + if ((cbCTypeEnergy->isChecked()) && + (repEnergyMedian->text() != QString(""))) { QJsonObject EnergyData; @@ -694,10 +1413,19 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { } } + QJsonObject decisionVariables; + + decisionVariables["Cost"] = cbCTypeCost->isChecked(); + decisionVariables["Time"] = cbCTypeTime->isChecked(); + decisionVariables["Carbon"] = cbCTypeCarbon->isChecked(); + decisionVariables["Energy"] = cbCTypeEnergy->isChecked(); + + lossData["DecisionVariables"] = decisionVariables; + lossData["ConsequenceDatabase"] = databaseConseq->currentText(); - if (databaseConseq->currentText() == "User Defined") { - lossData["ConsequenceDatabasePath"] = consequenceDataBasePath->text(); + if ((addComp->checkState() == 2) && (additionalComponentDB != "")){ + lossData["ConsequenceDatabasePath"] = additionalComponentDB; } lossData["MapApproach"] = mapApproach->currentText(); @@ -711,13 +1439,97 @@ bool PelicunLossRepairContainer::outputToJSON(QJsonObject &outputObject) { return 0; } +void PelicunLossRepairContainer::initPanel(){ + + replacementCheck->setChecked(false); + + cbCTypeCost->setChecked(false); + cbCTypeTime->setChecked(false); + cbCTypeCarbon->setChecked(false); + cbCTypeEnergy->setChecked(false); + + databaseConseq->setCurrentText("FEMA P-58"); + addComp->setChecked(false); + leAdditionalComponentDB->setText(""); + + this->updateComponentConsequenceDB(); + + repCostUnit->setText(""); + repCostMedian->setText(""); + repCostDistribution->setCurrentText("N/A"); + repCostTheta1->setText(""); + + repTimeUnit->setText(""); + repTimeMedian->setText(""); + repTimeDistribution->setCurrentText("N/A"); + repTimeTheta1->setText(""); + + repCarbonUnit->setText(""); + repCarbonMedian->setText(""); + repCarbonDistribution->setCurrentText("N/A"); + repCarbonTheta1->setText(""); + + repEnergyUnit->setText(""); + repEnergyMedian->setText(""); + repEnergyDistribution->setCurrentText("N/A"); + repEnergyTheta1->setText(""); + + mapApproach->setCurrentText("Automatic"); +} + bool PelicunLossRepairContainer::inputFromJSON(QJsonObject & inputObject) { replacementCheck->setChecked(false); + // initialize the panel + this->initPanel(); + if (inputObject.contains("BldgRepair")) { QJsonObject lossData = inputObject["BldgRepair"].toObject(); + if (lossData.contains("ConsequenceDatabase")) { + + // --- + // this is kept for backward compatibility - drop after PBE 4.0 + QString in_componentDB = lossData["ConsequenceDatabase"].toString(); + + if (in_componentDB == "User Defined") { + in_componentDB = "None"; + } + // --- + + databaseConseq->setCurrentText(in_componentDB); + } + + if (lossData.contains("ConsequenceDatabasePath")){ + this->setAdditionalComponentDB(lossData["ConsequenceDatabasePath"].toString()); + } else { + addComp->setChecked(false); + } + this->updateComponentConsequenceDB(); + + if (lossData.contains("DecisionVariables")){ + + QJsonObject decisionVariables = lossData["DecisionVariables"].toObject(); + + cbCTypeCost->setChecked(decisionVariables["Cost"].toBool()); + cbCTypeTime->setChecked(decisionVariables["Time"].toBool()); + cbCTypeCarbon->setChecked(decisionVariables["Carbon"].toBool()); + cbCTypeEnergy->setChecked(decisionVariables["Energy"].toBool()); + } else { + + // --- + // this is kept for backward compatibility - drop after PBE 4.0 + + cbCTypeCost->setChecked(cbCTypeCost->isEnabled()); + cbCTypeTime->setChecked(cbCTypeTime->isEnabled()); + cbCTypeCarbon->setChecked(cbCTypeCarbon->isEnabled()); + cbCTypeEnergy->setChecked(cbCTypeEnergy->isEnabled()); + + // --- + } + + if ((lossData.contains("ReplacementCost")) || (lossData.contains("ReplacementTime")) || (lossData.contains("ReplacementCarbon")) || @@ -744,13 +1556,6 @@ bool PelicunLossRepairContainer::inputFromJSON(QJsonObject & inputObject) { if (costData.contains("Theta_1")) { repCostTheta1->setText(costData["Theta_1"].toString()); } - } else { - - repCostUnit->setText(""); - repCostMedian->setText(""); - repCostDistribution->setCurrentText(QString("N/A")); - repCostTheta1->setText(""); - } if (lossData.contains("ReplacementTime")) { @@ -765,19 +1570,10 @@ bool PelicunLossRepairContainer::inputFromJSON(QJsonObject & inputObject) { } if (timeData.contains("Distribution")) { repTimeDistribution->setCurrentText(timeData["Distribution"].toString()); - } else { - repTimeDistribution->setCurrentText(QString("N/A")); } if (timeData.contains("Theta_1")) { repTimeTheta1->setText(timeData["Theta_1"].toString()); } - } else { - - repTimeUnit->setText(""); - repTimeMedian->setText(""); - repTimeDistribution->setCurrentText(QString("N/A")); - repTimeTheta1->setText(""); - } if (lossData.contains("ReplacementCarbon")) { @@ -792,18 +1588,10 @@ bool PelicunLossRepairContainer::inputFromJSON(QJsonObject & inputObject) { } if (carbonData.contains("Distribution")) { repCarbonDistribution->setCurrentText(carbonData["Distribution"].toString()); - } else { - repCarbonDistribution->setCurrentText(QString("N/A")); - } + } if (carbonData.contains("Theta_1")) { repCarbonTheta1->setText(carbonData["Theta_1"].toString()); } - } else { - - repCarbonUnit->setText(""); - repCarbonMedian->setText(""); - repCarbonDistribution->setCurrentText(QString("N/A")); - repCarbonTheta1->setText(""); } if (lossData.contains("ReplacementEnergy")) { @@ -818,26 +1606,10 @@ bool PelicunLossRepairContainer::inputFromJSON(QJsonObject & inputObject) { } if (energyData.contains("Distribution")) { repEnergyDistribution->setCurrentText(energyData["Distribution"].toString()); - } else { - repEnergyDistribution->setCurrentText(QString("N/A")); - } + } if (energyData.contains("Theta_1")) { repEnergyTheta1->setText(energyData["Theta_1"].toString()); } - } else { - - repEnergyUnit->setText(""); - repEnergyMedian->setText(""); - repEnergyDistribution->setCurrentText(QString("N/A")); - repEnergyTheta1->setText(""); - } - - if (lossData.contains("ConsequenceDatabase")) { - databaseConseq->setCurrentText(lossData["ConsequenceDatabase"].toString()); - - if (databaseConseq->currentText() == "User Defined"){ - consequenceDataBasePath->setText(lossData["ConsequenceDatabasePath"].toString()); - } } if (lossData.contains("MapApproach")) { From 5dcf11f4bce9545daec9b734e07596f870a1dfc2 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:22:45 -0700 Subject: [PATCH 6/9] azs - updates to the Loss tab - header file --- LossModel/PelicunLossRepairContainer.h | 51 +++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/LossModel/PelicunLossRepairContainer.h b/LossModel/PelicunLossRepairContainer.h index 5fe34a2..e0df892 100644 --- a/LossModel/PelicunLossRepairContainer.h +++ b/LossModel/PelicunLossRepairContainer.h @@ -40,8 +40,13 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. // Written: fmckenna, adamzs #include +#include #include "SimCenterAppWidget.h" +#include "PelicunShared.h" + +#include +#include class QCheckBox; class QComboBox; @@ -52,6 +57,7 @@ class QHBoxLayout; class QRadioButton; class QGridLayout; class QPushButton; +class QStringListModel; /*! * Widget for general loss assessment settings in PBE tool @@ -92,24 +98,49 @@ class PelicunLossRepairContainer : public SimCenterAppWidget */ QString getPelicunLossRepairContainerName() const; + int setAdditionalComponentDB(QString additionalComponentDB); + signals: public slots: + int updateAvailableComponents(); + + void updateComponentInfo(void); + void showSelectedComponent(void); + void showSelectedCType(void); void replacementCheckChanged(int newState); + void cTypeSetupChanged(int newState); + + void addComponentCheckChanged(int newState); void chooseConsequenceDataBase(void); void exportConsequenceDB(void); - void DBSelectionChanged(const QString &arg1); + //void DBSelectionChanged(const QString &arg1); void MAPApproachSelectionChanged(const QString &arg1); + void updateComponentConsequenceDB(); + void chooseMAP(void); private: + void deleteCompDB(); + void initPanel(); + QString generateConsequenceInfo(QString comp_DB_path); + QWidget * replacementSettings; + QWidget * repCostSettings; + QWidget * repTimeSettings; + QWidget * repCarbonSettings; + QWidget * repEnergySettings; + + QString cmpConsequenceDB; + QString additionalComponentDB; + QString cmpConsequenceDB_viz; + QString additionalComponentDB_viz; QLineEdit * repCostUnit; QLineEdit * repCostMedian; @@ -123,7 +154,7 @@ public slots: QLineEdit * repEnergyUnit; QLineEdit * repEnergyMedian; QLineEdit * repEnergyTheta1; - QLineEdit * consequenceDataBasePath; + QLineEdit * leAdditionalComponentDB; QLineEdit * mapPath; QComboBox * repCostDistribution; @@ -132,14 +163,30 @@ public slots: QComboBox * repEnergyDistribution; QComboBox * databaseConseq; QComboBox * mapApproach; + QComboBox * selectedCompCombo; + QStringListModel *selectedCBModel; + QComboBox * selectedCType; QPushButton * btnChooseConsequence; QPushButton * btnChooseMAP; QCheckBox *replacementCheck; + QCheckBox *addComp; + QCheckBox *cbCTypeCost; + QCheckBox *cbCTypeTime; + QCheckBox *cbCTypeCarbon; + QCheckBox *cbCTypeEnergy; + + QLabel *compInfo; + + // component DL information + QMap* > *compDB; QGridLayout *gridLayout; + // Display consequence information + QWebEngineView *consequenceViz; + }; #endif // PelicunLOSS_REPAIR_CONTAINER_H From bd6821209f946fba47b13200a675d4d913fadb7c Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:23:59 -0700 Subject: [PATCH 7/9] azs - update input file for example 1 --- Examples/pbdl-0001/src/input.json | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Examples/pbdl-0001/src/input.json b/Examples/pbdl-0001/src/input.json index ab0c68b..4910278 100644 --- a/Examples/pbdl-0001/src/input.json +++ b/Examples/pbdl-0001/src/input.json @@ -82,10 +82,16 @@ "Losses": { "BldgRepair": { "ConsequenceDatabase": "FEMA P-58", + "DecisionVariables": { + "Carbon": true, + "Cost": true, + "Energy": true, + "Time": true + }, "MapApproach": "Automatic", "ReplacementCarbon": { "Distribution": "normal", - "Median": "10000000", + "Median": "1e7", "Theta_1": "0.3", "Unit": "kg" }, @@ -97,10 +103,10 @@ }, "ReplacementEnergy": { "Distribution": "normal", - "Median": "100000000", + "Median": "1e9", "Theta_1": "0.3", "Unit": "MJ" - }, + }, "ReplacementTime": { "Distribution": "lognormal", "Median": "15000", @@ -187,7 +193,6 @@ "name": "", "planArea": 129600, "stories": 1, - "dampingRatio": 0.02, "units": { "force": "kips", "length": "in", @@ -217,6 +222,7 @@ "weight": 144 } ], + "dampingRatio": 0.02, "height": 144, "massX": 0, "massY": 0, @@ -250,13 +256,12 @@ "seed": 946 }, "saveWorkDir": true, - "uqEngine": "Dakota", "uqType": "Forward Propagation" }, - "localAppDir": "C:/SimCenter/", + "localAppDir": "/Users/adamzs/SimCenter", "randomVariables": [ ], - "remoteAppDir": "C:/SimCenter/", + "remoteAppDir": "/Users/adamzs/SimCenter", "runType": "runningLocal", - "workingDir": "C:/Workdir/PBE" + "workingDir": "/Users/adamzs/Documents/PBE/LocalWorkDir" } From 18c0a6e1226a78b48770989555285d8029491900 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:24:28 -0700 Subject: [PATCH 8/9] azs - update input file for example 2 --- Examples/pbdl-0002/src/input.json | 58 ++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/Examples/pbdl-0002/src/input.json b/Examples/pbdl-0002/src/input.json index 92c02ea..c16d138 100644 --- a/Examples/pbdl-0002/src/input.json +++ b/Examples/pbdl-0002/src/input.json @@ -58,8 +58,44 @@ "Losses": { "BldgRepair": { "ConsequenceDatabase": "Hazus Earthquake", + "DecisionVariables": { + "Carbon": false, + "Cost": true, + "Energy": false, + "Time": true + }, "MapApproach": "Automatic" } + }, + "Outputs": { + "Asset": { + "Sample": true, + "Statistics": true + }, + "Damage": { + "GroupedSample": true, + "GroupedStatistics": true, + "Sample": true, + "Statistics": true + }, + "Demand": { + "Sample": true, + "Statistics": true + }, + "Format": { + "CSV": true, + "JSON": false + }, + "Loss": { + "BldgRepair": { + "AggregateSample": true, + "AggregateStatistics": true, + "GroupedSample": true, + "GroupedStatistics": true, + "Sample": true, + "Statistics": true + } + } } }, "DefaultValues": { @@ -67,14 +103,14 @@ "edpFiles": [ "EDP.json" ], - "filenameBIM": "BIM.json", - "filenameDL": "BIM.json", + "filenameAIM": "AIM.json", + "filenameDL": "AIM.json", "filenameEDP": "EDP.json", "filenameEVENT": "EVENT.json", "filenameSAM": "SAM.json", "filenameSIM": "SIM.json", "rvFiles": [ - "BIM.json", + "AIM.json", "SAM.json", "EVENT.json", "SIM.json" @@ -98,6 +134,8 @@ "GeneralInformation": { "NumberOfStories": 3, "PlanArea": 129600, + "StructureType": "RM1", + "YearBuilt": 1990, "depth": 360, "height": 144, "location": { @@ -158,6 +196,7 @@ "weight": 144 } ], + "dampingRatio": 0.02, "height": 48, "massX": 0, "massY": 0, @@ -175,8 +214,6 @@ "analysis": "Transient -numSubLevels 2 -numSubSteps 10", "convergenceTest": "NormUnbalance 1.0e-2 10", "dampingModel": "Rayleigh Damping", - "dampingRatio": 0.02, - "dampingRatioModal": 0.02, "firstMode": 1, "integration": "Newmark 0.5 0.25", "modalRayleighTangentRatio": 0, @@ -192,10 +229,13 @@ "samples": 40, "seed": 867 }, - "uqEngine": "Dakota", + "saveWorkDir": true, "uqType": "Forward Propagation" }, - "localAppDir": "C:/SimCenter/", + "correlationMatrix": [ + 1 + ], + "localAppDir": "/Users/adamzs/SimCenter", "randomVariables": [ { "distribution": "Normal", @@ -208,7 +248,7 @@ "variableClass": "Uncertain" } ], - "remoteAppDir": "C:/SimCenter/", + "remoteAppDir": "/Users/adamzs/SimCenter", "runType": "runningLocal", - "workingDir": "C:/Workdir/PBE" + "workingDir": "/Users/adamzs/Documents/PBE/LocalWorkDir" } From 0822d80123f97812277c0da025f44601318606b7 Mon Sep 17 00:00:00 2001 From: Adam Zsarnoczay <33822153+zsarnoczay@users.noreply.github.com> Date: Thu, 4 May 2023 19:26:14 -0700 Subject: [PATCH 9/9] azs - new file with shared functions - currently only the csv parser --- LossModel/PelicunShared.cpp | 92 +++++++++++++++++++++++++++++++++++++ LossModel/PelicunShared.h | 50 ++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 LossModel/PelicunShared.cpp create mode 100644 LossModel/PelicunShared.h diff --git a/LossModel/PelicunShared.cpp b/LossModel/PelicunShared.cpp new file mode 100644 index 0000000..4c8b53e --- /dev/null +++ b/LossModel/PelicunShared.cpp @@ -0,0 +1,92 @@ +/* ***************************************************************************** +Copyright (c) 2016-2023, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: adamzs + +#include "PelicunShared.h" + +void +parseCSVLine(QString &line, QStringList &line_list, + SimCenterAppWidget *parent) +{ + // parse the line considering "" and , and \n + bool in_commented_block = false; + bool save_element = false; + int c_0 = 0; + + for (int c=0; cstatusMessage("Error while parsing CSV file at the following line: " + line); + } + } else { + c_0 ++; + c++; + } + } + } + } + } +} \ No newline at end of file diff --git a/LossModel/PelicunShared.h b/LossModel/PelicunShared.h new file mode 100644 index 0000000..a06ed7a --- /dev/null +++ b/LossModel/PelicunShared.h @@ -0,0 +1,50 @@ +#ifndef PELICUN_SHARED_H +#define PELICUN_SHARED_H + +/* ***************************************************************************** +Copyright (c) 2016-2023, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: adamzs + +#include + +class QString; +class QStringList; + +void parseCSVLine(QString &line, QStringList &line_list, + SimCenterAppWidget *parent=nullptr); + +#endif // PELICUN_SHARED_H \ No newline at end of file