Skip to content
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

Fix #4439 - Correctly Reverse Translate gbXML Schedules #4440

Merged
merged 3 commits into from Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions resources/CMakeLists.txt
Expand Up @@ -269,6 +269,7 @@ SET(gbxml_resources_src
gbxml/ZNETH.xml
gbxml/3951_Geometry_bug.xml
gbxml/3997_WindowScaling_bug.xml
gbxml/TestSchedules.xml
)

# update the resources
Expand Down
164 changes: 164 additions & 0 deletions resources/gbxml/TestSchedules.xml
@@ -0,0 +1,164 @@
<gbXML xmlns="http://www.gbxml.org/schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://www.gbxml.org/schema http://gbxml.org/schema/6-01/GreenBuildingXML_Ver6.01.xsd" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" useSIUnitsForResults="true" SurfaceReferenceLocation="Centerline" temperatureUnit="F" lengthUnit="Feet" areaUnit="SquareFeet" volumeUnit="CubicFeet" version="6.01">
<Campus id="Facility">

<Description>A gbxml test file for Schedules</Description>

<Building id="1">
<Area>200000</Area>
<BuildingStorey id="storey-1">
<Name>storey 1</Name>
<Level>0</Level>
</BuildingStorey>
</Building>
</Campus>

<Schedule type="Fraction" id="Simple_Schedule">
<YearSchedule id="Simple_Schedule_YearSchedule">
<BeginDate>2017-01-01</BeginDate>
<EndDate>2017-12-31</EndDate>
<WeekScheduleId weekScheduleIdRef="Simple_Schedule_WeekSchedule" />
</YearSchedule>
<Name>Simple Year Schedule</Name>
</Schedule>
Comment on lines +15 to +22
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A simple schedule

<WeekSchedule type="Fraction" id="Simple_Schedule_WeekSchedule">
<Day dayScheduleIdRef="Simple_Schedule_DaySchedule" dayType="All" />
<Name>Simple Year Schedule - Typical Week</Name>
</WeekSchedule>
<DaySchedule type="Fraction" id="Simple_Schedule_DaySchedule">
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0.1</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.8</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.2</ScheduleValue>
<ScheduleValue>0.2</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<Name>Simple Year Schedule - Typical Day</Name>
</DaySchedule>


<Schedule type="Fraction" id="Complex_Schedule">
<YearSchedule id="Complex_Schedule_YearSchedule_BeginYear">
<BeginDate>2017-01-01</BeginDate>
<EndDate>2017-06-30</EndDate>
<WeekScheduleId weekScheduleIdRef="Complex_Schedule_WeekSchedule_BeginYear" />
</YearSchedule>
<YearSchedule id="Complex_Schedule_YearSchedule_EndYear">
<BeginDate>2017-07-01</BeginDate>
<EndDate>2017-12-31</EndDate>
<WeekScheduleId weekScheduleIdRef="Complex_Schedule_WeekSchedule_EndYear" />
</YearSchedule>
<Name>Complex Year Schedule</Name>
</Schedule>
<WeekSchedule type="Fraction" id="Complex_Schedule_WeekSchedule_BeginYear">
<Day dayScheduleIdRef="Complex_Schedule_DaySchedule_BeginYear" dayType="All" />
<Name>Complex Year Schedule - Typical Week January to June</Name>
</WeekSchedule>
<DaySchedule type="Fraction" id="Complex_Schedule_DaySchedule_BeginYear">
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0.1</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.8</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.9</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.3</ScheduleValue>
<ScheduleValue>0.2</ScheduleValue>
<ScheduleValue>0.2</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<Name>Complex Year Schedule - Typical Day January to June</Name>
</DaySchedule>

<WeekSchedule type="Fraction" id="Complex_Schedule_WeekSchedule_EndYear">
<Day dayScheduleIdRef="Complex_Schedule_DaySchedule_EndYear_Weekday" dayType="Weekday" />
<Day dayScheduleIdRef="Complex_Schedule_DaySchedule_EndYear_Weekend" dayType="Weekend" />
<Name>Complex Year Schedule - Typical Week July to December</Name>
</WeekSchedule>
<DaySchedule type="Fraction" id="Complex_Schedule_DaySchedule_EndYear_Weekday">
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0.5</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<Name>Complex Year Schedule - Typical Weekday July to December</Name>
</DaySchedule>
<DaySchedule type="Fraction" id="Complex_Schedule_DaySchedule_EndYear_Weekend">
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>1.0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<ScheduleValue>0</ScheduleValue>
<Name>Complex Year Schedule - Typical Weekend July to December</Name>
</DaySchedule>
Comment on lines +56 to +159
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A more complex schedule: two separate periods

  • Jan to June, same day for all
  • July to December, one day schedule for weekday and one for weekends



</gbXML>


2 changes: 1 addition & 1 deletion src/gbxml/MapSchedules.cpp
Expand Up @@ -218,7 +218,7 @@ namespace gbxml {
OS_ASSERT(yd.calendarYear().get() == std::stoi(endDateParts.at(0)));
openstudio::Date endDate = yd.makeDate(std::stoi(endDateParts.at(1)), std::stoi(endDateParts.at(2)));

std::string weekScheduleId = element.child("WeekScheduleId").attribute("weekScheduleIdRef").value();
std::string weekScheduleId = scheduleYearElement.child("WeekScheduleId").attribute("weekScheduleIdRef").value();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actual fix...

Really we need error handling in gbxml... There is currently no validation against the gbXML schema happening and there is very little checking that is done manually (like ensuring that required values/attributes are supplied, or checking that a YearSchedule references a weekScheduleIdRef you make sure it can be found)

I'll open a separate enhancement request for that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

indeed, it's worth discussing adding in some logic or external lib that can validate gbXML. Thanks for opening up an enhancement request.


// this can be made more efficient using QXPath in QXmlPatterns later
for (auto& scheduleWeekElement : root.children("WeekSchedule")) {
Expand Down
174 changes: 173 additions & 1 deletion src/gbxml/Test/ReverseTranslator_GTest.cpp
Expand Up @@ -46,6 +46,12 @@
#include "../../model/Building_Impl.hpp"
#include "../../model/ThermalZone.hpp"
#include "../../model/ThermalZone_Impl.hpp"
#include "../../model/ScheduleDay.hpp"
#include "../../model/ScheduleDay_Impl.hpp"
#include "../../model/ScheduleWeek.hpp"
#include "../../model/ScheduleWeek_Impl.hpp"
#include "../../model/ScheduleYear.hpp"
#include "../../model/ScheduleYear_Impl.hpp"
#include "../../model/Space.hpp"
#include "../../model/Space_Impl.hpp"
#include "../../model/Surface.hpp"
Expand All @@ -56,17 +62,21 @@
#include "../../model/SubSurface_Impl.hpp"
#include "../../model/StandardOpaqueMaterial.hpp"
#include "../../model/StandardOpaqueMaterial_Impl.hpp"
#include "../../model/YearDescription.hpp"
#include "../../model/YearDescription_Impl.hpp"

#include "../../utilities/idf/Workspace.hpp"
#include "../../utilities/core/Optional.hpp"
#include "../../utilities/geometry/Plane.hpp"
#include "../../utilities/time/Date.hpp"

#include <utilities/idd/OS_Surface_FieldEnums.hxx>
#include <utilities/idd/OS_SubSurface_FieldEnums.hxx>

#include <resources.hxx>

#include <sstream>
#include <utility>

using namespace openstudio::energyplus;
using namespace openstudio::model;
Expand Down Expand Up @@ -265,7 +275,7 @@ TEST_F(gbXMLFixture, ReverseTranslator_FloorSurfaces) {
struct ExpectedSurfaceInfo
{
ExpectedSurfaceInfo(std::string t_name, std::string t_surfaceType, std::string t_spaceName)
: name(t_name), surfaceType(t_surfaceType), spaceName(t_spaceName){};
: name(std::move(t_name)), surfaceType(std::move(t_surfaceType)), spaceName(std::move(t_spaceName)){};

const std::string name;
const std::string surfaceType;
Expand Down Expand Up @@ -590,3 +600,165 @@ TEST_F(gbXMLFixture, ReverseTranslator_3997_WindowScaling) {
EXPECT_EQ("Outdoors", _surf->outsideBoundaryCondition());
}
}

TEST_F(gbXMLFixture, ReverseTranslator_Schedules_Basic) {

// Test for #4439 - Properly RT gbxml Schedules
openstudio::path inputPath = resourcesPath() / openstudio::toPath("gbxml/TestCube.xml");

openstudio::gbxml::ReverseTranslator reverseTranslator;
boost::optional<openstudio::model::Model> model = reverseTranslator.loadModel(inputPath);
ASSERT_TRUE(model);

EXPECT_EQ(2U, model->getConcreteModelObjects<ScheduleYear>().size());
EXPECT_EQ(2U, model->getConcreteModelObjects<ScheduleWeek>().size());
EXPECT_EQ(2U, model->getConcreteModelObjects<ScheduleDay>().size());
}

TEST_F(gbXMLFixture, ReverseTranslator_Schedules_Complex) {

// Test for #4439 - Properly RT gbxml Schedules
openstudio::path inputPath = resourcesPath() / openstudio::toPath("gbxml/TestSchedules.xml");

openstudio::gbxml::ReverseTranslator reverseTranslator;
boost::optional<openstudio::model::Model> model_ = reverseTranslator.loadModel(inputPath);
ASSERT_TRUE(model_);
auto m = model_.get();

m.save(resourcesPath() / openstudio::toPath("gbxml/TestSchedules.osm"), true);

// One Schedule is simple: 1 YearSchedule, 1 WeekSchedule, 1 DaySchedule
// The other is complex: Two week schedules, one with a single day schedules, and one with two
EXPECT_EQ(2U, m.getConcreteModelObjects<ScheduleYear>().size());
EXPECT_EQ(3U, m.getConcreteModelObjects<ScheduleWeek>().size());
EXPECT_EQ(4U, m.getConcreteModelObjects<ScheduleDay>().size());

ASSERT_TRUE(m.yearDescription());
auto yd = m.getUniqueModelObject<model::YearDescription>();
ASSERT_TRUE(yd.calendarYear());
EXPECT_EQ(2017, yd.calendarYear().get());

// auto jan1 = yd.makeDate(1, 1);
auto june30 = yd.makeDate(6, 30);
// auto july1 = yd.makeDate(7, 1);
auto dec31 = yd.makeDate(12, 31);

// Test simple Schedule
{
auto schYear_ = m.getConcreteModelObjectByName<ScheduleYear>("Simple Year Schedule");
EXPECT_TRUE(schYear_);
ASSERT_EQ(1U, schYear_->dates().size());
EXPECT_EQ(dec31, schYear_->dates()[0]);
ASSERT_EQ(1U, schYear_->scheduleWeeks().size());
auto schWeek = schYear_->scheduleWeeks()[0];
EXPECT_EQ("Simple Year Schedule - Typical Week", schWeek.nameString());

auto schDay_ = m.getConcreteModelObjectByName<ScheduleDay>("Simple Year Schedule - Typical Day");
ASSERT_TRUE(schDay_);
auto schDay = schDay_.get();

ASSERT_TRUE(schWeek.sundaySchedule());
EXPECT_EQ(schDay, schWeek.sundaySchedule().get());
ASSERT_TRUE(schWeek.mondaySchedule());
EXPECT_EQ(schDay, schWeek.mondaySchedule().get());
ASSERT_TRUE(schWeek.tuesdaySchedule());
EXPECT_EQ(schDay, schWeek.tuesdaySchedule().get());
ASSERT_TRUE(schWeek.wednesdaySchedule());
EXPECT_EQ(schDay, schWeek.wednesdaySchedule().get());
ASSERT_TRUE(schWeek.thursdaySchedule());
EXPECT_EQ(schDay, schWeek.thursdaySchedule().get());
ASSERT_TRUE(schWeek.fridaySchedule());
EXPECT_EQ(schDay, schWeek.fridaySchedule().get());
ASSERT_TRUE(schWeek.saturdaySchedule());
EXPECT_EQ(schDay, schWeek.saturdaySchedule().get());
ASSERT_TRUE(schWeek.holidaySchedule());
EXPECT_EQ(schDay, schWeek.holidaySchedule().get());
ASSERT_TRUE(schWeek.summerDesignDaySchedule());
EXPECT_EQ(schDay, schWeek.summerDesignDaySchedule().get());
ASSERT_TRUE(schWeek.winterDesignDaySchedule());
EXPECT_EQ(schDay, schWeek.winterDesignDaySchedule().get());
ASSERT_TRUE(schWeek.customDay1Schedule());
EXPECT_EQ(schDay, schWeek.customDay1Schedule().get());
ASSERT_TRUE(schWeek.customDay2Schedule());
EXPECT_EQ(schDay, schWeek.customDay2Schedule().get());
}

// Test Complex Schedule
{
auto schYear_ = m.getConcreteModelObjectByName<ScheduleYear>("Complex Year Schedule");
EXPECT_TRUE(schYear_);
ASSERT_EQ(2U, schYear_->dates().size());
EXPECT_EQ(june30, schYear_->dates()[0]);
EXPECT_EQ(dec31, schYear_->dates()[1]);
ASSERT_EQ(2U, schYear_->scheduleWeeks().size());

{
auto schWeek = schYear_->scheduleWeeks()[0];
EXPECT_EQ("Complex Year Schedule - Typical Week January to June", schWeek.nameString());

auto schDay_ = m.getConcreteModelObjectByName<ScheduleDay>("Complex Year Schedule - Typical Day January to June");
ASSERT_TRUE(schDay_);
auto schDay = schDay_.get();

ASSERT_TRUE(schWeek.sundaySchedule());
EXPECT_EQ(schDay, schWeek.sundaySchedule().get());
ASSERT_TRUE(schWeek.mondaySchedule());
EXPECT_EQ(schDay, schWeek.mondaySchedule().get());
ASSERT_TRUE(schWeek.tuesdaySchedule());
EXPECT_EQ(schDay, schWeek.tuesdaySchedule().get());
ASSERT_TRUE(schWeek.wednesdaySchedule());
EXPECT_EQ(schDay, schWeek.wednesdaySchedule().get());
ASSERT_TRUE(schWeek.thursdaySchedule());
EXPECT_EQ(schDay, schWeek.thursdaySchedule().get());
ASSERT_TRUE(schWeek.fridaySchedule());
EXPECT_EQ(schDay, schWeek.fridaySchedule().get());
ASSERT_TRUE(schWeek.saturdaySchedule());
EXPECT_EQ(schDay, schWeek.saturdaySchedule().get());
ASSERT_TRUE(schWeek.holidaySchedule());
EXPECT_EQ(schDay, schWeek.holidaySchedule().get());
ASSERT_TRUE(schWeek.summerDesignDaySchedule());
EXPECT_EQ(schDay, schWeek.summerDesignDaySchedule().get());
ASSERT_TRUE(schWeek.winterDesignDaySchedule());
EXPECT_EQ(schDay, schWeek.winterDesignDaySchedule().get());
ASSERT_TRUE(schWeek.customDay1Schedule());
EXPECT_EQ(schDay, schWeek.customDay1Schedule().get());
ASSERT_TRUE(schWeek.customDay2Schedule());
EXPECT_EQ(schDay, schWeek.customDay2Schedule().get());
}

{
auto schWeek = schYear_->scheduleWeeks()[1];
EXPECT_EQ("Complex Year Schedule - Typical Week July to December", schWeek.nameString());

auto schDayWeekday_ = m.getConcreteModelObjectByName<ScheduleDay>("Complex Year Schedule - Typical Weekday July to December");
ASSERT_TRUE(schDayWeekday_);
auto schDayWeekday = schDayWeekday_.get();

auto schDayWeekend_ = m.getConcreteModelObjectByName<ScheduleDay>("Complex Year Schedule - Typical Weekend July to December");
ASSERT_TRUE(schDayWeekend_);
auto schDayWeekend = schDayWeekend_.get();

ASSERT_TRUE(schWeek.mondaySchedule());
EXPECT_EQ(schDayWeekday, schWeek.mondaySchedule().get());
ASSERT_TRUE(schWeek.tuesdaySchedule());
EXPECT_EQ(schDayWeekday, schWeek.tuesdaySchedule().get());
ASSERT_TRUE(schWeek.wednesdaySchedule());
EXPECT_EQ(schDayWeekday, schWeek.wednesdaySchedule().get());
ASSERT_TRUE(schWeek.thursdaySchedule());
EXPECT_EQ(schDayWeekday, schWeek.thursdaySchedule().get());
ASSERT_TRUE(schWeek.fridaySchedule());
EXPECT_EQ(schDayWeekday, schWeek.fridaySchedule().get());

ASSERT_TRUE(schWeek.saturdaySchedule());
EXPECT_EQ(schDayWeekend, schWeek.saturdaySchedule().get());
ASSERT_TRUE(schWeek.sundaySchedule());
EXPECT_EQ(schDayWeekend, schWeek.sundaySchedule().get());

EXPECT_FALSE(schWeek.holidaySchedule());
EXPECT_FALSE(schWeek.summerDesignDaySchedule());
EXPECT_FALSE(schWeek.winterDesignDaySchedule());
EXPECT_FALSE(schWeek.customDay1Schedule());
EXPECT_FALSE(schWeek.customDay2Schedule());
}
}
}
Comment on lines +604 to +764
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Test that everything works as expected.