Skip to content

Attempting to address 153, by allowing user to specifically import 99%,99.6%, 0.4%,1% and 2% annual design days #791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 40 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
91e8b00
Clang format
macumber Jan 11, 2025
9bde301
Checkpoint select imports working
antonszilasi Feb 10, 2025
068e8c3
Checkpoint appears to be working
antonszilasi Feb 10, 2025
ffc742d
Checkpoint
antonszilasi Feb 13, 2025
de4cd9a
Checkpoint looking better
antonszilasi Feb 14, 2025
67aa493
this is looking good
antonszilasi Feb 15, 2025
5a781d2
Checkpoint only considering annual design days now
antonszilasi Feb 15, 2025
5a7cc1e
Good checkpoint,
antonszilasi Feb 16, 2025
f0997a8
Highlight things
antonszilasi Feb 16, 2025
e192716
Checkpoint, remove widgets before they are added
antonszilasi Feb 16, 2025
2d7eb11
Checkpoint clean up and appears to be working
antonszilasi Feb 17, 2025
33a0e60
Checkpoint this is much cleaner
antonszilasi Feb 17, 2025
3c594ab
Checkpoint make the interface more like what Dan Macumber suggested
antonszilasi Feb 17, 2025
65644e8
Even better
antonszilasi Feb 18, 2025
f18a3cd
Looking better but layout still sucks
antonszilasi Feb 18, 2025
591deaf
Checkpoint basic functionality is there
antonszilasi Feb 18, 2025
f514fb9
Oopps
antonszilasi Feb 19, 2025
82fbd84
Checkpoint
antonszilasi Feb 21, 2025
f002dc8
Checkpoint
antonszilasi Feb 21, 2025
88f8188
Checkpoint
antonszilasi Feb 21, 2025
bd5085b
Checkpoint
antonszilasi Feb 21, 2025
bf8f017
Checkpoint looking good
antonszilasi Feb 21, 2025
78291c1
Just use boost::to_lower_copy
antonszilasi Feb 28, 2025
a5263ba
use QString contains and use openstudio::isEqual
antonszilasi Feb 28, 2025
b76aeff
Rever space for DesignDaysToInsert
antonszilasi Mar 1, 2025
b620b98
Avoid refiltering and delaying filtering until Ok button is clicked
antonszilasi Mar 1, 2025
73a9060
Only add check box if the design days exist in ddy
antonszilasi Mar 1, 2025
99a64c7
clag format
antonszilasi Mar 1, 2025
d763728
this is not needed
antonszilasi Mar 1, 2025
1e4af8d
Adding some documentation
antonszilasi Mar 1, 2025
d7d13af
Update LocationTabView.cpp
antonszilasi Mar 1, 2025
10a08ee
Refactor code to use a helper class to find the design day types and …
macumber Mar 2, 2025
5b73370
Remove unintended change
macumber Mar 2, 2025
a477eb4
Fix cppcheck
macumber Mar 2, 2025
ee66ca9
Avoid copying QVector around by adding design day key to radio button…
macumber Mar 2, 2025
fc925bf
Hide borders on cells when deleted, update select all check box when …
macumber Mar 8, 2025
7dbb1f0
Clang format
macumber Mar 8, 2025
1c153d9
Fixing bug in style which prevented lines from being drawn
macumber Mar 9, 2025
949b705
Update all checkbox when adding new objects too
macumber Mar 9, 2025
4b70fb4
Clang format
macumber Mar 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/model_editor/InspectorGadget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ void InspectorGadget::layoutComboBox(QVBoxLayout* layout, QWidget* parent, opens
idx = 0;
combo->insertItem(idx, QPixmap(":/images/alert_image.png"), curVal.c_str(), "Invalid");

//QString errormsg("We have a value:");
//QString errormsg("We have a value:");
//errormsg += curVal.c_str();
//errormsg += " that does not match the allowable values in the idd.Name:";
//errormsg += name.c_str();
Expand Down
202 changes: 143 additions & 59 deletions src/openstudio_lib/LocationTabView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
#include <QBoxLayout>
#include <QComboBox>
#include <QDateTime>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QDir>
#include <QFile>
#include <QFileDialog>
Expand All @@ -62,6 +64,11 @@
#include <QScrollArea>
#include <QSettings>
#include <QSizePolicy>
#include <vector>
#include <tuple>
#include <QCoreApplication>
#include <QObject>
#include <QPushButton>

static constexpr auto NAME("Name: ");
static constexpr auto LATITUDE("Latitude: ");
Expand Down Expand Up @@ -625,6 +632,127 @@ void LocationView::onWeatherFileBtnClicked() {
}
}

std::vector<model::DesignDay> filterDesignDays(const std::vector<model::DesignDay>& designDays, const std::string& dayType,
const std::string& percentage, const std::string& humidityConditionType = "") {
std::vector<model::DesignDay> filteredDesignDays;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably reserve first.

I think you could just do it in place instead of copying around though.

Copy link
Author

@antonszilasi antonszilasi Feb 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmarrec

do you mean something like this?

filteredDesignDays.reserve(designDays.size());

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Author

@antonszilasi antonszilasi Mar 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmarrec
done here b76aeff


std::copy_if(designDays.begin(), designDays.end(), std::back_inserter(filteredDesignDays), [&](const model::DesignDay& designDay) {
QString nameString = QString::fromStdString(designDay.name().get());

if (!nameString.contains("ann", Qt::CaseInsensitive)) {
return false;
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmarrec somehow your other comments were lost but I addressed two of them in

78291c1

and a5263ba

bool matchesHumidityConditionType =
humidityConditionType.empty() || openstudio::istringEqual(designDay.humidityConditionType(), humidityConditionType);
bool matchesPercentage = nameString.contains(QString::fromStdString(percentage)) || (percentage == "0.4%" && nameString.contains(".4%"));

bool matchesDesignDay = openstudio::istringEqual(designDay.dayType(), dayType);

return matchesPercentage && matchesDesignDay && matchesHumidityConditionType;
});

return filteredDesignDays;
}

std::vector<model::DesignDay> LocationView::showDesignDaySelectionDialog(const std::vector<openstudio::model::DesignDay>& allDesignDays) {
std::vector<openstudio::model::DesignDay> designDaysToInsert;
designDaysToInsert.reserve(allDesignDays.size()); // Reserve space for designDaysToInsert

QDialog dialog(this);
dialog.setWindowTitle(QCoreApplication::translate("LocationView", "Import Design Days"));

QGridLayout* layout = new QGridLayout(&dialog);

// Define row labels and percentages
QStringList rowLabels = {"Heating", "Cooling"};
std::vector<std::string> heatingPercentages = {"99.6%", "99%"};
std::vector<std::string> coolingPercentages = {"2%", "1%", "0.4%"};

// Ok and Cancel buttons
QPushButton* okButton = new QPushButton(tr("Ok"), &dialog);
QPushButton* cancelButton = new QPushButton(tr("Cancel"), &dialog);
QPushButton* importAllButton = new QPushButton(tr("Skip\nselection\nimport\nall DDYs"), &dialog);

// Set the same size for all buttons
okButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
cancelButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
importAllButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);

// Adjust the order of the buttons
layout->addWidget(importAllButton, rowLabels.size() * 2 + 3, 1);
layout->addWidget(okButton, rowLabels.size() * 2 + 3, 2);
layout->addWidget(cancelButton, rowLabels.size() * 2 + 3, 3);

okButton->setMinimumSize(cancelButton->sizeHint());
importAllButton->setMinimumSize(cancelButton->sizeHint());

okButton->setEnabled(false); // Initially disable the Ok button

connect(okButton, &QPushButton::clicked, [&dialog, &designDaysToInsert, &allDesignDays, rowLabels, heatingPercentages, coolingPercentages]() {
for (int row = 0; row < rowLabels.size(); ++row) {
const auto& percentages = (row == 0) ? heatingPercentages : coolingPercentages;
for (int col = 0; col < percentages.size(); ++col) {
QCheckBox* checkBox = dialog.findChild<QCheckBox*>(QString("checkBox_%1_%2").arg(row).arg(col));
if (checkBox && checkBox->isChecked()) {
std::string dayType = (row == 0) ? "WinterDesignDay" : "SummerDesignDay";
std::vector<model::DesignDay> filteredDays = filterDesignDays(allDesignDays, dayType, percentages[col]);
designDaysToInsert.insert(designDaysToInsert.end(), filteredDays.begin(), filteredDays.end());
}
}
}
dialog.accept();
});

connect(cancelButton, &QPushButton::clicked, &dialog, &QDialog::reject);
connect(importAllButton, &QPushButton::clicked, [&dialog, &designDaysToInsert, &allDesignDays]() {
designDaysToInsert = allDesignDays;
dialog.accept();
});

// Populate table for Heating and Cooling
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect a check to not include the checkboxes if the design days aren't in the DDY file to begin with.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (int row = 0; row < rowLabels.size(); ++row) {
QLabel* rowLabel = new QLabel(rowLabels[row]);
layout->addWidget(rowLabel, row * 2 + 1, 0, Qt::AlignCenter);

const auto& percentages = (row == 0) ? heatingPercentages : coolingPercentages;

for (int col = 0; col < percentages.size(); ++col) {
QLabel* percentageLabel = new QLabel(QString::fromStdString(percentages[col]));
layout->addWidget(percentageLabel, row * 2, col + 1, Qt::AlignCenter);

std::string dayType = (row == 0) ? "WinterDesignDay" : "SummerDesignDay";

if (filterDesignDays(allDesignDays, dayType, percentages[col]).empty()) {
continue;
}

QCheckBox* checkBox = new QCheckBox();
checkBox->setObjectName(QString("checkBox_%1_%2").arg(row).arg(col));
layout->addWidget(checkBox, row * 2 + 1, col + 1, Qt::AlignCenter);

connect(checkBox, &QCheckBox::toggled, [=, &dialog](bool checked) {
auto checkBoxes = dialog.findChildren<QCheckBox*>();
okButton->setEnabled(std::any_of(checkBoxes.begin(), checkBoxes.end(), [](QCheckBox* cb) { return cb->isChecked(); }));
});
}
}

// Add a spacer item to add more space between the checkboxes and the buttons
QSpacerItem* spacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
layout->addItem(spacer, rowLabels.size() * 2 + 2, 0, 1, 5);

dialog.setLayout(layout);
dialog.setMinimumSize(dialog.sizeHint());

// Execute the dialog and wait for user interaction
if (dialog.exec() == QDialog::Accepted) {
return designDaysToInsert;
} else {
return {};
}
}

void LocationView::onDesignDayBtnClicked() {
QString fileTypes("Files (*.ddy)");

Expand All @@ -644,87 +772,43 @@ void LocationView::onDesignDayBtnClicked() {
if (ddyIdfFile) {

openstudio::Workspace ddyWorkspace(StrictnessLevel::None, IddFileType::EnergyPlus);

for (const IdfObject& idfObject : ddyIdfFile->objects()) {
IddObjectType iddObjectType = idfObject.iddObject().type();
if ((iddObjectType == IddObjectType::SizingPeriod_DesignDay) || (iddObjectType == IddObjectType::SizingPeriod_WeatherFileDays)
|| (iddObjectType == IddObjectType::SizingPeriod_WeatherFileConditionType)) {

ddyWorkspace.addObject(idfObject);
}
}

energyplus::ReverseTranslator reverseTranslator;
openstudio::energyplus::ReverseTranslator reverseTranslator;
model::Model ddyModel = reverseTranslator.translateWorkspace(ddyWorkspace);

// Use a heuristic based on the ddy files provided by EnergyPlus
// Filter out the days that are not helpful.
if (!ddyModel.objects().empty()) {
// Containers to hold 99%, 99.6%, 2%, 1%, and 0.4% design points
std::vector<model::DesignDay> days99;
std::vector<model::DesignDay> days99_6;
std::vector<model::DesignDay> days2;
std::vector<model::DesignDay> days1;
std::vector<model::DesignDay> days0_4;

bool unknownDay = false;

for (const model::DesignDay& designDay : ddyModel.getConcreteModelObjects<model::DesignDay>()) {
boost::optional<std::string> name;
name = designDay.name();

if (name) {
QString qname = QString::fromStdString(name.get());

if (qname.contains("99%")) {
days99.push_back(designDay);
} else if (qname.contains("99.6%")) {
days99_6.push_back(designDay);
} else if (qname.contains("2%")) {
days2.push_back(designDay);
} else if (qname.contains("1%")) {
days1.push_back(designDay);
} else if (qname.contains(".4%")) {
days0_4.push_back(designDay);
} else {
unknownDay = true;
}
}
}

// Pick only the most stringent design points
if (!unknownDay) {
if (!days99_6.empty()) {
for (model::DesignDay designDay : days99) {
designDay.remove();
}
}

if (!days0_4.empty()) {
for (model::DesignDay designDay : days1) {
designDay.remove();
}
for (model::DesignDay designDay : days2) {
designDay.remove();
}
} else if (!days1.empty()) {
for (model::DesignDay designDay : days2) {
designDay.remove();
}
}
}

// Evan note: do not remove existing design days
//for (model::SizingPeriod sizingPeriod : m_model.getModelObjects<model::SizingPeriod>()){
// sizingPeriod.remove();
//}

//m_model.insertObjects(ddyModel.objects());

std::vector<openstudio::model::DesignDay> designDaysToInsert = showDesignDaySelectionDialog(ddyModel.getModelObjects<model::DesignDay>());

// Remove design days from ddyModel that are not in designDaysToInsert
for (auto& designDay : ddyModel.getConcreteModelObjects<model::DesignDay>()) {
if (std::find(designDaysToInsert.begin(), designDaysToInsert.end(), designDay) == designDaysToInsert.end()) {
designDay.remove();
}
}

m_model.insertObjects(ddyModel.objects());

m_lastDdyPathOpened = QFileInfo(fileName).absoluteFilePath();
}
}

QTimer::singleShot(0, this, &LocationView::checkNumDesignDays);
}
}

Expand Down Expand Up @@ -785,7 +869,7 @@ void LocationView::setDstStartDayOfWeekAndMonth(int newWeek, int newDay, int new
void LocationView::setDstStartDate(const QDate& newdate) {
auto dst = m_model.getUniqueModelObject<model::RunPeriodControlDaylightSavingTime>();

dst.setStartDate(monthOfYear(newdate.month()), newdate.day());
dst.setStartDate(MonthOfYear(newdate.month()), newdate.day());
}

void LocationView::setDstEndDayOfWeekAndMonth(int newWeek, int newDay, int newMonth) {
Expand All @@ -797,7 +881,7 @@ void LocationView::setDstEndDayOfWeekAndMonth(int newWeek, int newDay, int newMo
void LocationView::setDstEndDate(const QDate& newdate) {
auto dst = m_model.getUniqueModelObject<model::RunPeriodControlDaylightSavingTime>();

dst.setEndDate(monthOfYear(newdate.month()), newdate.day());
dst.setEndDate(MonthOfYear(newdate.month()), newdate.day());
}

void LocationView::onSelectItem() {
Expand Down
5 changes: 4 additions & 1 deletion src/openstudio_lib/LocationTabView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <openstudio/model/Model.hpp>
#include <openstudio/model/Site.hpp>
#include <openstudio/model/YearDescription.hpp>

#include <openstudio/model/DesignDay.hpp>
#include "MainTabView.hpp"
#include "YearSettingsWidget.hpp"

Expand Down Expand Up @@ -124,6 +124,9 @@ class LocationView : public QWidget

void onWeatherFileBtnClicked();

std::vector<openstudio::model::DesignDay>
showDesignDaySelectionDialog(const std::vector<openstudio::model::DesignDay, std::allocator<openstudio::model::DesignDay>>& allNonAnnual);

void onDesignDayBtnClicked();

void onASHRAEClimateZoneChanged(const QString& climateZone);
Expand Down
Loading