-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Import Schedule:Compact as ScheduleRuleset #605
Merged
chriswmackey
merged 8 commits into
ladybug-tools:master
from
samuelduchesne:290-import-schedulecompact-and-schedulew
Mar 4, 2021
Merged
Changes from 3 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
8be260c
isort
samuelduchesne 4fa6bd6
Adds logic to parse Schedule:Compact
samuelduchesne 339f0d7
Adds test
samuelduchesne 0436193
hidden function for less duplicated code
samuelduchesne 0cc9da1
Typo
samuelduchesne 31ffb72
situation if allotherdays is the only rule.
samuelduchesne 514ca93
Adds option to import compact schedules
samuelduchesne 8b76644
Sets compact to True
samuelduchesne File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,23 +2,22 @@ | |
"""Complete annual schedule object built from ScheduleDay and rules for applying them.""" | ||
from __future__ import division | ||
|
||
from .day import ScheduleDay | ||
from .rule import ScheduleRule | ||
from .typelimit import ScheduleTypeLimit | ||
from ..reader import parse_idf_string | ||
from ..writer import generate_idf_string | ||
import os | ||
import re | ||
|
||
from honeybee._lockable import lockable | ||
from honeybee.typing import valid_ep_string, tuple_with_length | ||
|
||
from ladybug.datacollection import HourlyContinuousCollection | ||
from ladybug.header import Header | ||
from honeybee.typing import tuple_with_length, valid_ep_string | ||
from ladybug.analysisperiod import AnalysisPeriod | ||
from ladybug.dt import Date | ||
from ladybug.datacollection import HourlyContinuousCollection | ||
from ladybug.datatype.generic import GenericType | ||
from ladybug.dt import Date, Time | ||
from ladybug.header import Header | ||
|
||
import re | ||
import os | ||
from ..reader import parse_idf_string | ||
from ..writer import generate_idf_string | ||
from .day import ScheduleDay | ||
from .rule import ScheduleRule | ||
from .typelimit import ScheduleTypeLimit | ||
|
||
|
||
@lockable | ||
|
@@ -1004,6 +1003,10 @@ def extract_all_from_idf_file(idf_file): | |
constant_pattern = re.compile(r"(?i)(Schedule:Constant,[\s\S]*?;)") | ||
constant_props = tuple(parse_idf_string(idf_string) for | ||
idf_string in constant_pattern.findall(file_contents)) | ||
# extract all of the Schedule:Compact objects and convert to ScheduleRuleset | ||
conpact_pattern = re.compile(r"(?i)(Schedule:Compact,[\s\S]*?;)") | ||
compact_props = tuple(parse_idf_string(idf_string) for | ||
idf_string in conpact_pattern.findall(file_contents)) | ||
# compile all of the ScheduleRuleset objects from extracted properties | ||
schedules = [] | ||
for year_sch in year_props: | ||
|
@@ -1043,6 +1046,151 @@ def extract_all_from_idf_file(idf_file): | |
sch_ruleset = ScheduleRuleset.from_constant_value( | ||
const_sch[0], sched_val, schedule_type) | ||
schedules.append(sch_ruleset) | ||
for compact_sch in compact_props: | ||
schedule_type = ( | ||
sch_type_dict[compact_sch[1]] if compact_sch[1] != "" else None | ||
) | ||
schedule_rules = [] | ||
holiday_schedule = None | ||
winter_designday_schedule = None | ||
summer_designday_schedule = None | ||
start_date = Date.from_doy(1) | ||
end_date = Date.from_doy(365) | ||
untils = [Time(0, 0)] # initialize list of until times. | ||
n = -1 # initialize the n-th until time | ||
rules = [] # initialize list of rules. | ||
for field in compact_sch[2:]: | ||
field = field.lower() | ||
if "through" in field: | ||
# Each `through` field generates a new ScheduleRule | ||
# initialize rule with ScheduleDay as placeholder. | ||
rule = ScheduleRule(ScheduleDay(compact_sch[0], [0], [Time(0, 0)])) | ||
|
||
# start_date is either Jan 1st or end_date from previous | ||
# `through` field | ||
start_date = ( | ||
start_date if end_date == Date.from_doy(365) else end_date | ||
) | ||
|
||
_, date = field.split(":") # get end_date from field | ||
month, day = date.split("/") | ||
end_date = Date.from_dict({"month": int(month), "day": int(day)}) | ||
elif "for" in field: | ||
# reset values for new set; each `for` is a new rule | ||
n = -1 # reset the n-th until time | ||
untils = [Time(0, 0)] # reset list of until times. | ||
rules = [] # reset list of rules for this `for` field. | ||
|
||
# Create a rule; all different `if` statements because we want to | ||
# catch more than one case, | ||
# eg. `For: Sunday Holidays AllOtherDays, !- Field 54` | ||
if "alldays" in field: | ||
rule = ScheduleRule(ScheduleDay("alldays", [0], [Time(0, 0)])) | ||
rule.apply_all = True | ||
rules.append(rule) | ||
if "weekdays" in field: | ||
rule = ScheduleRule(ScheduleDay("weekdays", [0], [Time(0, 0)])) | ||
rule.apply_weekday = True | ||
rules.append(rule) | ||
if "weekends" in field: | ||
rule = ScheduleRule(ScheduleDay("weekends", [0], [Time(0, 0)])) | ||
rule.apply_weekend = True | ||
rules.append(rule) | ||
if "sunday" in field: | ||
rule = ScheduleRule(ScheduleDay("sunday", [0], [Time(0, 0)])) | ||
rule.apply_sunday = True | ||
rules.append(rule) | ||
if "monday" in field: | ||
rule = ScheduleRule(ScheduleDay("monday", [0], [Time(0, 0)])) | ||
rule.apply_monday = True | ||
rules.append(rule) | ||
if "tuesday" in field: | ||
rule = ScheduleRule(ScheduleDay("tuesday", [0], [Time(0, 0)])) | ||
rule.apply_tuesday = True | ||
rules.append(rule) | ||
if "wednesday" in field: | ||
rule = ScheduleRule(ScheduleDay("wednesday", [0], [Time(0, 0)])) | ||
rule.apply_wednesday = True | ||
rules.append(rule) | ||
if "thursday" in field: | ||
rule = ScheduleRule(ScheduleDay("thursday", [0], [Time(0, 0)])) | ||
rule.apply_thursday = True | ||
rules.append(rule) | ||
if "friday" in field: | ||
rule = ScheduleRule(ScheduleDay("friday", [0], [Time(0, 0)])) | ||
rule.apply_friday = True | ||
rules.append(rule) | ||
if "saturday" in field: | ||
rule = ScheduleRule(ScheduleDay("saturday", [0], [Time(0, 0)])) | ||
rule.apply_saturday = True | ||
rules.append(rule) | ||
if "holiday" in field: | ||
rule = ScheduleRule(ScheduleDay("holiday", [0], [Time(0, 0)])) | ||
holiday_schedule = rule.schedule_day | ||
rules.append(rule) | ||
if "summerdesignday" in field: | ||
rule = ScheduleRule(ScheduleDay("summerdesignday", [0], [Time(0, 0)])) | ||
summer_designday_schedule = rule.schedule_day | ||
rules.append(rule) | ||
if "winterdesignday" in field: | ||
rule = ScheduleRule(ScheduleDay("winterdesignday", [0], [Time(0, 0)])) | ||
winter_designday_schedule = rule.schedule_day | ||
rules.append(rule) | ||
if "allotherdays" in field: | ||
rule = ScheduleRule(ScheduleDay("allotherdays", [0], [Time(0, 0)])) | ||
apply_mtx = [rul.week_apply_tuple for rul in schedule_rules] | ||
for j, dow in enumerate(zip(*apply_mtx)): | ||
if not any(dow): | ||
rule.apply_day_by_dow(j + 1) | ||
rules.append(rule) | ||
|
||
for rule in rules: | ||
# for each rule in this `for` field, add rules to | ||
# ScheduleRuleset list of rules and set start_date and end_date. | ||
if len(rule.days_applied) != 0: | ||
schedule_rules.append(rule) | ||
|
||
# set range for rule (from previous `through` field) | ||
rule.start_date = start_date | ||
rule.end_date = end_date | ||
elif "until" in field: | ||
_, hour, min = field.split(":") # get hour and minutes | ||
|
||
# value is applied `until` a certain Time, but `ScheduleDay` is | ||
# applied `from` a certain Time. Also, Time is 0:23 Hours while IDF | ||
# is 1:24 Hours. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's nice to know that I am not the only one who struggles with this convention. Why in the world EnergyPlus couldn't obey how time works, I do not know. But, from the number of thumbs up on this issue, hopefully future developers may be able to avoid it. |
||
until = Time(int(hour) - 1, int(min)) # to 0:23 Hours repr | ||
untils.append(until) | ||
|
||
# increment n | ||
n += 1 | ||
elif "interpolate" in field: | ||
# Set interpolate on all rules for this `for` field | ||
_, interpolate = field.split(":") | ||
for rule in rules: | ||
rule.schedule_day.interpolate = interpolate != "no" | ||
else: | ||
begin = untils[n] # index list of `until` times | ||
for rule in rules: | ||
# apply field value for each rules; try to replace the | ||
# placeholder value first, else add the value. | ||
try: | ||
rule.schedule_day.replace_value_by_time(begin, float(field)) | ||
except ValueError: | ||
rule.schedule_day.add_value(float(field), begin) | ||
default_day_schedule = schedule_rules[0].schedule_day | ||
sch_ruleset = ScheduleRuleset( | ||
default_day_schedule=default_day_schedule, | ||
identifier=compact_sch[0], | ||
schedule_type_limit=schedule_type, | ||
schedule_rules=schedule_rules[1:] | ||
) | ||
ScheduleRuleset._apply_designdays_with_check( | ||
sch_ruleset, | ||
holiday_schedule, | ||
summer_designday_schedule, | ||
winter_designday_schedule) | ||
schedules.append(sch_ruleset) | ||
return schedules | ||
|
||
@staticmethod | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whenever I see duplicated code like this, I know that there should be a function for it instead of copy/pasted code. I recommend making a hidden function on the class where you pass the type of day (eg. weekdays) and the rule list to which the rule would be appended.
Then, you don't even need an
if
statement and you essentially turn 50 lines of duplicated code into 3 lines.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized that I should give a little more explanation of what this hidden method would look like if you wanted to get rid fo the
if
statement. You could just have a dictionary that maps the word"weekdays"
to the name of the property on theScheduleRule
class ("apply_weekdays"
). Then you can just use the native pythonsetattr()
to set the property toTrue
on the ScheduleRule object instance.And that will save you from a lot of duplicate code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point: Is this what you had in mind? 0436193
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is much cleaner. There's just a typo that I noticed in the code here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!