diff --git a/EVENTS/ExistingPEER_Records.cpp b/EVENTS/ExistingPEER_Records.cpp index 4c77c247..6b43639c 100644 --- a/EVENTS/ExistingPEER_Records.cpp +++ b/EVENTS/ExistingPEER_Records.cpp @@ -81,7 +81,7 @@ PeerRecord::PeerRecord(RandomVariablesContainer *theRV_IW, QWidget *parent) layout->addWidget(button); layout->addWidget(labelFile); - layout->addWidget(file, 1.0); + layout->addWidget(file,1); layout->addWidget(chooseFile); layout->addWidget(labelDirn); layout->addWidget(dirn); @@ -166,7 +166,7 @@ PeerEvent::PeerEvent(RandomVariablesContainer *theRV_IW, QWidget *parent) //theName->setReadOnly(true); layout->addWidget(button); - layout->addWidget(theName); + layout->addWidget(theName,1); // QVBox Holding Peer Records, could be multiple recordLayout = new QVBoxLayout(); @@ -188,7 +188,7 @@ PeerEvent::PeerEvent(RandomVariablesContainer *theRV_IW, QWidget *parent) theRecords.append(theRecord); // connect(theRecord,SIGNAL(removeRecord()), this, SLOT(onRemoveRecord())); - layout->addLayout(recordLayout, 1.0); + layout->addLayout(recordLayout, 5); //this->setLayout(layout) @@ -445,6 +445,13 @@ void ExistingPEER_Records::loadEventsFromDir(void) { } else { + QString recordsCsv(directory.filePath("_SearchResults.csv")); + QFileInfo checkCsvFile(recordsCsv); + if (checkCsvFile.exists() && checkCsvFile.isFile()) { + this->parseSearchResults(directory.filePath("_SearchResults.csv")); + return; + } + QStringList fileList= directory.entryList(QStringList() << "*.AT2",QDir::Files); foreach(QString fileName, fileList) { @@ -595,4 +602,99 @@ ExistingPEER_Records::copyFiles(QString &dirName) { return true; } +void ExistingPEER_Records::parseSearchResults(QString searchResultsFilePath) +{ + QFile searchResultsFile(searchResultsFilePath); + if(!searchResultsFile.exists()) + return; + + if(!searchResultsFile.open(QFile::ReadOnly)) + return; + + QFileInfo fileInfo(searchResultsFile.fileName()); + QDir recordDir(fileInfo.dir()); + + QTextStream searchResultsStream(&searchResultsFile); + while (!searchResultsStream.atEnd()) + { + QString line = searchResultsStream.readLine(); + + //Parsing selected records information + if(line.contains("Metadata of Selected Records")) + { + //skip header + searchResultsStream.readLine(); + line = searchResultsStream.readLine(); + + while(!line.isEmpty()) + { + auto values = line.split(','); + qDebug() << values; + if (values[0].isEmpty()) { + break; + } + PeerEvent *theEvent = new PeerEvent(theRandVariableIW); // new PEER event + QString Ordination = values[1].trimmed(); + double ScaleFactor = values[4].toDouble(); + QString Horizontal1File = values[19].trimmed(); + QString Horizontal2File = values[20].trimmed(); + QString VerticalFile = values[21].trimmed(); + QString EventName(Horizontal1File); + EventName.chop(4); // remove ".AT" + EventName.chop(3); // remove direction key (last three + theEvent->theName->setText(EventName); + + if (Ordination.compare("H1")==0 || Ordination.compare("H2")==0) { + // single horizontal component + PeerRecord *theRecord = theEvent->theRecords.at(0); + if (theRecord != NULL) { + if (Ordination.compare("H1")==0) + theRecord->file->setText(recordDir.filePath(Horizontal1File)); + else + theRecord->file->setText(recordDir.filePath(Horizontal2File)); + theRecord->factor->setText(QString::number(ScaleFactor)); + theRecord->dirn->setValue(1); + } + } else { + // single vertical component + if (Ordination.compare("V")==0) { + PeerRecord *theRecord = theEvent->theRecords.at(0); + if (theRecord != NULL) { + theRecord->file->setText(recordDir.filePath(VerticalFile)); + theRecord->factor->setText(QString::number(ScaleFactor)); + theRecord->dirn->setValue(3); + } + } else { + // 2d horizontal components + PeerRecord *Record1 = theEvent->theRecords.at(0); + if (Record1 != NULL) { + Record1->file->setText(recordDir.filePath(Horizontal1File)); + Record1->factor->setText(QString::number(ScaleFactor)); + Record1->dirn->setValue(1); + } + PeerRecord *Record2 = new PeerRecord(theRandVariableIW); + theEvent->recordLayout->addWidget(Record2); + theEvent->theRecords.append(Record2); + Record2 = theEvent->theRecords.at(1); + if (Record2 != NULL) { + Record2->file->setText(recordDir.filePath(Horizontal2File)); + Record2->factor->setText(QString::number(ScaleFactor)); + Record2->dirn->setValue(2); + } + } + } + theEvents.append(theEvent); + eventLayout->insertWidget(eventLayout->count()-1, theEvent); + + line = searchResultsStream.readLine(); + qDebug() << line; + } + } + } + + searchResultsFile.close(); + qDebug() << "searchResultsFile closed."; + + return; +} diff --git a/EVENTS/ExistingPEER_Records.h b/EVENTS/ExistingPEER_Records.h index 7b65d77e..96adda5d 100644 --- a/EVENTS/ExistingPEER_Records.h +++ b/EVENTS/ExistingPEER_Records.h @@ -125,14 +125,14 @@ public slots: void removeEvents(void); void clear(void); void loadEventsFromDir(void); - + void parseSearchResults(QString searchResultsFilePath); private: QVBoxLayout *verticalLayout; QVBoxLayout *eventLayout; QVectortheEvents; - RandomVariablesContainer *theRandVariableIW; + RandomVariablesContainer *theRandVariableIW; }; #endif // EXISTING_PEER_RECORDS_H diff --git a/EVENTS/groundMotionModel/BakerJayaram2008.cpp b/EVENTS/groundMotionModel/BakerJayaram2008.cpp new file mode 100644 index 00000000..02f86b63 --- /dev/null +++ b/EVENTS/groundMotionModel/BakerJayaram2008.cpp @@ -0,0 +1,77 @@ +/* ***************************************************************************** +Copyright (c) 2016-2017, 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; + 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: kuanshi + +#include "math.h" +#include +#define PI 3.14159265 + +double BakerJayaram2008(double T1, double T2) { + + // min and max periods + double Tmin = std::min(T1,T2); + double Tmax = std::max(T1,T2); + + // coefficients + double C1 = (1.0-cos(PI/2.0)-0.366*log(Tmax/std::max(Tmin,0.109))); + double C2 = 1000.0; + if (Tmax < 0.2) { + C2 = 1.0-0.105*(1.0-1.0/(1.0+exp(100.0*Tmax-5.0)))*(Tmax-Tmin)/(Tmax-0.0099); + } + double C3 = C1; + if (Tmax < 0.109) { + C3 = C2; + } + double C4 = C1+0.5*(sqrt(C3)-C3)*(1.0+cos(PI*Tmin/0.109)); + + // rho + double rho = C2; + if (Tmax > 0.109) { + if (Tmin > 0.109) { + rho = C1; + } else { + if (Tmax < 0.2) { + rho = std::min(C2,C4); + } else { + rho = C4; + } + } + } + + // return + return rho; +} diff --git a/EVENTS/groundMotionModel/BakerJayaram2008.h b/EVENTS/groundMotionModel/BakerJayaram2008.h new file mode 100644 index 00000000..774082cb --- /dev/null +++ b/EVENTS/groundMotionModel/BakerJayaram2008.h @@ -0,0 +1,44 @@ +#ifndef BAKER_JAYARAM_2008_H +#define BAKER_JAYARAM_2008_H + +/* ***************************************************************************** +Copyright (c) 2016-2017, 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; + 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: kuanshi + +double BakerJayaram2008(double T1, double T2); + +#endif // BAKER_JAYARAM_2008_H diff --git a/EVENTS/peerNGA/NSHMPDeagg.cpp b/EVENTS/peerNGA/NSHMPDeagg.cpp new file mode 100644 index 00000000..9ce06b72 --- /dev/null +++ b/EVENTS/peerNGA/NSHMPDeagg.cpp @@ -0,0 +1,496 @@ +#include "NSHMPDeagg.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "groundMotionModel/BakerJayaram2008.h" + +NSHMPDeagg::NSHMPDeagg(GeneralInformationWidget* generalInfoWidget, QWidget* parent):AbstractTargetWidget(parent), generalInfoWidget(generalInfoWidget) +{ + auto layout = new QGridLayout(this); + layout->setColumnMinimumWidth(2, 30); + + double latitude, longitude; + generalInfoWidget->getBuildingLocation(latitude, longitude); + layout->addWidget(new QLabel(tr("Latitude")), 0, 0); + latitudeBox = new QLineEdit(); + layout->addWidget(latitudeBox, 0, 1); + latitudeBox->setText(QString::number(latitude)); + + layout->addWidget(new QLabel(tr("Longitude")), 1, 0); + longitudeBox = new QLineEdit(); + layout->addWidget(longitudeBox, 1, 1); + longitudeBox->setText(QString::number(longitude)); + + layout->addWidget(new QLabel(tr("Vs30")), 2, 0); + vs30Box = new QComboBox(); + layout->addWidget(vs30Box, 2, 1); + vs30Box->addItem("180 (Stiff/Soft Soil D/E)", "180"); + vs30Box->addItem("259 (Stiff Soil D)", "259"); + vs30Box->addItem("360 (C/D)", "360"); + vs30Box->addItem("537 (Very Dense Soil/Soft Rock - C)", "537"); + vs30Box->addItem("760 (B/C)", "760"); + vs30Box->addItem("1150 (Rock - B)", "1150"); + vs30Box->addItem("2000 (Hard Rock - A)", "2000"); + layout->addWidget(new QLabel(tr("m/s")), 2, 2); + vs30Box->setCurrentIndex(4); + + layout->addWidget(new QLabel(tr("Disagg. NSHM")), 3, 0); + editionBox = new QComboBox(); + layout->addWidget(editionBox, 3, 1); + editionBox->addItem("Conterminous U.S. 2014 v4.2.0", "https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2014B/COUS"); + editionBox->addItem("Conterminous U.S. 2014 v4.1.4", "https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2014/COUS"); + editionBox->addItem("Conterminous U.S. 2008 v3.3.3", "https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2008/COUS"); + editionBox->addItem("Alaska 2007 v2.1.2", "https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2007/AK"); + editionBox->setCurrentIndex(0); + + auto positiveIntegerValidator = new QIntValidator(1, 9999); // USGS limits the return period from 2 to 9999 + positiveIntegerValidator->setBottom(2); + layout->addWidget(new QLabel(tr("Return Period")), 4, 0); + returnPeriodBox = new QLineEdit("2475"); // default 2475 year + returnPeriodBox->setValidator(positiveIntegerValidator); + layout->addWidget(returnPeriodBox, 4, 1); + layout->addWidget(new QLabel(tr("years")), 4, 2); + + layout->addWidget(new QLabel(tr("GM Model")), 5, 0); + gmpeBox = new QComboBox(); + layout->addWidget(gmpeBox, 5, 1); + gmpeBox->addItem("Boore, Stewart, Syhan & Atkinson (2014)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=BSSA_14"); + gmpeBox->addItem("Boore, Stewart, Seyhan & Atkinson (2014) : Basin", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=BSSA_14_BASIN"); + gmpeBox->addItem("Campbell & Bozorgnia (2014)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=CB_14"); + gmpeBox->addItem("Campbell & Bozorgnia (2014) : Basin", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=CB_14_BASIN"); + gmpeBox->addItem("Chiou & Youngs (2014)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=CY_14"); + gmpeBox->addItem("Chiou & Youngs (2014) : Basin", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=CB_14_BASIN"); + gmpeBox->addItem("Idriss (2014)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=IDRISS_14"); + gmpeBox->addItem("Combined: CEUS 2014", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=COMBINED_CEUS_2014"); + gmpeBox->addItem("Combined: WUS 2014 (4.1)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=COMBINED_WUS_2014_41"); + gmpeBox->addItem("Combined: WUS 2014 (4.2)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=COMBINED_WUS_2014_42"); + gmpeBox->addItem("Combined: CEUS 2018 (5.0)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=COMBINED_CEUS_2018"); + gmpeBox->addItem("Combined: WUS 2018 (5.0)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=COMBINED_WUS_2018"); + gmpeBox->addItem("NGA-Sub Interface (2018)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=NGA_SUB_USGS_INTERFACE"); + gmpeBox->addItem("NGA-Sub Slab (2018)", "https://earthquake.usgs.gov/nshmp-haz-ws/gmm/spectra?gmm=NGA_SUB_USGS_SLAB"); + gmpeBox->setCurrentIndex(0); + + layout->addWidget(new QLabel(tr("Conditional IM")), 6, 0); + imtBox = new QComboBox(); + layout->addWidget(imtBox, 6, 1); + imtBox->addItem("Peak Ground Acceleration", "PGA"); + imtBox->addItem("Sa(0.1s)", "SA0P1"); + imtBox->addItem("Sa(0.2s)", "SA0P2"); + imtBox->addItem("Sa(0.3s)", "SA0P3"); + imtBox->addItem("Sa(0.5s)", "SA0P5"); + imtBox->addItem("Sa(0.75s)", "SA0P75"); + imtBox->addItem("Sa(1.0s)", "SA1P0"); + imtBox->addItem("Sa(2.0s)", "SA2P0"); + imtBox->addItem("Sa(3.0s)", "SA3P0"); + imtBox->addItem("Sa(4.0s)", "SA4P0"); + imtBox->addItem("Sa(5.0s)", "SA5P0"); + imtBox->addItem("Sa(Tx)", "SATX"); + imtBox->setCurrentIndex(0); + + TxValidator = new QDoubleValidator(0.001, 5.0, 3); + TxValidator->setNotation(QDoubleValidator::StandardNotation); + TxLabel1 = new QLabel(tr("Tx")); + layout->addWidget(TxLabel1, 7, 0); + TxBox = new QLineEdit("1.0"); + TxBox->setValidator(TxValidator); + layout->addWidget(TxBox, 7, 1); + TxLabel2 = new QLabel(tr("sec")); + layout->addWidget(TxLabel2, 7, 2); + TxLabel1->setVisible(false); + TxLabel2->setVisible(false); + TxBox->setVisible(false); + + seismicDisaggButton = new QPushButton(tr("Disagg. Hazard")); + layout->addWidget(seismicDisaggButton, 8, 0); + + layout->setRowStretch(layout->rowCount(), 1); + + connect(generalInfoWidget, &GeneralInformationWidget::buildingLocationChanged, this, [this](double latitude, double longitude){ + latitudeBox->setText(QString::number(latitude)); + longitudeBox->setText(QString::number(longitude)); + }); + + connect(latitudeBox, &QLineEdit::editingFinished, this, [this, generalInfoWidget](){ + generalInfoWidget->setBuildingLocation(latitudeBox->text().toDouble(), longitudeBox->text().toDouble()); + }); + + connect(longitudeBox, &QLineEdit::editingFinished, this, [this, generalInfoWidget](){ + generalInfoWidget->setBuildingLocation(latitudeBox->text().toDouble(), longitudeBox->text().toDouble()); + }); + + connect(editionBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index){ + for (int i=0; i<11; i++) { + this->SetComboBoxItemEnabled(imtBox, i, true); + } + for (int i=0; i<7; i++) { + this->SetComboBoxItemEnabled(vs30Box, i, true); + } + if(editionBox->itemData(index).toString().startsWith("https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2008")) + { + this->SetComboBoxItemEnabled(imtBox, 9, false); + this->SetComboBoxItemEnabled(imtBox, 10, false); + availPeriod = {0.001, 0.1, 0.2, 0.3, 0.5, 0.75, 1.0, 2.0, 3.0}; + TxValidator->setRange(0.001, 3.0, 3); + TxBox->setValidator(TxValidator); + } + if(editionBox->itemData(index).toString().startsWith("https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2014/COUS")) + { + this->SetComboBoxItemEnabled(imtBox, 5, false); + this->SetComboBoxItemEnabled(imtBox, 8, false); + this->SetComboBoxItemEnabled(imtBox, 9, false); + this->SetComboBoxItemEnabled(imtBox, 10, false); + availPeriod = {0.001, 0.1, 0.2, 0.3, 0.5, 1.0, 2.0}; + TxValidator->setRange(0.001, 2.0, 3); + TxBox->setValidator(TxValidator); + } + if(editionBox->itemData(index).toString().startsWith("https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2007")) + { + this->SetComboBoxItemEnabled(imtBox, 5, false); + this->SetComboBoxItemEnabled(imtBox, 8, false); + this->SetComboBoxItemEnabled(imtBox, 9, false); + this->SetComboBoxItemEnabled(imtBox, 10, false); + this->SetComboBoxItemEnabled(vs30Box, 0, false); + this->SetComboBoxItemEnabled(vs30Box, 1, false); + this->SetComboBoxItemEnabled(vs30Box, 2, false); + this->SetComboBoxItemEnabled(vs30Box, 3, false); + this->SetComboBoxItemEnabled(vs30Box, 5, false); + this->SetComboBoxItemEnabled(vs30Box, 6, false); + availPeriod = {0.001, 0.1, 0.2, 0.3, 0.5, 1.0, 2.0}; + TxValidator->setRange(0.001, 2.0, 3); + TxBox->setValidator(TxValidator); + } + if(editionBox->itemData(index).toString().startsWith("https://earthquake.usgs.gov/nshmp-haz-ws/deagg/E2014B")) + { + availPeriod = {0.001, 0.1, 0.2, 0.3, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0}; + TxValidator->setRange(0.001, 5.0, 3); + TxBox->setValidator(TxValidator); + } + }); + + connect(imtBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index){ + if(imtBox->itemData(index).toString().startsWith("SATX")) + { + TxLabel1->setVisible(true); + TxLabel2->setVisible(true); + TxBox->setVisible(true); + } else { + TxLabel1->setVisible(false); + TxLabel2->setVisible(false); + TxBox->setVisible(false); + } + }); + + connect(seismicDisaggButton, &QPushButton::clicked, this, [this]() { + this->deagginfo(); + }); +} + +QList>> NSHMPDeagg::getDeagg(QJsonObject& json) const +{ + qDebug() << "Processing USGS sesimic disaggregation results..."; + QList>> deagginfo_set; + QList>> deagginfo; + auto deaggRes = json["response"].toArray(); + + qDebug() << deaggRes[0].toObject()["metadata"].toObject()["edition"].toObject()["value"].toString(); + // Add an additional check of the return period range accepted by USGS + if (returnPeriodBox->text().isEmpty() || returnPeriodBox->text().toInt() < 2) + { + const_cast(this)->emit statusUpdated("Please input a valid return period (2~9999)."); + return deagginfo; + } + if (TxBox->text().isEmpty() || TxBox->text().toDouble() > availPeriod.last()) + { + const_cast(this)->emit statusUpdated("Please input a valid Tx (0.001~+"+ QString::number(availPeriod.last())+ ")."); + return deagginfo; + } + for (auto curDeagg: deaggRes) + { + auto imt = curDeagg.toObject()["metadata"].toObject()["imt"].toObject()["value"].toString(); + double period = 0; + if (imt.startsWith("SA")) + period = imt.remove("SA").replace('P', '.').toDouble(); + qDebug() << "Conditional period T = " + QString::number(period); + // psa + double psa = curDeagg.toObject()["data"].toArray()[0].toObject()["summary"].toArray()[0].toObject()["data"].toArray()[2].toObject()["value"].toDouble(); + // mean M, R, epsilon + double meanM = curDeagg.toObject()["data"].toArray()[0].toObject()["summary"].toArray()[3].toObject()["data"].toArray()[0].toObject()["value"].toDouble(); + double meanR = curDeagg.toObject()["data"].toArray()[0].toObject()["summary"].toArray()[3].toObject()["data"].toArray()[1].toObject()["value"].toDouble(); + double meanE = curDeagg.toObject()["data"].toArray()[0].toObject()["summary"].toArray()[3].toObject()["data"].toArray()[2].toObject()["value"].toDouble(); + qDebug() << "Disaggregated Sa, M, R, E = " + QString::number(psa) + ", " + QString::number(meanM) + ", " + QString::number(meanR) + ", " + QString::number(meanE); + const_cast(this)->emit statusUpdated("USGS Disaggregation: RP, T, Sa, M, R, epsilon = " + returnPeriodBox->text() + "yr, " + QString::number(period) +"s, " + QString::number(psa) + "g, Mw" + QString::number(meanM) + ", " + QString::number(meanR) + "km, " + QString::number(meanE)); + // collection + QList deaggVals = {psa, meanM, meanR, meanE}; + // append + deagginfo_set.append({period, deaggVals}); + } + + if(deagginfo_set.empty()) { + const_cast(this)->emit statusUpdated("USGS Disaggregation Error: Failed to retrieve deaggregation results with the inputs provided"); + return deagginfo; + } + + if (deagginfo_set.size()==1) { + deagginfo = deagginfo_set; + } else { + for (int i=0; itext().toDouble() && availPeriod[i+1]>=TxBox->text().toDouble()) { + deagginfo.append(deagginfo_set[i]); + deagginfo.append(deagginfo_set[i+1]); + break; + } + } + } + + return deagginfo; +} + +QList> NSHMPDeagg::getSpectrum(QJsonObject& json, double Tc, double Sac) const +{ + qDebug() << "Processing USGS deterministic GMPE results..."; + QList> spectrum; + QList> cms; // conditional mean spectrum + auto meanSpectra = json["means"].toObject()["data"].toArray(); + auto sigmaSpectra = json["sigmas"].toObject()["data"].toArray(); + + // Add an additional check of the return period range accepted by USGS + if (returnPeriodBox->text().isEmpty() || returnPeriodBox->text().toInt() < 2) + { + const_cast(this)->emit statusUpdated("Please input a valid return period (2~9999)."); + return spectrum; + } + + // append mean data and compute rho + QList> spectrum_rho; + double eps; + for (auto curMean: meanSpectra) + { + auto xs = curMean.toObject()["data"].toObject()["xs"].toArray(); + auto ys = curMean.toObject()["data"].toObject()["ys"].toArray(); + + for (int i=0; i= Tc) { + eps = log(Sac)-(log(ys[i].toDouble())+(log(Tc)-log(xs[i].toDouble()))*(log(ys[i+1].toDouble())-log(ys[i].toDouble()))/(log(xs[i+1].toDouble())-log(xs[i].toDouble()))); + qDebug() << "GMPE Sa(Tc) = " + QString::number(exp(log(ys[i].toDouble())+(log(Tc)-log(xs[i].toDouble()))*(log(ys[i+1].toDouble())-log(ys[i].toDouble()))/(log(xs[i+1].toDouble())-log(xs[i].toDouble())))); + break; + } + } + } + + QList> spectrum_sigmas; + for (auto curSigma: sigmaSpectra) + { + auto xs = curSigma.toObject()["data"].toObject()["xs"].toArray(); + auto ys = curSigma.toObject()["data"].toObject()["ys"].toArray(); + + for (int i=0; i= Tc) { + eps = eps/exp(log(ys[i].toDouble())+(log(Tc)-log(xs[i].toDouble()))*(log(ys[i+1].toDouble())-log(ys[i].toDouble()))/(log(xs[i+1].toDouble())-log(xs[i].toDouble()))); + break; + } + } + + qDebug() << "Back calculated epsilon = " + QString::number(eps); + } + + if(spectrum.empty()) { + const_cast(this)->emit statusUpdated("USGS Disaggregation Error: Failed to retrieve uniform hazard spectrum with the inputs provided"); + } + + // compute cms + for (int i=0; icurrentText(); + json["Edition"] = editionBox->currentText(); + json["ReturnPeriod"] = returnPeriodBox->text(); + + return json; +} + +void NSHMPDeagg::deserialize(const QJsonObject &json) +{ + vs30Box->setCurrentText(json["Vs30"].toString()); + editionBox->setCurrentText(json["Edition"].toString()); + returnPeriodBox->setText(json["ReturnPeriod"].toString()); + + double latitude, longitude; + generalInfoWidget->getBuildingLocation(latitude, longitude); + latitudeBox->setText(QString::number(latitude)); + longitudeBox->setText(QString::number(longitude)); +} + +QList> NSHMPDeagg::spectrum() const +{ + + // deagg first + auto deagg_data = this->deagginfo(); + + qDebug() << "USGS seismic disaggregation data processed."; + + QList>> spectrum_set; + QList> spectrum_tar; + + if (deagg_data.size()==0 || deagg_data.empty()) { + const_cast(this)->emit statusUpdated("Error in USGS seismic disaggregation data - no target spectrum calculated"); + return spectrum_tar; + } + + for (auto cur_deagg: deagg_data) { + QString url(gmpeBox->currentData().toString()); + + url.append("&mw=" + QString::number(cur_deagg.second[1])); + url.append("&rjb=" + QString::number(cur_deagg.second[2])); + url.append("&rrup=" + QString::number(cur_deagg.second[2])); + url.append("&rx=" + QString::number(cur_deagg.second[2])); + url.append("&vs30=" + vs30Box->currentData().toString()); + + qDebug() << "USGS deterministic GMPE URL = " + url; + + QNetworkRequest request(url); + + auto reply = networkManager.get(request); + + QEventLoop loop; + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + QJsonObject replyJson = QJsonDocument::fromJson(reply->readAll()).object(); + + qDebug() << "USGS deterministic GMPE results returned."; + + if(reply->error() != QNetworkReply::NoError) + { + qDebug() << "QNectworkReply Error."; + return QList>(); + } + else if(!replyJson.keys().contains("means")) + { + qDebug() << "USGS deterministic GMPE results not valid."; + if (replyJson.keys().contains("status") && replyJson["status"].toString() == "busy") + const_cast(this)->emit statusUpdated("USGS Disaggregation Error: " + replyJson["message"].toString()); + return QList>(); + } + + spectrum_set.append(getSpectrum(replyJson, cur_deagg.first, cur_deagg.second[0])); + } + + if (spectrum_set.size()==1) { + spectrum_tar = spectrum_set[0]; + } else { + for (int i=0; i>> NSHMPDeagg::deagginfo() const +{ + //GoogleAnalytics::Report("RecordSelection", "USGS-DEAGG"); + + QString url(editionBox->currentData().toString()); + + url.append("/" + longitudeBox->text()); + url.append("/" + latitudeBox->text()); + if (imtBox->currentData().toString() == "SATX") { + if (TxBox->text().isEmpty() || TxBox->text().toDouble() > availPeriod.last()) + { + const_cast(this)->emit statusUpdated("Please input a valid Tx (0.001~+"+ QString::number(availPeriod.last())+ ")."); + return QList>>(); + } + auto TxString = QString::number(TxBox->text().toDouble()); + for (int i=0; itext().toDouble() && availPeriod[i+1]>=TxBox->text().toDouble()) { + if (availPeriod[i]==TxBox->text().toDouble()) { + url.append("/" + imtBox->itemData(i).toString()); + break; + } + if (availPeriod[i+1]==TxBox->text().toDouble()) { + url.append("/" + imtBox->itemData(i+1).toString()); + break; + } + url.append("/any"); + break; + } + } + } else { + url.append("/" + imtBox->currentData().toString()); + } + url.append("/" + vs30Box->currentData().toString()); + if (returnPeriodBox->text().isEmpty() || returnPeriodBox->text().toInt() < 2) + { + const_cast(this)->emit statusUpdated("Please input a valid return period (2~9999)."); + return QList>>(); + } + url.append("/" + returnPeriodBox->text()); + + qDebug() << "USGS sesimic disaggregation URL = " + url; + + QNetworkRequest request(url); + + auto reply = networkManager.get(request); + + QEventLoop loop; + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + + QJsonObject replyJson = QJsonDocument::fromJson(reply->readAll()).object(); + + qDebug() << "USGS sesimic disaggregation results returned."; + + if(reply->error() != QNetworkReply::NoError) + { + qDebug() << "QNectworkReply Error."; + return QList>>(); + } + else if(!replyJson.keys().contains("response")) + { + qDebug() << "USGS sesimic disaggregation results not valid."; + if (replyJson.keys().contains("status") && replyJson["status"].toString() == "busy") + const_cast(this)->emit statusUpdated("USGS Disaggregation Error: " + replyJson["message"].toString()); + return QList>>(); + } + + return getDeagg(replyJson); +} + +void NSHMPDeagg::SetComboBoxItemEnabled(QComboBox * comboBox, int index, bool enabled) +{ + auto * model = qobject_cast(comboBox->model()); + assert(model); + if(!model) return; + + auto * item = model->item(index); + assert(item); + if(!item) return; + item->setEnabled(enabled); +} diff --git a/EVENTS/peerNGA/NSHMPDeagg.h b/EVENTS/peerNGA/NSHMPDeagg.h new file mode 100644 index 00000000..c1d623f2 --- /dev/null +++ b/EVENTS/peerNGA/NSHMPDeagg.h @@ -0,0 +1,52 @@ +#ifndef NSHMPTDeagg_H +#define NSHMPTDeagg_H +#include "AbstractTargetWidget.h" +#include +#include +#include +#include +#include +#include +#include + +class NSHMPDeagg : public AbstractTargetWidget +{ + Q_OBJECT +public: + explicit NSHMPDeagg(GeneralInformationWidget* generalInfoWidget, QWidget* parent = nullptr); + +private: + QLineEdit* latitudeBox; + QLineEdit* longitudeBox; + QComboBox* vs30Box; + QComboBox* editionBox; + QComboBox* imtBox; + QComboBox* gmpeBox; + GeneralInformationWidget* generalInfoWidget; + QLineEdit* returnPeriodBox; + QLineEdit* TxBox; + QLabel* TxLabel1; + QLabel* TxLabel2; + QList availPeriod = {0.001, 0.1, 0.2, 0.3, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0}; + QDoubleValidator* TxValidator; + + QPushButton* seismicDisaggButton; + + mutable QNetworkAccessManager networkManager; + + QList> getSpectrum(QJsonObject& json, double Tc, double Sac) const; + QList>> getDeagg(QJsonObject& json) const; + void SetComboBoxItemEnabled(QComboBox * comboBox, int index, bool enabled); + + // AbstractJsonSerializable interface +public: + QJsonObject serialize() const override; + void deserialize(const QJsonObject &json) override; + + // AbstractTargetWidget interface +public: + QList> spectrum() const override; + QList>> deagginfo() const; +}; + +#endif // NSHMPTDeagg_H diff --git a/EVENTS/peerNGA/PEER_NGA_Records.cpp b/EVENTS/peerNGA/PEER_NGA_Records.cpp index 057eecad..d515a77e 100644 --- a/EVENTS/peerNGA/PEER_NGA_Records.cpp +++ b/EVENTS/peerNGA/PEER_NGA_Records.cpp @@ -20,6 +20,7 @@ #include "UserSpectrumWidget.h" #include "USGSTargetWidget.h" #include "NSHMPTarget.h" +#include "NSHMPDeagg.h" #include #include #include @@ -55,6 +56,7 @@ void PEER_NGA_Records::setupUI(GeneralInformationWidget* generalInfoWidget) spectrumTypeComboBox->addItem("User Specified"); spectrumTypeComboBox->addItem("Design Spectrum (USGS Web Service)"); spectrumTypeComboBox->addItem("Uniform Hazard Spectrum (USGS NSHMP)"); + spectrumTypeComboBox->addItem("Conditional Mean Spectrum (USGS Disagg.)"); targetSpectrumDetails = new QStackedWidget(this); targetSpectrumLayout->addWidget(targetSpectrumDetails, 1, 0, 1, 3); @@ -66,6 +68,8 @@ void PEER_NGA_Records::setupUI(GeneralInformationWidget* generalInfoWidget) targetSpectrumDetails->addWidget(usgsSpectrumTarget); auto nshmpTarget = new NSHMPTarget(generalInfoWidget, this); targetSpectrumDetails->addWidget(nshmpTarget); + auto nshmpDeagg = new NSHMPDeagg(generalInfoWidget, this); + targetSpectrumDetails->addWidget(nshmpDeagg); auto recordSelectionGroup = new QGroupBox("Record Selection"); recordSelectionLayout = new QGridLayout(recordSelectionGroup); diff --git a/EarthquakeEvents.pri b/EarthquakeEvents.pri index c86a0baa..7324a62b 100644 --- a/EarthquakeEvents.pri +++ b/EarthquakeEvents.pri @@ -18,6 +18,7 @@ SOURCES += \ $$PWD/EVENTS/StochasticMotionInput/src/VlachosEtAlModel.cpp \ $$PWD/EVENTS/StochasticMotionInput/src/DabaghiDerKiureghianPulse.cpp \ $$PWD/EVENTS/peerNGA/ASCE710Target.cpp \ + $$PWD/EVENTS/peerNGA/NSHMPDeagg.cpp \ $$PWD/EVENTS/peerNGA/NSHMPTarget.cpp \ $$PWD/EVENTS/peerNGA/PeerLoginDialog.cpp \ $$PWD/EVENTS/peerNGA/PEER_NGA_Records.cpp \ @@ -26,7 +27,8 @@ SOURCES += \ $$PWD/EVENTS/peerNGA/USGSTargetWidget.cpp \ $$PWD/EVENTS/peerNGA/UserSpectrumModel.cpp \ $$PWD/EVENTS/peerNGA/UserSpectrumWidget.cpp \ - $$PWD/EVENTS/userDefinedDatabase/User_Defined_Database.cpp + $$PWD/EVENTS/userDefinedDatabase/User_Defined_Database.cpp \ + $$PWD/EVENTS/groundMotionModel/BakerJayaram2008.cpp HEADERS += \ $$PWD/EVENTS/EarthquakeEventSelection.h \ @@ -38,6 +40,7 @@ HEADERS += \ $$PWD/EVENTS/peerNGA/ASCE710Target.h \ $$PWD/EVENTS/peerNGA/AbstractJsonSerializable.h \ $$PWD/EVENTS/peerNGA/AbstractTargetWidget.h \ + $$PWD/EVENTS/peerNGA/NSHMPDeagg.h \ $$PWD/EVENTS/peerNGA/NSHMPTarget.h \ $$PWD/EVENTS/peerNGA/PeerLoginDialog.h \ $$PWD/EVENTS/peerNGA/PEER_NGA_Records.h \ @@ -47,4 +50,5 @@ HEADERS += \ $$PWD/EVENTS/peerNGA/UserSpectrumModel.h \ $$PWD/EVENTS/peerNGA/UserSpectrumWidget.h \ $$PWD/EVENTS/userDefinedDatabase/User_Defined_Database.h + $$PWD/EVENTS/groundMotionModel/BakerJayaram2008.h