From 76f4f41810cf593fdf4e0b69e83b49ddf8d5b101 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:06:50 -0700 Subject: [PATCH 01/68] Introduce new getValues method on ScheduleDay. --- src/model/ScheduleDay.cpp | 22 ++++++++++++++++++++++ src/model/ScheduleDay.hpp | 3 +++ src/model/ScheduleDay_Impl.hpp | 3 +++ 3 files changed, 28 insertions(+) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 66ddbc97a05..f6efb486ab8 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,6 +16,8 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" +#include "Timestep.hpp" +#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -212,6 +214,26 @@ namespace model { return result; } + std::vector getValues(const openstudio::model::Timestep& timestep) const { + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + std::vector result; + + int timesteps = 24.0 * timestep.numberOfTimestepsPerHour(); + for (size_t timestep = 0; timestep < timesteps; ++timestep) { + openstudio::Time t(timestep / timesteps); + size_t i = 0; + for (const openstudio::Time& time : times) { + if (t <= time) { + result.push_back(values[i]); + break; + } + ++i; + } + } + return result; + } + bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { if (scheduleTypeLimits.model() != model()) { return false; diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index ce64172a47e..ce012632ae6 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -69,6 +69,9 @@ namespace model { /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; + /// Returns the values for a given timestep. + std::vector getValues(const openstudio::model::Timestep& timestep) const; + //@} /** @name Setters */ //@{ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 564fec1a279..80f708a774c 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -72,6 +72,9 @@ namespace model { /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; + /// Returns the values for a given timestep. + std::vector getValues(const openstudio::model::Timestep& timestep) const; + //@} /** @name Setters */ //@{ From 48ac02d96674e5289626953265cb0822a6d8d935 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:07:05 -0700 Subject: [PATCH 02/68] Stub model test for new method. --- src/model/test/ScheduleDay_GTest.cpp | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index be5370b9180..f8823b9cfc4 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,6 +10,8 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" +#include "../Timestep.hpp" +#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" @@ -320,3 +322,31 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { EXPECT_FALSE(sch_day.addValue(t, std::numeric_limits::infinity())); EXPECT_FALSE(sch_day.addValue(t, -std::numeric_limits::infinity())); } + +TEST_F(ModelFixture, Schedule_Day_getValues) { + Model model; + + ScheduleDay sch_day(model); + + Time t1("08:15:00"); + sch_day.addValue(t1, 0); + Time t2("21:45:00"); + sch_day.addValue(t2, 1); + + auto timestep = model.getUniqueModelObject(): + + timestep.setNumberOfTimestepsPerHour(1); + std::vector values24 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 1, values24.size()); + + timestep.setNumberOfTimestepsPerHour(4); + std::vector values15 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 4, values15.size()); + + timestep.setNumberOfTimestepsPerHour(6); + std::vector values10 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 6, values10.size()); + + // TODO: check for 0s and 1s + // TODO: check interpolatetoTimestep doesn't matter +} From 0242a8cc13f3ea983f3689703ca1341e59a35924 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:07:19 -0700 Subject: [PATCH 03/68] Formatting. --- src/model/ScheduleDay.cpp | 2 +- src/model/test/ScheduleDay_GTest.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f6efb486ab8..c52025d4273 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -229,7 +229,7 @@ namespace model { break; } ++i; - } + } } return result; } diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index f8823b9cfc4..ad3c96b8fb8 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -333,9 +333,11 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model.getUniqueModelObject(): + auto timestep = model + .getUniqueModelObject() + : - timestep.setNumberOfTimestepsPerHour(1); + timestep.setNumberOfTimestepsPerHour(1); std::vector values24 = sch_day.getValues(timestep); EXPECT_EQ(24 * 1, values24.size()); From 389f6cb7bc14cde5369de2f44ed139fc2b40c9d0 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:14:53 -0700 Subject: [PATCH 04/68] Typo. --- src/model/test/ScheduleDay_GTest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index ad3c96b8fb8..96a72f40db6 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -333,11 +333,9 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model - .getUniqueModelObject() - : + auto timestep = model.getUniqueModelObject(); - timestep.setNumberOfTimestepsPerHour(1); + timestep.setNumberOfTimestepsPerHour(1); std::vector values24 = sch_day.getValues(timestep); EXPECT_EQ(24 * 1, values24.size()); From 6e075a3edf0ea91b2b1873c571b6b64cef812ed4 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 14 Mar 2024 11:30:14 -0700 Subject: [PATCH 05/68] Update scheduleday files and get new tests passing. --- src/model/ScheduleDay.cpp | 64 ++++++++++++++----- src/model/ScheduleDay.hpp | 16 +++-- src/model/ScheduleDay_Impl.hpp | 16 +++-- src/model/test/ScheduleDay_GTest.cpp | 93 +++++++++++++++++++++++----- 4 files changed, 151 insertions(+), 38 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index c52025d4273..f40ddd159a4 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,8 +16,6 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" -#include "Timestep.hpp" -#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -173,13 +171,20 @@ namespace model { return m_cachedValues.get(); } - double ScheduleDay_Impl::getValue(const openstudio::Time& time) const { + double ScheduleDay_Impl::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { if (time.totalMinutes() < 0.0 || time.totalDays() > 1.0) { return 0.0; } - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector values; + std::vector times; + if (numberOfTimestepsPerHour > 0) { + values = this->getValues(numberOfTimestepsPerHour); + times = this->getTimes(numberOfTimestepsPerHour); + } else { + values = this->values(); // these are already sorted + times = this->times(); // these are already sorted + } unsigned N = times.size(); OS_ASSERT(values.size() == N); @@ -203,7 +208,7 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (this->interpolatetoTimestep()) { + if (numberOfTimestepsPerHour > 0) { interpMethod = LinearInterp; } else { interpMethod = HoldNextInterp; @@ -214,14 +219,36 @@ namespace model { return result; } - std::vector getValues(const openstudio::model::Timestep& timestep) const { - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector ScheduleDay_Impl::getTimes(int numberOfTimestepsPerHour) const { + std::vector result; + + std::vector allowables{1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}; + if (std::find(allowables.begin(), allowables.end(), numberOfTimestepsPerHour) == allowables.end()) { + return result; + } + + int minutes = 60 / numberOfTimestepsPerHour; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + result.push_back(t); + } else { + openstudio::Time t(0, hour, minute); + result.push_back(t); + } + } + } + return result; + } + + std::vector ScheduleDay_Impl::getValues(int numberOfTimestepsPerHour) const { + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + std::vector getTimes = this->getTimes(numberOfTimestepsPerHour); // these are already sorted std::vector result; - int timesteps = 24.0 * timestep.numberOfTimestepsPerHour(); - for (size_t timestep = 0; timestep < timesteps; ++timestep) { - openstudio::Time t(timestep / timesteps); + for (const openstudio::Time& t : getTimes) { size_t i = 0; for (const openstudio::Time& time : times) { if (t <= time) { @@ -253,7 +280,6 @@ namespace model { bool ScheduleDay_Impl::setInterpolatetoTimestep(bool interpolatetoTimestep) { return setBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); - ; } void ScheduleDay_Impl::resetInterpolatetoTimestep() { @@ -432,8 +458,16 @@ namespace model { return getImpl()->values(); } - double ScheduleDay::getValue(const openstudio::Time& time) const { - return getImpl()->getValue(time); + double ScheduleDay::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { + return getImpl()->getValue(time, numberOfTimestepsPerHour); + } + + std::vector ScheduleDay::getTimes(int numberOfTimestepsPerHour) const { + return getImpl()->getTimes(numberOfTimestepsPerHour); + } + + std::vector ScheduleDay::getValues(int numberOfTimestepsPerHour) const { + return getImpl()->getValues(numberOfTimestepsPerHour); } bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index ce012632ae6..8d21a4c133d 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -66,11 +66,19 @@ namespace model { /// Returns a vector of values in the same order and with the same number of elements as times. std::vector values() const; - /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time) const; + /// Returns the value in effect at the given time. + /// If time is less than 0 days or greater than 1 day, 0 is returned. + double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; - /// Returns the values for a given timestep. - std::vector getValues(const openstudio::model::Timestep& timestep) const; + /// Returns the vector of times marking the end value intervals for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + /// These times will be in order and have the same number of elements as getValues. + /// All times will be less than or equal to 1 day. + std::vector getTimes(int numberOfTimestepsPerHour) const; + + /// Returns the values for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + std::vector getValues(int numberOfTimestepsPerHour) const; //@} /** @name Setters */ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 80f708a774c..d604e43fb17 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -69,11 +69,19 @@ namespace model { /// Returns a vector of values in the same order and with the same number of elements as times. virtual std::vector values() const override; - /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time) const; + /// Returns the value in effect at the given time. + /// If time is less than 0 days or greater than 1 day, 0 is returned. + double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; - /// Returns the values for a given timestep. - std::vector getValues(const openstudio::model::Timestep& timestep) const; + /// Returns the vector of times marking the end value intervals for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + /// These times will be in order and have the same number of elements as getValues. + /// All times will be less than or equal to 1 day. + std::vector getTimes(int numberOfTimestepsPerHour) const; + + /// Returns the values for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + std::vector getValues(int numberOfTimestepsPerHour) const; //@} /** @name Setters */ diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 96a72f40db6..796d6eca5f7 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,8 +10,6 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" -#include "../Timestep.hpp" -#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" @@ -195,10 +193,10 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); - EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); // FIXME: Fails. Should be 1.0? + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); // FIXME: Fails. Should be 1.0? EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); // FIXME: Fails. Should be 0.0? EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } @@ -326,6 +324,8 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { TEST_F(ModelFixture, Schedule_Day_getValues) { Model model; + double tol = 1e-5; + ScheduleDay sch_day(model); Time t1("08:15:00"); @@ -333,20 +333,83 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model.getUniqueModelObject(); + std::vector times = sch_day.getTimes(7); + EXPECT_EQ(0, times.size()); + + std::vector times24 = sch_day.getTimes(1); + EXPECT_EQ(24 * 1, times24.size()); + + std::vector times15 = sch_day.getTimes(4); + EXPECT_EQ(24 * 4, times15.size()); - timestep.setNumberOfTimestepsPerHour(1); - std::vector values24 = sch_day.getValues(timestep); + std::vector times10 = sch_day.getTimes(6); + EXPECT_EQ(24 * 6, times10.size()); + Time times10_1("00:10:00"); + EXPECT_EQ(times10_1, times10[0]); + Time times10_48("08:00:00"); + EXPECT_EQ(times10_48, times10[47]); + Time times10_49("08:10:00"); + EXPECT_EQ(times10_49, times10[48]); + Time times10_50("08:20:00"); + EXPECT_EQ(times10_50, times10[49]); + Time times10_144("24:00:00"); + EXPECT_EQ(times10_144, times10[143]); + + std::vector values = sch_day.getValues(18); + EXPECT_EQ(0, values.size()); + + std::vector values24 = sch_day.getValues(1); EXPECT_EQ(24 * 1, values24.size()); - timestep.setNumberOfTimestepsPerHour(4); - std::vector values15 = sch_day.getValues(timestep); + std::vector values15 = sch_day.getValues(4); EXPECT_EQ(24 * 4, values15.size()); - timestep.setNumberOfTimestepsPerHour(6); - std::vector values10 = sch_day.getValues(timestep); + std::vector values10 = sch_day.getValues(6); EXPECT_EQ(24 * 6, values10.size()); - - // TODO: check for 0s and 1s - // TODO: check interpolatetoTimestep doesn't matter + EXPECT_DOUBLE_EQ(0.0, values10[0]); + EXPECT_DOUBLE_EQ(0.0, values10[47]); + EXPECT_DOUBLE_EQ(0.0, values10[48]); + EXPECT_DOUBLE_EQ(1.0, values10[49]); + EXPECT_DOUBLE_EQ(0.0, values10[143]); + + double value; + + Time t3("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 1); + EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + value = sch_day.getValue(t3, 4); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 6); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 10); + EXPECT_DOUBLE_EQ(0.0, value); + + Time t4("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); + value = sch_day.getValue(t4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t4, 1); + EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + value = sch_day.getValue(t4, 4); + EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + value = sch_day.getValue(t4, 6); + EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + value = sch_day.getValue(t4, 10); + EXPECT_DOUBLE_EQ(1.0, value); + + Time t5("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 1); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 6); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 10); + EXPECT_DOUBLE_EQ(1.0, value); } From 27865fa2ec7189bcd602c28aed3a081940a094fd Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 15:15:26 -0700 Subject: [PATCH 06/68] Return timeseries instead of separate getTimes and getValues. --- src/model/ScheduleDay.cpp | 51 ++++++++++++++++++++++++---------- src/model/ScheduleDay.hpp | 11 ++------ src/model/ScheduleDay_Impl.hpp | 13 +++------ 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f40ddd159a4..2ea822d6ea5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,6 +16,8 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" +#include "Timestep.hpp" +#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -25,6 +27,7 @@ #include "../utilities/core/Assert.hpp" #include "../utilities/time/Time.hpp" +#include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" namespace openstudio { @@ -242,23 +245,45 @@ namespace model { return result; } - std::vector ScheduleDay_Impl::getValues(int numberOfTimestepsPerHour) const { - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted - std::vector getTimes = this->getTimes(numberOfTimestepsPerHour); // these are already sorted - std::vector result; + openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - for (const openstudio::Time& t : getTimes) { + auto timestep = model().getUniqueModelObject(); + int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + + DateTimeVector dateTimes; + int minutes = 60 / numberOfTimestepsPerHour; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + dateTimes.push_back(startDateTime + t); + } else { + openstudio::Time t(0, hour, minute); + dateTimes.push_back(startDateTime + t); + } + } + } + + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + + Vector values2(dateTimes.size()); + for (const openstudio::DateTime& dt : dateTimes) { size_t i = 0; for (const openstudio::Time& time : times) { - if (t <= time) { - result.push_back(values[i]); + if (dt.time() <= time) { + values2(i) = values[i]; break; } ++i; } } - return result; + + TimeSeries timeSeries(dateTimes, values2); + + return timeSeries; } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { @@ -462,12 +487,8 @@ namespace model { return getImpl()->getValue(time, numberOfTimestepsPerHour); } - std::vector ScheduleDay::getTimes(int numberOfTimestepsPerHour) const { - return getImpl()->getTimes(numberOfTimestepsPerHour); - } - - std::vector ScheduleDay::getValues(int numberOfTimestepsPerHour) const { - return getImpl()->getValues(numberOfTimestepsPerHour); + openstudio::TimeSeries ScheduleDay::timeSeries() const { + return getImpl()->timeSeries(); } bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 8d21a4c133d..04ece4d35b6 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -70,15 +70,8 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; - /// Returns the vector of times marking the end value intervals for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - /// These times will be in order and have the same number of elements as getValues. - /// All times will be less than or equal to 1 day. - std::vector getTimes(int numberOfTimestepsPerHour) const; - - /// Returns the values for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - std::vector getValues(int numberOfTimestepsPerHour) const; + /// Returns the values for the timesteps per hour. + openstudio::TimeSeries timeSeries() const; //@} /** @name Setters */ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index d604e43fb17..0655ca782cb 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -13,6 +13,8 @@ namespace openstudio { +class TimeSeries; + namespace model { class ScheduleTypeLimits; @@ -73,15 +75,8 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; - /// Returns the vector of times marking the end value intervals for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - /// These times will be in order and have the same number of elements as getValues. - /// All times will be less than or equal to 1 day. - std::vector getTimes(int numberOfTimestepsPerHour) const; - - /// Returns the values for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - std::vector getValues(int numberOfTimestepsPerHour) const; + /// Returns the values for the timesteps per hour. + openstudio::TimeSeries timeSeries() const; //@} /** @name Setters */ From 80ef75b0261d5a3b945dda5da6b320d850f5155d Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 15:30:32 -0700 Subject: [PATCH 07/68] Clean up and try again. --- src/model/ScheduleDay.cpp | 39 +++++++++------------------------- src/model/ScheduleDay.hpp | 2 +- src/model/ScheduleDay_Impl.hpp | 2 +- 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 2ea822d6ea5..d55e2351eec 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -174,16 +174,20 @@ namespace model { return m_cachedValues.get(); } - double ScheduleDay_Impl::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { + double ScheduleDay_Impl::getValue(const openstudio::Time& time) const { if (time.totalMinutes() < 0.0 || time.totalDays() > 1.0) { return 0.0; } std::vector values; std::vector times; - if (numberOfTimestepsPerHour > 0) { - values = this->getValues(numberOfTimestepsPerHour); - times = this->getTimes(numberOfTimestepsPerHour); + if (this->interpolateToTimestep()) { + openstudio::TimeSeries timeSeries = timeSeries(); + values = timeSeries.values(); + DateTimeVector dateTimes = timeSeries.dateTimes(); + for (const openstudio::DateTime& dt : dateTimes) { + times.push_back(dt.time()); + } } else { values = this->values(); // these are already sorted times = this->times(); // these are already sorted @@ -211,7 +215,7 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (numberOfTimestepsPerHour > 0) { + if (this->interpolatetoTimestep()) { interpMethod = LinearInterp; } else { interpMethod = HoldNextInterp; @@ -222,29 +226,6 @@ namespace model { return result; } - std::vector ScheduleDay_Impl::getTimes(int numberOfTimestepsPerHour) const { - std::vector result; - - std::vector allowables{1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}; - if (std::find(allowables.begin(), allowables.end(), numberOfTimestepsPerHour) == allowables.end()) { - return result; - } - - int minutes = 60 / numberOfTimestepsPerHour; - for (size_t hour = 0; hour < 24; ++hour) { - for (size_t minute = minutes; minute <= 60; minute += minutes) { - if (minute == 60) { - openstudio::Time t(0, hour + 1, 0); - result.push_back(t); - } else { - openstudio::Time t(0, hour, minute); - result.push_back(t); - } - } - } - return result; - } - openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0, 0)); @@ -281,7 +262,7 @@ namespace model { } } - TimeSeries timeSeries(dateTimes, values2); + TimeSeries timeSeries(dateTimes, values2, ""); return timeSeries; } diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 04ece4d35b6..207a5d10e02 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -68,7 +68,7 @@ namespace model { /// Returns the value in effect at the given time. /// If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; + double getValue(const openstudio::Time& time) const; /// Returns the values for the timesteps per hour. openstudio::TimeSeries timeSeries() const; diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 0655ca782cb..4226af95ae3 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -73,7 +73,7 @@ namespace model { /// Returns the value in effect at the given time. /// If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; + double getValue(const openstudio::Time& time) const; /// Returns the values for the timesteps per hour. openstudio::TimeSeries timeSeries() const; From f01fba784e07544ae1cce1cb0983b6686bbdd591 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:24:38 -0700 Subject: [PATCH 08/68] Update idd for new interpolation method keys. --- resources/model/OpenStudio.idd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd index 41670d9174b..6880de50cb8 100644 --- a/resources/model/OpenStudio.idd +++ b/resources/model/OpenStudio.idd @@ -4594,12 +4594,13 @@ OS:Schedule:Day, \type object-list \object-list ScheduleTypeLimitsNames A4, \field Interpolate to Timestep - \note when the interval does not match the user specified timestep a Yes choice will average between the intervals request (to - \note timestep resolution. a No choice will use the interval value at the simulation timestep without regard to if it matches - \note the boundary or not. + \note when the interval does not match the user specified timestep a Average choice will average between the intervals request (to + \note timestep resolution. A No choice will use the interval value at the simulation timestep without regard to if it matches + \note the boundary or not. A Linear choice will interpolate linearly between successive values. \type choice \default No - \key Yes + \key Average + \key Linear \key No N1, \field Hour \type integer From a365a9918f6368dd801d1893265f2985fb0429ee Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:24:59 -0700 Subject: [PATCH 09/68] Update model files and tests. --- src/model/ScheduleDay.cpp | 44 ++++--- src/model/ScheduleDay.hpp | 4 +- src/model/ScheduleDay_Impl.hpp | 4 +- src/model/test/ScheduleDay_GTest.cpp | 173 ++++++++++++++------------- 4 files changed, 120 insertions(+), 105 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index d55e2351eec..5af7182a358 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -118,8 +118,10 @@ namespace model { return !getObject().getModelObjectTarget(OS_Schedule_DayFields::ScheduleTypeLimitsName); } - bool ScheduleDay_Impl::interpolatetoTimestep() const { - return getBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep); + std::string ScheduleDay_Impl::interpolatetoTimestep() const { + boost::optional value = getString(OS_Schedule_DayFields::InterpolatetoTimestep, true); + OS_ASSERT(value); + return value.get(); } bool ScheduleDay_Impl::isInterpolatetoTimestepDefaulted() const { @@ -181,16 +183,20 @@ namespace model { std::vector values; std::vector times; - if (this->interpolateToTimestep()) { - openstudio::TimeSeries timeSeries = timeSeries(); - values = timeSeries.values(); + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + if (istringEqual(interpolatetoTimestep, "Linear")) { + values = this->values(); // these are already sorted + times = this->times(); // these are already sorted + } else { // No or Average + openstudio::TimeSeries timeSeries = this->timeSeries(); + Vector values2 = timeSeries.values(); + for (size_t i = 0; i < values2.size(); ++i) { + values.push_back(values2[i]); + } DateTimeVector dateTimes = timeSeries.dateTimes(); for (const openstudio::DateTime& dt : dateTimes) { times.push_back(dt.time()); } - } else { - values = this->values(); // these are already sorted - times = this->times(); // these are already sorted } unsigned N = times.size(); @@ -215,10 +221,12 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (this->interpolatetoTimestep()) { + if (istringEqual("No", interpolatetoTimestep)) { + interpMethod = LinearInterp; // LinearInterp or HoldNextInterp? + } else if (istringEqual("Average", interpolatetoTimestep)) { + interpMethod = LinearInterp; // FIXME: new AverageInterp? + } else if (istringEqual("Linear", interpolatetoTimestep)) { interpMethod = LinearInterp; - } else { - interpMethod = HoldNextInterp; } double result = interp(x, y, time.totalDays(), interpMethod, NoneExtrap); @@ -230,7 +238,7 @@ namespace model { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - auto timestep = model().getUniqueModelObject(); + auto timestep = this->model().getUniqueModelObject(); int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); DateTimeVector dateTimes; @@ -284,8 +292,8 @@ namespace model { return false; } - bool ScheduleDay_Impl::setInterpolatetoTimestep(bool interpolatetoTimestep) { - return setBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); + bool ScheduleDay_Impl::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) { + return setString(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); } void ScheduleDay_Impl::resetInterpolatetoTimestep() { @@ -448,7 +456,7 @@ namespace model { return getImpl()->isScheduleTypeLimitsDefaulted(); } - bool ScheduleDay::interpolatetoTimestep() const { + std::string ScheduleDay::interpolatetoTimestep() const { return getImpl()->interpolatetoTimestep(); } @@ -464,15 +472,15 @@ namespace model { return getImpl()->values(); } - double ScheduleDay::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { - return getImpl()->getValue(time, numberOfTimestepsPerHour); + double ScheduleDay::getValue(const openstudio::Time& time) const { + return getImpl()->getValue(time); } openstudio::TimeSeries ScheduleDay::timeSeries() const { return getImpl()->timeSeries(); } - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { + bool ScheduleDay::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) { return getImpl()->setInterpolatetoTimestep(interpolatetoTimestep); } diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 207a5d10e02..7b651f2adff 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -54,7 +54,7 @@ namespace model { * inherits one from a Schedule. */ bool isScheduleTypeLimitsDefaulted() const; - bool interpolatetoTimestep() const; + std::string interpolatetoTimestep() const; bool isInterpolatetoTimestepDefaulted() const; @@ -77,7 +77,7 @@ namespace model { /** @name Setters */ //@{ - bool setInterpolatetoTimestep(bool interpolatetoTimestep); + bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 4226af95ae3..201aecb58a9 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -59,7 +59,7 @@ namespace model { bool isScheduleTypeLimitsDefaulted() const; - bool interpolatetoTimestep() const; + std::string interpolatetoTimestep() const; bool isInterpolatetoTimestepDefaulted() const; @@ -86,7 +86,7 @@ namespace model { virtual bool resetScheduleTypeLimits() override; - bool setInterpolatetoTimestep(bool interpolatetoTimestep); + bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 796d6eca5f7..dba1766963f 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,9 +10,12 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" +#include "../Timestep.hpp" +#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" +#include "../../utilities/data/TimeSeries.hpp" using namespace openstudio::model; using namespace openstudio; @@ -174,7 +177,7 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { double tol = 1e-5; ScheduleDay daySchedule(model); - EXPECT_FALSE(daySchedule.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule.interpolatetoTimestep()); EXPECT_TRUE(daySchedule.isInterpolatetoTimestepDefaulted()); // schedule is 1 until 12:00 @@ -188,8 +191,8 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); - daySchedule.setInterpolatetoTimestep(true); - EXPECT_TRUE(daySchedule.interpolatetoTimestep()); + daySchedule.setInterpolatetoTimestep("Linear"); + EXPECT_EQ("Linear", daySchedule.interpolatetoTimestep()); EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); @@ -321,7 +324,7 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { EXPECT_FALSE(sch_day.addValue(t, -std::numeric_limits::infinity())); } -TEST_F(ModelFixture, Schedule_Day_getValues) { +TEST_F(ModelFixture, Schedule_Day_timeSeries) { Model model; double tol = 1e-5; @@ -333,83 +336,87 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - std::vector times = sch_day.getTimes(7); - EXPECT_EQ(0, times.size()); - - std::vector times24 = sch_day.getTimes(1); - EXPECT_EQ(24 * 1, times24.size()); - - std::vector times15 = sch_day.getTimes(4); - EXPECT_EQ(24 * 4, times15.size()); - - std::vector times10 = sch_day.getTimes(6); - EXPECT_EQ(24 * 6, times10.size()); - Time times10_1("00:10:00"); - EXPECT_EQ(times10_1, times10[0]); - Time times10_48("08:00:00"); - EXPECT_EQ(times10_48, times10[47]); - Time times10_49("08:10:00"); - EXPECT_EQ(times10_49, times10[48]); - Time times10_50("08:20:00"); - EXPECT_EQ(times10_50, times10[49]); - Time times10_144("24:00:00"); - EXPECT_EQ(times10_144, times10[143]); - - std::vector values = sch_day.getValues(18); - EXPECT_EQ(0, values.size()); - - std::vector values24 = sch_day.getValues(1); - EXPECT_EQ(24 * 1, values24.size()); - - std::vector values15 = sch_day.getValues(4); - EXPECT_EQ(24 * 4, values15.size()); - - std::vector values10 = sch_day.getValues(6); - EXPECT_EQ(24 * 6, values10.size()); - EXPECT_DOUBLE_EQ(0.0, values10[0]); - EXPECT_DOUBLE_EQ(0.0, values10[47]); - EXPECT_DOUBLE_EQ(0.0, values10[48]); - EXPECT_DOUBLE_EQ(1.0, values10[49]); - EXPECT_DOUBLE_EQ(0.0, values10[143]); - - double value; - - Time t3("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); - value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 1); - EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval - value = sch_day.getValue(t3, 4); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 6); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 10); - EXPECT_DOUBLE_EQ(0.0, value); - - Time t4("08:18:00"); - EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); - value = sch_day.getValue(t4); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t4, 1); - EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval - value = sch_day.getValue(t4, 4); - EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval - value = sch_day.getValue(t4, 6); - EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval - value = sch_day.getValue(t4, 10); - EXPECT_DOUBLE_EQ(1.0, value); - - Time t5("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); - value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 1); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 4); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 6); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 10); - EXPECT_DOUBLE_EQ(1.0, value); + { // Interpolate to Timestep = No + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); + EXPECT_EQ("No", sch_day.interpolatetoTimestep()); + + auto timestep = model.getUniqueModelObject(); + + Time t3("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); + Time t4("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + value = sch_day.getValue(t4); + EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + Time times10_1("00:10:00"); + EXPECT_EQ(times10_1, timeSeries.dateTimes()[0].time()); + Time times10_48("08:00:00"); + EXPECT_EQ(times10_48, timeSeries.dateTimes()[47].time()); + Time times10_49("08:10:00"); + EXPECT_EQ(times10_49, timeSeries.dateTimes()[48].time()); + Time times10_50("08:20:00"); + EXPECT_EQ(times10_50, timeSeries.dateTimes()[49].time()); + Time times10_144("24:00:00"); + EXPECT_EQ(times10_144, timeSeries.dateTimes()[143].time()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[0]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[47]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[48]); + EXPECT_DOUBLE_EQ(1.0, timeSeries.values()[49]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[143]); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + } + + { + // Interpolate to Timestep = Average + + } + + { // Interpolate to Timestep = Linear + } } From d96338a88d77fc52b44da0d4c28fdd84cd5a2559 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:25:19 -0700 Subject: [PATCH 10/68] Update ft and rt files and tests. --- .../ForwardTranslateScheduleDay.cpp | 6 +----- .../ReverseTranslateScheduleDayInterval.cpp | 8 +------- src/energyplus/Test/ScheduleRuleset_GTest.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp index f4a15c27a48..960598b4172 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp @@ -39,11 +39,7 @@ namespace energyplus { } } - if (modelObject.interpolatetoTimestep()) { - scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "Average"); - } else { - scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "No"); - } + scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, modelObject.interpolatetoTimestep()); std::vector values = modelObject.values(); std::vector times = modelObject.times(); diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp index 69a76331a3d..59e88bce0fc 100644 --- a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp +++ b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp @@ -50,13 +50,7 @@ namespace energyplus { s = workspaceObject.getString(Schedule_Day_IntervalFields::InterpolatetoTimestep); if (s) { - if (openstudio::istringEqual(*s, "No")) { - scheduleDay.setInterpolatetoTimestep(false); - } else if (openstudio::istringEqual(*s, "Linear")) { - scheduleDay.setInterpolatetoTimestep(true); - } else if (openstudio::istringEqual(*s, "Average")) { - scheduleDay.setInterpolatetoTimestep(true); - } + scheduleDay.setInterpolatetoTimestep(*s); } //get extensible groups diff --git a/src/energyplus/Test/ScheduleRuleset_GTest.cpp b/src/energyplus/Test/ScheduleRuleset_GTest.cpp index e9badad37ae..858bb862248 100644 --- a/src/energyplus/Test/ScheduleRuleset_GTest.cpp +++ b/src/energyplus/Test/ScheduleRuleset_GTest.cpp @@ -698,7 +698,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetSimple EXPECT_EQ(0, scheduleRule.ruleIndex()); ScheduleDay daySchedule = scheduleRule.daySchedule(); EXPECT_EQ(daySchedule.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule.values().size()); EXPECT_TRUE(scheduleRule.applySunday()); EXPECT_TRUE(scheduleRule.applyMonday()); @@ -864,7 +864,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(2, scheduleRule1.ruleIndex()); ScheduleDay daySchedule1 = scheduleRule1.daySchedule(); EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule1.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule1.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule1.values().size()); EXPECT_TRUE(scheduleRule1.applySunday()); EXPECT_TRUE(scheduleRule1.applyMonday()); @@ -888,7 +888,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(1, scheduleRule2.ruleIndex()); ScheduleDay daySchedule2 = scheduleRule2.daySchedule(); EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2"); - EXPECT_FALSE(daySchedule2.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule2.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule2.values().size()); EXPECT_TRUE(scheduleRule2.applySunday()); EXPECT_TRUE(scheduleRule2.applyMonday()); @@ -912,7 +912,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(0, scheduleRule3.ruleIndex()); ScheduleDay daySchedule3 = scheduleRule3.daySchedule(); EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1"); - EXPECT_FALSE(daySchedule3.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule3.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule3.values().size()); EXPECT_FALSE(scheduleRule3.applySunday()); EXPECT_FALSE(scheduleRule3.applyMonday()); @@ -1220,7 +1220,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(2, scheduleRule1.ruleIndex()); ScheduleDay daySchedule1 = scheduleRule1.daySchedule(); EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule1.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule1.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule1.values().size()); EXPECT_TRUE(scheduleRule1.applySunday()); EXPECT_TRUE(scheduleRule1.applyMonday()); @@ -1244,7 +1244,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(1, scheduleRule2.ruleIndex()); ScheduleDay daySchedule2 = scheduleRule2.daySchedule(); EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2"); - EXPECT_FALSE(daySchedule2.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule2.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule2.values().size()); EXPECT_TRUE(scheduleRule2.applySunday()); EXPECT_TRUE(scheduleRule2.applyMonday()); @@ -1268,7 +1268,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(0, scheduleRule3.ruleIndex()); ScheduleDay daySchedule3 = scheduleRule3.daySchedule(); EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1"); - EXPECT_FALSE(daySchedule3.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule3.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule3.values().size()); EXPECT_FALSE(scheduleRule3.applySunday()); EXPECT_FALSE(scheduleRule3.applyMonday()); From 9fa369a7e2a5d0d2209b26631d1057ea38211911 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 19 Mar 2024 14:37:59 -0700 Subject: [PATCH 11/68] Get interpolation working on timeseries. --- src/model/ScheduleDay.cpp | 32 +++-- src/model/test/ScheduleDay_GTest.cpp | 205 ++++++++++++++++++++++----- 2 files changed, 187 insertions(+), 50 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5af7182a358..ce97fb77782 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -195,7 +195,12 @@ namespace model { } DateTimeVector dateTimes = timeSeries.dateTimes(); for (const openstudio::DateTime& dt : dateTimes) { - times.push_back(dt.time()); + if (dt.time().totalDays() > 0) { + times.push_back(dt.time()); + } else { // this is 00:00:00 from the next day + openstudio::Time t(0, 24, 0); + times.push_back(t); + } } } @@ -222,9 +227,9 @@ namespace model { InterpMethod interpMethod; if (istringEqual("No", interpolatetoTimestep)) { - interpMethod = LinearInterp; // LinearInterp or HoldNextInterp? + interpMethod = LinearInterp; } else if (istringEqual("Average", interpolatetoTimestep)) { - interpMethod = LinearInterp; // FIXME: new AverageInterp? + interpMethod = AverageInterp; } else if (istringEqual("Linear", interpolatetoTimestep)) { interpMethod = LinearInterp; } @@ -235,12 +240,12 @@ namespace model { } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { - Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary - DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - auto timestep = this->model().getUniqueModelObject(); int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + DateTime startDateTime(startDate, Time(0, 0, 0)); + DateTimeVector dateTimes; int minutes = 60 / numberOfTimestepsPerHour; for (size_t hour = 0; hour < 24; ++hour) { @@ -258,15 +263,18 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted + openstudio::Time dtt; Vector values2(dateTimes.size()); - for (const openstudio::DateTime& dt : dateTimes) { - size_t i = 0; - for (const openstudio::Time& time : times) { - if (dt.time() <= time) { - values2(i) = values[i]; + for (unsigned i = 0; i < dateTimes.size(); ++i) { + dtt = dateTimes[i].time(); + if (dtt.totalDays() == 0.0) { // this is 00:00:00 from the next day + dtt = openstudio::Time(0, 24, 0); + } + for (unsigned j = 0; j < times.size(); ++j) { + if (dtt <= times[j]) { + values2[i] = values[j]; break; } - ++i; } } diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index dba1766963f..4cb7d58e46e 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -331,10 +331,10 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { ScheduleDay sch_day(model); - Time t1("08:15:00"); - sch_day.addValue(t1, 0); + Time t1("08:05:00"); + sch_day.addValue(t1, 0.1); Time t2("21:45:00"); - sch_day.addValue(t2, 1); + sch_day.addValue(t2, 1.0); { // Interpolate to Timestep = No EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); @@ -342,12 +342,14 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); - Time t4("08:18:00"); - EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); openstudio::TimeSeries timeSeries; double value; @@ -357,66 +359,193 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + EXPECT_NEAR(0.175, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + EXPECT_NEAR(0.4, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); - Time times10_1("00:10:00"); - EXPECT_EQ(times10_1, timeSeries.dateTimes()[0].time()); - Time times10_48("08:00:00"); - EXPECT_EQ(times10_48, timeSeries.dateTimes()[47].time()); - Time times10_49("08:10:00"); - EXPECT_EQ(times10_49, timeSeries.dateTimes()[48].time()); - Time times10_50("08:20:00"); - EXPECT_EQ(times10_50, timeSeries.dateTimes()[49].time()); - Time times10_144("24:00:00"); - EXPECT_EQ(times10_144, timeSeries.dateTimes()[143].time()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[0]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[47]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[48]); - EXPECT_DOUBLE_EQ(1.0, timeSeries.values()[49]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[143]); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + EXPECT_NEAR(0.55, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.85, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); } - { - // Interpolate to Timestep = Average + { // Interpolate to Timestep = Average + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Average")); + EXPECT_EQ("Average", sch_day.interpolatetoTimestep()); + auto timestep = model.getUniqueModelObject(); + + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.175, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.4, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.55, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.85, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); } { // Interpolate to Timestep = Linear + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Linear")); + EXPECT_EQ("Linear", sch_day.interpolatetoTimestep()); + + auto timestep = model.getUniqueModelObject(); + + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); } } From 3282bda0bbdad7616ec5ebfdd51a1d8940f2af28 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 19 Mar 2024 14:38:14 -0700 Subject: [PATCH 12/68] Stub new AverageInterp in vector files. --- src/utilities/data/Vector.cpp | 4 ++++ src/utilities/data/Vector.hpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index d96f302fe99..5d30c4ea256 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -142,6 +142,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // set to next value result = y(info.ib); break; + case AverageInterp: + // average interpolation + result = info.wa * y(info.ia) + info.wb * y(info.ib); // FIXME + break; } } diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index 7c61a925a87..a8cca34ea07 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -59,7 +59,8 @@ enum InterpMethod LinearInterp, NearestInterp, HoldLastInterp, - HoldNextInterp + HoldNextInterp, + AverageInterp }; /** Enum to specify the extrapolation method. */ From 47d03f331530028f2aebbd2043ce9effce8c1171 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 21 Mar 2024 16:34:54 -0700 Subject: [PATCH 13/68] Take a cut at the average interpolation. --- src/model/ScheduleDay.cpp | 146 ++++++++++-------- src/model/test/ScheduleDay_GTest.cpp | 220 ++++++++++++++++----------- src/utilities/data/Vector.cpp | 4 - 3 files changed, 207 insertions(+), 163 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index ce97fb77782..2a52635f295 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -181,62 +181,28 @@ namespace model { return 0.0; } - std::vector values; - std::vector times; - std::string interpolatetoTimestep = this->interpolatetoTimestep(); - if (istringEqual(interpolatetoTimestep, "Linear")) { - values = this->values(); // these are already sorted - times = this->times(); // these are already sorted - } else { // No or Average - openstudio::TimeSeries timeSeries = this->timeSeries(); - Vector values2 = timeSeries.values(); - for (size_t i = 0; i < values2.size(); ++i) { - values.push_back(values2[i]); - } - DateTimeVector dateTimes = timeSeries.dateTimes(); - for (const openstudio::DateTime& dt : dateTimes) { - if (dt.time().totalDays() > 0) { - times.push_back(dt.time()); - } else { // this is 00:00:00 from the next day - openstudio::Time t(0, 24, 0); - times.push_back(t); - } - } - } - - unsigned N = times.size(); - OS_ASSERT(values.size() == N); - - if (N == 0) { - return 0.0; - } - - openstudio::Vector x(N + 2); - openstudio::Vector y(N + 2); + TimeSeries ts = this->timeSeries(); - x[0] = -0.000001; - y[0] = 0.0; - - for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); - y[i + 1] = values[i]; - } + DateTimeVector dateTimes = ts.dateTimes(); + Vector values = ts.values(); - x[N + 1] = 1.000001; - y[N + 1] = 0.0; + for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { + openstudio::Time t0 = dateTimes[i].time(); + openstudio::Time t1 = dateTimes[i + 1].time(); + if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day + t1 = openstudio::Time(0, 24, 0); + } - InterpMethod interpMethod; - if (istringEqual("No", interpolatetoTimestep)) { - interpMethod = LinearInterp; - } else if (istringEqual("Average", interpolatetoTimestep)) { - interpMethod = AverageInterp; - } else if (istringEqual("Linear", interpolatetoTimestep)) { - interpMethod = LinearInterp; + if (t0 == time) { + double value = values[i]; + } else if (t1 == time) { + double value = values[i + 1]; + } else if ((t0 < time) && (time < t1)) { + double value = values[i + 1]; + } } - double result = interp(x, y, time.totalDays(), interpMethod, NoneExtrap); - - return result; + return value; } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { @@ -246,16 +212,16 @@ namespace model { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0)); - DateTimeVector dateTimes; + DateTimeVector tsDateTimes; int minutes = 60 / numberOfTimestepsPerHour; for (size_t hour = 0; hour < 24; ++hour) { for (size_t minute = minutes; minute <= 60; minute += minutes) { if (minute == 60) { openstudio::Time t(0, hour + 1, 0); - dateTimes.push_back(startDateTime + t); + tsDateTimes.push_back(startDateTime + t); } else { openstudio::Time t(0, hour, minute); - dateTimes.push_back(startDateTime + t); + tsDateTimes.push_back(startDateTime + t); } } } @@ -263,24 +229,72 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted - openstudio::Time dtt; - Vector values2(dateTimes.size()); - for (unsigned i = 0; i < dateTimes.size(); ++i) { - dtt = dateTimes[i].time(); - if (dtt.totalDays() == 0.0) { // this is 00:00:00 from the next day - dtt = openstudio::Time(0, 24, 0); + unsigned N = times.size(); + OS_ASSERT(values.size() == N); + + TimeSeries result; + if (N == 0) { + return result; + } + + Vector x(N + 2); + Vector y(N + 2); + + x[0] = -0.000001; + y[0] = 0.0; + + for (unsigned i = 0; i < N; ++i) { + x[i + 1] = times[i].totalDays(); + y[i + 1] = values[i]; + } + + x[N + 1] = 1.000001; + y[N + 1] = 0.0; + + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + Vector tsValues(tsDateTimes.size()); + for (unsigned j = 0; j < tsDateTimes.size(); ++j) { + openstudio::Time t0 = tsDateTimes[j].time(); + if (t0.totalDays() == 0.0) { // this is 00:00:00 from the next day + t0 = openstudio::Time(0, 24, 0); } - for (unsigned j = 0; j < times.size(); ++j) { - if (dtt <= times[j]) { - values2[i] = values[j]; - break; + + if (istringEqual("No", interpolatetoTimestep)) { + double val = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); + tsValues[j] = val; + } else if (istringEqual("Average", interpolatetoTimestep)) { + if (j == 0) { + tsValues[j] = values[0]; + } else if (j == tsDateTimes.size() - 1) { + tsValues[j] = values[-1]; + } else { + openstudio::Time t1 = tsDateTimes[j - 1].time(); + if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day + t1 = openstudio::Time(0, 24, 0); + } + + for (unsigned i = 0; i < times.size(); ++i) { + if ((t1 < times[i]) && (times[i] < t0)) { // schedule value is between timesteps + double interval = (t0 - t1).totalDays(); // timestep interval + double int1 = (times[i] - t1).totalDays() / interval; // fraction that is the value before the schedule change + double int2 = (t0 - times[i]).totalDays() / interval; // fraction that is the value after the schedule change + tsValues[j] = (values[i] * int1) + (values[i + 1] * int2); + break; + } else if (t0 <= times[i]) { + tsValues[j] = values[i]; + break; + } + } } + } else if (istringEqual("Linear", interpolatetoTimestep)) { + double val = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); + tsValues[j] = val; } } - TimeSeries timeSeries(dateTimes, values2, ""); + result = TimeSeries(tsDateTimes, tsValues, ""); - return timeSeries; + return result; } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 4cb7d58e46e..f87f42906d1 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -336,21 +336,25 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { Time t2("21:45:00"); sch_day.addValue(t2, 1.0); + Time t0800("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t0800.totalDays(), tol); + Time t0805("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t0805.totalDays(), tol); + Time t0810("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t0810.totalDays(), tol); + Time t0818("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t0818.totalDays(), tol); + Time t0820("08:20:00"); + EXPECT_NEAR((8.0 + (20.0 / 60.0)) / 24.0, t0820.totalDays(), tol); + Time t0900("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t0900.totalDays(), tol); + { // Interpolate to Timestep = No EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); EXPECT_EQ("No", sch_day.interpolatetoTimestep()); auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -358,52 +362,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.175, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.25, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.4, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.7, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.55, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.85, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); } @@ -413,15 +433,6 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -429,52 +440,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.175, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.25, value, tol); - value = sch_day.getValue(t6); - EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0900); + EXPECT_NEAR(0.925, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.4, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); EXPECT_NEAR(0.7, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.55, value, tol); + value = sch_day.getValue(t0810); EXPECT_NEAR(0.55, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.85, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); } @@ -484,15 +511,6 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -500,52 +518,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.110975, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.110975, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.127439, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.127439, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t0810); EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.116463, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.116463, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.101097, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.107682, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.114268, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.120853, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); } } diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 5d30c4ea256..d96f302fe99 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -142,10 +142,6 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // set to next value result = y(info.ib); break; - case AverageInterp: - // average interpolation - result = info.wa * y(info.ia) + info.wb * y(info.ib); // FIXME - break; } } From aed3dea3490b5ca20895dce56adf23469335bee0 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 21 Mar 2024 16:43:34 -0700 Subject: [PATCH 14/68] One more typo. --- src/model/ScheduleDay.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 2a52635f295..97dbcc46a12 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -186,6 +186,7 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); + double value; for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { openstudio::Time t0 = dateTimes[i].time(); openstudio::Time t1 = dateTimes[i + 1].time(); @@ -194,11 +195,11 @@ namespace model { } if (t0 == time) { - double value = values[i]; + value = values[i]; } else if (t1 == time) { - double value = values[i + 1]; + value = values[i + 1]; } else if ((t0 < time) && (time < t1)) { - double value = values[i + 1]; + value = values[i + 1]; } } From 7bee45bbfddb927aac211062d6820e9d54e6405e Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 22 Mar 2024 09:22:49 -0700 Subject: [PATCH 15/68] Move average interp code into AverageInterp. --- src/model/ScheduleDay.cpp | 32 +++++--------------------------- src/utilities/data/Matrix.cpp | 18 +++++++++--------- src/utilities/data/Matrix.hpp | 8 ++++---- src/utilities/data/Matrix.i | 4 ++-- src/utilities/data/Vector.cpp | 34 +++++++++++++++++++++++++++------- src/utilities/data/Vector.hpp | 7 ++++--- src/utilities/data/Vector.i | 7 ++++--- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 97dbcc46a12..57c28734dd5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -261,35 +261,13 @@ namespace model { } if (istringEqual("No", interpolatetoTimestep)) { - double val = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); - tsValues[j] = val; + tsValues[j] = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { - if (j == 0) { - tsValues[j] = values[0]; - } else if (j == tsDateTimes.size() - 1) { - tsValues[j] = values[-1]; - } else { - openstudio::Time t1 = tsDateTimes[j - 1].time(); - if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day - t1 = openstudio::Time(0, 24, 0); - } - - for (unsigned i = 0; i < times.size(); ++i) { - if ((t1 < times[i]) && (times[i] < t0)) { // schedule value is between timesteps - double interval = (t0 - t1).totalDays(); // timestep interval - double int1 = (times[i] - t1).totalDays() / interval; // fraction that is the value before the schedule change - double int2 = (t0 - times[i]).totalDays() / interval; // fraction that is the value after the schedule change - tsValues[j] = (values[i] * int1) + (values[i + 1] * int2); - break; - } else if (t0 <= times[i]) { - tsValues[j] = values[i]; - break; - } - } - } + double minutes = 60.0 / numberOfTimestepsPerHour; + double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + tsValues[j] = interp(x, y, t0.totalDays(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { - double val = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); - tsValues[j] = val; + tsValues[j] = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); } } diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index 41d6293894b..dd068e79caf 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -38,7 +38,7 @@ bool operator!=(const Matrix& lhs, const Matrix& rhs) { /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { double result = 0.0; size_t M = x.size(); @@ -48,7 +48,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub return result; } - InterpInfo xInfo = interpInfo(x, xi); + InterpInfo xInfo = interpInfo(x, xi, ti); if (xInfo.extrapolated) { switch (extrapMethod) { @@ -91,7 +91,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub } } - InterpInfo yInfo = interpInfo(y, yi); + InterpInfo yInfo = interpInfo(y, yi, ti); if (yInfo.extrapolated) { switch (extrapMethod) { @@ -143,7 +143,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t M = x.size(); Vector result(M); @@ -153,7 +153,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x } for (unsigned i = 0; i < M; ++i) { - result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod); + result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod, ti); } return result; @@ -161,7 +161,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = y.size(); Vector result(N); @@ -171,7 +171,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons } for (unsigned j = 0; j < N; ++j) { - result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod); + result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod, ti); } return result; @@ -180,7 +180,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod, - ExtrapMethod extrapMethod) { + ExtrapMethod extrapMethod, double ti) { size_t M = x.size(); size_t N = y.size(); @@ -192,7 +192,7 @@ Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { - result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod); + result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod, ti); } } diff --git a/src/utilities/data/Matrix.hpp b/src/utilities/data/Matrix.hpp index 136224348b1..9bade37a0a8 100644 --- a/src/utilities/data/Matrix.hpp +++ b/src/utilities/data/Matrix.hpp @@ -33,22 +33,22 @@ UTILITIES_API bool operator!=(const Matrix& lhs, const Matrix& rhs); /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing UTILITIES_API double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, - InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap); + InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// matrix product UTILITIES_API Matrix prod(const Matrix& lop, const Matrix& rop); diff --git a/src/utilities/data/Matrix.i b/src/utilities/data/Matrix.i index 504e55f6fd6..eb63e040636 100644 --- a/src/utilities/data/Matrix.i +++ b/src/utilities/data/Matrix.i @@ -138,11 +138,11 @@ public: /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap); +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap); +Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0); /// outer product Matrix outerProd(const Vector& lhs, const Vector& rhs); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index d96f302fe99..3cca6aa100d 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -54,7 +54,7 @@ bool operator!=(const Vector& lhs, const Vector& rhs) { /// linear interpolation of the function y = f(x) at point xi /// assumes that x is strictly increasing -InterpInfo interpInfo(const Vector& x, double xi) { +InterpInfo interpInfo(const Vector& x, double xi, double ti) { size_t N = x.size(); InterpInfo result; @@ -64,24 +64,28 @@ InterpInfo interpInfo(const Vector& x, double xi) { result.ib = 0; result.wa = 1.0; result.wb = 0.0; + result.ti = 1.0; result.extrapolated = false; } else if (xi < x(0)) { result.ia = 0; result.ib = 0; result.wa = 1.0; result.wb = 0.0; + result.ti = 1.0; result.extrapolated = true; } else if (x(N - 1) == xi) { result.ia = N - 1; result.ib = N - 1; result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; result.extrapolated = false; } else if (xi > x(N - 1)) { result.ia = N - 1; result.ib = N - 1; result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; result.extrapolated = true; } else { @@ -92,8 +96,20 @@ InterpInfo interpInfo(const Vector& x, double xi) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); - result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); + if (ti == 0.0) { + result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); + result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); + } else { + result.wb = xi - x(result.ia); + result.wa = ti - result.wb; + result.ti = 1.0; + if ((result.wb > 0.0) && (result.wb < ti)) { + result.ti = ti; + } else { + result.wa = 0.0; + result.wb = 1.0; + } + } } return result; @@ -101,7 +117,7 @@ InterpInfo interpInfo(const Vector& x, double xi) { /// linear interpolation of the function y = f(x) at point xi /// assumes that x is strictly increasing -double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = x.size(); @@ -111,7 +127,7 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe return result; } - InterpInfo info = interpInfo(x, xi); + InterpInfo info = interpInfo(x, xi, ti); if (info.extrapolated) { switch (extrapMethod) { @@ -130,6 +146,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // linear interpolation result = info.wa * y(info.ia) + info.wb * y(info.ib); break; + case AverageInterp: + // average interpolation + result = (info.wa * y(info.ia) + info.wb * y(info.ib)) / info.ti; + break; case NearestInterp: // pick closest point result = (info.wa > info.wb ? y(info.ia) : y(info.ib)); @@ -150,7 +170,7 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe /// linear interpolation of the function y = f(x) at points xi /// assumes that x is strictly increasing -Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = x.size(); @@ -161,7 +181,7 @@ Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod i } for (unsigned i = 0; i < N; ++i) { - result(i) = interp(x, y, xi(i), interpMethod, extrapMethod); + result(i) = interp(x, y, xi(i), interpMethod, extrapMethod, ti); } return result; diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index a8cca34ea07..39a2a6a88f2 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -76,21 +76,22 @@ struct UTILITIES_API InterpInfo bool extrapolated; // was point out of range unsigned ia, ib; // indices of two nearest points double wa, wb; // weights of two nearest points + double ti; // length of interval }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing. */ -UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi); +UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly * increasing. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); //@} /** @name Common Methods and Vector Operations */ diff --git a/src/utilities/data/Vector.i b/src/utilities/data/Vector.i index ce8606dceee..3e45d9e0d78 100644 --- a/src/utilities/data/Vector.i +++ b/src/utilities/data/Vector.i @@ -167,23 +167,24 @@ struct UTILITIES_API InterpInfo{ bool extrapolated; // was point out of range unsigned ia, ib; // indices of two nearest points double wa, wb; // weights of two nearest points + double ti; // length of interval }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing. */ -UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi); +UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly * increasing. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); //@} /** @name Common Methods and Vector Operations */ From 8f1aed5084bbd59644fbffdfe20854490fab63f4 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 22 Mar 2024 09:26:38 -0700 Subject: [PATCH 16/68] Formatting. --- src/utilities/data/Matrix.cpp | 9 ++++++--- src/utilities/data/Vector.cpp | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index dd068e79caf..ba5b07773e0 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -38,7 +38,8 @@ bool operator!=(const Matrix& lhs, const Matrix& rhs) { /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { double result = 0.0; size_t M = x.size(); @@ -143,7 +144,8 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { size_t M = x.size(); Vector result(M); @@ -161,7 +163,8 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { size_t N = y.size(); Vector result(N); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 3cca6aa100d..ba981ec4017 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -96,7 +96,7 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - if (ti == 0.0) { + if (ti == 0.0) { result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); } else { @@ -109,7 +109,7 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.wa = 0.0; result.wb = 1.0; } - } + } } return result; From 81cfbd0117eba8e97c0f763bb33e568c2098b3dc Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 12:56:00 -0700 Subject: [PATCH 17/68] Cache timeseries results and clear when object changes. --- src/model/ScheduleDay.cpp | 150 +++++++++++++++------------ src/model/ScheduleDay_Impl.hpp | 2 + src/model/Timestep.cpp | 1 + src/model/test/ScheduleDay_GTest.cpp | 6 +- 4 files changed, 89 insertions(+), 70 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 57c28734dd5..f2f47086ed0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -186,94 +186,109 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); - double value; - for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { - openstudio::Time t0 = dateTimes[i].time(); - openstudio::Time t1 = dateTimes[i + 1].time(); - if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day - t1 = openstudio::Time(0, 24, 0); - } + unsigned N = dateTimes.size(); + OS_ASSERT(values.size() == N); + + if (N == 0) { + return 0.0; + } + + Vector x(N + 2); + Vector y(N + 2); + + x[0] = 0.0; + y[0] = 0.0; - if (t0 == time) { - value = values[i]; - } else if (t1 == time) { - value = values[i + 1]; - } else if ((t0 < time) && (time < t1)) { - value = values[i + 1]; + for (unsigned i = 0; i < N; ++i) { + openstudio::Time t = dateTimes[i].time(); + if (t.totalDays() == 0.0) { // this is 00:00:00 from the next day + t = openstudio::Time(0, 24, 0); } + + x[i + 1] = t.totalDays(); + y[i + 1] = values[i]; } - return value; + x[N + 1] = 1.0; + y[N + 1] = values[N - 1]; + + double result = interp(x, y, time.totalDays(), HoldNextInterp, NoneExtrap); + + return result; } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { - auto timestep = this->model().getUniqueModelObject(); - int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); - - Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary - DateTime startDateTime(startDate, Time(0, 0, 0)); - - DateTimeVector tsDateTimes; - int minutes = 60 / numberOfTimestepsPerHour; - for (size_t hour = 0; hour < 24; ++hour) { - for (size_t minute = minutes; minute <= 60; minute += minutes) { - if (minute == 60) { - openstudio::Time t(0, hour + 1, 0); - tsDateTimes.push_back(startDateTime + t); - } else { - openstudio::Time t(0, hour, minute); - tsDateTimes.push_back(startDateTime + t); + if (!m_cachedTimeSeries) { + + auto timestep = this->model().getUniqueModelObject(); + int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + int minutes = 60 / numberOfTimestepsPerHour; + DateTime startDateTime(startDate, Time(0, 0, 0)); + + DateTimeVector tsDateTimes; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + tsDateTimes.push_back(startDateTime + t); + } else { + openstudio::Time t(0, hour, minute); + tsDateTimes.push_back(startDateTime + t); + } } } - } - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted - unsigned N = times.size(); - OS_ASSERT(values.size() == N); + unsigned N = times.size(); + OS_ASSERT(values.size() == N); - TimeSeries result; - if (N == 0) { - return result; - } + TimeSeries result; + if (N == 0) { + return result; + } - Vector x(N + 2); - Vector y(N + 2); + Vector x(N + 2); + Vector y(N + 2); - x[0] = -0.000001; - y[0] = 0.0; + x[0] = -0.000001; + y[0] = 0.0; - for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); - y[i + 1] = values[i]; - } + for (unsigned i = 0; i < N; ++i) { + x[i + 1] = times[i].totalDays(); + y[i + 1] = values[i]; + } - x[N + 1] = 1.000001; - y[N + 1] = 0.0; + x[N + 1] = 1.000001; + y[N + 1] = 0.0; - std::string interpolatetoTimestep = this->interpolatetoTimestep(); - Vector tsValues(tsDateTimes.size()); - for (unsigned j = 0; j < tsDateTimes.size(); ++j) { - openstudio::Time t0 = tsDateTimes[j].time(); - if (t0.totalDays() == 0.0) { // this is 00:00:00 from the next day - t0 = openstudio::Time(0, 24, 0); - } + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + Vector tsValues(tsDateTimes.size()); + for (unsigned j = 0; j < tsDateTimes.size(); ++j) { + openstudio::Time t = tsDateTimes[j].time(); + if (t.totalDays() == 0.0) { // this is 00:00:00 from the next day + t = openstudio::Time(0, 24, 0); + } - if (istringEqual("No", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); - } else if (istringEqual("Average", interpolatetoTimestep)) { - double minutes = 60.0 / numberOfTimestepsPerHour; - double ti = minutes / (60.0 * 24.0); // total days of the timestep interval - tsValues[j] = interp(x, y, t0.totalDays(), AverageInterp, NoneExtrap, ti); - } else if (istringEqual("Linear", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); + if (istringEqual("No", interpolatetoTimestep)) { + tsValues[j] = interp(x, y, t.totalDays(), HoldNextInterp, NoneExtrap); + } else if (istringEqual("Average", interpolatetoTimestep)) { + double minutes = 60.0 / numberOfTimestepsPerHour; + double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + tsValues[j] = interp(x, y, t.totalDays(), AverageInterp, NoneExtrap, ti); + } else if (istringEqual("Linear", interpolatetoTimestep)) { + tsValues[j] = interp(x, y, t.totalDays(), LinearInterp, NoneExtrap); + } } - } - result = TimeSeries(tsDateTimes, tsValues, ""); + result = TimeSeries(tsDateTimes, tsValues, ""); + m_cachedTimeSeries = result; + } - return result; + return m_cachedTimeSeries.get(); } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { @@ -432,6 +447,7 @@ namespace model { void ScheduleDay_Impl::clearCachedVariables() { m_cachedTimes.reset(); m_cachedValues.reset(); + m_cachedTimeSeries.reset(); } } // namespace detail diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 201aecb58a9..fd408fc359b 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -10,6 +10,7 @@ #include "ScheduleBase_Impl.hpp" #include "../utilities/time/Time.hpp" +#include "../utilities/data/TimeSeries.hpp" namespace openstudio { @@ -119,6 +120,7 @@ namespace model { mutable boost::optional> m_cachedTimes; mutable boost::optional> m_cachedValues; + mutable boost::optional m_cachedTimeSeries; }; } // namespace detail diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index 90b803e3355..b8767089db4 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -9,6 +9,7 @@ #include "SimulationControl_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" +#include "ScheduleDay_Impl.hpp" #include "../utilities/core/Assert.hpp" #include #include diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index f87f42906d1..06fda138014 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -196,10 +196,10 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); - EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); // FIXME: Fails. Should be 1.0? - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); // FIXME: Fails. Should be 1.0? + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); // FIXME: Fails. Should be 0.0? + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } From 07992ed36c558f9a76517e11c49ddbfdc3bd7cc1 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 14:05:53 -0700 Subject: [PATCH 18/68] Add AverageInterp no-op case to matrix cpp. --- src/utilities/data/Matrix.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index ba5b07773e0..30d1a80e62f 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -69,6 +69,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub // linear interpolation // no-op break; + case AverageInterp: + // average interpolation + // no-op + break; case NearestInterp: // pick closest point if (xInfo.wa > xInfo.wb) { @@ -112,6 +116,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub // linear interpolation // no-op break; + case AverageInterp: + // average interpolation + // no-op + break; case NearestInterp: // pick closest point if (yInfo.wa > yInfo.wb) { From b178a6b62c1fe2fd7e87d14b18a6da20452823c6 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 14:11:01 -0700 Subject: [PATCH 19/68] Update docs for new timeseries method. --- src/model/ScheduleDay.hpp | 2 +- src/model/ScheduleDay_Impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 7b651f2adff..70feeba5e18 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -70,7 +70,7 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; - /// Returns the values for the timesteps per hour. + /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method. openstudio::TimeSeries timeSeries() const; //@} diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index fd408fc359b..2a23a025d8e 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -76,7 +76,7 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; - /// Returns the values for the timesteps per hour. + /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method. openstudio::TimeSeries timeSeries() const; //@} From f9a2eae3f8a9eb7ca21ca8e063a2d0ce2742e208 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 16:31:35 -0700 Subject: [PATCH 20/68] Set left endpoint of getvalue. --- src/model/ScheduleDay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f2f47086ed0..e1fa086bbc0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -197,7 +197,7 @@ namespace model { Vector y(N + 2); x[0] = 0.0; - y[0] = 0.0; + y[0] = values[0]; for (unsigned i = 0; i < N; ++i) { openstudio::Time t = dateTimes[i].time(); From d1d77084aeac4b9d706fe8051a960b79a652319a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 26 Mar 2024 10:14:22 -0700 Subject: [PATCH 21/68] Update left endpoint per method and update tests. --- src/model/ScheduleDay.cpp | 9 ++++++++- src/model/test/ScheduleDay_GTest.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index e1fa086bbc0..dd4674a86d0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -197,7 +197,14 @@ namespace model { Vector y(N + 2); x[0] = 0.0; - y[0] = values[0]; + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + if (istringEqual("No", interpolatetoTimestep)) { + y[0] = values[0]; + } else if (istringEqual("Average", interpolatetoTimestep)) { + y[0] = values[0]; + } else if (istringEqual("Linear", interpolatetoTimestep)) { + y[0] = 0.0; + } for (unsigned i = 0; i < N; ++i) { openstudio::Time t = dateTimes[i].time(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 06fda138014..7c406ac2dcd 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -53,6 +53,7 @@ TEST_F(ModelFixture, Schedule_Day) { EXPECT_EQ(0.0, daySchedule.getValue(Time(0, -1, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 0))); + EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 1))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 6, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 8, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 9, 0))); @@ -197,11 +198,25 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(0.013890, daySchedule.getValue(Time(0, 0, 1)), tol); EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); + + daySchedule.setInterpolatetoTimestep("Average"); + EXPECT_EQ("Average", daySchedule.interpolatetoTimestep()); + EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); + + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 1)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 6, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 18, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } TEST_F(ModelFixture, Schedule_Day_Remove) { From 160585aa22366d19bfe970c47b038d59bee2907a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 10:19:10 -0700 Subject: [PATCH 22/68] Interpolate using seconds instead of days. --- src/model/ScheduleDay.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index dd4674a86d0..5cc936bbeb0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -265,11 +265,11 @@ namespace model { y[0] = 0.0; for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); + x[i + 1] = times[i].totalSeconds(); y[i + 1] = values[i]; } - x[N + 1] = 1.000001; + x[N + 1] = 86400.000001; y[N + 1] = 0.0; std::string interpolatetoTimestep = this->interpolatetoTimestep(); @@ -281,13 +281,13 @@ namespace model { } if (istringEqual("No", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t.totalDays(), HoldNextInterp, NoneExtrap); + tsValues[j] = interp(x, y, t.totalSeconds(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { double minutes = 60.0 / numberOfTimestepsPerHour; double ti = minutes / (60.0 * 24.0); // total days of the timestep interval - tsValues[j] = interp(x, y, t.totalDays(), AverageInterp, NoneExtrap, ti); + tsValues[j] = interp(x, y, t.totalSeconds(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t.totalDays(), LinearInterp, NoneExtrap); + tsValues[j] = interp(x, y, t.totalSeconds(), LinearInterp, NoneExtrap); } } From 686b725d0393f98abcc2ec2175c50b7ad64ad64f Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 11:23:39 -0700 Subject: [PATCH 23/68] Need ti in seconds and not days. --- src/model/ScheduleDay.cpp | 2 +- src/utilities/data/Vector.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5cc936bbeb0..203fe026546 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -284,7 +284,7 @@ namespace model { tsValues[j] = interp(x, y, t.totalSeconds(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { double minutes = 60.0 / numberOfTimestepsPerHour; - double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + double ti = minutes * 60.0; // total seconds of the timestep interval tsValues[j] = interp(x, y, t.totalSeconds(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { tsValues[j] = interp(x, y, t.totalSeconds(), LinearInterp, NoneExtrap); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index ba981ec4017..ecaa75c072e 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -102,12 +102,12 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { } else { result.wb = xi - x(result.ia); result.wa = ti - result.wb; - result.ti = 1.0; if ((result.wb > 0.0) && (result.wb < ti)) { result.ti = ti; } else { result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; } } } From e74296693870beb9b0afeb016218d3dd38ae6da8 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 14:59:34 -0700 Subject: [PATCH 24/68] Try updating timestep with cache clear. --- src/model/Timestep.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index b8767089db4..bc3bc6679aa 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -9,6 +9,7 @@ #include "SimulationControl_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" +#include "ScheduleDay.hpp" #include "ScheduleDay_Impl.hpp" #include "../utilities/core/Assert.hpp" #include @@ -67,11 +68,20 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { + int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); + if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedVariables(); + } + } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; } void Timestep_Impl::resetNumberOfTimestepsPerHour() { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedVariables(); + } bool result = setString(OS_TimestepFields::NumberofTimestepsperHour, ""); OS_ASSERT(result); } From 2ded73033bc17e1b41e9bf33f86e8b2435992197 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 15:28:10 -0700 Subject: [PATCH 25/68] New protected method for clearing ts, and friend timestep. --- src/model/ScheduleDay.cpp | 4 ++++ src/model/ScheduleDay_Impl.hpp | 4 ++++ src/model/Timestep.cpp | 9 +++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 203fe026546..34212e5361c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -457,6 +457,10 @@ namespace model { m_cachedTimeSeries.reset(); } + void ScheduleDay_Impl::clearCachedTimeSeries() { + m_cachedTimeSeries.reset(); + } + } // namespace detail ScheduleDay::ScheduleDay(const Model& model) : ScheduleBase(ScheduleDay::iddObjectType(), model) { diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 2a23a025d8e..b80a0e18b46 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -111,6 +111,10 @@ namespace model { virtual bool okToResetScheduleTypeLimits() const override; + void clearCachedTimeSeries(); + + friend class detail::Timestep_Impl; + //private slots: private: void clearCachedVariables(); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index bc3bc6679aa..89eaba247e1 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,11 +68,8 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); - if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { - for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedVariables(); - } + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedTimeSeries(); } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; @@ -80,7 +77,7 @@ namespace model { void Timestep_Impl::resetNumberOfTimestepsPerHour() { for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedVariables(); + sch_day.getImpl()->clearCachedTimeSeries(); } bool result = setString(OS_TimestepFields::NumberofTimestepsperHour, ""); OS_ASSERT(result); From bfb876f80b57f0cdd8b32912cf756543b4e643d6 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 15:53:18 -0700 Subject: [PATCH 26/68] Updates for vt and deprecating interp setter. --- src/model/ScheduleDay.cpp | 13 ++++++++++ src/model/ScheduleDay.hpp | 3 +++ src/model/ScheduleDay_Impl.hpp | 5 ++-- src/model/Timestep.cpp | 7 ++++-- src/osversion/VersionTranslator.cpp | 25 +++++++++++++++++++ .../test/3_8_0/test_vt_ScheduleDay.osm | 14 +++++++++++ .../test/3_8_0/test_vt_ScheduleDay.rb | 10 ++++++++ .../test/VersionTranslator_GTest.cpp | 21 ++++++++++++++++ 8 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/osversion/test/3_8_0/test_vt_ScheduleDay.osm create mode 100644 src/osversion/test/3_8_0/test_vt_ScheduleDay.rb diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 34212e5361c..66bcaa66a1c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -30,6 +30,8 @@ #include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" +#include "../utilities/core/DeprecatedHelpers.hpp" // For deprecation + namespace openstudio { namespace model { @@ -528,6 +530,17 @@ namespace model { getImpl()->clearValues(); } + // DEPRECATED + + bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) const { + DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); + if (interpolatetoTimestep) { + return getImpl()->setInterpolatetoTimestep("Average"); + } else { + return getImpl()->setInterpolatetoTimestep("No"); + } + } + /// @cond ScheduleDay::ScheduleDay(std::shared_ptr impl) : ScheduleBase(std::move(impl)) {} /// @endcond diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 70feeba5e18..34623f0f52d 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -9,6 +9,8 @@ #include "ModelAPI.hpp" #include "ScheduleBase.hpp" +#include "../utilities/core/Deprecated.hpp" + namespace openstudio { class Time; @@ -78,6 +80,7 @@ namespace model { //@{ bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); + OS_DEPRECATED(3, 8, 0) bool setInterpolatetoTimestep(bool interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index b80a0e18b46..ff704c4ac07 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -22,6 +22,8 @@ namespace model { namespace detail { + class Timestep_Impl; + /** ScheduleDay_Impl is a ResourceObject_Impl that is the implementation class for ScheduleDay.*/ class MODEL_API ScheduleDay_Impl : public ScheduleBase_Impl { @@ -111,10 +113,9 @@ namespace model { virtual bool okToResetScheduleTypeLimits() const override; + friend class Timestep_Impl; void clearCachedTimeSeries(); - friend class detail::Timestep_Impl; - //private slots: private: void clearCachedVariables(); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index 89eaba247e1..d7a0cba1fbe 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,8 +68,11 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedTimeSeries(); + const int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); + if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedTimeSeries(); + } } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index ad7436325f7..b3e42fb6ad5 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9160,6 +9160,31 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); + } else if (iddname == "OS:Schedule:Day" ) { + + // 1 Field has been added from 3.7.0 to 3.8.0: + // ---------------------------------------------- + // * Interpolate to Timestep * 3 + + auto iddObject = idd_3_8_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + if (i == 3) { + if (istringEqual(value.get(), "Yes")) { + newObject.setString(3, "Average"); + } else { + newObject.setString(3, "No"); + } + } + newObject.setString(i, value.get()); + } + } + + ss << newObject; + m_refactored.emplace_back(std::move(object), std::move(newObject)); + // No-op } else { ss << object; diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm new file mode 100644 index 00000000000..c265fde6cda --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm @@ -0,0 +1,14 @@ + +OS:Version, + {9d4d2ac6-81f7-466e-be47-92edf03bbde0}, !- Handle + 3.7.0; !- Version Identifier + +OS:Schedule:Day, + {b39f42af-eb9f-4079-ad11-5a527a726900}, !- Handle + Schedule Day 1, !- Name + , !- Schedule Type Limits Name + Yes, !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb new file mode 100644 index 00000000000..9af267e319c --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb @@ -0,0 +1,10 @@ +#require '/usr/local/openstudio-3.6.1/Ruby/openstudio' + +include OpenStudio::Model + +m = Model.new + +sch_day = ScheduleDay.new(m) +sch_day.setInterpolatetoTimestep(true) + +m.save('test_vt_ScheduleDay.osm', true) diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 6d12d3c4439..4a06beca16a 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -4186,3 +4186,24 @@ TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_PeopleDefinition) { EXPECT_TRUE(def.isEmpty(9)); // Enable ASHRAE 55 Comfort Warnings EXPECT_EQ("EnclosureAveraged", def.getString(10).get()); // Mean Radiant Temperature Calculation Type } + +TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_ScheduleDay) { + openstudio::path path = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay.osm"); + osversion::VersionTranslator vt; + boost::optional model = vt.loadModel(path); + ASSERT_TRUE(model) << "Failed to load " << path; + + openstudio::path outPath = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay_updated.osm"); + model->save(outPath, true); + + std::vector sch_days = model->getObjectsByType("OS:Schedule:Day"); + ASSERT_EQ(1u, sch_days.size()); + WorkspaceObject sch_day = sch_days[0]; + + EXPECT_EQ("Schedule Day 1", sch_day.getString(1).get()); // Name + EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name + EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep + EXPECT_EQ(24, sch_day.getInt(4)); // Hour 1 + EXPECT_EQ(0, sch_day.getInt(5)); // Minute 1 + EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 +} From dd39ffd6f5ba99e613e268fdd043d1f9fc336a98 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 19:23:00 -0700 Subject: [PATCH 27/68] Building but tests failing. --- src/model/ScheduleDay.cpp | 2 +- src/model/Timestep.cpp | 3 +-- src/osversion/VersionTranslator.cpp | 8 ++++---- src/osversion/test/VersionTranslator_GTest.cpp | 10 +++++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 66bcaa66a1c..5798189daa8 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -532,7 +532,7 @@ namespace model { // DEPRECATED - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) const { + bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); if (interpolatetoTimestep) { return getImpl()->setInterpolatetoTimestep("Average"); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index d7a0cba1fbe..77bfd6b81f0 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,8 +68,7 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - const int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); - if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + if (numberOfTimestepsPerHour != this->numberOfTimestepsPerHour()) { for (auto& sch_day : model().getConcreteModelObjects()) { sch_day.getImpl()->clearCachedTimeSeries(); } diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index b3e42fb6ad5..ee8785e6f7c 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9160,15 +9160,15 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); - } else if (iddname == "OS:Schedule:Day" ) { + } else if (iddname == "OS:Schedule:Day") { // 1 Field has been added from 3.7.0 to 3.8.0: // ---------------------------------------------- // * Interpolate to Timestep * 3 - + auto iddObject = idd_3_8_0.getObject(iddname); IdfObject newObject(iddObject.get()); - + for (size_t i = 0; i < object.numFields(); ++i) { if ((value = object.getString(i))) { if (i == 3) { @@ -9184,7 +9184,7 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); - + // No-op } else { ss << object; diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 4a06beca16a..d7d81842494 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -4201,9 +4201,9 @@ TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_ScheduleDay) { WorkspaceObject sch_day = sch_days[0]; EXPECT_EQ("Schedule Day 1", sch_day.getString(1).get()); // Name - EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name - EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep - EXPECT_EQ(24, sch_day.getInt(4)); // Hour 1 - EXPECT_EQ(0, sch_day.getInt(5)); // Minute 1 - EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 + EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name + EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep + EXPECT_EQ(24, sch_day.getInt(4).get()); // Hour 1 + EXPECT_EQ(0, sch_day.getInt(5).get()); // Minute 1 + EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 } From 4af6ee361d26665276195aff54496064f94f88d2 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 19:29:15 -0700 Subject: [PATCH 28/68] Fix the new vt. --- src/osversion/VersionTranslator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index ee8785e6f7c..4ef6e4d12ca 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9177,8 +9177,9 @@ namespace osversion { } else { newObject.setString(3, "No"); } + } else { + newObject.setString(i, value.get()); } - newObject.setString(i, value.get()); } } From 9be8c906e67987df9a80dd8fe4448d93a56865e1 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 28 Mar 2024 08:37:16 -0700 Subject: [PATCH 29/68] Remove deprecation of old setter. --- src/model/ScheduleDay.cpp | 13 ------------- src/model/ScheduleDay.hpp | 3 --- src/model/test/ScheduleDay_GTest.cpp | 2 +- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5798189daa8..34212e5361c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -30,8 +30,6 @@ #include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" -#include "../utilities/core/DeprecatedHelpers.hpp" // For deprecation - namespace openstudio { namespace model { @@ -530,17 +528,6 @@ namespace model { getImpl()->clearValues(); } - // DEPRECATED - - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { - DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); - if (interpolatetoTimestep) { - return getImpl()->setInterpolatetoTimestep("Average"); - } else { - return getImpl()->setInterpolatetoTimestep("No"); - } - } - /// @cond ScheduleDay::ScheduleDay(std::shared_ptr impl) : ScheduleBase(std::move(impl)) {} /// @endcond diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 34623f0f52d..70feeba5e18 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -9,8 +9,6 @@ #include "ModelAPI.hpp" #include "ScheduleBase.hpp" -#include "../utilities/core/Deprecated.hpp" - namespace openstudio { class Time; @@ -80,7 +78,6 @@ namespace model { //@{ bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); - OS_DEPRECATED(3, 8, 0) bool setInterpolatetoTimestep(bool interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 7c406ac2dcd..0a951877c7a 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -192,7 +192,7 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); - daySchedule.setInterpolatetoTimestep("Linear"); + EXPECT_TRUE(daySchedule.setInterpolatetoTimestep("Linear")); EXPECT_EQ("Linear", daySchedule.interpolatetoTimestep()); EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); From bb57a4d1c7584ed2c04ffec0d552e7bb629a6328 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 28 Mar 2024 08:45:34 -0700 Subject: [PATCH 30/68] Add one more test showing change in getValue for small enough timestep. --- src/model/test/ScheduleDay_GTest.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 0a951877c7a..c102655304b 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -380,7 +380,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -397,7 +397,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -414,7 +414,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -431,7 +431,24 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(12)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 12, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 12, timeSeries.values().size()); + value = sch_day.getValue(t0800); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.1, value, tol); // at this timestep, we do return the 0.1 value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); From 6c33a6b84d6ca45e27172f153751352ad86827c8 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 08:59:41 -0700 Subject: [PATCH 31/68] Update comments and release notes. --- .../doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md | 4 ++++ src/model/ScheduleDay.cpp | 5 +++++ src/osversion/VersionTranslator.cpp | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md index a232fe46b1f..d309942e0b8 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md @@ -86,6 +86,10 @@ For a list of deprecated and removed methods, please refer to [deprecated_method * A number of methods have been renamed (and the old ones deprecated) to conform to the API for other `SpaceLoadInstance` / `SpaceLoadDefinition` objects * Mostly `getWattsperUnit` is changed to `getDesignLevel` and `getWattsperZoneFloorArea` is changed to `getPowerPerFloorArea` * Refer to [deprecated_methods.csv](../../ruby/deprecated_methods.csv) for the complete list +* [#5111](https://github.com/NREL/OpenStudio/pull/5111) - ScheduleDay: new timeseries method and interpolation options + * The `ScheduleDay` has API-breaking changes related to setters and getters for its `Interpolate To Timestep` field. They now use `string` rather than `bool` to conform to the IDD type `\choice` + * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in ``Interpolate to Timestep field + * A new `timeseries()` method is introduced for returning vectors of times and values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time ## Minor changes and bug fixes diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 34212e5361c..da51078c7cf 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -181,6 +181,11 @@ namespace model { return 0.0; } + // We'll calculate the entire day when we request a single value but that's on purpose: + // * We're talking about max 60 timesteps * 24 hours = 1440 points, + // but realistically more often than not you'll have a timestep of 6 (our default) or 4 so 96 to 144 points. So not a lot of points + // * We cache the timeSeries, and, + // * More often than not, the use case is to do it for the entire day anyways (eg: openstudio-standards to determine occupancy schedules) TimeSeries ts = this->timeSeries(); DateTimeVector dateTimes = ts.dateTimes(); diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index 4ef6e4d12ca..b4c7b138e15 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9162,9 +9162,9 @@ namespace osversion { } else if (iddname == "OS:Schedule:Day") { - // 1 Field has been added from 3.7.0 to 3.8.0: + // 1 Field has been modified from 3.7.0 to 3.8.0: // ---------------------------------------------- - // * Interpolate to Timestep * 3 + // * Interpolate to Timestep * 3 - Changed from bool to string choice auto iddObject = idd_3_8_0.getObject(iddname); IdfObject newObject(iddObject.get()); From e8b00150f74eb22283b0861d3c8aee0ec7922e3e Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 10:14:26 -0700 Subject: [PATCH 32/68] Update ti default to -9999, add assert, update comments. --- src/model/ScheduleDay.cpp | 4 ++-- src/utilities/data/Matrix.hpp | 16 ++++++++++++---- src/utilities/data/Vector.cpp | 3 ++- src/utilities/data/Vector.hpp | 13 ++++++++----- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index da51078c7cf..f6727d4e4e5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -191,7 +191,7 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); - unsigned N = dateTimes.size(); + const unsigned N = dateTimes.size(); OS_ASSERT(values.size() == N); if (N == 0) { @@ -255,7 +255,7 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted - unsigned N = times.size(); + const unsigned N = times.size(); OS_ASSERT(values.size() == N); TimeSeries result; diff --git a/src/utilities/data/Matrix.hpp b/src/utilities/data/Matrix.hpp index 9bade37a0a8..ecf6a9b0508 100644 --- a/src/utilities/data/Matrix.hpp +++ b/src/utilities/data/Matrix.hpp @@ -32,23 +32,31 @@ UTILITIES_API bool operator!=(const Matrix& lhs, const Matrix& rhs); /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, - InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// matrix product UTILITIES_API Matrix prod(const Matrix& lop, const Matrix& rop); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index ecaa75c072e..7660e59b895 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -96,10 +96,11 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - if (ti == 0.0) { + if (ti < 0.0) { result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); } else { + OS_ASSERT(ti > 0.0); result.wb = xi - x(result.ia); result.wa = ti - result.wb; if ((result.wb > 0.0) && (result.wb < ti)) { diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index 39a2a6a88f2..f1b1ebd7e02 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -80,18 +80,21 @@ struct UTILITIES_API InterpInfo }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly - * increasing. */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly - * increasing */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly - * increasing. */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); //@} /** @name Common Methods and Vector Operations */ From c74f8b6df3d3653cc509afd594ce863a16ecce6e Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 10:16:47 -0700 Subject: [PATCH 33/68] Few more updates to release notes. --- .../doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md index d309942e0b8..63a8e31bcee 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md @@ -88,8 +88,8 @@ For a list of deprecated and removed methods, please refer to [deprecated_method * Refer to [deprecated_methods.csv](../../ruby/deprecated_methods.csv) for the complete list * [#5111](https://github.com/NREL/OpenStudio/pull/5111) - ScheduleDay: new timeseries method and interpolation options * The `ScheduleDay` has API-breaking changes related to setters and getters for its `Interpolate To Timestep` field. They now use `string` rather than `bool` to conform to the IDD type `\choice` - * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in ``Interpolate to Timestep field - * A new `timeseries()` method is introduced for returning vectors of times and values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time + * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in `Interpolate to Timestep` field + * A new `timeseries()` method is introduced for returning vectors of times and (interpolated) values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time ## Minor changes and bug fixes From d2c195dfb63237373525540e861a1370a2ce49e4 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:06:50 -0700 Subject: [PATCH 34/68] Introduce new getValues method on ScheduleDay. --- src/model/ScheduleDay.cpp | 22 ++++++++++++++++++++++ src/model/ScheduleDay.hpp | 3 +++ src/model/ScheduleDay_Impl.hpp | 3 +++ 3 files changed, 28 insertions(+) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 66ddbc97a05..f6efb486ab8 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,6 +16,8 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" +#include "Timestep.hpp" +#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -212,6 +214,26 @@ namespace model { return result; } + std::vector getValues(const openstudio::model::Timestep& timestep) const { + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + std::vector result; + + int timesteps = 24.0 * timestep.numberOfTimestepsPerHour(); + for (size_t timestep = 0; timestep < timesteps; ++timestep) { + openstudio::Time t(timestep / timesteps); + size_t i = 0; + for (const openstudio::Time& time : times) { + if (t <= time) { + result.push_back(values[i]); + break; + } + ++i; + } + } + return result; + } + bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { if (scheduleTypeLimits.model() != model()) { return false; diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index ce64172a47e..ce012632ae6 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -69,6 +69,9 @@ namespace model { /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; + /// Returns the values for a given timestep. + std::vector getValues(const openstudio::model::Timestep& timestep) const; + //@} /** @name Setters */ //@{ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 564fec1a279..80f708a774c 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -72,6 +72,9 @@ namespace model { /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; + /// Returns the values for a given timestep. + std::vector getValues(const openstudio::model::Timestep& timestep) const; + //@} /** @name Setters */ //@{ From 5037966f321d81013ae425f8d1f56c6f48a80ef7 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:07:05 -0700 Subject: [PATCH 35/68] Stub model test for new method. --- src/model/test/ScheduleDay_GTest.cpp | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index be5370b9180..f8823b9cfc4 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,6 +10,8 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" +#include "../Timestep.hpp" +#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" @@ -320,3 +322,31 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { EXPECT_FALSE(sch_day.addValue(t, std::numeric_limits::infinity())); EXPECT_FALSE(sch_day.addValue(t, -std::numeric_limits::infinity())); } + +TEST_F(ModelFixture, Schedule_Day_getValues) { + Model model; + + ScheduleDay sch_day(model); + + Time t1("08:15:00"); + sch_day.addValue(t1, 0); + Time t2("21:45:00"); + sch_day.addValue(t2, 1); + + auto timestep = model.getUniqueModelObject(): + + timestep.setNumberOfTimestepsPerHour(1); + std::vector values24 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 1, values24.size()); + + timestep.setNumberOfTimestepsPerHour(4); + std::vector values15 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 4, values15.size()); + + timestep.setNumberOfTimestepsPerHour(6); + std::vector values10 = sch_day.getValues(timestep); + EXPECT_EQ(24 * 6, values10.size()); + + // TODO: check for 0s and 1s + // TODO: check interpolatetoTimestep doesn't matter +} From 96e95147b972e59fa0af61d5c7bd6fec9a721d7a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:07:19 -0700 Subject: [PATCH 36/68] Formatting. --- src/model/ScheduleDay.cpp | 2 +- src/model/test/ScheduleDay_GTest.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f6efb486ab8..c52025d4273 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -229,7 +229,7 @@ namespace model { break; } ++i; - } + } } return result; } diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index f8823b9cfc4..ad3c96b8fb8 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -333,9 +333,11 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model.getUniqueModelObject(): + auto timestep = model + .getUniqueModelObject() + : - timestep.setNumberOfTimestepsPerHour(1); + timestep.setNumberOfTimestepsPerHour(1); std::vector values24 = sch_day.getValues(timestep); EXPECT_EQ(24 * 1, values24.size()); From d55dc2017f9fab4c86d8988e45c7f309abc64e80 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 13 Mar 2024 14:14:53 -0700 Subject: [PATCH 37/68] Typo. --- src/model/test/ScheduleDay_GTest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index ad3c96b8fb8..96a72f40db6 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -333,11 +333,9 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model - .getUniqueModelObject() - : + auto timestep = model.getUniqueModelObject(); - timestep.setNumberOfTimestepsPerHour(1); + timestep.setNumberOfTimestepsPerHour(1); std::vector values24 = sch_day.getValues(timestep); EXPECT_EQ(24 * 1, values24.size()); From a58faef33c77c470fb1443e4492ffe6b5687d837 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 14 Mar 2024 11:30:14 -0700 Subject: [PATCH 38/68] Update scheduleday files and get new tests passing. --- src/model/ScheduleDay.cpp | 64 ++++++++++++++----- src/model/ScheduleDay.hpp | 16 +++-- src/model/ScheduleDay_Impl.hpp | 16 +++-- src/model/test/ScheduleDay_GTest.cpp | 93 +++++++++++++++++++++++----- 4 files changed, 151 insertions(+), 38 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index c52025d4273..f40ddd159a4 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,8 +16,6 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" -#include "Timestep.hpp" -#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -173,13 +171,20 @@ namespace model { return m_cachedValues.get(); } - double ScheduleDay_Impl::getValue(const openstudio::Time& time) const { + double ScheduleDay_Impl::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { if (time.totalMinutes() < 0.0 || time.totalDays() > 1.0) { return 0.0; } - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector values; + std::vector times; + if (numberOfTimestepsPerHour > 0) { + values = this->getValues(numberOfTimestepsPerHour); + times = this->getTimes(numberOfTimestepsPerHour); + } else { + values = this->values(); // these are already sorted + times = this->times(); // these are already sorted + } unsigned N = times.size(); OS_ASSERT(values.size() == N); @@ -203,7 +208,7 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (this->interpolatetoTimestep()) { + if (numberOfTimestepsPerHour > 0) { interpMethod = LinearInterp; } else { interpMethod = HoldNextInterp; @@ -214,14 +219,36 @@ namespace model { return result; } - std::vector getValues(const openstudio::model::Timestep& timestep) const { - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector ScheduleDay_Impl::getTimes(int numberOfTimestepsPerHour) const { + std::vector result; + + std::vector allowables{1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}; + if (std::find(allowables.begin(), allowables.end(), numberOfTimestepsPerHour) == allowables.end()) { + return result; + } + + int minutes = 60 / numberOfTimestepsPerHour; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + result.push_back(t); + } else { + openstudio::Time t(0, hour, minute); + result.push_back(t); + } + } + } + return result; + } + + std::vector ScheduleDay_Impl::getValues(int numberOfTimestepsPerHour) const { + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + std::vector getTimes = this->getTimes(numberOfTimestepsPerHour); // these are already sorted std::vector result; - int timesteps = 24.0 * timestep.numberOfTimestepsPerHour(); - for (size_t timestep = 0; timestep < timesteps; ++timestep) { - openstudio::Time t(timestep / timesteps); + for (const openstudio::Time& t : getTimes) { size_t i = 0; for (const openstudio::Time& time : times) { if (t <= time) { @@ -253,7 +280,6 @@ namespace model { bool ScheduleDay_Impl::setInterpolatetoTimestep(bool interpolatetoTimestep) { return setBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); - ; } void ScheduleDay_Impl::resetInterpolatetoTimestep() { @@ -432,8 +458,16 @@ namespace model { return getImpl()->values(); } - double ScheduleDay::getValue(const openstudio::Time& time) const { - return getImpl()->getValue(time); + double ScheduleDay::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { + return getImpl()->getValue(time, numberOfTimestepsPerHour); + } + + std::vector ScheduleDay::getTimes(int numberOfTimestepsPerHour) const { + return getImpl()->getTimes(numberOfTimestepsPerHour); + } + + std::vector ScheduleDay::getValues(int numberOfTimestepsPerHour) const { + return getImpl()->getValues(numberOfTimestepsPerHour); } bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index ce012632ae6..8d21a4c133d 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -66,11 +66,19 @@ namespace model { /// Returns a vector of values in the same order and with the same number of elements as times. std::vector values() const; - /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time) const; + /// Returns the value in effect at the given time. + /// If time is less than 0 days or greater than 1 day, 0 is returned. + double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; - /// Returns the values for a given timestep. - std::vector getValues(const openstudio::model::Timestep& timestep) const; + /// Returns the vector of times marking the end value intervals for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + /// These times will be in order and have the same number of elements as getValues. + /// All times will be less than or equal to 1 day. + std::vector getTimes(int numberOfTimestepsPerHour) const; + + /// Returns the values for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + std::vector getValues(int numberOfTimestepsPerHour) const; //@} /** @name Setters */ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 80f708a774c..d604e43fb17 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -69,11 +69,19 @@ namespace model { /// Returns a vector of values in the same order and with the same number of elements as times. virtual std::vector values() const override; - /// Returns the value in effect at the given time. If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time) const; + /// Returns the value in effect at the given time. + /// If time is less than 0 days or greater than 1 day, 0 is returned. + double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; - /// Returns the values for a given timestep. - std::vector getValues(const openstudio::model::Timestep& timestep) const; + /// Returns the vector of times marking the end value intervals for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + /// These times will be in order and have the same number of elements as getValues. + /// All times will be less than or equal to 1 day. + std::vector getTimes(int numberOfTimestepsPerHour) const; + + /// Returns the values for a given timesteps per hour. + /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. + std::vector getValues(int numberOfTimestepsPerHour) const; //@} /** @name Setters */ diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 96a72f40db6..796d6eca5f7 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,8 +10,6 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" -#include "../Timestep.hpp" -#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" @@ -195,10 +193,10 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); - EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); // FIXME: Fails. Should be 1.0? + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); // FIXME: Fails. Should be 1.0? EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); // FIXME: Fails. Should be 0.0? EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } @@ -326,6 +324,8 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { TEST_F(ModelFixture, Schedule_Day_getValues) { Model model; + double tol = 1e-5; + ScheduleDay sch_day(model); Time t1("08:15:00"); @@ -333,20 +333,83 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - auto timestep = model.getUniqueModelObject(); + std::vector times = sch_day.getTimes(7); + EXPECT_EQ(0, times.size()); + + std::vector times24 = sch_day.getTimes(1); + EXPECT_EQ(24 * 1, times24.size()); + + std::vector times15 = sch_day.getTimes(4); + EXPECT_EQ(24 * 4, times15.size()); - timestep.setNumberOfTimestepsPerHour(1); - std::vector values24 = sch_day.getValues(timestep); + std::vector times10 = sch_day.getTimes(6); + EXPECT_EQ(24 * 6, times10.size()); + Time times10_1("00:10:00"); + EXPECT_EQ(times10_1, times10[0]); + Time times10_48("08:00:00"); + EXPECT_EQ(times10_48, times10[47]); + Time times10_49("08:10:00"); + EXPECT_EQ(times10_49, times10[48]); + Time times10_50("08:20:00"); + EXPECT_EQ(times10_50, times10[49]); + Time times10_144("24:00:00"); + EXPECT_EQ(times10_144, times10[143]); + + std::vector values = sch_day.getValues(18); + EXPECT_EQ(0, values.size()); + + std::vector values24 = sch_day.getValues(1); EXPECT_EQ(24 * 1, values24.size()); - timestep.setNumberOfTimestepsPerHour(4); - std::vector values15 = sch_day.getValues(timestep); + std::vector values15 = sch_day.getValues(4); EXPECT_EQ(24 * 4, values15.size()); - timestep.setNumberOfTimestepsPerHour(6); - std::vector values10 = sch_day.getValues(timestep); + std::vector values10 = sch_day.getValues(6); EXPECT_EQ(24 * 6, values10.size()); - - // TODO: check for 0s and 1s - // TODO: check interpolatetoTimestep doesn't matter + EXPECT_DOUBLE_EQ(0.0, values10[0]); + EXPECT_DOUBLE_EQ(0.0, values10[47]); + EXPECT_DOUBLE_EQ(0.0, values10[48]); + EXPECT_DOUBLE_EQ(1.0, values10[49]); + EXPECT_DOUBLE_EQ(0.0, values10[143]); + + double value; + + Time t3("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 1); + EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + value = sch_day.getValue(t3, 4); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 6); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t3, 10); + EXPECT_DOUBLE_EQ(0.0, value); + + Time t4("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); + value = sch_day.getValue(t4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t4, 1); + EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + value = sch_day.getValue(t4, 4); + EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + value = sch_day.getValue(t4, 6); + EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + value = sch_day.getValue(t4, 10); + EXPECT_DOUBLE_EQ(1.0, value); + + Time t5("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 1); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 6); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5, 10); + EXPECT_DOUBLE_EQ(1.0, value); } From 94685d52074559a63f0bfd40759f7e818323bab7 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 15:15:26 -0700 Subject: [PATCH 39/68] Return timeseries instead of separate getTimes and getValues. --- src/model/ScheduleDay.cpp | 51 ++++++++++++++++++++++++---------- src/model/ScheduleDay.hpp | 11 ++------ src/model/ScheduleDay_Impl.hpp | 13 +++------ 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f40ddd159a4..2ea822d6ea5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -16,6 +16,8 @@ #include "ScheduleRuleset_Impl.hpp" #include "ScheduleRule.hpp" #include "ScheduleRule_Impl.hpp" +#include "Timestep.hpp" +#include "Timestep_Impl.hpp" #include "../utilities/idf/IdfExtensibleGroup.hpp" #include @@ -25,6 +27,7 @@ #include "../utilities/core/Assert.hpp" #include "../utilities/time/Time.hpp" +#include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" namespace openstudio { @@ -242,23 +245,45 @@ namespace model { return result; } - std::vector ScheduleDay_Impl::getValues(int numberOfTimestepsPerHour) const { - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted - std::vector getTimes = this->getTimes(numberOfTimestepsPerHour); // these are already sorted - std::vector result; + openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - for (const openstudio::Time& t : getTimes) { + auto timestep = model().getUniqueModelObject(); + int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + + DateTimeVector dateTimes; + int minutes = 60 / numberOfTimestepsPerHour; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + dateTimes.push_back(startDateTime + t); + } else { + openstudio::Time t(0, hour, minute); + dateTimes.push_back(startDateTime + t); + } + } + } + + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted + + Vector values2(dateTimes.size()); + for (const openstudio::DateTime& dt : dateTimes) { size_t i = 0; for (const openstudio::Time& time : times) { - if (t <= time) { - result.push_back(values[i]); + if (dt.time() <= time) { + values2(i) = values[i]; break; } ++i; } } - return result; + + TimeSeries timeSeries(dateTimes, values2); + + return timeSeries; } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { @@ -462,12 +487,8 @@ namespace model { return getImpl()->getValue(time, numberOfTimestepsPerHour); } - std::vector ScheduleDay::getTimes(int numberOfTimestepsPerHour) const { - return getImpl()->getTimes(numberOfTimestepsPerHour); - } - - std::vector ScheduleDay::getValues(int numberOfTimestepsPerHour) const { - return getImpl()->getValues(numberOfTimestepsPerHour); + openstudio::TimeSeries ScheduleDay::timeSeries() const { + return getImpl()->timeSeries(); } bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 8d21a4c133d..04ece4d35b6 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -70,15 +70,8 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; - /// Returns the vector of times marking the end value intervals for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - /// These times will be in order and have the same number of elements as getValues. - /// All times will be less than or equal to 1 day. - std::vector getTimes(int numberOfTimestepsPerHour) const; - - /// Returns the values for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - std::vector getValues(int numberOfTimestepsPerHour) const; + /// Returns the values for the timesteps per hour. + openstudio::TimeSeries timeSeries() const; //@} /** @name Setters */ diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index d604e43fb17..0655ca782cb 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -13,6 +13,8 @@ namespace openstudio { +class TimeSeries; + namespace model { class ScheduleTypeLimits; @@ -73,15 +75,8 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; - /// Returns the vector of times marking the end value intervals for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - /// These times will be in order and have the same number of elements as getValues. - /// All times will be less than or equal to 1 day. - std::vector getTimes(int numberOfTimestepsPerHour) const; - - /// Returns the values for a given timesteps per hour. - /// Allowable values include 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, and 60. - std::vector getValues(int numberOfTimestepsPerHour) const; + /// Returns the values for the timesteps per hour. + openstudio::TimeSeries timeSeries() const; //@} /** @name Setters */ From 1549488deb72c2440345ad7407cddf29fff8e6a4 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 15:30:32 -0700 Subject: [PATCH 40/68] Clean up and try again. --- src/model/ScheduleDay.cpp | 39 +++++++++------------------------- src/model/ScheduleDay.hpp | 2 +- src/model/ScheduleDay_Impl.hpp | 2 +- 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 2ea822d6ea5..d55e2351eec 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -174,16 +174,20 @@ namespace model { return m_cachedValues.get(); } - double ScheduleDay_Impl::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { + double ScheduleDay_Impl::getValue(const openstudio::Time& time) const { if (time.totalMinutes() < 0.0 || time.totalDays() > 1.0) { return 0.0; } std::vector values; std::vector times; - if (numberOfTimestepsPerHour > 0) { - values = this->getValues(numberOfTimestepsPerHour); - times = this->getTimes(numberOfTimestepsPerHour); + if (this->interpolateToTimestep()) { + openstudio::TimeSeries timeSeries = timeSeries(); + values = timeSeries.values(); + DateTimeVector dateTimes = timeSeries.dateTimes(); + for (const openstudio::DateTime& dt : dateTimes) { + times.push_back(dt.time()); + } } else { values = this->values(); // these are already sorted times = this->times(); // these are already sorted @@ -211,7 +215,7 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (numberOfTimestepsPerHour > 0) { + if (this->interpolatetoTimestep()) { interpMethod = LinearInterp; } else { interpMethod = HoldNextInterp; @@ -222,29 +226,6 @@ namespace model { return result; } - std::vector ScheduleDay_Impl::getTimes(int numberOfTimestepsPerHour) const { - std::vector result; - - std::vector allowables{1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}; - if (std::find(allowables.begin(), allowables.end(), numberOfTimestepsPerHour) == allowables.end()) { - return result; - } - - int minutes = 60 / numberOfTimestepsPerHour; - for (size_t hour = 0; hour < 24; ++hour) { - for (size_t minute = minutes; minute <= 60; minute += minutes) { - if (minute == 60) { - openstudio::Time t(0, hour + 1, 0); - result.push_back(t); - } else { - openstudio::Time t(0, hour, minute); - result.push_back(t); - } - } - } - return result; - } - openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0, 0)); @@ -281,7 +262,7 @@ namespace model { } } - TimeSeries timeSeries(dateTimes, values2); + TimeSeries timeSeries(dateTimes, values2, ""); return timeSeries; } diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 04ece4d35b6..207a5d10e02 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -68,7 +68,7 @@ namespace model { /// Returns the value in effect at the given time. /// If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour = 0) const; + double getValue(const openstudio::Time& time) const; /// Returns the values for the timesteps per hour. openstudio::TimeSeries timeSeries() const; diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 0655ca782cb..4226af95ae3 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -73,7 +73,7 @@ namespace model { /// Returns the value in effect at the given time. /// If time is less than 0 days or greater than 1 day, 0 is returned. - double getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const; + double getValue(const openstudio::Time& time) const; /// Returns the values for the timesteps per hour. openstudio::TimeSeries timeSeries() const; From a75a333d9614811e4dcea7f6fef947d96c085f21 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:24:38 -0700 Subject: [PATCH 41/68] Update idd for new interpolation method keys. --- resources/model/OpenStudio.idd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd index d9b314c5b7b..105e0d2169f 100644 --- a/resources/model/OpenStudio.idd +++ b/resources/model/OpenStudio.idd @@ -4594,12 +4594,13 @@ OS:Schedule:Day, \type object-list \object-list ScheduleTypeLimitsNames A4, \field Interpolate to Timestep - \note when the interval does not match the user specified timestep a Yes choice will average between the intervals request (to - \note timestep resolution. a No choice will use the interval value at the simulation timestep without regard to if it matches - \note the boundary or not. + \note when the interval does not match the user specified timestep a Average choice will average between the intervals request (to + \note timestep resolution. A No choice will use the interval value at the simulation timestep without regard to if it matches + \note the boundary or not. A Linear choice will interpolate linearly between successive values. \type choice \default No - \key Yes + \key Average + \key Linear \key No N1, \field Hour \type integer From 838df447ddacda2f585f9c9b7ef1dedd7793b7e1 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:24:59 -0700 Subject: [PATCH 42/68] Update model files and tests. --- src/model/ScheduleDay.cpp | 44 ++++--- src/model/ScheduleDay.hpp | 4 +- src/model/ScheduleDay_Impl.hpp | 4 +- src/model/test/ScheduleDay_GTest.cpp | 173 ++++++++++++++------------- 4 files changed, 120 insertions(+), 105 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index d55e2351eec..5af7182a358 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -118,8 +118,10 @@ namespace model { return !getObject().getModelObjectTarget(OS_Schedule_DayFields::ScheduleTypeLimitsName); } - bool ScheduleDay_Impl::interpolatetoTimestep() const { - return getBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep); + std::string ScheduleDay_Impl::interpolatetoTimestep() const { + boost::optional value = getString(OS_Schedule_DayFields::InterpolatetoTimestep, true); + OS_ASSERT(value); + return value.get(); } bool ScheduleDay_Impl::isInterpolatetoTimestepDefaulted() const { @@ -181,16 +183,20 @@ namespace model { std::vector values; std::vector times; - if (this->interpolateToTimestep()) { - openstudio::TimeSeries timeSeries = timeSeries(); - values = timeSeries.values(); + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + if (istringEqual(interpolatetoTimestep, "Linear")) { + values = this->values(); // these are already sorted + times = this->times(); // these are already sorted + } else { // No or Average + openstudio::TimeSeries timeSeries = this->timeSeries(); + Vector values2 = timeSeries.values(); + for (size_t i = 0; i < values2.size(); ++i) { + values.push_back(values2[i]); + } DateTimeVector dateTimes = timeSeries.dateTimes(); for (const openstudio::DateTime& dt : dateTimes) { times.push_back(dt.time()); } - } else { - values = this->values(); // these are already sorted - times = this->times(); // these are already sorted } unsigned N = times.size(); @@ -215,10 +221,12 @@ namespace model { y[N + 1] = 0.0; InterpMethod interpMethod; - if (this->interpolatetoTimestep()) { + if (istringEqual("No", interpolatetoTimestep)) { + interpMethod = LinearInterp; // LinearInterp or HoldNextInterp? + } else if (istringEqual("Average", interpolatetoTimestep)) { + interpMethod = LinearInterp; // FIXME: new AverageInterp? + } else if (istringEqual("Linear", interpolatetoTimestep)) { interpMethod = LinearInterp; - } else { - interpMethod = HoldNextInterp; } double result = interp(x, y, time.totalDays(), interpMethod, NoneExtrap); @@ -230,7 +238,7 @@ namespace model { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - auto timestep = model().getUniqueModelObject(); + auto timestep = this->model().getUniqueModelObject(); int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); DateTimeVector dateTimes; @@ -284,8 +292,8 @@ namespace model { return false; } - bool ScheduleDay_Impl::setInterpolatetoTimestep(bool interpolatetoTimestep) { - return setBooleanFieldValue(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); + bool ScheduleDay_Impl::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) { + return setString(OS_Schedule_DayFields::InterpolatetoTimestep, interpolatetoTimestep); } void ScheduleDay_Impl::resetInterpolatetoTimestep() { @@ -448,7 +456,7 @@ namespace model { return getImpl()->isScheduleTypeLimitsDefaulted(); } - bool ScheduleDay::interpolatetoTimestep() const { + std::string ScheduleDay::interpolatetoTimestep() const { return getImpl()->interpolatetoTimestep(); } @@ -464,15 +472,15 @@ namespace model { return getImpl()->values(); } - double ScheduleDay::getValue(const openstudio::Time& time, int numberOfTimestepsPerHour) const { - return getImpl()->getValue(time, numberOfTimestepsPerHour); + double ScheduleDay::getValue(const openstudio::Time& time) const { + return getImpl()->getValue(time); } openstudio::TimeSeries ScheduleDay::timeSeries() const { return getImpl()->timeSeries(); } - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { + bool ScheduleDay::setInterpolatetoTimestep(const std::string& interpolatetoTimestep) { return getImpl()->setInterpolatetoTimestep(interpolatetoTimestep); } diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 207a5d10e02..7b651f2adff 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -54,7 +54,7 @@ namespace model { * inherits one from a Schedule. */ bool isScheduleTypeLimitsDefaulted() const; - bool interpolatetoTimestep() const; + std::string interpolatetoTimestep() const; bool isInterpolatetoTimestepDefaulted() const; @@ -77,7 +77,7 @@ namespace model { /** @name Setters */ //@{ - bool setInterpolatetoTimestep(bool interpolatetoTimestep); + bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 4226af95ae3..201aecb58a9 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -59,7 +59,7 @@ namespace model { bool isScheduleTypeLimitsDefaulted() const; - bool interpolatetoTimestep() const; + std::string interpolatetoTimestep() const; bool isInterpolatetoTimestepDefaulted() const; @@ -86,7 +86,7 @@ namespace model { virtual bool resetScheduleTypeLimits() override; - bool setInterpolatetoTimestep(bool interpolatetoTimestep); + bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 796d6eca5f7..dba1766963f 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -10,9 +10,12 @@ #include "../ScheduleDay_Impl.hpp" #include "../ScheduleTypeLimits.hpp" #include "../ScheduleTypeLimits_Impl.hpp" +#include "../Timestep.hpp" +#include "../Timestep_Impl.hpp" #include "../../utilities/time/Date.hpp" #include "../../utilities/time/Time.hpp" +#include "../../utilities/data/TimeSeries.hpp" using namespace openstudio::model; using namespace openstudio; @@ -174,7 +177,7 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { double tol = 1e-5; ScheduleDay daySchedule(model); - EXPECT_FALSE(daySchedule.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule.interpolatetoTimestep()); EXPECT_TRUE(daySchedule.isInterpolatetoTimestepDefaulted()); // schedule is 1 until 12:00 @@ -188,8 +191,8 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); - daySchedule.setInterpolatetoTimestep(true); - EXPECT_TRUE(daySchedule.interpolatetoTimestep()); + daySchedule.setInterpolatetoTimestep("Linear"); + EXPECT_EQ("Linear", daySchedule.interpolatetoTimestep()); EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); @@ -321,7 +324,7 @@ TEST_F(ModelFixture, Schedule_Day_addValue_NaN_Infinity) { EXPECT_FALSE(sch_day.addValue(t, -std::numeric_limits::infinity())); } -TEST_F(ModelFixture, Schedule_Day_getValues) { +TEST_F(ModelFixture, Schedule_Day_timeSeries) { Model model; double tol = 1e-5; @@ -333,83 +336,87 @@ TEST_F(ModelFixture, Schedule_Day_getValues) { Time t2("21:45:00"); sch_day.addValue(t2, 1); - std::vector times = sch_day.getTimes(7); - EXPECT_EQ(0, times.size()); - - std::vector times24 = sch_day.getTimes(1); - EXPECT_EQ(24 * 1, times24.size()); - - std::vector times15 = sch_day.getTimes(4); - EXPECT_EQ(24 * 4, times15.size()); - - std::vector times10 = sch_day.getTimes(6); - EXPECT_EQ(24 * 6, times10.size()); - Time times10_1("00:10:00"); - EXPECT_EQ(times10_1, times10[0]); - Time times10_48("08:00:00"); - EXPECT_EQ(times10_48, times10[47]); - Time times10_49("08:10:00"); - EXPECT_EQ(times10_49, times10[48]); - Time times10_50("08:20:00"); - EXPECT_EQ(times10_50, times10[49]); - Time times10_144("24:00:00"); - EXPECT_EQ(times10_144, times10[143]); - - std::vector values = sch_day.getValues(18); - EXPECT_EQ(0, values.size()); - - std::vector values24 = sch_day.getValues(1); - EXPECT_EQ(24 * 1, values24.size()); - - std::vector values15 = sch_day.getValues(4); - EXPECT_EQ(24 * 4, values15.size()); - - std::vector values10 = sch_day.getValues(6); - EXPECT_EQ(24 * 6, values10.size()); - EXPECT_DOUBLE_EQ(0.0, values10[0]); - EXPECT_DOUBLE_EQ(0.0, values10[47]); - EXPECT_DOUBLE_EQ(0.0, values10[48]); - EXPECT_DOUBLE_EQ(1.0, values10[49]); - EXPECT_DOUBLE_EQ(0.0, values10[143]); - - double value; - - Time t3("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); - value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 1); - EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval - value = sch_day.getValue(t3, 4); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 6); - EXPECT_DOUBLE_EQ(0.0, value); - value = sch_day.getValue(t3, 10); - EXPECT_DOUBLE_EQ(0.0, value); - - Time t4("08:18:00"); - EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); - value = sch_day.getValue(t4); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t4, 1); - EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval - value = sch_day.getValue(t4, 4); - EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval - value = sch_day.getValue(t4, 6); - EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval - value = sch_day.getValue(t4, 10); - EXPECT_DOUBLE_EQ(1.0, value); - - Time t5("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); - value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 1); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 4); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 6); - EXPECT_DOUBLE_EQ(1.0, value); - value = sch_day.getValue(t5, 10); - EXPECT_DOUBLE_EQ(1.0, value); + { // Interpolate to Timestep = No + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); + EXPECT_EQ("No", sch_day.interpolatetoTimestep()); + + auto timestep = model.getUniqueModelObject(); + + Time t3("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); + Time t4("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + value = sch_day.getValue(t4); + EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + Time times10_1("00:10:00"); + EXPECT_EQ(times10_1, timeSeries.dateTimes()[0].time()); + Time times10_48("08:00:00"); + EXPECT_EQ(times10_48, timeSeries.dateTimes()[47].time()); + Time times10_49("08:10:00"); + EXPECT_EQ(times10_49, timeSeries.dateTimes()[48].time()); + Time times10_50("08:20:00"); + EXPECT_EQ(times10_50, timeSeries.dateTimes()[49].time()); + Time times10_144("24:00:00"); + EXPECT_EQ(times10_144, timeSeries.dateTimes()[143].time()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[0]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[47]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[48]); + EXPECT_DOUBLE_EQ(1.0, timeSeries.values()[49]); + EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[143]); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_DOUBLE_EQ(0.0, value); + value = sch_day.getValue(t4); + EXPECT_DOUBLE_EQ(1.0, value); + value = sch_day.getValue(t5); + EXPECT_DOUBLE_EQ(1.0, value); + } + + { + // Interpolate to Timestep = Average + + } + + { // Interpolate to Timestep = Linear + } } From 2b919abdc5380f3534821b450da97807d1c48c34 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 18 Mar 2024 21:25:19 -0700 Subject: [PATCH 43/68] Update ft and rt files and tests. --- .../ForwardTranslateScheduleDay.cpp | 6 +----- .../ReverseTranslateScheduleDayInterval.cpp | 8 +------- src/energyplus/Test/ScheduleRuleset_GTest.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp index f4a15c27a48..960598b4172 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateScheduleDay.cpp @@ -39,11 +39,7 @@ namespace energyplus { } } - if (modelObject.interpolatetoTimestep()) { - scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "Average"); - } else { - scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, "No"); - } + scheduleDay.setString(Schedule_Day_IntervalFields::InterpolatetoTimestep, modelObject.interpolatetoTimestep()); std::vector values = modelObject.values(); std::vector times = modelObject.times(); diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp index 69a76331a3d..59e88bce0fc 100644 --- a/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp +++ b/src/energyplus/ReverseTranslator/ReverseTranslateScheduleDayInterval.cpp @@ -50,13 +50,7 @@ namespace energyplus { s = workspaceObject.getString(Schedule_Day_IntervalFields::InterpolatetoTimestep); if (s) { - if (openstudio::istringEqual(*s, "No")) { - scheduleDay.setInterpolatetoTimestep(false); - } else if (openstudio::istringEqual(*s, "Linear")) { - scheduleDay.setInterpolatetoTimestep(true); - } else if (openstudio::istringEqual(*s, "Average")) { - scheduleDay.setInterpolatetoTimestep(true); - } + scheduleDay.setInterpolatetoTimestep(*s); } //get extensible groups diff --git a/src/energyplus/Test/ScheduleRuleset_GTest.cpp b/src/energyplus/Test/ScheduleRuleset_GTest.cpp index 946fa1bbe99..e3e0ea7b611 100644 --- a/src/energyplus/Test/ScheduleRuleset_GTest.cpp +++ b/src/energyplus/Test/ScheduleRuleset_GTest.cpp @@ -698,7 +698,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetSimple EXPECT_EQ(0, scheduleRule.ruleIndex()); ScheduleDay daySchedule = scheduleRule.daySchedule(); EXPECT_EQ(daySchedule.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule.values().size()); EXPECT_TRUE(scheduleRule.applySunday()); EXPECT_TRUE(scheduleRule.applyMonday()); @@ -864,7 +864,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(2, scheduleRule1.ruleIndex()); ScheduleDay daySchedule1 = scheduleRule1.daySchedule(); EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule1.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule1.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule1.values().size()); EXPECT_TRUE(scheduleRule1.applySunday()); EXPECT_TRUE(scheduleRule1.applyMonday()); @@ -888,7 +888,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(1, scheduleRule2.ruleIndex()); ScheduleDay daySchedule2 = scheduleRule2.daySchedule(); EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2"); - EXPECT_FALSE(daySchedule2.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule2.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule2.values().size()); EXPECT_TRUE(scheduleRule2.applySunday()); EXPECT_TRUE(scheduleRule2.applyMonday()); @@ -912,7 +912,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekDailyToRulesetComple EXPECT_EQ(0, scheduleRule3.ruleIndex()); ScheduleDay daySchedule3 = scheduleRule3.daySchedule(); EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1"); - EXPECT_FALSE(daySchedule3.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule3.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule3.values().size()); EXPECT_FALSE(scheduleRule3.applySunday()); EXPECT_FALSE(scheduleRule3.applyMonday()); @@ -1220,7 +1220,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(2, scheduleRule1.ruleIndex()); ScheduleDay daySchedule1 = scheduleRule1.daySchedule(); EXPECT_EQ(daySchedule1.nameString(), "occupants schedule allday1 1"); - EXPECT_FALSE(daySchedule1.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule1.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule1.values().size()); EXPECT_TRUE(scheduleRule1.applySunday()); EXPECT_TRUE(scheduleRule1.applyMonday()); @@ -1244,7 +1244,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(1, scheduleRule2.ruleIndex()); ScheduleDay daySchedule2 = scheduleRule2.daySchedule(); EXPECT_EQ(daySchedule2.nameString(), "occupants schedule allday1 2"); - EXPECT_FALSE(daySchedule2.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule2.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule2.values().size()); EXPECT_TRUE(scheduleRule2.applySunday()); EXPECT_TRUE(scheduleRule2.applyMonday()); @@ -1268,7 +1268,7 @@ TEST_F(EnergyPlusFixture, ReverseTranslator_ScheduleYearWeekCompactToRulesetComp EXPECT_EQ(0, scheduleRule3.ruleIndex()); ScheduleDay daySchedule3 = scheduleRule3.daySchedule(); EXPECT_EQ(daySchedule3.nameString(), "occupants schedule allday2 1"); - EXPECT_FALSE(daySchedule3.interpolatetoTimestep()); + EXPECT_EQ("No", daySchedule3.interpolatetoTimestep()); EXPECT_EQ(8u, daySchedule3.values().size()); EXPECT_FALSE(scheduleRule3.applySunday()); EXPECT_FALSE(scheduleRule3.applyMonday()); From 8eede82e975612f1373729a0d944a63a00c3046d Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 19 Mar 2024 14:37:59 -0700 Subject: [PATCH 44/68] Get interpolation working on timeseries. --- src/model/ScheduleDay.cpp | 32 +++-- src/model/test/ScheduleDay_GTest.cpp | 205 ++++++++++++++++++++++----- 2 files changed, 187 insertions(+), 50 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5af7182a358..ce97fb77782 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -195,7 +195,12 @@ namespace model { } DateTimeVector dateTimes = timeSeries.dateTimes(); for (const openstudio::DateTime& dt : dateTimes) { - times.push_back(dt.time()); + if (dt.time().totalDays() > 0) { + times.push_back(dt.time()); + } else { // this is 00:00:00 from the next day + openstudio::Time t(0, 24, 0); + times.push_back(t); + } } } @@ -222,9 +227,9 @@ namespace model { InterpMethod interpMethod; if (istringEqual("No", interpolatetoTimestep)) { - interpMethod = LinearInterp; // LinearInterp or HoldNextInterp? + interpMethod = LinearInterp; } else if (istringEqual("Average", interpolatetoTimestep)) { - interpMethod = LinearInterp; // FIXME: new AverageInterp? + interpMethod = AverageInterp; } else if (istringEqual("Linear", interpolatetoTimestep)) { interpMethod = LinearInterp; } @@ -235,12 +240,12 @@ namespace model { } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { - Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary - DateTime startDateTime(startDate, Time(0, 0, 0, 0)); - auto timestep = this->model().getUniqueModelObject(); int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + DateTime startDateTime(startDate, Time(0, 0, 0)); + DateTimeVector dateTimes; int minutes = 60 / numberOfTimestepsPerHour; for (size_t hour = 0; hour < 24; ++hour) { @@ -258,15 +263,18 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted + openstudio::Time dtt; Vector values2(dateTimes.size()); - for (const openstudio::DateTime& dt : dateTimes) { - size_t i = 0; - for (const openstudio::Time& time : times) { - if (dt.time() <= time) { - values2(i) = values[i]; + for (unsigned i = 0; i < dateTimes.size(); ++i) { + dtt = dateTimes[i].time(); + if (dtt.totalDays() == 0.0) { // this is 00:00:00 from the next day + dtt = openstudio::Time(0, 24, 0); + } + for (unsigned j = 0; j < times.size(); ++j) { + if (dtt <= times[j]) { + values2[i] = values[j]; break; } - ++i; } } diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index dba1766963f..4cb7d58e46e 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -331,10 +331,10 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { ScheduleDay sch_day(model); - Time t1("08:15:00"); - sch_day.addValue(t1, 0); + Time t1("08:05:00"); + sch_day.addValue(t1, 0.1); Time t2("21:45:00"); - sch_day.addValue(t2, 1); + sch_day.addValue(t2, 1.0); { // Interpolate to Timestep = No EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); @@ -342,12 +342,14 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t3.totalDays(), tol); - Time t4("08:18:00"); - EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t5.totalDays(), tol); + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); openstudio::TimeSeries timeSeries; double value; @@ -357,66 +359,193 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_NEAR(10.0 / 60.0, value, tol); // 10 min in a 60 min interval + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(18.0 / 60.0, value, tol); // 18 min in a 60 min interval + EXPECT_NEAR(0.175, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(3.0 / 15.0, value, tol); // 3 min in a 15 min interval + EXPECT_NEAR(0.4, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); - Time times10_1("00:10:00"); - EXPECT_EQ(times10_1, timeSeries.dateTimes()[0].time()); - Time times10_48("08:00:00"); - EXPECT_EQ(times10_48, timeSeries.dateTimes()[47].time()); - Time times10_49("08:10:00"); - EXPECT_EQ(times10_49, timeSeries.dateTimes()[48].time()); - Time times10_50("08:20:00"); - EXPECT_EQ(times10_50, timeSeries.dateTimes()[49].time()); - Time times10_144("24:00:00"); - EXPECT_EQ(times10_144, timeSeries.dateTimes()[143].time()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[0]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[47]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[48]); - EXPECT_DOUBLE_EQ(1.0, timeSeries.values()[49]); - EXPECT_DOUBLE_EQ(0.0, timeSeries.values()[143]); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_NEAR(8.0 / 10.0, value, tol); // 8 min in a 10 min interval + EXPECT_NEAR(0.55, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); value = sch_day.getValue(t3); - EXPECT_DOUBLE_EQ(0.0, value); + EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t4); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(0.85, value, tol); value = sch_day.getValue(t5); - EXPECT_DOUBLE_EQ(1.0, value); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); } - { - // Interpolate to Timestep = Average + { // Interpolate to Timestep = Average + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Average")); + EXPECT_EQ("Average", sch_day.interpolatetoTimestep()); + auto timestep = model.getUniqueModelObject(); + + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.175, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.4, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.55, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.85, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(1.0, value, tol); } { // Interpolate to Timestep = Linear + EXPECT_TRUE(sch_day.setInterpolatetoTimestep("Linear")); + EXPECT_EQ("Linear", sch_day.interpolatetoTimestep()); + + auto timestep = model.getUniqueModelObject(); + + Time t3("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); + Time t4("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); + Time t5("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); + Time t6("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); + + openstudio::TimeSeries timeSeries; + double value; + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(1)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 1, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 4, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); + timeSeries = sch_day.timeSeries(); + ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); + ASSERT_EQ(24 * 6, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 10, timeSeries.values().size()); + value = sch_day.getValue(t3); + EXPECT_NEAR(0.098969, value, tol); + value = sch_day.getValue(t4); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t5); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t6); + EXPECT_NEAR(0.160365, value, tol); } } From 8da80858ff3957e233f977a51187987affa0d819 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 19 Mar 2024 14:38:14 -0700 Subject: [PATCH 45/68] Stub new AverageInterp in vector files. --- src/utilities/data/Vector.cpp | 4 ++++ src/utilities/data/Vector.hpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index d96f302fe99..5d30c4ea256 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -142,6 +142,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // set to next value result = y(info.ib); break; + case AverageInterp: + // average interpolation + result = info.wa * y(info.ia) + info.wb * y(info.ib); // FIXME + break; } } diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index 7c61a925a87..a8cca34ea07 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -59,7 +59,8 @@ enum InterpMethod LinearInterp, NearestInterp, HoldLastInterp, - HoldNextInterp + HoldNextInterp, + AverageInterp }; /** Enum to specify the extrapolation method. */ From 85da8ef8ff43fe6a11037eb587462fede28fa472 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 21 Mar 2024 16:34:54 -0700 Subject: [PATCH 46/68] Take a cut at the average interpolation. --- src/model/ScheduleDay.cpp | 146 ++++++++++-------- src/model/test/ScheduleDay_GTest.cpp | 220 ++++++++++++++++----------- src/utilities/data/Vector.cpp | 4 - 3 files changed, 207 insertions(+), 163 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index ce97fb77782..2a52635f295 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -181,62 +181,28 @@ namespace model { return 0.0; } - std::vector values; - std::vector times; - std::string interpolatetoTimestep = this->interpolatetoTimestep(); - if (istringEqual(interpolatetoTimestep, "Linear")) { - values = this->values(); // these are already sorted - times = this->times(); // these are already sorted - } else { // No or Average - openstudio::TimeSeries timeSeries = this->timeSeries(); - Vector values2 = timeSeries.values(); - for (size_t i = 0; i < values2.size(); ++i) { - values.push_back(values2[i]); - } - DateTimeVector dateTimes = timeSeries.dateTimes(); - for (const openstudio::DateTime& dt : dateTimes) { - if (dt.time().totalDays() > 0) { - times.push_back(dt.time()); - } else { // this is 00:00:00 from the next day - openstudio::Time t(0, 24, 0); - times.push_back(t); - } - } - } - - unsigned N = times.size(); - OS_ASSERT(values.size() == N); - - if (N == 0) { - return 0.0; - } - - openstudio::Vector x(N + 2); - openstudio::Vector y(N + 2); + TimeSeries ts = this->timeSeries(); - x[0] = -0.000001; - y[0] = 0.0; - - for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); - y[i + 1] = values[i]; - } + DateTimeVector dateTimes = ts.dateTimes(); + Vector values = ts.values(); - x[N + 1] = 1.000001; - y[N + 1] = 0.0; + for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { + openstudio::Time t0 = dateTimes[i].time(); + openstudio::Time t1 = dateTimes[i + 1].time(); + if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day + t1 = openstudio::Time(0, 24, 0); + } - InterpMethod interpMethod; - if (istringEqual("No", interpolatetoTimestep)) { - interpMethod = LinearInterp; - } else if (istringEqual("Average", interpolatetoTimestep)) { - interpMethod = AverageInterp; - } else if (istringEqual("Linear", interpolatetoTimestep)) { - interpMethod = LinearInterp; + if (t0 == time) { + double value = values[i]; + } else if (t1 == time) { + double value = values[i + 1]; + } else if ((t0 < time) && (time < t1)) { + double value = values[i + 1]; + } } - double result = interp(x, y, time.totalDays(), interpMethod, NoneExtrap); - - return result; + return value; } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { @@ -246,16 +212,16 @@ namespace model { Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary DateTime startDateTime(startDate, Time(0, 0, 0)); - DateTimeVector dateTimes; + DateTimeVector tsDateTimes; int minutes = 60 / numberOfTimestepsPerHour; for (size_t hour = 0; hour < 24; ++hour) { for (size_t minute = minutes; minute <= 60; minute += minutes) { if (minute == 60) { openstudio::Time t(0, hour + 1, 0); - dateTimes.push_back(startDateTime + t); + tsDateTimes.push_back(startDateTime + t); } else { openstudio::Time t(0, hour, minute); - dateTimes.push_back(startDateTime + t); + tsDateTimes.push_back(startDateTime + t); } } } @@ -263,24 +229,72 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted - openstudio::Time dtt; - Vector values2(dateTimes.size()); - for (unsigned i = 0; i < dateTimes.size(); ++i) { - dtt = dateTimes[i].time(); - if (dtt.totalDays() == 0.0) { // this is 00:00:00 from the next day - dtt = openstudio::Time(0, 24, 0); + unsigned N = times.size(); + OS_ASSERT(values.size() == N); + + TimeSeries result; + if (N == 0) { + return result; + } + + Vector x(N + 2); + Vector y(N + 2); + + x[0] = -0.000001; + y[0] = 0.0; + + for (unsigned i = 0; i < N; ++i) { + x[i + 1] = times[i].totalDays(); + y[i + 1] = values[i]; + } + + x[N + 1] = 1.000001; + y[N + 1] = 0.0; + + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + Vector tsValues(tsDateTimes.size()); + for (unsigned j = 0; j < tsDateTimes.size(); ++j) { + openstudio::Time t0 = tsDateTimes[j].time(); + if (t0.totalDays() == 0.0) { // this is 00:00:00 from the next day + t0 = openstudio::Time(0, 24, 0); } - for (unsigned j = 0; j < times.size(); ++j) { - if (dtt <= times[j]) { - values2[i] = values[j]; - break; + + if (istringEqual("No", interpolatetoTimestep)) { + double val = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); + tsValues[j] = val; + } else if (istringEqual("Average", interpolatetoTimestep)) { + if (j == 0) { + tsValues[j] = values[0]; + } else if (j == tsDateTimes.size() - 1) { + tsValues[j] = values[-1]; + } else { + openstudio::Time t1 = tsDateTimes[j - 1].time(); + if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day + t1 = openstudio::Time(0, 24, 0); + } + + for (unsigned i = 0; i < times.size(); ++i) { + if ((t1 < times[i]) && (times[i] < t0)) { // schedule value is between timesteps + double interval = (t0 - t1).totalDays(); // timestep interval + double int1 = (times[i] - t1).totalDays() / interval; // fraction that is the value before the schedule change + double int2 = (t0 - times[i]).totalDays() / interval; // fraction that is the value after the schedule change + tsValues[j] = (values[i] * int1) + (values[i + 1] * int2); + break; + } else if (t0 <= times[i]) { + tsValues[j] = values[i]; + break; + } + } } + } else if (istringEqual("Linear", interpolatetoTimestep)) { + double val = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); + tsValues[j] = val; } } - TimeSeries timeSeries(dateTimes, values2, ""); + result = TimeSeries(tsDateTimes, tsValues, ""); - return timeSeries; + return result; } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 4cb7d58e46e..f87f42906d1 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -336,21 +336,25 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { Time t2("21:45:00"); sch_day.addValue(t2, 1.0); + Time t0800("08:00:00"); + EXPECT_NEAR(8.0 / 24.0, t0800.totalDays(), tol); + Time t0805("08:05:00"); + EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t0805.totalDays(), tol); + Time t0810("08:10:00"); + EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t0810.totalDays(), tol); + Time t0818("08:18:00"); + EXPECT_NEAR((8.0 + (18.0 / 60.0)) / 24.0, t0818.totalDays(), tol); + Time t0820("08:20:00"); + EXPECT_NEAR((8.0 + (20.0 / 60.0)) / 24.0, t0820.totalDays(), tol); + Time t0900("09:00:00"); + EXPECT_NEAR(9.0 / 24.0, t0900.totalDays(), tol); + { // Interpolate to Timestep = No EXPECT_TRUE(sch_day.setInterpolatetoTimestep("No")); EXPECT_EQ("No", sch_day.interpolatetoTimestep()); auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -358,52 +362,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.175, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.25, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.4, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.7, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.55, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.85, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); } @@ -413,15 +433,6 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -429,52 +440,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.175, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.25, value, tol); - value = sch_day.getValue(t6); - EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.925, value, tol); + value = sch_day.getValue(t0900); + EXPECT_NEAR(0.925, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.4, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); EXPECT_NEAR(0.7, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.7, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.55, value, tol); + value = sch_day.getValue(t0810); EXPECT_NEAR(0.55, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.85, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.25, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); EXPECT_NEAR(1.0, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(1.0, value, tol); } @@ -484,15 +511,6 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { auto timestep = model.getUniqueModelObject(); - Time t3("08:00:00"); - EXPECT_NEAR(8.0 / 24.0, t3.totalDays(), tol); - Time t4("08:05:00"); - EXPECT_NEAR((8.0 + (5.0 / 60.0)) / 24.0, t4.totalDays(), tol); - Time t5("08:10:00"); - EXPECT_NEAR((8.0 + (10.0 / 60.0)) / 24.0, t5.totalDays(), tol); - Time t6("09:00:00"); - EXPECT_NEAR(9.0 / 24.0, t6.totalDays(), tol); - openstudio::TimeSeries timeSeries; double value; @@ -500,52 +518,68 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 1, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 1, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.160365, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(4)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 4, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 4, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.110975, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.110975, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.127439, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.127439, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(6)); timeSeries = sch_day.timeSeries(); ASSERT_EQ(24 * 6, timeSeries.dateTimes().size()); ASSERT_EQ(24 * 6, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.105487, value, tol); + value = sch_day.getValue(t0810); EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.116463, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.116463, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(10)); timeSeries = sch_day.timeSeries(); EXPECT_EQ(24 * 10, timeSeries.dateTimes().size()); EXPECT_EQ(24 * 10, timeSeries.values().size()); - value = sch_day.getValue(t3); + value = sch_day.getValue(t0800); EXPECT_NEAR(0.098969, value, tol); - value = sch_day.getValue(t4); - EXPECT_NEAR(0.1, value, tol); - value = sch_day.getValue(t5); - EXPECT_NEAR(0.105487, value, tol); - value = sch_day.getValue(t6); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.101097, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(0.107682, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(0.114268, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(0.120853, value, tol); + value = sch_day.getValue(t0900); EXPECT_NEAR(0.160365, value, tol); } } diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 5d30c4ea256..d96f302fe99 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -142,10 +142,6 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // set to next value result = y(info.ib); break; - case AverageInterp: - // average interpolation - result = info.wa * y(info.ia) + info.wb * y(info.ib); // FIXME - break; } } From 065d022b3228979fda08bcffc3bc03ef0c3dc86d Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 21 Mar 2024 16:43:34 -0700 Subject: [PATCH 47/68] One more typo. --- src/model/ScheduleDay.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 2a52635f295..97dbcc46a12 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -186,6 +186,7 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); + double value; for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { openstudio::Time t0 = dateTimes[i].time(); openstudio::Time t1 = dateTimes[i + 1].time(); @@ -194,11 +195,11 @@ namespace model { } if (t0 == time) { - double value = values[i]; + value = values[i]; } else if (t1 == time) { - double value = values[i + 1]; + value = values[i + 1]; } else if ((t0 < time) && (time < t1)) { - double value = values[i + 1]; + value = values[i + 1]; } } From 11046001cb964d3e1ca28f9b921db8b3466f5c14 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 22 Mar 2024 09:22:49 -0700 Subject: [PATCH 48/68] Move average interp code into AverageInterp. --- src/model/ScheduleDay.cpp | 32 +++++--------------------------- src/utilities/data/Matrix.cpp | 18 +++++++++--------- src/utilities/data/Matrix.hpp | 8 ++++---- src/utilities/data/Matrix.i | 4 ++-- src/utilities/data/Vector.cpp | 34 +++++++++++++++++++++++++++------- src/utilities/data/Vector.hpp | 7 ++++--- src/utilities/data/Vector.i | 7 ++++--- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 97dbcc46a12..57c28734dd5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -261,35 +261,13 @@ namespace model { } if (istringEqual("No", interpolatetoTimestep)) { - double val = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); - tsValues[j] = val; + tsValues[j] = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { - if (j == 0) { - tsValues[j] = values[0]; - } else if (j == tsDateTimes.size() - 1) { - tsValues[j] = values[-1]; - } else { - openstudio::Time t1 = tsDateTimes[j - 1].time(); - if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day - t1 = openstudio::Time(0, 24, 0); - } - - for (unsigned i = 0; i < times.size(); ++i) { - if ((t1 < times[i]) && (times[i] < t0)) { // schedule value is between timesteps - double interval = (t0 - t1).totalDays(); // timestep interval - double int1 = (times[i] - t1).totalDays() / interval; // fraction that is the value before the schedule change - double int2 = (t0 - times[i]).totalDays() / interval; // fraction that is the value after the schedule change - tsValues[j] = (values[i] * int1) + (values[i + 1] * int2); - break; - } else if (t0 <= times[i]) { - tsValues[j] = values[i]; - break; - } - } - } + double minutes = 60.0 / numberOfTimestepsPerHour; + double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + tsValues[j] = interp(x, y, t0.totalDays(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { - double val = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); - tsValues[j] = val; + tsValues[j] = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); } } diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index 41d6293894b..dd068e79caf 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -38,7 +38,7 @@ bool operator!=(const Matrix& lhs, const Matrix& rhs) { /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { double result = 0.0; size_t M = x.size(); @@ -48,7 +48,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub return result; } - InterpInfo xInfo = interpInfo(x, xi); + InterpInfo xInfo = interpInfo(x, xi, ti); if (xInfo.extrapolated) { switch (extrapMethod) { @@ -91,7 +91,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub } } - InterpInfo yInfo = interpInfo(y, yi); + InterpInfo yInfo = interpInfo(y, yi, ti); if (yInfo.extrapolated) { switch (extrapMethod) { @@ -143,7 +143,7 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t M = x.size(); Vector result(M); @@ -153,7 +153,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x } for (unsigned i = 0; i < M; ++i) { - result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod); + result(i) = interp(x, y, v, xi(i), yi, interpMethod, extrapMethod, ti); } return result; @@ -161,7 +161,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = y.size(); Vector result(N); @@ -171,7 +171,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons } for (unsigned j = 0; j < N; ++j) { - result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod); + result(j) = interp(x, y, v, xi, yi(j), interpMethod, extrapMethod, ti); } return result; @@ -180,7 +180,7 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, cons /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod, - ExtrapMethod extrapMethod) { + ExtrapMethod extrapMethod, double ti) { size_t M = x.size(); size_t N = y.size(); @@ -192,7 +192,7 @@ Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { - result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod); + result(i, j) = interp(x, y, v, xi(i), yi(j), interpMethod, extrapMethod, ti); } } diff --git a/src/utilities/data/Matrix.hpp b/src/utilities/data/Matrix.hpp index 136224348b1..9bade37a0a8 100644 --- a/src/utilities/data/Matrix.hpp +++ b/src/utilities/data/Matrix.hpp @@ -33,22 +33,22 @@ UTILITIES_API bool operator!=(const Matrix& lhs, const Matrix& rhs); /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing UTILITIES_API double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing UTILITIES_API Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, - InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap); + InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /// matrix product UTILITIES_API Matrix prod(const Matrix& lop, const Matrix& rop); diff --git a/src/utilities/data/Matrix.i b/src/utilities/data/Matrix.i index 504e55f6fd6..eb63e040636 100644 --- a/src/utilities/data/Matrix.i +++ b/src/utilities/data/Matrix.i @@ -138,11 +138,11 @@ public: /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap); +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap); +Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, InterpMethod interpMethod = linearInterp, ExtrapMethod extrapMethod = noneExtrap, double ti = 0.0); /// outer product Matrix outerProd(const Vector& lhs, const Vector& rhs); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index d96f302fe99..3cca6aa100d 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -54,7 +54,7 @@ bool operator!=(const Vector& lhs, const Vector& rhs) { /// linear interpolation of the function y = f(x) at point xi /// assumes that x is strictly increasing -InterpInfo interpInfo(const Vector& x, double xi) { +InterpInfo interpInfo(const Vector& x, double xi, double ti) { size_t N = x.size(); InterpInfo result; @@ -64,24 +64,28 @@ InterpInfo interpInfo(const Vector& x, double xi) { result.ib = 0; result.wa = 1.0; result.wb = 0.0; + result.ti = 1.0; result.extrapolated = false; } else if (xi < x(0)) { result.ia = 0; result.ib = 0; result.wa = 1.0; result.wb = 0.0; + result.ti = 1.0; result.extrapolated = true; } else if (x(N - 1) == xi) { result.ia = N - 1; result.ib = N - 1; result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; result.extrapolated = false; } else if (xi > x(N - 1)) { result.ia = N - 1; result.ib = N - 1; result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; result.extrapolated = true; } else { @@ -92,8 +96,20 @@ InterpInfo interpInfo(const Vector& x, double xi) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); - result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); + if (ti == 0.0) { + result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); + result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); + } else { + result.wb = xi - x(result.ia); + result.wa = ti - result.wb; + result.ti = 1.0; + if ((result.wb > 0.0) && (result.wb < ti)) { + result.ti = ti; + } else { + result.wa = 0.0; + result.wb = 1.0; + } + } } return result; @@ -101,7 +117,7 @@ InterpInfo interpInfo(const Vector& x, double xi) { /// linear interpolation of the function y = f(x) at point xi /// assumes that x is strictly increasing -double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = x.size(); @@ -111,7 +127,7 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe return result; } - InterpInfo info = interpInfo(x, xi); + InterpInfo info = interpInfo(x, xi, ti); if (info.extrapolated) { switch (extrapMethod) { @@ -130,6 +146,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe // linear interpolation result = info.wa * y(info.ia) + info.wb * y(info.ib); break; + case AverageInterp: + // average interpolation + result = (info.wa * y(info.ia) + info.wb * y(info.ib)) / info.ti; + break; case NearestInterp: // pick closest point result = (info.wa > info.wb ? y(info.ia) : y(info.ib)); @@ -150,7 +170,7 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe /// linear interpolation of the function y = f(x) at points xi /// assumes that x is strictly increasing -Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod) { +Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { size_t N = x.size(); @@ -161,7 +181,7 @@ Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod i } for (unsigned i = 0; i < N; ++i) { - result(i) = interp(x, y, xi(i), interpMethod, extrapMethod); + result(i) = interp(x, y, xi(i), interpMethod, extrapMethod, ti); } return result; diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index a8cca34ea07..39a2a6a88f2 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -76,21 +76,22 @@ struct UTILITIES_API InterpInfo bool extrapolated; // was point out of range unsigned ia, ib; // indices of two nearest points double wa, wb; // weights of two nearest points + double ti; // length of interval }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing. */ -UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi); +UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly * increasing. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); //@} /** @name Common Methods and Vector Operations */ diff --git a/src/utilities/data/Vector.i b/src/utilities/data/Vector.i index ce8606dceee..3e45d9e0d78 100644 --- a/src/utilities/data/Vector.i +++ b/src/utilities/data/Vector.i @@ -167,23 +167,24 @@ struct UTILITIES_API InterpInfo{ bool extrapolated; // was point out of range unsigned ia, ib; // indices of two nearest points double wa, wb; // weights of two nearest points + double ti; // length of interval }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing. */ -UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi); +UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly * increasing */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly * increasing. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap); + ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); //@} /** @name Common Methods and Vector Operations */ From 4af64a03456c599e65cccd2c9cf73fe054b51763 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 22 Mar 2024 09:26:38 -0700 Subject: [PATCH 49/68] Formatting. --- src/utilities/data/Matrix.cpp | 9 ++++++--- src/utilities/data/Vector.cpp | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index dd068e79caf..ba5b07773e0 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -38,7 +38,8 @@ bool operator!=(const Matrix& lhs, const Matrix& rhs) { /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing -double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { double result = 0.0; size_t M = x.size(); @@ -143,7 +144,8 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { size_t M = x.size(); Vector result(M); @@ -161,7 +163,8 @@ Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& x /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing -Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, double ti) { +Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod, ExtrapMethod extrapMethod, + double ti) { size_t N = y.size(); Vector result(N); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 3cca6aa100d..ba981ec4017 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -96,7 +96,7 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - if (ti == 0.0) { + if (ti == 0.0) { result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); } else { @@ -109,7 +109,7 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.wa = 0.0; result.wb = 1.0; } - } + } } return result; From dc202f1aa5ee4e0454d7b994a89e6a04dce2b23a Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 12:56:00 -0700 Subject: [PATCH 50/68] Cache timeseries results and clear when object changes. --- src/model/ScheduleDay.cpp | 150 +++++++++++++++------------ src/model/ScheduleDay_Impl.hpp | 2 + src/model/Timestep.cpp | 1 + src/model/test/ScheduleDay_GTest.cpp | 6 +- 4 files changed, 89 insertions(+), 70 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 57c28734dd5..f2f47086ed0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -186,94 +186,109 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); - double value; - for (unsigned i = 0; i < dateTimes.size() - 1; ++i) { - openstudio::Time t0 = dateTimes[i].time(); - openstudio::Time t1 = dateTimes[i + 1].time(); - if (t1.totalDays() == 0.0) { // this is 00:00:00 from the next day - t1 = openstudio::Time(0, 24, 0); - } + unsigned N = dateTimes.size(); + OS_ASSERT(values.size() == N); + + if (N == 0) { + return 0.0; + } + + Vector x(N + 2); + Vector y(N + 2); + + x[0] = 0.0; + y[0] = 0.0; - if (t0 == time) { - value = values[i]; - } else if (t1 == time) { - value = values[i + 1]; - } else if ((t0 < time) && (time < t1)) { - value = values[i + 1]; + for (unsigned i = 0; i < N; ++i) { + openstudio::Time t = dateTimes[i].time(); + if (t.totalDays() == 0.0) { // this is 00:00:00 from the next day + t = openstudio::Time(0, 24, 0); } + + x[i + 1] = t.totalDays(); + y[i + 1] = values[i]; } - return value; + x[N + 1] = 1.0; + y[N + 1] = values[N - 1]; + + double result = interp(x, y, time.totalDays(), HoldNextInterp, NoneExtrap); + + return result; } openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { - auto timestep = this->model().getUniqueModelObject(); - int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); - - Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary - DateTime startDateTime(startDate, Time(0, 0, 0)); - - DateTimeVector tsDateTimes; - int minutes = 60 / numberOfTimestepsPerHour; - for (size_t hour = 0; hour < 24; ++hour) { - for (size_t minute = minutes; minute <= 60; minute += minutes) { - if (minute == 60) { - openstudio::Time t(0, hour + 1, 0); - tsDateTimes.push_back(startDateTime + t); - } else { - openstudio::Time t(0, hour, minute); - tsDateTimes.push_back(startDateTime + t); + if (!m_cachedTimeSeries) { + + auto timestep = this->model().getUniqueModelObject(); + int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + + Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary + int minutes = 60 / numberOfTimestepsPerHour; + DateTime startDateTime(startDate, Time(0, 0, 0)); + + DateTimeVector tsDateTimes; + for (size_t hour = 0; hour < 24; ++hour) { + for (size_t minute = minutes; minute <= 60; minute += minutes) { + if (minute == 60) { + openstudio::Time t(0, hour + 1, 0); + tsDateTimes.push_back(startDateTime + t); + } else { + openstudio::Time t(0, hour, minute); + tsDateTimes.push_back(startDateTime + t); + } } } - } - std::vector values = this->values(); // these are already sorted - std::vector times = this->times(); // these are already sorted + std::vector values = this->values(); // these are already sorted + std::vector times = this->times(); // these are already sorted - unsigned N = times.size(); - OS_ASSERT(values.size() == N); + unsigned N = times.size(); + OS_ASSERT(values.size() == N); - TimeSeries result; - if (N == 0) { - return result; - } + TimeSeries result; + if (N == 0) { + return result; + } - Vector x(N + 2); - Vector y(N + 2); + Vector x(N + 2); + Vector y(N + 2); - x[0] = -0.000001; - y[0] = 0.0; + x[0] = -0.000001; + y[0] = 0.0; - for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); - y[i + 1] = values[i]; - } + for (unsigned i = 0; i < N; ++i) { + x[i + 1] = times[i].totalDays(); + y[i + 1] = values[i]; + } - x[N + 1] = 1.000001; - y[N + 1] = 0.0; + x[N + 1] = 1.000001; + y[N + 1] = 0.0; - std::string interpolatetoTimestep = this->interpolatetoTimestep(); - Vector tsValues(tsDateTimes.size()); - for (unsigned j = 0; j < tsDateTimes.size(); ++j) { - openstudio::Time t0 = tsDateTimes[j].time(); - if (t0.totalDays() == 0.0) { // this is 00:00:00 from the next day - t0 = openstudio::Time(0, 24, 0); - } + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + Vector tsValues(tsDateTimes.size()); + for (unsigned j = 0; j < tsDateTimes.size(); ++j) { + openstudio::Time t = tsDateTimes[j].time(); + if (t.totalDays() == 0.0) { // this is 00:00:00 from the next day + t = openstudio::Time(0, 24, 0); + } - if (istringEqual("No", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t0.totalDays(), HoldNextInterp, NoneExtrap); - } else if (istringEqual("Average", interpolatetoTimestep)) { - double minutes = 60.0 / numberOfTimestepsPerHour; - double ti = minutes / (60.0 * 24.0); // total days of the timestep interval - tsValues[j] = interp(x, y, t0.totalDays(), AverageInterp, NoneExtrap, ti); - } else if (istringEqual("Linear", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t0.totalDays(), LinearInterp, NoneExtrap); + if (istringEqual("No", interpolatetoTimestep)) { + tsValues[j] = interp(x, y, t.totalDays(), HoldNextInterp, NoneExtrap); + } else if (istringEqual("Average", interpolatetoTimestep)) { + double minutes = 60.0 / numberOfTimestepsPerHour; + double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + tsValues[j] = interp(x, y, t.totalDays(), AverageInterp, NoneExtrap, ti); + } else if (istringEqual("Linear", interpolatetoTimestep)) { + tsValues[j] = interp(x, y, t.totalDays(), LinearInterp, NoneExtrap); + } } - } - result = TimeSeries(tsDateTimes, tsValues, ""); + result = TimeSeries(tsDateTimes, tsValues, ""); + m_cachedTimeSeries = result; + } - return result; + return m_cachedTimeSeries.get(); } bool ScheduleDay_Impl::setScheduleTypeLimits(const ScheduleTypeLimits& scheduleTypeLimits) { @@ -432,6 +447,7 @@ namespace model { void ScheduleDay_Impl::clearCachedVariables() { m_cachedTimes.reset(); m_cachedValues.reset(); + m_cachedTimeSeries.reset(); } } // namespace detail diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 201aecb58a9..fd408fc359b 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -10,6 +10,7 @@ #include "ScheduleBase_Impl.hpp" #include "../utilities/time/Time.hpp" +#include "../utilities/data/TimeSeries.hpp" namespace openstudio { @@ -119,6 +120,7 @@ namespace model { mutable boost::optional> m_cachedTimes; mutable boost::optional> m_cachedValues; + mutable boost::optional m_cachedTimeSeries; }; } // namespace detail diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index 90b803e3355..b8767089db4 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -9,6 +9,7 @@ #include "SimulationControl_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" +#include "ScheduleDay_Impl.hpp" #include "../utilities/core/Assert.hpp" #include #include diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index f87f42906d1..06fda138014 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -196,10 +196,10 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); - EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); // FIXME: Fails. Should be 1.0? - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); // FIXME: Fails. Should be 1.0? + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); - EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); // FIXME: Fails. Should be 0.0? + EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } From 30fd11d8f1736eca4da26781ac95fd5462904360 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 14:05:53 -0700 Subject: [PATCH 51/68] Add AverageInterp no-op case to matrix cpp. --- src/utilities/data/Matrix.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utilities/data/Matrix.cpp b/src/utilities/data/Matrix.cpp index ba5b07773e0..30d1a80e62f 100644 --- a/src/utilities/data/Matrix.cpp +++ b/src/utilities/data/Matrix.cpp @@ -69,6 +69,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub // linear interpolation // no-op break; + case AverageInterp: + // average interpolation + // no-op + break; case NearestInterp: // pick closest point if (xInfo.wa > xInfo.wb) { @@ -112,6 +116,10 @@ double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, doub // linear interpolation // no-op break; + case AverageInterp: + // average interpolation + // no-op + break; case NearestInterp: // pick closest point if (yInfo.wa > yInfo.wb) { From 8d50877b32712a1f92d1f0e597b8bb7340e92d61 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 14:11:01 -0700 Subject: [PATCH 52/68] Update docs for new timeseries method. --- src/model/ScheduleDay.hpp | 2 +- src/model/ScheduleDay_Impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 7b651f2adff..70feeba5e18 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -70,7 +70,7 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; - /// Returns the values for the timesteps per hour. + /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method. openstudio::TimeSeries timeSeries() const; //@} diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index fd408fc359b..2a23a025d8e 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -76,7 +76,7 @@ namespace model { /// If time is less than 0 days or greater than 1 day, 0 is returned. double getValue(const openstudio::Time& time) const; - /// Returns the values for the timesteps per hour. + /// Returns the timeseries corresponding to simulation timestep and chosen interpolation method. openstudio::TimeSeries timeSeries() const; //@} From 825b27071dc9fb217e916a637f5665c731916f9b Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Mon, 25 Mar 2024 16:31:35 -0700 Subject: [PATCH 53/68] Set left endpoint of getvalue. --- src/model/ScheduleDay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f2f47086ed0..e1fa086bbc0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -197,7 +197,7 @@ namespace model { Vector y(N + 2); x[0] = 0.0; - y[0] = 0.0; + y[0] = values[0]; for (unsigned i = 0; i < N; ++i) { openstudio::Time t = dateTimes[i].time(); From bbd26f83f1f4bf44bf4d0d031879ec7e08df5321 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 26 Mar 2024 10:14:22 -0700 Subject: [PATCH 54/68] Update left endpoint per method and update tests. --- src/model/ScheduleDay.cpp | 9 ++++++++- src/model/test/ScheduleDay_GTest.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index e1fa086bbc0..dd4674a86d0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -197,7 +197,14 @@ namespace model { Vector y(N + 2); x[0] = 0.0; - y[0] = values[0]; + std::string interpolatetoTimestep = this->interpolatetoTimestep(); + if (istringEqual("No", interpolatetoTimestep)) { + y[0] = values[0]; + } else if (istringEqual("Average", interpolatetoTimestep)) { + y[0] = values[0]; + } else if (istringEqual("Linear", interpolatetoTimestep)) { + y[0] = 0.0; + } for (unsigned i = 0; i < N; ++i) { openstudio::Time t = dateTimes[i].time(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 06fda138014..7c406ac2dcd 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -53,6 +53,7 @@ TEST_F(ModelFixture, Schedule_Day) { EXPECT_EQ(0.0, daySchedule.getValue(Time(0, -1, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 0))); + EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 0, 1))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 6, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 8, 0))); EXPECT_EQ(1.0, daySchedule.getValue(Time(0, 9, 0))); @@ -197,11 +198,25 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(0.013890, daySchedule.getValue(Time(0, 0, 1)), tol); EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 6, 0)), tol); EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); EXPECT_NEAR(0.5, daySchedule.getValue(Time(0, 18, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); + + daySchedule.setInterpolatetoTimestep("Average"); + EXPECT_EQ("Average", daySchedule.interpolatetoTimestep()); + EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); + + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, -1, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 0, 1)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 6, 0)), tol); + EXPECT_NEAR(1.0, daySchedule.getValue(Time(0, 12, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 18, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); + EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); } TEST_F(ModelFixture, Schedule_Day_Remove) { From e2572091c3f99714ee7c6356542818565145b504 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 10:19:10 -0700 Subject: [PATCH 55/68] Interpolate using seconds instead of days. --- src/model/ScheduleDay.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index dd4674a86d0..5cc936bbeb0 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -265,11 +265,11 @@ namespace model { y[0] = 0.0; for (unsigned i = 0; i < N; ++i) { - x[i + 1] = times[i].totalDays(); + x[i + 1] = times[i].totalSeconds(); y[i + 1] = values[i]; } - x[N + 1] = 1.000001; + x[N + 1] = 86400.000001; y[N + 1] = 0.0; std::string interpolatetoTimestep = this->interpolatetoTimestep(); @@ -281,13 +281,13 @@ namespace model { } if (istringEqual("No", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t.totalDays(), HoldNextInterp, NoneExtrap); + tsValues[j] = interp(x, y, t.totalSeconds(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { double minutes = 60.0 / numberOfTimestepsPerHour; double ti = minutes / (60.0 * 24.0); // total days of the timestep interval - tsValues[j] = interp(x, y, t.totalDays(), AverageInterp, NoneExtrap, ti); + tsValues[j] = interp(x, y, t.totalSeconds(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { - tsValues[j] = interp(x, y, t.totalDays(), LinearInterp, NoneExtrap); + tsValues[j] = interp(x, y, t.totalSeconds(), LinearInterp, NoneExtrap); } } From a22dbb2a95f7f6d5e2c4c276f5146f43bc97596d Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 11:23:39 -0700 Subject: [PATCH 56/68] Need ti in seconds and not days. --- src/model/ScheduleDay.cpp | 2 +- src/utilities/data/Vector.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5cc936bbeb0..203fe026546 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -284,7 +284,7 @@ namespace model { tsValues[j] = interp(x, y, t.totalSeconds(), HoldNextInterp, NoneExtrap); } else if (istringEqual("Average", interpolatetoTimestep)) { double minutes = 60.0 / numberOfTimestepsPerHour; - double ti = minutes / (60.0 * 24.0); // total days of the timestep interval + double ti = minutes * 60.0; // total seconds of the timestep interval tsValues[j] = interp(x, y, t.totalSeconds(), AverageInterp, NoneExtrap, ti); } else if (istringEqual("Linear", interpolatetoTimestep)) { tsValues[j] = interp(x, y, t.totalSeconds(), LinearInterp, NoneExtrap); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index ba981ec4017..ecaa75c072e 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -102,12 +102,12 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { } else { result.wb = xi - x(result.ia); result.wa = ti - result.wb; - result.ti = 1.0; if ((result.wb > 0.0) && (result.wb < ti)) { result.ti = ti; } else { result.wa = 0.0; result.wb = 1.0; + result.ti = 1.0; } } } From 138957798ad5f38a0918875e601f882c679d9e3e Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 14:59:34 -0700 Subject: [PATCH 57/68] Try updating timestep with cache clear. --- src/model/Timestep.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index b8767089db4..bc3bc6679aa 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -9,6 +9,7 @@ #include "SimulationControl_Impl.hpp" #include "Model.hpp" #include "Model_Impl.hpp" +#include "ScheduleDay.hpp" #include "ScheduleDay_Impl.hpp" #include "../utilities/core/Assert.hpp" #include @@ -67,11 +68,20 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { + int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); + if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedVariables(); + } + } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; } void Timestep_Impl::resetNumberOfTimestepsPerHour() { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedVariables(); + } bool result = setString(OS_TimestepFields::NumberofTimestepsperHour, ""); OS_ASSERT(result); } From 805f14c7c2fbc7dfce65e07663bc303d7e929721 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 15:28:10 -0700 Subject: [PATCH 58/68] New protected method for clearing ts, and friend timestep. --- src/model/ScheduleDay.cpp | 4 ++++ src/model/ScheduleDay_Impl.hpp | 4 ++++ src/model/Timestep.cpp | 9 +++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 203fe026546..34212e5361c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -457,6 +457,10 @@ namespace model { m_cachedTimeSeries.reset(); } + void ScheduleDay_Impl::clearCachedTimeSeries() { + m_cachedTimeSeries.reset(); + } + } // namespace detail ScheduleDay::ScheduleDay(const Model& model) : ScheduleBase(ScheduleDay::iddObjectType(), model) { diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index 2a23a025d8e..b80a0e18b46 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -111,6 +111,10 @@ namespace model { virtual bool okToResetScheduleTypeLimits() const override; + void clearCachedTimeSeries(); + + friend class detail::Timestep_Impl; + //private slots: private: void clearCachedVariables(); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index bc3bc6679aa..89eaba247e1 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,11 +68,8 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); - if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { - for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedVariables(); - } + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedTimeSeries(); } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; @@ -80,7 +77,7 @@ namespace model { void Timestep_Impl::resetNumberOfTimestepsPerHour() { for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedVariables(); + sch_day.getImpl()->clearCachedTimeSeries(); } bool result = setString(OS_TimestepFields::NumberofTimestepsperHour, ""); OS_ASSERT(result); From 740a0b27b9a5e62e7b5de43cbf2148d99b503079 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 15:53:18 -0700 Subject: [PATCH 59/68] Updates for vt and deprecating interp setter. --- src/model/ScheduleDay.cpp | 13 ++++++++++ src/model/ScheduleDay.hpp | 3 +++ src/model/ScheduleDay_Impl.hpp | 5 ++-- src/model/Timestep.cpp | 7 ++++-- src/osversion/VersionTranslator.cpp | 25 +++++++++++++++++++ .../test/3_8_0/test_vt_ScheduleDay.osm | 14 +++++++++++ .../test/3_8_0/test_vt_ScheduleDay.rb | 10 ++++++++ .../test/VersionTranslator_GTest.cpp | 21 ++++++++++++++++ 8 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/osversion/test/3_8_0/test_vt_ScheduleDay.osm create mode 100644 src/osversion/test/3_8_0/test_vt_ScheduleDay.rb diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 34212e5361c..66bcaa66a1c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -30,6 +30,8 @@ #include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" +#include "../utilities/core/DeprecatedHelpers.hpp" // For deprecation + namespace openstudio { namespace model { @@ -528,6 +530,17 @@ namespace model { getImpl()->clearValues(); } + // DEPRECATED + + bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) const { + DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); + if (interpolatetoTimestep) { + return getImpl()->setInterpolatetoTimestep("Average"); + } else { + return getImpl()->setInterpolatetoTimestep("No"); + } + } + /// @cond ScheduleDay::ScheduleDay(std::shared_ptr impl) : ScheduleBase(std::move(impl)) {} /// @endcond diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 70feeba5e18..34623f0f52d 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -9,6 +9,8 @@ #include "ModelAPI.hpp" #include "ScheduleBase.hpp" +#include "../utilities/core/Deprecated.hpp" + namespace openstudio { class Time; @@ -78,6 +80,7 @@ namespace model { //@{ bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); + OS_DEPRECATED(3, 8, 0) bool setInterpolatetoTimestep(bool interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/ScheduleDay_Impl.hpp b/src/model/ScheduleDay_Impl.hpp index b80a0e18b46..ff704c4ac07 100644 --- a/src/model/ScheduleDay_Impl.hpp +++ b/src/model/ScheduleDay_Impl.hpp @@ -22,6 +22,8 @@ namespace model { namespace detail { + class Timestep_Impl; + /** ScheduleDay_Impl is a ResourceObject_Impl that is the implementation class for ScheduleDay.*/ class MODEL_API ScheduleDay_Impl : public ScheduleBase_Impl { @@ -111,10 +113,9 @@ namespace model { virtual bool okToResetScheduleTypeLimits() const override; + friend class Timestep_Impl; void clearCachedTimeSeries(); - friend class detail::Timestep_Impl; - //private slots: private: void clearCachedVariables(); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index 89eaba247e1..d7a0cba1fbe 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,8 +68,11 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - for (auto& sch_day : model().getConcreteModelObjects()) { - sch_day.getImpl()->clearCachedTimeSeries(); + const int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); + if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + for (auto& sch_day : model().getConcreteModelObjects()) { + sch_day.getImpl()->clearCachedTimeSeries(); + } } bool result = setInt(OS_TimestepFields::NumberofTimestepsperHour, numberOfTimestepsPerHour); return result; diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index ad7436325f7..b3e42fb6ad5 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9160,6 +9160,31 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); + } else if (iddname == "OS:Schedule:Day" ) { + + // 1 Field has been added from 3.7.0 to 3.8.0: + // ---------------------------------------------- + // * Interpolate to Timestep * 3 + + auto iddObject = idd_3_8_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + if (i == 3) { + if (istringEqual(value.get(), "Yes")) { + newObject.setString(3, "Average"); + } else { + newObject.setString(3, "No"); + } + } + newObject.setString(i, value.get()); + } + } + + ss << newObject; + m_refactored.emplace_back(std::move(object), std::move(newObject)); + // No-op } else { ss << object; diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm new file mode 100644 index 00000000000..c265fde6cda --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.osm @@ -0,0 +1,14 @@ + +OS:Version, + {9d4d2ac6-81f7-466e-be47-92edf03bbde0}, !- Handle + 3.7.0; !- Version Identifier + +OS:Schedule:Day, + {b39f42af-eb9f-4079-ad11-5a527a726900}, !- Handle + Schedule Day 1, !- Name + , !- Schedule Type Limits Name + Yes, !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + diff --git a/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb new file mode 100644 index 00000000000..9af267e319c --- /dev/null +++ b/src/osversion/test/3_8_0/test_vt_ScheduleDay.rb @@ -0,0 +1,10 @@ +#require '/usr/local/openstudio-3.6.1/Ruby/openstudio' + +include OpenStudio::Model + +m = Model.new + +sch_day = ScheduleDay.new(m) +sch_day.setInterpolatetoTimestep(true) + +m.save('test_vt_ScheduleDay.osm', true) diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 6d12d3c4439..4a06beca16a 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -4186,3 +4186,24 @@ TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_PeopleDefinition) { EXPECT_TRUE(def.isEmpty(9)); // Enable ASHRAE 55 Comfort Warnings EXPECT_EQ("EnclosureAveraged", def.getString(10).get()); // Mean Radiant Temperature Calculation Type } + +TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_ScheduleDay) { + openstudio::path path = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay.osm"); + osversion::VersionTranslator vt; + boost::optional model = vt.loadModel(path); + ASSERT_TRUE(model) << "Failed to load " << path; + + openstudio::path outPath = resourcesPath() / toPath("osversion/3_8_0/test_vt_ScheduleDay_updated.osm"); + model->save(outPath, true); + + std::vector sch_days = model->getObjectsByType("OS:Schedule:Day"); + ASSERT_EQ(1u, sch_days.size()); + WorkspaceObject sch_day = sch_days[0]; + + EXPECT_EQ("Schedule Day 1", sch_day.getString(1).get()); // Name + EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name + EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep + EXPECT_EQ(24, sch_day.getInt(4)); // Hour 1 + EXPECT_EQ(0, sch_day.getInt(5)); // Minute 1 + EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 +} From f20d8402d2ca0086e27a6d200efc5234e8c3c6c7 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 19:23:00 -0700 Subject: [PATCH 60/68] Building but tests failing. --- src/model/ScheduleDay.cpp | 2 +- src/model/Timestep.cpp | 3 +-- src/osversion/VersionTranslator.cpp | 8 ++++---- src/osversion/test/VersionTranslator_GTest.cpp | 10 +++++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 66bcaa66a1c..5798189daa8 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -532,7 +532,7 @@ namespace model { // DEPRECATED - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) const { + bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); if (interpolatetoTimestep) { return getImpl()->setInterpolatetoTimestep("Average"); diff --git a/src/model/Timestep.cpp b/src/model/Timestep.cpp index d7a0cba1fbe..77bfd6b81f0 100644 --- a/src/model/Timestep.cpp +++ b/src/model/Timestep.cpp @@ -68,8 +68,7 @@ namespace model { } bool Timestep_Impl::setNumberOfTimestepsPerHour(int numberOfTimestepsPerHour) { - const int currentNumberOfTimestepsPerHour = numberOfTimestepsPerHour(); - if (currentNumberOfTimestepsPerHour != numberOfTimestepsPerHour) { + if (numberOfTimestepsPerHour != this->numberOfTimestepsPerHour()) { for (auto& sch_day : model().getConcreteModelObjects()) { sch_day.getImpl()->clearCachedTimeSeries(); } diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index b3e42fb6ad5..ee8785e6f7c 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9160,15 +9160,15 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); - } else if (iddname == "OS:Schedule:Day" ) { + } else if (iddname == "OS:Schedule:Day") { // 1 Field has been added from 3.7.0 to 3.8.0: // ---------------------------------------------- // * Interpolate to Timestep * 3 - + auto iddObject = idd_3_8_0.getObject(iddname); IdfObject newObject(iddObject.get()); - + for (size_t i = 0; i < object.numFields(); ++i) { if ((value = object.getString(i))) { if (i == 3) { @@ -9184,7 +9184,7 @@ namespace osversion { ss << newObject; m_refactored.emplace_back(std::move(object), std::move(newObject)); - + // No-op } else { ss << object; diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 4a06beca16a..d7d81842494 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -4201,9 +4201,9 @@ TEST_F(OSVersionFixture, update_3_7_0_to_3_8_0_ScheduleDay) { WorkspaceObject sch_day = sch_days[0]; EXPECT_EQ("Schedule Day 1", sch_day.getString(1).get()); // Name - EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name - EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep - EXPECT_EQ(24, sch_day.getInt(4)); // Hour 1 - EXPECT_EQ(0, sch_day.getInt(5)); // Minute 1 - EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 + EXPECT_TRUE(sch_day.isEmpty(2)); // Schedule Type Limits Name + EXPECT_EQ("Average", sch_day.getString(3).get()); // Interpolate to Timestep + EXPECT_EQ(24, sch_day.getInt(4).get()); // Hour 1 + EXPECT_EQ(0, sch_day.getInt(5).get()); // Minute 1 + EXPECT_EQ(0, sch_day.getDouble(6).get()); // Value Until Time 1 } From 881d27c9e0c06767f52e7460ccd967e3d3e5f033 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 27 Mar 2024 19:29:15 -0700 Subject: [PATCH 61/68] Fix the new vt. --- src/osversion/VersionTranslator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index ee8785e6f7c..4ef6e4d12ca 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9177,8 +9177,9 @@ namespace osversion { } else { newObject.setString(3, "No"); } + } else { + newObject.setString(i, value.get()); } - newObject.setString(i, value.get()); } } From 1794d58cfd66bfd6e43a2125aa01104af811378c Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 28 Mar 2024 08:37:16 -0700 Subject: [PATCH 62/68] Remove deprecation of old setter. --- src/model/ScheduleDay.cpp | 13 ------------- src/model/ScheduleDay.hpp | 3 --- src/model/test/ScheduleDay_GTest.cpp | 2 +- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 5798189daa8..34212e5361c 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -30,8 +30,6 @@ #include "../utilities/data/TimeSeries.hpp" #include "../utilities/data/Vector.hpp" -#include "../utilities/core/DeprecatedHelpers.hpp" // For deprecation - namespace openstudio { namespace model { @@ -530,17 +528,6 @@ namespace model { getImpl()->clearValues(); } - // DEPRECATED - - bool ScheduleDay::setInterpolatetoTimestep(bool interpolatetoTimestep) { - DEPRECATED_AT_MSG(3, 8, 0, "Use setInterpolatetoTimestep(No, Average, Linear) instead."); - if (interpolatetoTimestep) { - return getImpl()->setInterpolatetoTimestep("Average"); - } else { - return getImpl()->setInterpolatetoTimestep("No"); - } - } - /// @cond ScheduleDay::ScheduleDay(std::shared_ptr impl) : ScheduleBase(std::move(impl)) {} /// @endcond diff --git a/src/model/ScheduleDay.hpp b/src/model/ScheduleDay.hpp index 34623f0f52d..70feeba5e18 100644 --- a/src/model/ScheduleDay.hpp +++ b/src/model/ScheduleDay.hpp @@ -9,8 +9,6 @@ #include "ModelAPI.hpp" #include "ScheduleBase.hpp" -#include "../utilities/core/Deprecated.hpp" - namespace openstudio { class Time; @@ -80,7 +78,6 @@ namespace model { //@{ bool setInterpolatetoTimestep(const std::string& interpolatetoTimestep); - OS_DEPRECATED(3, 8, 0) bool setInterpolatetoTimestep(bool interpolatetoTimestep); void resetInterpolatetoTimestep(); diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 7c406ac2dcd..0a951877c7a 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -192,7 +192,7 @@ TEST_F(ModelFixture, Schedule_Day_Interp) { EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 24, 0)), tol); EXPECT_NEAR(0.0, daySchedule.getValue(Time(0, 25, 0)), tol); - daySchedule.setInterpolatetoTimestep("Linear"); + EXPECT_TRUE(daySchedule.setInterpolatetoTimestep("Linear")); EXPECT_EQ("Linear", daySchedule.interpolatetoTimestep()); EXPECT_FALSE(daySchedule.isInterpolatetoTimestepDefaulted()); From e4cef89e658617a38eb75a662aa77d8682f3de90 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 28 Mar 2024 08:45:34 -0700 Subject: [PATCH 63/68] Add one more test showing change in getValue for small enough timestep. --- src/model/test/ScheduleDay_GTest.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/model/test/ScheduleDay_GTest.cpp b/src/model/test/ScheduleDay_GTest.cpp index 0a951877c7a..c102655304b 100644 --- a/src/model/test/ScheduleDay_GTest.cpp +++ b/src/model/test/ScheduleDay_GTest.cpp @@ -380,7 +380,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -397,7 +397,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -414,7 +414,7 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); @@ -431,7 +431,24 @@ TEST_F(ModelFixture, Schedule_Day_timeSeries) { value = sch_day.getValue(t0800); EXPECT_NEAR(0.1, value, tol); value = sch_day.getValue(t0805); - EXPECT_NEAR(1.0, value, tol); // FIXME: should this be 0.1? + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0810); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0818); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0820); + EXPECT_NEAR(1.0, value, tol); + value = sch_day.getValue(t0900); + EXPECT_NEAR(1.0, value, tol); + + EXPECT_TRUE(timestep.setNumberOfTimestepsPerHour(12)); + timeSeries = sch_day.timeSeries(); + EXPECT_EQ(24 * 12, timeSeries.dateTimes().size()); + EXPECT_EQ(24 * 12, timeSeries.values().size()); + value = sch_day.getValue(t0800); + EXPECT_NEAR(0.1, value, tol); + value = sch_day.getValue(t0805); + EXPECT_NEAR(0.1, value, tol); // at this timestep, we do return the 0.1 value = sch_day.getValue(t0810); EXPECT_NEAR(1.0, value, tol); value = sch_day.getValue(t0818); From 138cbad532afb15e5d11a5e3b9c51e6738e05daa Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 08:59:41 -0700 Subject: [PATCH 64/68] Update comments and release notes. --- .../doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md | 4 ++++ src/model/ScheduleDay.cpp | 5 +++++ src/osversion/VersionTranslator.cpp | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md index a232fe46b1f..d309942e0b8 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md @@ -86,6 +86,10 @@ For a list of deprecated and removed methods, please refer to [deprecated_method * A number of methods have been renamed (and the old ones deprecated) to conform to the API for other `SpaceLoadInstance` / `SpaceLoadDefinition` objects * Mostly `getWattsperUnit` is changed to `getDesignLevel` and `getWattsperZoneFloorArea` is changed to `getPowerPerFloorArea` * Refer to [deprecated_methods.csv](../../ruby/deprecated_methods.csv) for the complete list +* [#5111](https://github.com/NREL/OpenStudio/pull/5111) - ScheduleDay: new timeseries method and interpolation options + * The `ScheduleDay` has API-breaking changes related to setters and getters for its `Interpolate To Timestep` field. They now use `string` rather than `bool` to conform to the IDD type `\choice` + * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in ``Interpolate to Timestep field + * A new `timeseries()` method is introduced for returning vectors of times and values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time ## Minor changes and bug fixes diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index 34212e5361c..da51078c7cf 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -181,6 +181,11 @@ namespace model { return 0.0; } + // We'll calculate the entire day when we request a single value but that's on purpose: + // * We're talking about max 60 timesteps * 24 hours = 1440 points, + // but realistically more often than not you'll have a timestep of 6 (our default) or 4 so 96 to 144 points. So not a lot of points + // * We cache the timeSeries, and, + // * More often than not, the use case is to do it for the entire day anyways (eg: openstudio-standards to determine occupancy schedules) TimeSeries ts = this->timeSeries(); DateTimeVector dateTimes = ts.dateTimes(); diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index 4ef6e4d12ca..b4c7b138e15 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -9162,9 +9162,9 @@ namespace osversion { } else if (iddname == "OS:Schedule:Day") { - // 1 Field has been added from 3.7.0 to 3.8.0: + // 1 Field has been modified from 3.7.0 to 3.8.0: // ---------------------------------------------- - // * Interpolate to Timestep * 3 + // * Interpolate to Timestep * 3 - Changed from bool to string choice auto iddObject = idd_3_8_0.getObject(iddname); IdfObject newObject(iddObject.get()); From 4572fc0b2aec4e4c4e94155afc5138b95978a127 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 10:14:26 -0700 Subject: [PATCH 65/68] Update ti default to -9999, add assert, update comments. --- src/model/ScheduleDay.cpp | 4 ++-- src/utilities/data/Matrix.hpp | 16 ++++++++++++---- src/utilities/data/Vector.cpp | 3 ++- src/utilities/data/Vector.hpp | 13 ++++++++----- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index da51078c7cf..f6727d4e4e5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -191,7 +191,7 @@ namespace model { DateTimeVector dateTimes = ts.dateTimes(); Vector values = ts.values(); - unsigned N = dateTimes.size(); + const unsigned N = dateTimes.size(); OS_ASSERT(values.size() == N); if (N == 0) { @@ -255,7 +255,7 @@ namespace model { std::vector values = this->values(); // these are already sorted std::vector times = this->times(); // these are already sorted - unsigned N = times.size(); + const unsigned N = times.size(); OS_ASSERT(values.size() == N); TimeSeries result; diff --git a/src/utilities/data/Matrix.hpp b/src/utilities/data/Matrix.hpp index 9bade37a0a8..ecf6a9b0508 100644 --- a/src/utilities/data/Matrix.hpp +++ b/src/utilities/data/Matrix.hpp @@ -32,23 +32,31 @@ UTILITIES_API bool operator!=(const Matrix& lhs, const Matrix& rhs); /// linear interpolation of the function v = f(x, y) at point xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API double interp(const Vector& x, const Vector& y, const Matrix& v, double xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, double yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Matrix& v, double xi, const Vector& yi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// linear interpolation of the function v = f(x, y) at points xi, yi /// assumes that x and y are strictly increasing +/// ti is the total seconds of the timestep interval; it is used for +/// AverageInterp and must be positive UTILITIES_API Matrix interp(const Vector& x, const Vector& y, const Matrix& v, const Vector& xi, const Vector& yi, - InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + InterpMethod interpMethod = LinearInterp, ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /// matrix product UTILITIES_API Matrix prod(const Matrix& lop, const Matrix& rop); diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index ecaa75c072e..7660e59b895 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -96,10 +96,11 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.ia = (unsigned)(it - begin - 1); result.ib = (unsigned)(it - begin); - if (ti == 0.0) { + if (ti < 0.0) { result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); } else { + OS_ASSERT(ti > 0.0); result.wb = xi - x(result.ia); result.wa = ti - result.wb; if ((result.wb > 0.0) && (result.wb < ti)) { diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index 39a2a6a88f2..f1b1ebd7e02 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -80,18 +80,21 @@ struct UTILITIES_API InterpInfo }; /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly - * increasing. */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API InterpInfo interpInfo(const Vector& x, double xi, double ti); /** Linear interpolation of the function y = f(x) at point xi. Assumes that x is strictly - * increasing */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); /** Linear interpolation of the function y = f(x) at points xi. Assumes that x is strictly - * increasing. */ + * increasing. ti is the total seconds of the timestep interval; it is used for + * AverageInterp and must be positive. */ UTILITIES_API Vector interp(const Vector& x, const Vector& y, const Vector& xi, InterpMethod interpMethod = LinearInterp, - ExtrapMethod extrapMethod = NoneExtrap, double ti = 0.0); + ExtrapMethod extrapMethod = NoneExtrap, double ti = -9999.0); //@} /** @name Common Methods and Vector Operations */ From ceba9098f50bf2fc7c4ba8cf2db0da38e5a7510b Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 18 Apr 2024 10:16:47 -0700 Subject: [PATCH 66/68] Few more updates to release notes. --- .../doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md index d309942e0b8..63a8e31bcee 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_8_0_TBD.md @@ -88,8 +88,8 @@ For a list of deprecated and removed methods, please refer to [deprecated_method * Refer to [deprecated_methods.csv](../../ruby/deprecated_methods.csv) for the complete list * [#5111](https://github.com/NREL/OpenStudio/pull/5111) - ScheduleDay: new timeseries method and interpolation options * The `ScheduleDay` has API-breaking changes related to setters and getters for its `Interpolate To Timestep` field. They now use `string` rather than `bool` to conform to the IDD type `\choice` - * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in ``Interpolate to Timestep field - * A new `timeseries()` method is introduced for returning vectors of times and values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time + * The forward translator for `ScheduleDay` replaces always setting "Average" with the interpolation method stored in `Interpolate to Timestep` field + * A new `timeseries()` method is introduced for returning vectors of times and (interpolated) values for the given number of timesteps per hour established by the `Timestep` object; `getValue` references this vector for an interpolated value at a given time ## Minor changes and bug fixes From 012f076b8476fb752e849672bc1b2f1bb08f6843 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 25 Apr 2024 15:24:55 +0200 Subject: [PATCH 67/68] Missing include --- src/utilities/data/Vector.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 7660e59b895..492f08e83e1 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -5,6 +5,8 @@ #include "Vector.hpp" +#include "../core/Assert.hpp" + #include // this should all be moved to a utilities/core/Random.h From fddbc7da1d0fcc720b8631cd9b959c75a6fa0815 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Thu, 25 Apr 2024 10:05:30 -0700 Subject: [PATCH 68/68] Update assert and get optional timestep object. --- src/model/ScheduleDay.cpp | 8 ++++++-- src/model/test/ModelMerger_GTest.cpp | 9 ++++----- src/utilities/data/Vector.cpp | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/model/ScheduleDay.cpp b/src/model/ScheduleDay.cpp index f6727d4e4e5..5efe02d0fc5 100644 --- a/src/model/ScheduleDay.cpp +++ b/src/model/ScheduleDay.cpp @@ -232,8 +232,12 @@ namespace model { openstudio::TimeSeries ScheduleDay_Impl::timeSeries() const { if (!m_cachedTimeSeries) { - auto timestep = this->model().getUniqueModelObject(); - int numberOfTimestepsPerHour = timestep.numberOfTimestepsPerHour(); + int numberOfTimestepsPerHour; + if (boost::optional timestep = this->model().getOptionalUniqueModelObject()) { + numberOfTimestepsPerHour = timestep->numberOfTimestepsPerHour(); + } else { + numberOfTimestepsPerHour = 6; + } Date startDate(Date(MonthOfYear(MonthOfYear::Jan), 1)); // this is arbitrary int minutes = 60 / numberOfTimestepsPerHour; diff --git a/src/model/test/ModelMerger_GTest.cpp b/src/model/test/ModelMerger_GTest.cpp index 294d90af21d..7854e090282 100644 --- a/src/model/test/ModelMerger_GTest.cpp +++ b/src/model/test/ModelMerger_GTest.cpp @@ -914,10 +914,10 @@ TEST_F(ModelFixture, ModelMerger_Issue_5153) { }; std::vector floorprint2_2{ - {5, 5, 0}, + {5, 5, 0}, {10, 5, 0}, {10, 0, 0}, - {5, 0, 0}, + {5, 0, 0}, }; // set up model 2 @@ -935,14 +935,13 @@ TEST_F(ModelFixture, ModelMerger_Issue_5153) { space1_2->matchSurfaces(*space2_2); - auto testModel = [](const Model& model) { - + auto testModel = [](const Model& model) { unsigned numOutdoorSurfaces = 0; unsigned numGroundSurfaces = 0; unsigned numAdjacentSurfaces = 0; unsigned numOutdoorSubSurfaces = 0; unsigned numAdjacentSubSurfaces = 0; - + for (const auto& surface : model.getConcreteModelObjects()) { if (surface.outsideBoundaryCondition() == "Outdoors") { ++numOutdoorSurfaces; diff --git a/src/utilities/data/Vector.cpp b/src/utilities/data/Vector.cpp index 492f08e83e1..007c3271117 100644 --- a/src/utilities/data/Vector.cpp +++ b/src/utilities/data/Vector.cpp @@ -102,7 +102,6 @@ InterpInfo interpInfo(const Vector& x, double xi, double ti) { result.wa = (x(result.ib) - xi) / (x(result.ib) - x(result.ia)); result.wb = (xi - x(result.ia)) / (x(result.ib) - x(result.ia)); } else { - OS_ASSERT(ti > 0.0); result.wb = xi - x(result.ia); result.wa = ti - result.wb; if ((result.wb > 0.0) && (result.wb < ti)) { @@ -130,6 +129,10 @@ double interp(const Vector& x, const Vector& y, double xi, InterpMethod interpMe return result; } + if (interpMethod == AverageInterp && ti <= 0.0) { + LOG_FREE_AND_THROW("openstudio.Vector", "Value of ti must be positive when interpolating using the AverageInterp method."); + } + InterpInfo info = interpInfo(x, xi, ti); if (info.extrapolated) {