diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d0de3a9a..869989e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,7 +272,7 @@ endif() # TODO: Modify the more specific variables as needed to indicate prerelease, etc # Keep in beta in-between release cycles. Set to empty string (or comment out) for official) -set(PROJECT_VERSION_PRERELEASE "rc1") +set(PROJECT_VERSION_PRERELEASE "rc2") # OpenStudio version: Only include Major.Minor.Patch, eg "3.0.0", even if you have a prerelease tag set(OPENSTUDIOAPPLICATION_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/FindOpenStudioSDK.cmake b/FindOpenStudioSDK.cmake index 67ee92bba..12f23670f 100644 --- a/FindOpenStudioSDK.cmake +++ b/FindOpenStudioSDK.cmake @@ -37,6 +37,11 @@ elseif(UNIX) else() set(OPENSTUDIO_EXPECTED_HASH 209820bd2f9b487f0d0f4d4df311753f) endif() + elseif(LSB_RELEASE_ID_SHORT MATCHES "AlmaLinux") + if (ARCH MATCHES "arm64") + message(FATAL_ERROR "OpenStudio SDK for AlmaLinux is only built for x86_64") + endif() + set(OPENSTUDIO_EXPECTED_HASH 7ed93ad951b654cc6466803e365ddc17) else() message(FATAL_ERROR "OpenStudio SDK no longer provides packages for Ubuntu 20.04 or older") endif() diff --git a/ruby/CMakeLists.txt b/ruby/CMakeLists.txt index 201e81388..b454f10b8 100644 --- a/ruby/CMakeLists.txt +++ b/ruby/CMakeLists.txt @@ -147,6 +147,7 @@ if(BUILD_TESTING) "/usr/share/rvm/rubies/ruby-3.2.2/bin/" "$ENV{HOME}/.rvm/rubies/ruby-3.2.2/bin/" "$ENV{HOME}/.rbenv/versions/3.2.2/bin/" + "/opt/rbenv/versions/3.2.2/bin/" "C:/Ruby32-x64/bin/" diff --git a/src/openstudio_app/Resources/default/hvac_library.osm b/src/openstudio_app/Resources/default/hvac_library.osm index 6cfc0ecf9..5a1207bf5 100644 --- a/src/openstudio_app/Resources/default/hvac_library.osm +++ b/src/openstudio_app/Resources/default/hvac_library.osm @@ -13068,7 +13068,7 @@ OS:Fan:ConstantVolume, OS:Coil:Heating:Gas:MultiStage, {3b1fedfa-eb94-4c41-9ff0-eb695f74535d}, !- Handle Multi Speed HP Gas Htg Coil, !- Name - {1540674d-a780-43fe-a8dd-b0b23e85b39e}, !- Availability Schedule + {9f54092d-a4a8-41b8-a381-c4c332ecb843}, !- Availability Schedule , !- Air Inlet Node , !- Air Outlet Node , !- Part Load Fraction Correlation Curve @@ -13317,7 +13317,7 @@ OS:AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed, , !- Controlling Zone or Thermostat Location {0f1dd656-a681-48a5-839e-80d7417180c6}, !- Supply Air Fan DrawThrough, !- Supply Air Fan Placement - {1540674d-a780-43fe-a8dd-b0b23e85b39e}, !- Supply Air Fan Operating Mode Schedule + {9f54092d-a4a8-41b8-a381-c4c332ecb843}, !- Supply Air Fan Operating Mode Schedule {3b1fedfa-eb94-4c41-9ff0-eb695f74535d}, !- Heating Coil -8, !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} {a76a42fb-2594-4514-afb9-fd45a05494fc}, !- Cooling Coil @@ -13342,20 +13342,6 @@ OS:AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed, autosize, !- Speed 3 Supply Air Flow Rate During Cooling Operation {m3/s} autosize; !- Speed 4 Supply Air Flow Rate During Cooling Operation {m3/s} -OS:Schedule:Constant, - {1540674d-a780-43fe-a8dd-b0b23e85b39e}, !- Handle - Always On Discrete, !- Name - {0dd600d4-b8cb-4c84-8eb6-780de152cd00}, !- Schedule Type Limits Name - 1; !- Value - -OS:ScheduleTypeLimits, - {0dd600d4-b8cb-4c84-8eb6-780de152cd00}, !- Handle - OnOff 1, !- Name - 0, !- Lower Limit Value - 1, !- Upper Limit Value - Discrete, !- Numeric Type - Availability; !- Unit Type - OS:Coil:Cooling:DX:VariableSpeed, {3ef4dbff-bbcf-4645-93ab-fcd09507f984}, !- Handle Coil Cooling DX Variable Speed - Two Speeds, !- Name @@ -13607,3 +13593,65 @@ OS:Schedule:Day, 0, !- Minute 1 27; !- Value Until Time 1 +OS:ZoneHVAC:EvaporativeCoolerUnit, + {d2f28626-5582-4e24-82ed-dfab77b63326}, !- Handle + Zone HVAC Evaporative Cooler Unit, !- Name + {9f54092d-a4a8-41b8-a381-c4c332ecb843}, !- Availability Schedule Name + , !- Availability Manager List Name + , !- Outdoor Air Inlet Node Name + , !- Cooler Outlet Node Name + , !- Zone Relief Air Node Name + {3247e7b6-3164-4d86-8f4e-a8238615ac29}, !- Supply Air Fan Name + autosize, !- Design Supply Air Flow Rate {m3/s} + BlowThrough, !- Fan Placement + ZoneTemperatureDeadbandOnOffCycling, !- Cooler Unit Control Method + 1, !- Throttling Range Temperature Difference {deltaC} + 100, !- Cooling Load Control Threshold Heat Transfer Rate {W} + {5e5b2500-4e30-4444-914c-39676a69a23b}, !- First Evaporative Cooler + , !- Second Evaporative Cooler + , !- Design Specification ZoneHVAC Sizing + 100; !- Shut Off Relative Humidity {percent} + +OS:Fan:SystemModel, + {3247e7b6-3164-4d86-8f4e-a8238615ac29}, !- Handle + Zone HVAC Evaporative Cooler Unit FanSystemModel, !- Name + {9f54092d-a4a8-41b8-a381-c4c332ecb843}, !- Availability Schedule Name + , !- Air Inlet Node Name + , !- Air Outlet Node Name + autosize, !- Design Maximum Air Flow Rate {m3/s} + Discrete, !- Speed Control Method + 0.2, !- Electric Power Minimum Flow Rate Fraction + 500, !- Design Pressure Rise {Pa} + 0.9, !- Motor Efficiency + 1, !- Motor In Air Stream Fraction + autosize, !- Design Electric Power Consumption {W} + PowerPerFlowPerPressure, !- Design Power Sizing Method + 840, !- Electric Power Per Unit Flow Rate {W/(m3/s)} + 1.66667, !- Electric Power Per Unit Flow Rate Per Unit Pressure {W-s/m3-Pa} + 0.7, !- Fan Total Efficiency + , !- Electric Power Function of Flow Fraction Curve Name + , !- Night Ventilation Mode Pressure Rise {Pa} + , !- Night Ventilation Mode Flow Fraction + , !- Motor Loss Zone Name + 0, !- Motor Loss Radiative Fraction + General; !- End-Use Subcategory + +OS:EvaporativeCooler:Direct:ResearchSpecial, + {5e5b2500-4e30-4444-914c-39676a69a23b}, !- Handle + Zone HVAC Evaporative Cooler Unit First Evap Cooler, !- Name + {9f54092d-a4a8-41b8-a381-c4c332ecb843}, !- Availability Schedule Name + 1, !- Cooler Design Effectiveness + 0, !- Recirculating Water Pump Power Consumption {W} + , !- Primary Air Design Flow Rate {m3/s} + , !- Air Inlet Node Name + , !- Air Outlet Node Name + , !- Sensor Node Name + 0, !- Drift Loss Fraction + 0, !- Blowdown Concentration Ratio + , !- Effectiveness Flow Ratio Modifier Curve Name + 0.1, !- Water Pump Power Sizing Factor {W/(m3/s)} + , !- Water Pump Power Modifier Curve Name + 16, !- Evaporative Operation Minimum Drybulb Temperature + 24, !- Evaporative Operation Maximum Limit Wetbulb Temperature + 28; !- Evaporative Operation Maximum Limit Drybulb Temperature + diff --git a/src/openstudio_lib/IconLibrary.cpp b/src/openstudio_lib/IconLibrary.cpp index d1969eb21..59664f894 100644 --- a/src/openstudio_lib/IconLibrary.cpp +++ b/src/openstudio_lib/IconLibrary.cpp @@ -230,6 +230,8 @@ IconLibrary::IconLibrary() { m_icons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_Dehumidifier_DX).value()] = new QPixmap(":/images/dehumidifier_dx.png"); m_icons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_EnergyRecoveryVentilator).value()] = new QPixmap(":/images/energy_recov_vent.png"); + m_icons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_EvaporativeCoolerUnit).value()] = + new QPixmap(":/images/zonehvac_evaporativecoolerunit.png"); m_icons[openstudio::IddObjectType(openstudio::IddObjectType::OS_Coil_Heating_Water_Baseboard).value()] = new QPixmap(":/images/coilheatingwater_baseboard.png"); m_icons[openstudio::IddObjectType(openstudio::IddObjectType::OS_Coil_Heating_Water_Baseboard_Radiant).value()] = @@ -701,6 +703,8 @@ IconLibrary::IconLibrary() { new QPixmap(":/images/mini_icons/coilheatingwater_baseboard_mini.png"); m_miniIcons[openstudio::IddObjectType(openstudio::IddObjectType::OS_Coil_Heating_Water_Baseboard_Radiant).value()] = new QPixmap(":/images/mini_icons/Coil_Heating_Water_Baseboard_Radiant.png"); + m_miniIcons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_EvaporativeCoolerUnit).value()] = + new QPixmap(":/images/mini_icons/zonehvac_evaporativecoolerunit.png"); m_miniIcons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_FourPipeFanCoil).value()] = new QPixmap(":/images/mini_single_ducts_constant_vol_4pipe.png"); m_miniIcons[openstudio::IddObjectType(openstudio::IddObjectType::OS_ZoneHVAC_HighTemperatureRadiant).value()] = diff --git a/src/openstudio_lib/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index a9051b6e8..cf9dcd884 100644 --- a/src/openstudio_lib/LocationTabView.cpp +++ b/src/openstudio_lib/LocationTabView.cpp @@ -13,7 +13,10 @@ #include "OSItemSelectorButtons.hpp" #include "SchedulesTabController.hpp" +#include "../shared_gui_components/OSComboBox.hpp" #include "../shared_gui_components/OSGridView.hpp" +#include "../shared_gui_components/OSQuantityEdit.hpp" +#include "../shared_gui_components/OSSwitch.hpp" #include "../openstudio_app/OpenStudioApp.hpp" @@ -70,6 +73,7 @@ #include #include #include +#include static constexpr auto NAME("Name: "); static constexpr auto LATITUDE("Latitude: "); @@ -174,6 +178,11 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& weatherFileGridLayout->setContentsMargins(7, 3, 7, 7); weatherFileGridLayout->setSpacing(7); + // ***** Measure Tags GridLayout ***** + auto* siteInfoGridLayout = new QGridLayout(); + siteInfoGridLayout->setContentsMargins(7, 7, 7, 7); + siteInfoGridLayout->setSpacing(7); + // ***** Measure Tags GridLayout ***** auto* measureTagsGridLayout = new QGridLayout(); measureTagsGridLayout->setContentsMargins(7, 7, 7, 7); @@ -236,16 +245,13 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& weatherFileGridLayout->addLayout(hLayout, i++, 0); - m_latitudeLbl = new QLabel(tr("Latitude: ")); + m_latitudeLbl = new QLabel(tr(LATITUDE)); weatherFileGridLayout->addWidget(m_latitudeLbl, i++, 0); - m_longitudeLbl = new QLabel(tr("Longitude: ")); + m_longitudeLbl = new QLabel(tr(LONGITUDE)); weatherFileGridLayout->addWidget(m_longitudeLbl, i++, 0); - m_elevationLbl = new QLabel(tr("Elevation: ")); - weatherFileGridLayout->addWidget(m_elevationLbl, i++, 0); - - m_timeZoneLbl = new QLabel(tr("Time Zone: ")); + m_timeZoneLbl = new QLabel(tr(TIME_ZONE)); weatherFileGridLayout->addWidget(m_timeZoneLbl, i++, 0); // ***** Weather File Download Location ***** @@ -258,6 +264,91 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& leftVLayout->addLayout(weatherFileGridLayout); leftVLayout->addStretch(); + // Site Information + { + label = new QLabel(tr("Site Information:")); + label->setObjectName("H2"); + leftVLayout->addWidget(label); + + i = 0; + + { + label = new QLabel(tr("Keep Site Location Information")); + label->setToolTip(tr("If enabled, this will write the Site:Location object that will keep the Elevation change for example.")); + + m_keepSiteLocationInfo = new OSSwitch2(); + + m_keepSiteLocationInfo->bind(*m_site, BoolGetter([this] { return m_site->keepSiteLocationInformation(); }), + boost::optional([this](bool b) { + bool result = m_site->setKeepSiteLocationInformation(b); + + if (result) { + + // force the style to update + m_elevation->clearCachedText(); + + if (b) { + // set elevation if turning on + if (m_site->isElevationDefaulted()) { + m_site->setElevation(m_weatherFileElevation); + } else { + m_site->setElevation(m_site->elevation()); + } + } else { + // reset elevation if turning off + if (std::abs(m_weatherFileElevation) > 0.01) { + m_site->setElevation(m_weatherFileElevation); + } else { + m_site->resetElevation(); + } + } + } + return result; + }), + boost::optional([this] { m_site->resetKeepSiteLocationInformation(); }), + boost::optional([this] { return m_site->isKeepSiteLocationInformationDefaulted(); })); + + siteInfoGridLayout->addWidget(label, i, 0); + siteInfoGridLayout->addWidget(m_keepSiteLocationInfo, i++, 1); + } + { + label = new QLabel(tr(ELEVATION)); + label->setToolTip(tr("Elevation affects the wind speed at the site, and is defaulted to the Weather File's elevation")); + + m_elevation = new OSQuantityEdit2("m", "m", "ft", m_isIP); + connect(this, &LocationView::toggleUnitsClicked, m_elevation, &OSQuantityEdit2::onUnitSystemChange); + + // Bind is delayed until after update() is called, so that the weatherFileElevation is set correctly. + + m_elevation->setFixedWidth(200); + + siteInfoGridLayout->addWidget(label, i, 0); + siteInfoGridLayout->addWidget(m_elevation, i++, 1); + } + // Terrain + { + label = new QLabel(tr("Terrain")); + label->setToolTip(tr("Terrain affects the wind speed at the site.")); + + m_terrain = new OSComboBox2(); + m_terrain->bind(*m_site, static_cast(&openstudio::toString), &model::Site::validTerrainValues, + std::bind(&model::Site::terrain, m_site.get_ptr()), + std::bind(&model::Site::setTerrain, m_site.get_ptr(), std::placeholders::_1), + boost::optional(std::bind(&model::Site::resetTerrain, m_site.get_ptr())), + boost::optional(std::bind(&model::Site::isTerrainDefaulted, m_site.get_ptr()))); + + m_terrain->setFixedWidth(200); + + siteInfoGridLayout->addWidget(label, i, 0); + siteInfoGridLayout->addWidget(m_terrain, i++, 1); + } + + // ***** Site Info GridLayout ***** + siteInfoGridLayout->setColumnStretch(++i, 10); + leftVLayout->addLayout(siteInfoGridLayout); + leftVLayout->addStretch(); + } + // ***** Climate Zones ***** label = new QLabel(tr("Measure Tags (Optional):")); label->setObjectName("H2"); @@ -400,11 +491,37 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& connect(m_itemSelectorButtons, &OSItemSelectorButtons::purgeClicked, m_designDaysGridView, &DesignDayGridView::onPurgeClicked); update(); + { + m_elevation->bind(m_isIP, *m_site, DoubleGetter([this] { return m_site->elevation(); }), boost::optional([this](double d) { + // turn keep site info on + m_site->setKeepSiteLocationInformation(true); + return m_site->setElevation(d); + }), + boost::optional([this] { + // turn keep site info off + m_site->setKeepSiteLocationInformation(false); + + // force the style to update + m_elevation->clearCachedText(); + + if (std::abs(m_weatherFileElevation) > 0.01) { + m_site->setElevation(m_weatherFileElevation); + } else { + m_site->resetElevation(); + } + }), + boost::none, // autosize + boost::none, // autocalculate + boost::optional([this] { // + return (m_site->isElevationDefaulted() || !m_site->keepSiteLocationInformation()); + })); + } onSelectItem(); } LocationView::~LocationView() { + // m_terrain->unbind(); // NOTE: I don't think this is necessary saveQSettings(); } @@ -496,6 +613,7 @@ void LocationView::update() { if (fileExists) { m_weatherFileBtn->setText(tr("Change Weather File")); + m_weatherFileElevation = weatherFile->elevation(); setSiteInfo(); } else { m_weatherFileBtn->setText(tr("Set Weather File")); @@ -526,11 +644,6 @@ void LocationView::setSiteInfo() { info += temp; m_longitudeLbl->setText(info); - info = tr(ELEVATION); - temp.setNum(m_site->elevation()); - info += temp; - m_elevationLbl->setText(info); - info = tr(TIME_ZONE); temp.setNum(m_site->timeZone()); info += temp; @@ -544,9 +657,9 @@ void LocationView::clearSiteInfo() { m_longitudeLbl->setText(tr(LONGITUDE)); - m_elevationLbl->setText(tr(ELEVATION)); - m_timeZoneLbl->setText(tr(TIME_ZONE)); + + m_weatherFileElevation = 0.0; } // ***** SLOTS ***** @@ -637,7 +750,10 @@ void LocationView::onWeatherFileBtnClicked() { m_site->setName(weatherFile->city()); m_site->setLatitude(weatherFile->latitude()); m_site->setLongitude(weatherFile->longitude()); + m_weatherFileElevation = weatherFile->elevation(); + m_site->setKeepSiteLocationInformation(false); m_site->setElevation(weatherFile->elevation()); + m_site->resetTerrain(); m_site->setTimeZone(weatherFile->timeZone()); m_lastEpwPathOpened = QFileInfo(fileName).absoluteFilePath(); diff --git a/src/openstudio_lib/LocationTabView.hpp b/src/openstudio_lib/LocationTabView.hpp index 4aea184d8..5df69a75c 100644 --- a/src/openstudio_lib/LocationTabView.hpp +++ b/src/openstudio_lib/LocationTabView.hpp @@ -23,7 +23,10 @@ namespace openstudio { class EpwFile; class DesignDayGridView; +class OSComboBox2; class OSItemSelectorButtons; +class OSQuantityEdit2; +class OSSwitch2; namespace model { class Model; @@ -97,17 +100,23 @@ class LocationView : public QWidget YearSettingsWidget* m_yearSettingsWidget = nullptr; DesignDayGridView* m_designDaysGridView = nullptr; OSItemSelectorButtons* m_itemSelectorButtons = nullptr; - QString m_modelTempDir = QString(); - QString m_lastEpwPathOpened = QString(); - QString m_lastDdyPathOpened = QString(); - QComboBox* m_ashraeClimateZone = nullptr; - QComboBox* m_cecClimateZone = nullptr; + QString m_modelTempDir; + QString m_lastEpwPathOpened; + QString m_lastDdyPathOpened; + + QPushButton* m_weatherFileBtn = nullptr; QLineEdit* m_siteName = nullptr; QLabel* m_latitudeLbl = nullptr; QLabel* m_longitudeLbl = nullptr; - QLabel* m_elevationLbl = nullptr; QLabel* m_timeZoneLbl = nullptr; - QPushButton* m_weatherFileBtn = nullptr; + + OSComboBox2* m_terrain = nullptr; + OSSwitch2* m_keepSiteLocationInfo = nullptr; + OSQuantityEdit2* m_elevation = nullptr; + double m_weatherFileElevation = 0.0; + QComboBox* m_ashraeClimateZone = nullptr; + QComboBox* m_cecClimateZone = nullptr; + bool m_isIP; signals: diff --git a/src/openstudio_lib/MainRightColumnController.cpp b/src/openstudio_lib/MainRightColumnController.cpp index 5a91d635b..cffb0f17b 100644 --- a/src/openstudio_lib/MainRightColumnController.cpp +++ b/src/openstudio_lib/MainRightColumnController.cpp @@ -729,15 +729,6 @@ void MainRightColumnController::configureForFacilitySubTab(int subTabID) { myLibraryList->setItemsRemoveable(false); myLibraryList->setItemsType(OSItemType::LibraryItem); - myLibraryList->addModelObjectType(IddObjectType::OS_Fan_ZoneExhaust, "Fan Zone Exhaust"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_PackagedTerminalHeatPump, "PTHP"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner, "PTAC"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_WaterToAirHeatPump, "Water To Air HP"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_ConstantFlow, "Low Temp Radiant Constant Flow"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_VariableFlow, "Low Temp Radiant Variable Flow"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_Electric, "Low Temp Radiant Electric"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_HighTemperatureRadiant, "High Temp Radiant"); - myLibraryList->addModelObjectCategoryPlaceholder("Zone HVAC"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_WindowDataFile, "Window Data File Constructions"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_FfactorGroundFloor, "F-factor Ground Floor Constructions"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_CfactorUndergroundWall, "C-factor Underground Wall Constructions"); @@ -856,15 +847,6 @@ void MainRightColumnController::configureForSpacesSubTab(int subTabID) { myLibraryList->addModelObjectType(IddObjectType::OS_WindowProperty_FrameAndDivider, "Frame And Divider Window Property"); myLibraryList->addModelObjectType(IddObjectType::OS_DaylightingDevice_Shelf, "DaylightingDevice Shelf"); myLibraryList->addModelObjectCategoryPlaceholder("Daylighting"); - myLibraryList->addModelObjectType(IddObjectType::OS_Fan_ZoneExhaust, "Fan Zone Exhaust"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_PackagedTerminalHeatPump, "PTHP"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner, "PTAC"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_WaterToAirHeatPump, "Water To Air HP"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_ConstantFlow, "Low Temp Radiant Constant Flow"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_VariableFlow, "Low Temp Radiant Variable Flow"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_LowTemperatureRadiant_Electric, "Low Temp Radiant Electric"); - myLibraryList->addModelObjectType(IddObjectType::OS_ZoneHVAC_HighTemperatureRadiant, "High Temp Radiant"); - myLibraryList->addModelObjectCategoryPlaceholder("Zone HVAC"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_WindowDataFile, "Window Data File Constructions"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_FfactorGroundFloor, "F-factor Ground Floor Constructions"); myLibraryList->addModelObjectType(IddObjectType::OS_Construction_CfactorUndergroundWall, "C-factor Underground Wall Constructions"); @@ -949,6 +931,7 @@ void MainRightColumnController::configureForThermalZonesSubTab(int subTabID) { libraryWidget->addModelObjectCategoryPlaceholder("Water Heaters"); libraryWidget->addModelObjectType(IddObjectType::OS_AirLoopHVAC_UnitarySystem, "Unitary System"); libraryWidget->addModelObjectCategoryPlaceholder("Unitary Systems"); + libraryWidget->addModelObjectType(IddObjectType::OS_ZoneHVAC_EvaporativeCoolerUnit, "Evaporative Cooler Unit"); libraryWidget->addModelObjectType(IddObjectType::OS_ZoneHVAC_CoolingPanel_RadiantConvective_Water, "Cooling Panel Radiant Convective Water"); libraryWidget->addModelObjectType(IddObjectType::OS_ZoneHVAC_Baseboard_Convective_Electric, "Baseboard Convective Electric"); libraryWidget->addModelObjectType(IddObjectType::OS_ZoneHVAC_Baseboard_Convective_Water, "Baseboard Convective Water"); diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index cca519b31..a6727c420 100644 --- a/src/openstudio_lib/SimSettingsView.cpp +++ b/src/openstudio_lib/SimSettingsView.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -300,6 +302,10 @@ void SimSettingsView::createWidgets() { collapsibleInspector = new CollapsibleInspector("Output Diagnostics", createOutputDiagnosticsWidget()); mainLayout->addWidget(collapsibleInspector); + //******************* OS:OutputControl:ResilienceSummaries ******************* + collapsibleInspector = new CollapsibleInspector("Output Control Resilience Summaries", createOutputControlResilienceSummariesWidget()); + mainLayout->addWidget(collapsibleInspector); + mainLayout->addStretch(); } @@ -1135,6 +1141,29 @@ QWidget* SimSettingsView::createOutputDiagnosticsWidget() { return widget; } +QWidget* SimSettingsView::createOutputControlResilienceSummariesWidget() { + + auto* gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(7, 7, 7, 7); + gridLayout->setSpacing(GRID_LAYOUT_SPACING); + gridLayout->setAlignment(Qt::AlignLeft); + + int row = 0; + int col = 0; + + addField(gridLayout, row, col, "Heat Index Algorithm", m_outputControlResilienceSummaries_heatIndexAlgorithm); + col++; + for (const auto& hiAlgo : model::OutputControlResilienceSummaries::heatIndexAlgorithmValues()) { + m_json_optionType->addItem(hiAlgo.c_str()); + } + + auto* widget = new QWidget(); + widget->setLayout(gridLayout); + widget->hide(); + + return widget; +} + void SimSettingsView::addField(QGridLayout* gridLayout, int row, int column, QString text, OSComboBox2*& comboBox) { auto* label = new QLabel(text, this); label->setFixedWidth(TEXT_FIELD_WIDTH); @@ -1245,6 +1274,7 @@ void SimSettingsView::attachAll() { attachOutputJSON(); attachOutputTableSummaryReports(); attachOutputDiagnostics(); + attachOutputControlResilienceSummaries(); } void SimSettingsView::detachAll() { @@ -1267,6 +1297,7 @@ void SimSettingsView::detachAll() { detachOutputJSON(); detachOutputTableSummaryReports(); detachOutputDiagnostics(); + detachOutputControlResilienceSummaries(); } void SimSettingsView::attachRunPeriod() { @@ -1934,6 +1965,19 @@ void SimSettingsView::attachOutputDiagnostics() { ); } +void SimSettingsView::attachOutputControlResilienceSummaries() { + // If it wasn't already in the model, it'll be initialized, and the Ctor defaults to "Simplified" which is the same as NOT having it in the model + auto mo = m_model.getUniqueModelObject(); + + m_outputControlResilienceSummaries_heatIndexAlgorithm->bind( + mo, static_cast(&openstudio::toString), &model::OutputControlResilienceSummaries::heatIndexAlgorithmValues, + StringGetter(std::bind(&model::OutputControlResilienceSummaries::heatIndexAlgorithm, mo)), + std::bind(&model::OutputControlResilienceSummaries::setHeatIndexAlgorithm, mo, std::placeholders::_1), + boost::none, // No reset + boost::none // No isDefaulted + ); +} + void SimSettingsView::detachRunPeriod() { m_useWeatherFileHolidaysandSpecialDays->unbind(); m_useWeatherFileDaylightSavingsPeriod->unbind(); @@ -2065,6 +2109,10 @@ void SimSettingsView::detachOutputDiagnostics() { m_diagnostics_displayExtraWarnings->unbind(); } +void SimSettingsView::detachOutputControlResilienceSummaries() { + m_outputControlResilienceSummaries_heatIndexAlgorithm->unbind(); +} + //***** SLOTS ***** void SimSettingsView::on_runPeriodGroupClicked(int idx) { diff --git a/src/openstudio_lib/SimSettingsView.hpp b/src/openstudio_lib/SimSettingsView.hpp index 21abcffd0..a54eb8d6b 100644 --- a/src/openstudio_lib/SimSettingsView.hpp +++ b/src/openstudio_lib/SimSettingsView.hpp @@ -71,6 +71,7 @@ class SimSettingsView QWidget* createOutputJSONWidget(); QWidget* createOutputTableSummaryReportsWidget(); QWidget* createOutputDiagnosticsWidget(); + QWidget* createOutputControlResilienceSummariesWidget(); void addField(QGridLayout* gridLayout, int row, int column, QString text, OSComboBox2*& comboBox); @@ -110,6 +111,7 @@ class SimSettingsView void attachOutputJSON(); void attachOutputTableSummaryReports(); void attachOutputDiagnostics(); + void attachOutputControlResilienceSummaries(); void detachAll(); void detachRunPeriod(); @@ -131,6 +133,7 @@ class SimSettingsView void detachOutputJSON(); void detachOutputTableSummaryReports(); void detachOutputDiagnostics(); + void detachOutputControlResilienceSummaries(); model::Model m_model; boost::optional m_shadowCalculation; @@ -272,6 +275,8 @@ class SimSettingsView OSSwitch2* m_table_allSummary; OSSwitch2* m_diagnostics_displayExtraWarnings; + OSComboBox2* m_outputControlResilienceSummaries_heatIndexAlgorithm; + signals: void toggleUnitsClicked(bool displayIP); diff --git a/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit.png b/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit.png new file mode 100644 index 000000000..523f20cc7 Binary files /dev/null and b/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit.png differ diff --git a/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit@2x.png b/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit@2x.png new file mode 100644 index 000000000..692da3d2c Binary files /dev/null and b/src/openstudio_lib/images/mini_icons/zonehvac_evaporativecoolerunit@2x.png differ diff --git a/src/openstudio_lib/images/zonehvac_evaporativecoolerunit.png b/src/openstudio_lib/images/zonehvac_evaporativecoolerunit.png new file mode 100644 index 000000000..9bf7182f3 Binary files /dev/null and b/src/openstudio_lib/images/zonehvac_evaporativecoolerunit.png differ diff --git a/src/openstudio_lib/images/zonehvac_evaporativecoolerunit@2x.png b/src/openstudio_lib/images/zonehvac_evaporativecoolerunit@2x.png new file mode 100644 index 000000000..a881738df Binary files /dev/null and b/src/openstudio_lib/images/zonehvac_evaporativecoolerunit@2x.png differ diff --git a/src/openstudio_lib/library/OpenStudioPolicy.xml b/src/openstudio_lib/library/OpenStudioPolicy.xml index 13804b279..15143aa1a 100644 --- a/src/openstudio_lib/library/OpenStudioPolicy.xml +++ b/src/openstudio_lib/library/OpenStudioPolicy.xml @@ -153,6 +153,13 @@ + + + + + + + diff --git a/src/openstudio_lib/openstudio.qrc b/src/openstudio_lib/openstudio.qrc index c254c7fb1..2a984c23c 100644 --- a/src/openstudio_lib/openstudio.qrc +++ b/src/openstudio_lib/openstudio.qrc @@ -655,6 +655,8 @@ images/zone_icon_off@2x.png images/zone_icon_pressed.png images/zone_icon_pressed@2x.png + images/zonehvac_evaporativecoolerunit.png + images/zonehvac_evaporativecoolerunit@2x.png images/zonehvac_low_temperature_radiant_electric.png images/zonehvac_low_temperature_radiant_electric@2x.png images/zonehvac_coolingpanel_radiantconvective_water.png @@ -1122,6 +1124,8 @@ images/mini_icons/window_material_gasmixture@2x.png images/mini_icons/window_material_glazing.png images/mini_icons/window_material_glazing@2x.png + images/mini_icons/zonehvac_evaporativecoolerunit.png + images/mini_icons/zonehvac_evaporativecoolerunit@2x.png images/mini_icons/zonehvac_low_temperature_radiant_electric.png images/mini_icons/zonehvac_low_temperature_radiant_electric@2x.png images/mini_icons/zonehvac_coolingpanel_radiantconvective_water.png diff --git a/src/openstudio_lib/test/IconLibrary_GTest.cpp b/src/openstudio_lib/test/IconLibrary_GTest.cpp index ada2d8f5a..6ab0e5592 100644 --- a/src/openstudio_lib/test/IconLibrary_GTest.cpp +++ b/src/openstudio_lib/test/IconLibrary_GTest.cpp @@ -99,6 +99,7 @@ TEST_F(OpenStudioLibFixture, IconLibrary_Icon) { //iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_Screen); //iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_Shade); //iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_SimpleGlazingSystem); + iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_EvaporativeCoolerUnit); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_CoolingPanel_RadiantConvective_Water); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_PackagedTerminalHeatPump); @@ -198,6 +199,7 @@ TEST_F(OpenStudioLibFixture, IconLibrary_MiniIcon) { iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_Screen); iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_Shade); iddObjectTypes.push_back(IddObjectType::OS_WindowMaterial_SimpleGlazingSystem); + iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_EvaporativeCoolerUnit); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_CoolingPanel_RadiantConvective_Water); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner); iddObjectTypes.push_back(IddObjectType::OS_ZoneHVAC_PackagedTerminalHeatPump); diff --git a/src/shared_gui_components/BuildingComponentDialogCentralWidget.cpp b/src/shared_gui_components/BuildingComponentDialogCentralWidget.cpp index 364c3cede..ade6236e9 100644 --- a/src/shared_gui_components/BuildingComponentDialogCentralWidget.cpp +++ b/src/shared_gui_components/BuildingComponentDialogCentralWidget.cpp @@ -15,6 +15,7 @@ #include #include + #include #include #include @@ -168,89 +169,53 @@ void BuildingComponentDialogCentralWidget::setTid() { requestComponents(m_filterType, m_tid, m_pageIdx, m_searchString); } -std::vector BuildingComponentDialogCentralWidget::fetchAndSortResponses(const std::string& filterType, int tid, - const QString& searchString) { - m_allResponses.clear(); - - RemoteBCL remoteBCL; - remoteBCL.setTimeOutSeconds(m_timeoutSeconds); - - std::vector responses; - int totalPages = 1; - int currentPage = 0; - - // Collect all responses from all pages - do { - std::vector pageResponses; - if (filterType == "components") { - pageResponses = remoteBCL.searchComponentLibrary(searchString.toStdString(), tid, currentPage); - } else if (filterType == "measures") { - pageResponses = remoteBCL.searchMeasureLibrary(searchString.toStdString(), tid, currentPage); - } - responses.insert(responses.end(), pageResponses.begin(), pageResponses.end()); - totalPages = remoteBCL.numResultPages(); - } while (++currentPage < totalPages); - - if (!responses.empty()) { - std::sort(responses.begin(), responses.end(), [](const BCLSearchResult& a, const BCLSearchResult& b) { return a.name() < b.name(); }); - } - - return responses; -} - // Note: don't call this directly if the "wait" screen is desired void BuildingComponentDialogCentralWidget::setTid(const std::string& filterType, int tid, int pageIdx, const QString& title, const QString& searchString) { - std::string newKey = std::to_string(tid) + filterType + searchString.toStdString(); - std::string currentKey = std::to_string(m_tid) + m_filterType + m_searchString.toStdString(); + if (m_tid != tid || m_searchString != searchString) { + m_collapsibleComponentList->firstPage(); + } - m_searchString = searchString; m_filterType = filterType; + m_tid = tid; - if (newKey != currentKey) { - m_allResponses = fetchAndSortResponses(filterType, tid, searchString); - m_collapsibleComponentList->firstPage(); - pageIdx = 0; - } + m_searchString = searchString; - // Clear existing components + //std::vector components = m_collapsibleComponentList->components(); std::vector components = m_componentList->components(); // TODO replace with code above + for (auto& comp : components) { delete comp; } - // Paginate responses - int itemsPerPage = 10; // Assuming 10 items per page - - if (!m_allResponses.empty()) { - size_t startIdx = pageIdx * itemsPerPage; - size_t endIdx = std::min(startIdx + itemsPerPage, m_allResponses.size()); - std::vector paginatedResponses(m_allResponses.begin() + startIdx, m_allResponses.begin() + endIdx); + RemoteBCL remoteBCL; + remoteBCL.setTimeOutSeconds(m_timeoutSeconds); + std::vector responses; + if (filterType == "components") { + responses = remoteBCL.searchComponentLibrary(searchString.toStdString(), tid, pageIdx); + } else if (filterType == "measures") { + responses = remoteBCL.searchMeasureLibrary(searchString.toStdString(), tid, pageIdx); + } - for (const auto& response : paginatedResponses) { - auto* component = new Component(response); + for (const auto& response : responses) { + auto* component = new Component(response); - // TODO replace with a componentList owned by m_collapsibleComponentList - m_componentList->addComponent(component); - } + // TODO replace with a componentList owned by m_collapsibleComponentList + m_componentList->addComponent(component); } // the parent taxonomy m_collapsibleComponentList->setText(title); // the total number of results - int lastTotalResults = m_allResponses.size(); + int lastTotalResults = remoteBCL.lastTotalResults(); m_collapsibleComponentList->setNumResults(lastTotalResults); // the number of pages of results - if (lastTotalResults == 0) { - m_collapsibleComponentList->setNumPages(0); - } else { - int numResultPages = (lastTotalResults % itemsPerPage == 0) ? (lastTotalResults / itemsPerPage) : (lastTotalResults / itemsPerPage) + 1; - m_collapsibleComponentList->setNumPages(numResultPages); - } + int numResultPages = remoteBCL.numResultPages(); + m_collapsibleComponentList->setNumPages(numResultPages); // make sure the header is expanded if (m_collapsibleComponentList->checkedCollapsibleComponent()) { diff --git a/src/shared_gui_components/BuildingComponentDialogCentralWidget.hpp b/src/shared_gui_components/BuildingComponentDialogCentralWidget.hpp index 10728ea57..b1e1cc2d5 100644 --- a/src/shared_gui_components/BuildingComponentDialogCentralWidget.hpp +++ b/src/shared_gui_components/BuildingComponentDialogCentralWidget.hpp @@ -16,7 +16,6 @@ #include // Signal-Slot replacement #include #include -#include #include "../shared_gui_components/ProgressBarWithError.hpp" @@ -55,9 +54,6 @@ class BuildingComponentDialogCentralWidget void setTid(); void componentDownloadComplete(const std::string& uid, const boost::optional& component); void measureDownloadComplete(const std::string& uid, const boost::optional& measure); - std::vector m_allResponses; - - std::vector fetchAndSortResponses(const std::string& filterType, int tid, const QString& searchString); int m_tid; CollapsibleComponentList* m_collapsibleComponentList; diff --git a/src/shared_gui_components/Component.cpp b/src/shared_gui_components/Component.cpp index a97bc061f..c5283782c 100644 --- a/src/shared_gui_components/Component.cpp +++ b/src/shared_gui_components/Component.cpp @@ -430,17 +430,20 @@ void Component::createAbridgedLayout() { label = new QLabel(string); leftLayout->addWidget(label); + QString labelString; + QString typeString = "Unknown"; + if (m_componentType == "component") { + labelString = "Type: "; + } else if (m_componentType == "measure" || m_componentType == "MeasureType") { + labelString = "Measure Type: "; + } for (const Attribute& attribute : m_attributes) { string = attribute.name().c_str(); if (m_componentType == "component") { if (string.toStdString() == OPENSTUDIO_TYPE) { openstudio::AttributeValueType type = attribute.valueType(); if (type == AttributeValueType::String) { - string = attribute.valueAsString().c_str(); - QString temp("Type: "); - temp += string; - label = new QLabel(temp); - leftLayout->addWidget(label); + typeString = attribute.valueAsString().c_str(); break; } } @@ -448,16 +451,16 @@ void Component::createAbridgedLayout() { if (string.toStdString() == "Measure Type") { openstudio::AttributeValueType type = attribute.valueType(); if (type == AttributeValueType::String) { - string = attribute.valueAsString().c_str(); - QString temp("Measure Type: "); - temp += string; - label = new QLabel(temp); - leftLayout->addWidget(label); + typeString = attribute.valueAsString().c_str(); } } } } + labelString += typeString; + label = new QLabel(labelString); + leftLayout->addWidget(label); + m_msg = new QLabel(this); if (m_error) { m_msg->setStyleSheet("color:#F00;font-style:italic;"); diff --git a/src/shared_gui_components/OSComboBox.cpp b/src/shared_gui_components/OSComboBox.cpp index fa3de7d53..a5c58e87e 100644 --- a/src/shared_gui_components/OSComboBox.cpp +++ b/src/shared_gui_components/OSComboBox.cpp @@ -250,6 +250,14 @@ void OSComboBox2::onModelObjectRemoved(const Handle& handle) { unbind(); } +void OSComboBox2::onActivated(int index) { + if (m_choiceConcept) { + if (index == this->currentIndex() && m_choiceConcept->isDefaulted()) { + this->onCurrentIndexChanged(this->currentText()); + } + } +} + void OSComboBox2::onCurrentIndexChanged(const QString& text) { emit inFocus(m_focused, hasData()); @@ -347,6 +355,7 @@ void OSComboBox2::completeBind() { m_modelObject->getImpl() ->onRemoveFromWorkspace.connect(this); + connect(this, static_cast(&OSComboBox2::activated), this, &OSComboBox2::onActivated); connect(this, static_cast(&OSComboBox2::currentTextChanged), this, &OSComboBox2::onCurrentIndexChanged); if (isEditable()) { diff --git a/src/shared_gui_components/OSComboBox.hpp b/src/shared_gui_components/OSComboBox.hpp index 7f13c6751..2549b5090 100644 --- a/src/shared_gui_components/OSComboBox.hpp +++ b/src/shared_gui_components/OSComboBox.hpp @@ -180,6 +180,8 @@ class OSComboBox2 void onModelObjectRemoved(const Handle& handle); + void onActivated(int index); + void onCurrentIndexChanged(const QString& text); void onEditTextChanged(const QString& text); diff --git a/src/shared_gui_components/OSQuantityEdit.cpp b/src/shared_gui_components/OSQuantityEdit.cpp index d480dc84c..6b705b65a 100644 --- a/src/shared_gui_components/OSQuantityEdit.cpp +++ b/src/shared_gui_components/OSQuantityEdit.cpp @@ -82,6 +82,10 @@ void OSQuantityEdit2::setLocked(bool locked) { m_lineEdit->setLocked(locked); } +void OSQuantityEdit2::clearCachedText() { + m_text = "UNINITIALIZED"; +} + QDoubleValidator* OSQuantityEdit2::doubleValidator() { return m_doubleValidator; } diff --git a/src/shared_gui_components/OSQuantityEdit.hpp b/src/shared_gui_components/OSQuantityEdit.hpp index 43267575a..fbd8c53a8 100644 --- a/src/shared_gui_components/OSQuantityEdit.hpp +++ b/src/shared_gui_components/OSQuantityEdit.hpp @@ -84,6 +84,8 @@ class OSQuantityEdit2 void setLocked(bool locked); + void clearCachedText(); + QDoubleValidator* doubleValidator(); void bind(bool isIP, const model::ModelObject& modelObject, DoubleGetter get, boost::optional set = boost::none,