honeybee-schema 1.59.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. honeybee_schema/__init__.py +1 -0
  2. honeybee_schema/__main__.py +4 -0
  3. honeybee_schema/_base.py +42 -0
  4. honeybee_schema/altnumber.py +18 -0
  5. honeybee_schema/boundarycondition.py +81 -0
  6. honeybee_schema/cli.py +115 -0
  7. honeybee_schema/comparison.py +208 -0
  8. honeybee_schema/doe2/__init__.py +0 -0
  9. honeybee_schema/doe2/properties.py +75 -0
  10. honeybee_schema/energy/__init__.py +0 -0
  11. honeybee_schema/energy/_base.py +64 -0
  12. honeybee_schema/energy/construction.py +324 -0
  13. honeybee_schema/energy/constructionset.py +359 -0
  14. honeybee_schema/energy/daylight.py +62 -0
  15. honeybee_schema/energy/designday.py +212 -0
  16. honeybee_schema/energy/generator.py +140 -0
  17. honeybee_schema/energy/global_constructionset.py +129 -0
  18. honeybee_schema/energy/hvac/__init__.py +0 -0
  19. honeybee_schema/energy/hvac/_template.py +38 -0
  20. honeybee_schema/energy/hvac/allair.py +257 -0
  21. honeybee_schema/energy/hvac/detailed.py +20 -0
  22. honeybee_schema/energy/hvac/doas.py +248 -0
  23. honeybee_schema/energy/hvac/heatcool.py +309 -0
  24. honeybee_schema/energy/hvac/idealair.py +107 -0
  25. honeybee_schema/energy/internalmass.py +25 -0
  26. honeybee_schema/energy/load.py +627 -0
  27. honeybee_schema/energy/material.py +949 -0
  28. honeybee_schema/energy/programtype.py +117 -0
  29. honeybee_schema/energy/properties.py +382 -0
  30. honeybee_schema/energy/schedule.py +350 -0
  31. honeybee_schema/energy/shw.py +53 -0
  32. honeybee_schema/energy/simulation.py +440 -0
  33. honeybee_schema/energy/ventcool.py +337 -0
  34. honeybee_schema/geometry.py +161 -0
  35. honeybee_schema/model.py +473 -0
  36. honeybee_schema/projectinfo.py +94 -0
  37. honeybee_schema/radiance/__init__.py +0 -0
  38. honeybee_schema/radiance/_base.py +22 -0
  39. honeybee_schema/radiance/asset.py +191 -0
  40. honeybee_schema/radiance/global_modifierset.py +92 -0
  41. honeybee_schema/radiance/modifier.py +373 -0
  42. honeybee_schema/radiance/modifierset.py +296 -0
  43. honeybee_schema/radiance/properties.py +149 -0
  44. honeybee_schema/radiance/state.py +69 -0
  45. honeybee_schema/updater/__init__.py +0 -0
  46. honeybee_schema/updater/version_1_39_12.py +14 -0
  47. honeybee_schema/updater/version_1_40_1.py +153 -0
  48. honeybee_schema/updater/version_1_43_1.py +18 -0
  49. honeybee_schema/updater/version_1_43_2.py +12 -0
  50. honeybee_schema/updater/version_1_43_5.py +11 -0
  51. honeybee_schema/validation.py +205 -0
  52. honeybee_schema-1.59.1.dist-info/METADATA +108 -0
  53. honeybee_schema-1.59.1.dist-info/RECORD +57 -0
  54. honeybee_schema-1.59.1.dist-info/WHEEL +5 -0
  55. honeybee_schema-1.59.1.dist-info/entry_points.txt +2 -0
  56. honeybee_schema-1.59.1.dist-info/licenses/LICENSE +23 -0
  57. honeybee_schema-1.59.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,4 @@
1
+ from honeybee_schema.cli import main
2
+
3
+ if __name__ == '__main__':
4
+ main()
@@ -0,0 +1,42 @@
1
+ """Base class for all objects requiring a valid names for all engines."""
2
+ from pydantic import BaseModel, Field, Extra
3
+
4
+
5
+ class NoExtraBaseModel(BaseModel):
6
+ """Base class for all objects that are not extensible with additional keys.
7
+
8
+ This effectively includes all objects except for the Properties classes
9
+ that are assigned to geometry objects.
10
+ """
11
+
12
+ class Config:
13
+ extra = Extra.forbid
14
+
15
+
16
+ class IDdBaseModel(NoExtraBaseModel):
17
+ """Base class for all objects requiring a identifiers acceptable for all engines."""
18
+
19
+ identifier: str = Field(
20
+ ...,
21
+ regex=r'^[.A-Za-z0-9_-]+$',
22
+ min_length=1,
23
+ max_length=100,
24
+ description='Text string for a unique object ID. This identifier remains '
25
+ 'constant as the object is mutated, copied, and serialized to different '
26
+ 'formats (eg. dict, idf, rad). This identifier is also used to reference '
27
+ 'the object across a Model. It must be < 100 characters and not contain '
28
+ 'any spaces or special characters.'
29
+ )
30
+
31
+ display_name: str = Field(
32
+ default=None,
33
+ description='Display name of the object with no character restrictions.'
34
+ )
35
+
36
+ user_data: dict = Field(
37
+ default=None,
38
+ description='Optional dictionary of user data associated with the object.'
39
+ 'All keys and values of this dictionary should be of a standard data '
40
+ 'type to ensure correct serialization of the object (eg. str, float, '
41
+ 'int, list).'
42
+ )
@@ -0,0 +1,18 @@
1
+ """Objects used as alternatives to numerical properties."""
2
+ from pydantic import constr
3
+ from ._base import NoExtraBaseModel
4
+
5
+
6
+ class NoLimit(NoExtraBaseModel):
7
+
8
+ type: constr(regex='^NoLimit$') = 'NoLimit'
9
+
10
+
11
+ class Autocalculate(NoExtraBaseModel):
12
+
13
+ type: constr(regex='^Autocalculate$') = 'Autocalculate'
14
+
15
+
16
+ class Autosize(NoExtraBaseModel):
17
+
18
+ type: constr(regex='^Autosize$') = 'Autosize'
@@ -0,0 +1,81 @@
1
+ """Boundary condition schemas."""
2
+ from pydantic import Field, constr
3
+ from typing import List, Union
4
+
5
+ from ._base import NoExtraBaseModel
6
+ from .altnumber import Autocalculate
7
+
8
+
9
+ class Outdoors(NoExtraBaseModel):
10
+
11
+ type: constr(regex='^Outdoors$') = 'Outdoors'
12
+
13
+ sun_exposure: bool = Field(
14
+ True,
15
+ description='A boolean noting whether the boundary is exposed to sun.'
16
+ )
17
+
18
+ wind_exposure: bool = Field(
19
+ True,
20
+ description='A boolean noting whether the boundary is exposed to wind.'
21
+ )
22
+
23
+ view_factor: Union[Autocalculate, float] = Field(
24
+ Autocalculate(),
25
+ ge=0,
26
+ le=1,
27
+ description='A number for the view factor to the ground. This can also be '
28
+ 'an Autocalculate object to have the view factor automatically calculated.'
29
+ )
30
+
31
+
32
+ class Surface(NoExtraBaseModel):
33
+
34
+ type: constr(regex='^Surface$') = 'Surface'
35
+
36
+ boundary_condition_objects: List[str] = Field(
37
+ ...,
38
+ min_items=2,
39
+ max_items=3,
40
+ description='A list of up to 3 object identifiers that are adjacent to this one.'
41
+ ' The first object is always the one that is immediately adjacent and is of '
42
+ 'the same object type (Face, Aperture, Door). When this boundary condition '
43
+ 'is applied to a Face, the second object in the tuple will be the parent '
44
+ 'Room of the adjacent object. When the boundary condition is applied to a '
45
+ 'sub-face (Door or Aperture), the second object will be the parent Face '
46
+ 'of the adjacent sub-face and the third object will be the parent Room '
47
+ 'of the adjacent sub-face.'
48
+ )
49
+
50
+
51
+ class Ground(NoExtraBaseModel):
52
+
53
+ type: constr(regex='^Ground$') = 'Ground'
54
+
55
+
56
+ class Adiabatic(NoExtraBaseModel):
57
+
58
+ type: constr(regex='^Adiabatic$') = 'Adiabatic'
59
+
60
+
61
+ class OtherSideTemperature(NoExtraBaseModel):
62
+
63
+ type: constr(regex='^OtherSideTemperature$') = 'OtherSideTemperature'
64
+
65
+ heat_transfer_coefficient: float = Field(
66
+ 0,
67
+ ge=0,
68
+ description='A value in W/m2-K to indicate the combined convective/radiative '
69
+ 'film coefficient. If equal to 0, then the specified temperature above is '
70
+ 'equal to the exterior surface temperature. Otherwise, the temperature above '
71
+ 'is considered the outside air temperature and this coefficient is used to '
72
+ 'determine the difference between this outside air temperature and the '
73
+ 'exterior surface temperature.'
74
+ )
75
+
76
+ temperature: Union[Autocalculate, float] = Field(
77
+ Autocalculate(),
78
+ description='A temperature value in Celsius to note the temperature on the '
79
+ 'other side of the object. This input can also be an Autocalculate object '
80
+ 'to signify that the temperature is equal to the outdoor air temperature.'
81
+ )
honeybee_schema/cli.py ADDED
@@ -0,0 +1,115 @@
1
+ """Command Line Interface (CLI) entry point for honeybee schema."""
2
+
3
+ try:
4
+ import click
5
+ except ImportError:
6
+ raise ImportError(
7
+ 'click module is not installed. Try `pip install honeybee-schema[cli]` command.'
8
+ )
9
+
10
+ import sys
11
+ import logging
12
+ import json
13
+ import importlib
14
+ from inspect import getmembers, isfunction
15
+ import pkgutil
16
+
17
+ from honeybee_schema import updater
18
+
19
+
20
+ @click.group()
21
+ @click.version_option()
22
+ def main():
23
+ pass
24
+
25
+
26
+ _logger = logging.getLogger(__name__)
27
+
28
+
29
+ @main.command('update-model')
30
+ @click.argument('model-json', type=click.Path(
31
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
32
+ @click.option('--version', '-v', help='Text to indicate the version to which the model '
33
+ 'JSON will be updated (eg. 1.41.2). Versions must always consist of '
34
+ 'three integers separated b periods. If None, the Model JSON will '
35
+ 'be updated to the last release that included a breaking change.',
36
+ type=str, default=None)
37
+ @click.option('--output-file', help='Optional file to output the JSON string of '
38
+ 'the config object. By default, it will be printed out to stdout',
39
+ type=click.File('w'), default='-', show_default=True)
40
+ def update_model(model_json, version, output_file):
41
+ """Update a Honeybee Model JSON to a newer version of honeybee-schema.
42
+
43
+ \b
44
+ Args:
45
+ model_json: Full path to a Model JSON file.
46
+ """
47
+ try:
48
+ # get the version to which the model will be updated
49
+ up_version = (999, 999, 999) if version is None else \
50
+ tuple(int(v) for v in version.split('.'))
51
+
52
+ # load the model dictionary from the json file and get the version of it
53
+ with open(model_json) as json_file:
54
+ model_dict = json.load(json_file)
55
+ assert 'version' in model_dict, 'No version was found in the input model ' \
56
+ 'JSON. Update process cannot be run.'
57
+ print(f'Input model version: {model_dict["version"]}', file=sys.stderr)
58
+ model_version = tuple(int(v) for v in model_dict['version'].split('.'))
59
+
60
+ if model_version >= up_version:
61
+ # no point for updating. Normally we should assert here but by writing
62
+ # the same file to a new file we make this command more flexible for cases
63
+ # that we don't know the version for the input model and we want to update
64
+ # it just in case.
65
+ mv = '.'.join(map(str, model_version))
66
+ uv = '.'.join(map(str, up_version))
67
+ print(
68
+ f'The input file has a higher version ({mv}) than the target version'
69
+ f' ({uv}).', file=sys.stderr
70
+ )
71
+ output_file.write(json.dumps(model_dict))
72
+ # let's consider exporting the same file as success
73
+ sys.exit(0)
74
+
75
+ # get functions with a higher version than model_version
76
+ updaters = []
77
+
78
+ for sub_module in pkgutil.walk_packages(updater.__path__):
79
+ if not sub_module.name.startswith('version_'):
80
+ continue
81
+ module = importlib.import_module(f'honeybee_schema.updater.{sub_module.name}')
82
+ for name, func in getmembers(module, isfunction):
83
+ if not name.startswith('version_'):
84
+ continue
85
+ func_version = tuple(int(v) for v in name.split('_')[1:])
86
+ if model_version > func_version or func_version > up_version:
87
+ continue
88
+ updaters.append((func_version, func))
89
+
90
+ # sort updaters based on version
91
+ updaters = sorted(updaters, key=lambda x: x[0])
92
+
93
+ # update the dictionary
94
+ for func_version, up_func in updaters:
95
+ print(
96
+ f'Updating to version {".".join(map(str, func_version))}',
97
+ file=sys.stderr
98
+ )
99
+ model_dict = up_func(model_dict)
100
+
101
+ # update the model dictionary version and write it to log file
102
+ if version:
103
+ model_dict['version'] = version
104
+ elif updaters:
105
+ model_dict['version'] = '.'.join((str(i) for i in updaters[-1][0]))
106
+ output_file.write(json.dumps(model_dict))
107
+ except Exception as e:
108
+ _logger.exception('Failed to update Honeybee Model JSON.\n{}'.format(e))
109
+ sys.exit(1)
110
+ else:
111
+ sys.exit(0)
112
+
113
+
114
+ if __name__ == "__main__":
115
+ main()
@@ -0,0 +1,208 @@
1
+ """Schema for the comparison object returned by the comparison command"""
2
+ from pydantic import BaseModel, Field, constr
3
+ from typing import List
4
+ from enum import Enum
5
+
6
+
7
+ class GeometryObjectTypes(str, Enum):
8
+ """Types of Honeybee geometry objects."""
9
+ shade = 'Shade'
10
+ aperture = 'Aperture'
11
+ door = 'Door'
12
+ face = 'Face'
13
+ room = 'Room'
14
+
15
+
16
+ class _DiffObjectBase(BaseModel):
17
+
18
+ element_type: GeometryObjectTypes = Field(
19
+ ...,
20
+ description='Text for the type of object that has been changed.'
21
+ )
22
+
23
+ element_id: str = Field(
24
+ ...,
25
+ regex=r'^[^,;!\n\t]+$',
26
+ min_length=1,
27
+ max_length=100,
28
+ description='Text string for the unique object ID that has changed.'
29
+ )
30
+
31
+ element_name: str = Field(
32
+ None,
33
+ description='Text string for the display name of the object that has changed.'
34
+ )
35
+
36
+
37
+ class ChangedObject(_DiffObjectBase):
38
+
39
+ type: constr(regex='^ChangedObject$') = 'ChangedObject'
40
+
41
+ geometry_changed: bool = Field(
42
+ ...,
43
+ description='A boolean to note whether the geometry of the object has changed '
44
+ '(True) or not (False). For the case of a Room, any change in the geometry of '
45
+ 'child Faces, Apertures or Doors will cause this property to be True. Note that '
46
+ 'this property is only True if the change in geometry produces a visible '
47
+ 'change greater than the base model tolerance. So converting the model '
48
+ 'between different unit systems, removing colinear vertices, or doing '
49
+ 'other transformations that are common for export to simulation engines '
50
+ 'will not trigger this property to become True.'
51
+ )
52
+
53
+ energy_changed: bool = Field(
54
+ False,
55
+ description='A boolean to note whether the energy properties of the object '
56
+ 'have changed (True) or not (False) such that it is possible for the '
57
+ 'properties of the changed object to be applied to the base model. '
58
+ 'For Rooms, this property will only be true if the energy property '
59
+ 'assigned to the Room has changed and will not be true if a property '
60
+ 'assigned to an individual child Face or Aperture has changed.'
61
+ )
62
+
63
+ radiance_changed: bool = Field(
64
+ False,
65
+ description='A boolean to note whether the radiance properties of the object '
66
+ 'have changed (True) or not (False) such that it is possible for the '
67
+ 'properties of the changed object to be applied to the base model. '
68
+ 'For Rooms, this property will only be true if the radiance property '
69
+ 'assigned to the Room has changed and will not be true if a property '
70
+ 'assigned to an individual child Face or Aperture has changed.'
71
+ )
72
+
73
+ geometry: List[dict] = Field(
74
+ ...,
75
+ description='A list of DisplayFace3D dictionaries for the new, changed '
76
+ 'geometry. The schema of DisplayFace3D can be found in the ladybug-display-'
77
+ 'schema documentation (https://www.ladybug.tools/ladybug-display-schema) '
78
+ 'and these objects can be used to generate visualizations of individual '
79
+ 'objects that have been changed. Note that this attribute is always '
80
+ 'included in the ChangedObject, even when geometry_changed is False.'
81
+ )
82
+
83
+ existing_geometry: List[dict] = Field(
84
+ default=None,
85
+ description='A list of DisplayFace3D dictionaries for the existing (base) '
86
+ 'geometry. The schema of DisplayFace3D can be found in the ladybug-display-'
87
+ 'schema documentation (https://www.ladybug.tools/ladybug-display-schema) '
88
+ 'and these objects can be used to generate visualizations of individual '
89
+ 'objects that have been changed. This attribute is optional and will '
90
+ 'NOT be output if geometry_changed is False.'
91
+ )
92
+
93
+
94
+ class DeletedObject(_DiffObjectBase):
95
+
96
+ type: constr(regex='^DeletedObject$') = 'DeletedObject'
97
+
98
+ geometry: List[dict] = Field(
99
+ ...,
100
+ description='A list of DisplayFace3D dictionaries for the deleted '
101
+ 'geometry. The schema of DisplayFace3D can be found in the ladybug-display-'
102
+ 'schema documentation (https://www.ladybug.tools/ladybug-display-schema) '
103
+ 'and these objects can be used to generate visualizations of individual '
104
+ 'objects that have been deleted.'
105
+ )
106
+
107
+
108
+ class AddedObject(_DiffObjectBase):
109
+
110
+ type: constr(regex='^AddedObject$') = 'AddedObject'
111
+
112
+ geometry: List[dict] = Field(
113
+ ...,
114
+ description='A list of DisplayFace3D dictionaries for the added '
115
+ 'geometry. The schema of DisplayFace3D can be found in the ladybug-display-'
116
+ 'schema documentation (https://www.ladybug.tools/ladybug-display-schema) '
117
+ 'and these objects can be used to generate visualizations of individual '
118
+ 'objects that have been added.'
119
+ )
120
+
121
+
122
+ class ComparisonReport(BaseModel):
123
+
124
+ type: constr(regex='^ComparisonReport$') = 'ComparisonReport'
125
+
126
+ changed_objects: List[ChangedObject] = Field(
127
+ default=None,
128
+ description='A list of ChangedObject definitions for each top-level object '
129
+ 'that has changed in the model. To be a changed object, the object identifier '
130
+ 'must be the same in both models but some other property (either geometry '
131
+ 'or extension attributes) has experienced a meaningful change.'
132
+ )
133
+
134
+ deleted_objects: List[DeletedObject] = Field(
135
+ default=None,
136
+ description='A list of DeletedObject definitions for each top-level object '
137
+ 'that has been deleted in the process of going from the base model to the '
138
+ 'new model.'
139
+ )
140
+
141
+ added_objects: List[AddedObject] = Field(
142
+ default=None,
143
+ description='A list of AddedObject definitions for each top-level object '
144
+ 'that has been added in the process of going from the base model to the '
145
+ 'new model.'
146
+ )
147
+
148
+
149
+ class ChangedInstruction(_DiffObjectBase):
150
+
151
+ type: constr(regex='^ChangedInstruction$') = 'ChangedInstruction'
152
+
153
+ update_geometry: bool = Field(
154
+ True,
155
+ description='A boolean to note whether the geometry of the object in the '
156
+ 'new/updated model should replace the base/existing geometry (True) or '
157
+ 'the existing geometry should be kept (False).'
158
+ )
159
+
160
+ update_energy: bool = Field(
161
+ True,
162
+ description='A boolean to note whether the energy properties of the '
163
+ 'object in the new/updated model should replace the base/existing energy '
164
+ 'properties (True) or the base/existing energy properties should '
165
+ 'be kept (False).'
166
+ )
167
+
168
+ update_radiance: bool = Field(
169
+ True,
170
+ description='A boolean to note whether the radiance properties of the '
171
+ 'object in the new/updated model should replace the base/existing radiance '
172
+ 'properties (True) or the base/existing radiance properties should '
173
+ 'be kept (False).'
174
+ )
175
+
176
+
177
+ class DeletedInstruction(_DiffObjectBase):
178
+
179
+ type: constr(regex='^DeletedInstruction$') = 'DeletedInstruction'
180
+
181
+
182
+ class AddedInstruction(_DiffObjectBase):
183
+
184
+ type: constr(regex='^AddedInstruction$') = 'AddedInstruction'
185
+
186
+
187
+ class SyncInstructions(BaseModel):
188
+
189
+ type: constr(regex='^SyncInstructions$') = 'SyncInstructions'
190
+
191
+ changed_objects: List[ChangedInstruction] = Field(
192
+ default=None,
193
+ description='A list of ChangedInstruction definitions for each top-level '
194
+ 'object with properties to transfer from the new/updated model to the '
195
+ 'base/existing model.'
196
+ )
197
+
198
+ deleted_objects: List[DeletedInstruction] = Field(
199
+ default=None,
200
+ description='A list of DeletedInstruction definitions for each top-level object '
201
+ 'to be deleted from the base/existing model.'
202
+ )
203
+
204
+ added_objects: List[AddedInstruction] = Field(
205
+ default=None,
206
+ description='A list of AddedInstruction definitions for each top-level object '
207
+ 'to be added to the base/existing model from the new/updated model.'
208
+ )
File without changes
@@ -0,0 +1,75 @@
1
+ """Model DOE-2 properties."""
2
+ from pydantic import Field, constr
3
+ from typing import Union
4
+
5
+ from .._base import NoExtraBaseModel
6
+ from ..altnumber import Autocalculate
7
+ from ..geometry import Face3D
8
+
9
+
10
+ class RoomDoe2Properties(NoExtraBaseModel):
11
+
12
+ type: constr(regex='^RoomDoe2Properties$') = \
13
+ 'RoomDoe2Properties'
14
+
15
+ assigned_flow: Union[Autocalculate, float] = Field(
16
+ Autocalculate(),
17
+ ge=0,
18
+ description='A number for the design supply air flow rate for the zone '
19
+ 'the Room is assigned to (cfm). This establishes the minimum allowed '
20
+ 'design air flow. Note that the actual design flow may be larger. If '
21
+ 'Autocalculate, this parameter will not be written into the INP.'
22
+ )
23
+
24
+ flow_per_area: Union[Autocalculate, float] = Field(
25
+ Autocalculate(),
26
+ ge=0,
27
+ description='A number for the design supply air flow rate to the zone '
28
+ 'per unit floor area (cfm/ft2). If Autocalculate, this parameter will '
29
+ 'not be written into the INP.'
30
+ )
31
+
32
+ min_flow_ratio: Union[Autocalculate, float] = Field(
33
+ Autocalculate(),
34
+ ge=0,
35
+ le=1,
36
+ description='A number between 0 and 1 for the minimum allowable zone '
37
+ 'air supply flow rate, expressed as a fraction of design flow rate. Applicable '
38
+ 'to variable-volume type systems only. If Autocalculate, this parameter will '
39
+ 'not be written into the INP.'
40
+ )
41
+
42
+ min_flow_per_area: Union[Autocalculate, float] = Field(
43
+ Autocalculate(),
44
+ ge=0,
45
+ description='A number for the minimum air flow per square foot of '
46
+ 'floor area (cfm/ft2). This is an alternative way of specifying the '
47
+ 'min_flow_ratio. If Autocalculate, this parameter will not be written '
48
+ 'into the INP.'
49
+ )
50
+
51
+ hmax_flow_ratio: Union[Autocalculate, float] = Field(
52
+ Autocalculate(),
53
+ ge=0,
54
+ le=1,
55
+ description='A number between 0 and 1 for the ratio of the maximum (or fixed) '
56
+ 'heating airflow to the cooling airflow. The specific meaning varies according '
57
+ 'to the type of zone terminal. If Autocalculate, this parameter will '
58
+ 'not be written into the INP.'
59
+ )
60
+
61
+ space_polygon_geometry: Face3D = Field(
62
+ default=None,
63
+ description='An optional horizontal Face3D object, which will '
64
+ 'be used to set the SPACE polygon during export to INP. If None, '
65
+ 'the SPACE polygon is auto-calculated from the 3D Room geometry. '
66
+ 'Specifying a geometry here can help overcome some limitations of '
67
+ 'this auto-calculation, particularly for cases where the floors '
68
+ 'of the Room are composed of AirBoundaries.'
69
+ )
70
+
71
+
72
+ class ModelDoe2Properties(NoExtraBaseModel):
73
+
74
+ type: constr(regex='^ModelDoe2Properties$') = \
75
+ 'ModelDoe2Properties'
File without changes
@@ -0,0 +1,64 @@
1
+ """Base class used by various schema objects."""
2
+ from pydantic import Field
3
+ import datetime
4
+
5
+ from .._base import NoExtraBaseModel
6
+
7
+
8
+ class EnergyBaseModel(NoExtraBaseModel):
9
+ """Base class for all objects requiring a valid EnergyPlus identifier."""
10
+
11
+ identifier: str = Field(
12
+ ...,
13
+ regex=r'^[^,;!\n\t]+$',
14
+ min_length=1,
15
+ max_length=100,
16
+ description='Text string for a unique object ID. This identifier remains '
17
+ 'constant as the object is mutated, copied, and serialized to different '
18
+ 'formats (eg. dict, idf, osm). This identifier is also used to reference '
19
+ 'the object across a Model. It must be < 100 characters, use only '
20
+ 'ASCII characters and exclude (, ; ! \\n \\t).'
21
+ )
22
+
23
+ display_name: str = Field(
24
+ default=None,
25
+ description='Display name of the object with no character restrictions.'
26
+ )
27
+
28
+
29
+ class IDdEnergyBaseModel(EnergyBaseModel):
30
+ """Base class for all objects requiring an EnergyPlus identifier and user_data."""
31
+
32
+ user_data: dict = Field(
33
+ default=None,
34
+ description='Optional dictionary of user data associated with the object.'
35
+ 'All keys and values of this dictionary should be of a standard data '
36
+ 'type to ensure correct serialization of the object (eg. str, float, '
37
+ 'int, list).'
38
+ )
39
+
40
+
41
+ class DatedBaseModel(NoExtraBaseModel):
42
+ """Base class for all objects needing to check for a valid Date."""
43
+
44
+ @staticmethod
45
+ def check_date(v, leap_pear_override=None):
46
+ """Ensure valid date.
47
+
48
+ Args:
49
+ v: The Date array to be validated.
50
+ leap_pear_override: Boolean to override the typical check for
51
+ leap year serialization of date arrays. If not None, this
52
+ boolean wil dictate whether the date is a leap year or not.
53
+ """
54
+ if (len(v) == 3 and v[2]) or leap_pear_override:
55
+ try:
56
+ datetime.date(2016, v[0], v[1])
57
+ except ValueError:
58
+ raise ValueError('{}/{} is not a valid date.'.format(v[0], v[1]))
59
+ else:
60
+ try:
61
+ datetime.date(2017, v[0], v[1])
62
+ except ValueError:
63
+ raise ValueError('{}/{} is not a valid date.'.format(v[0], v[1]))
64
+ return v