honeybee-core 1.64.12__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.
- honeybee/__init__.py +23 -0
- honeybee/__main__.py +4 -0
- honeybee/_base.py +331 -0
- honeybee/_basewithshade.py +310 -0
- honeybee/_lockable.py +99 -0
- honeybee/altnumber.py +47 -0
- honeybee/aperture.py +997 -0
- honeybee/boundarycondition.py +358 -0
- honeybee/checkdup.py +173 -0
- honeybee/cli/__init__.py +118 -0
- honeybee/cli/compare.py +132 -0
- honeybee/cli/create.py +265 -0
- honeybee/cli/edit.py +559 -0
- honeybee/cli/lib.py +103 -0
- honeybee/cli/setconfig.py +43 -0
- honeybee/cli/validate.py +224 -0
- honeybee/colorobj.py +363 -0
- honeybee/config.json +5 -0
- honeybee/config.py +347 -0
- honeybee/dictutil.py +54 -0
- honeybee/door.py +746 -0
- honeybee/extensionutil.py +208 -0
- honeybee/face.py +2360 -0
- honeybee/facetype.py +153 -0
- honeybee/logutil.py +79 -0
- honeybee/model.py +4272 -0
- honeybee/orientation.py +132 -0
- honeybee/properties.py +845 -0
- honeybee/room.py +3485 -0
- honeybee/search.py +107 -0
- honeybee/shade.py +514 -0
- honeybee/shademesh.py +362 -0
- honeybee/typing.py +498 -0
- honeybee/units.py +88 -0
- honeybee/writer/__init__.py +7 -0
- honeybee/writer/aperture.py +6 -0
- honeybee/writer/door.py +6 -0
- honeybee/writer/face.py +6 -0
- honeybee/writer/model.py +6 -0
- honeybee/writer/room.py +6 -0
- honeybee/writer/shade.py +6 -0
- honeybee/writer/shademesh.py +6 -0
- honeybee_core-1.64.12.dist-info/METADATA +94 -0
- honeybee_core-1.64.12.dist-info/RECORD +48 -0
- honeybee_core-1.64.12.dist-info/WHEEL +5 -0
- honeybee_core-1.64.12.dist-info/entry_points.txt +2 -0
- honeybee_core-1.64.12.dist-info/licenses/LICENSE +661 -0
- honeybee_core-1.64.12.dist-info/top_level.txt +1 -0
honeybee/facetype.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Face Types."""
|
|
2
|
+
from ladybug_geometry.geometry3d.pointvector import Vector3D
|
|
3
|
+
import re
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class _FaceType(object):
|
|
8
|
+
__slots__ = ()
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def name(self):
|
|
15
|
+
return self.__class__.__name__
|
|
16
|
+
|
|
17
|
+
def ToString(self):
|
|
18
|
+
return self.__repr__()
|
|
19
|
+
|
|
20
|
+
def __eq__(self, other):
|
|
21
|
+
return self.__class__ == other.__class__
|
|
22
|
+
|
|
23
|
+
def __ne__(self, other):
|
|
24
|
+
return not self.__eq__(other)
|
|
25
|
+
|
|
26
|
+
def __repr__(self):
|
|
27
|
+
return self.name
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Wall(_FaceType):
|
|
31
|
+
"""Type for walls."""
|
|
32
|
+
__slots__ = ()
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class RoofCeiling(_FaceType):
|
|
37
|
+
"""Type for roofs and ceilings."""
|
|
38
|
+
__slots__ = ()
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Floor(_FaceType):
|
|
43
|
+
"""Type for floors."""
|
|
44
|
+
__slots__ = ()
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class AirBoundary(_FaceType):
|
|
49
|
+
"""Type for air boundaries (aka. virtual partitions) between Rooms."""
|
|
50
|
+
__slots__ = ()
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _FaceTypes(object):
|
|
55
|
+
"""Face types."""
|
|
56
|
+
|
|
57
|
+
def __init__(self):
|
|
58
|
+
self._wall = Wall()
|
|
59
|
+
self._roof_ceiling = RoofCeiling()
|
|
60
|
+
self._floor = Floor()
|
|
61
|
+
self._air_boundary = AirBoundary()
|
|
62
|
+
self._type_name_dict = None
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def wall(self):
|
|
66
|
+
return self._wall
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def roof_ceiling(self):
|
|
70
|
+
return self._roof_ceiling
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def floor(self):
|
|
74
|
+
return self._floor
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def air_boundary(self):
|
|
78
|
+
return self._air_boundary
|
|
79
|
+
|
|
80
|
+
def by_name(self, face_type_name):
|
|
81
|
+
"""Get a Face Type instance from its name.
|
|
82
|
+
|
|
83
|
+
This method will correct for capitalization as well as the presence of
|
|
84
|
+
spaces and underscores.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
face_type_name: A text string for the face type (eg. "Wall").
|
|
88
|
+
"""
|
|
89
|
+
if self._type_name_dict is None:
|
|
90
|
+
self._build_type_name_dict()
|
|
91
|
+
try:
|
|
92
|
+
return self._type_name_dict[re.sub(r'[\s_]', '', face_type_name.lower())]
|
|
93
|
+
except KeyError:
|
|
94
|
+
raise ValueError(
|
|
95
|
+
'"{}" is not a valid face type name.\nChoose from the following'
|
|
96
|
+
': {}'.format(face_type_name, list(self._type_name_dict.keys())))
|
|
97
|
+
|
|
98
|
+
def _build_type_name_dict(self):
|
|
99
|
+
"""Build a dictionary that can be used to lookup face types by name."""
|
|
100
|
+
attr = [atr for atr in dir(self) if not atr.startswith('_')]
|
|
101
|
+
clean_attr = [re.sub(r'[\s_]', '', atr.lower()) for atr in attr]
|
|
102
|
+
self._type_name_dict = {}
|
|
103
|
+
for atr_name, atr in zip(clean_attr, attr):
|
|
104
|
+
try:
|
|
105
|
+
full_attr = getattr(self, '_' + atr)
|
|
106
|
+
self._type_name_dict[atr_name] = full_attr
|
|
107
|
+
except AttributeError:
|
|
108
|
+
pass # callable method that has no static default object
|
|
109
|
+
|
|
110
|
+
def __contains__(self, value):
|
|
111
|
+
return isinstance(value, _FaceType)
|
|
112
|
+
|
|
113
|
+
def __repr__(self):
|
|
114
|
+
attr = [atr for atr in dir(self) if not atr.startswith('_') and atr != 'by_name']
|
|
115
|
+
return 'Face Types:\n{}'.format('\n'.join(attr))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
face_types = _FaceTypes()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_type_from_normal(normal_vector, roof_angle=60, floor_angle=130):
|
|
122
|
+
"""Return face type based on the angle between Z axis and normal vector.
|
|
123
|
+
|
|
124
|
+
Angles between 0 and roof_angle will be set to roof_ceiling.
|
|
125
|
+
Angles between roof_angle and floor_angle will be set to wall.
|
|
126
|
+
Angles larger than floor angle will be set to floor.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
normal_vector: Normal vector as a ladybug_geometry Vector3D.
|
|
130
|
+
roof_angle: A number between 0 and 90 to set the angle from the horizontal
|
|
131
|
+
plane below which faces will be considered roofs instead of
|
|
132
|
+
walls. 90 indicates that all vertical faces are roofs and 0
|
|
133
|
+
indicates that all horizontal faces are walls. (Default: 60,
|
|
134
|
+
recommended by the ASHRAE 90.1 standard).
|
|
135
|
+
floor_angle: A number between 90 and 180 to set the angle from the horizontal
|
|
136
|
+
plane above which faces will be considered floors instead of
|
|
137
|
+
walls. 180 indicates that all vertical faces are floors and 0
|
|
138
|
+
indicates that all horizontal faces are walls. (Default: 130,
|
|
139
|
+
recommended by the ASHRAE 90.1 standard).
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Face type instance.
|
|
143
|
+
"""
|
|
144
|
+
z_axis = Vector3D(0, 0, 1)
|
|
145
|
+
angle = math.degrees(z_axis.angle(normal_vector))
|
|
146
|
+
if angle < roof_angle:
|
|
147
|
+
return face_types.roof_ceiling
|
|
148
|
+
elif roof_angle <= angle < floor_angle:
|
|
149
|
+
return face_types.wall
|
|
150
|
+
else:
|
|
151
|
+
return face_types.floor
|
|
152
|
+
|
|
153
|
+
return face_types.wall
|
honeybee/logutil.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
3
|
+
import os
|
|
4
|
+
import tempfile
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# This is copied from logging module since python 2 doesn't have it under the same name.
|
|
8
|
+
CRITICAL = 50
|
|
9
|
+
FATAL = CRITICAL
|
|
10
|
+
ERROR = 40
|
|
11
|
+
WARNING = 30
|
|
12
|
+
WARN = WARNING
|
|
13
|
+
INFO = 20
|
|
14
|
+
DEBUG = 10
|
|
15
|
+
NOTSET = 0
|
|
16
|
+
|
|
17
|
+
_name_to_level = {
|
|
18
|
+
'CRITICAL': CRITICAL,
|
|
19
|
+
'FATAL': FATAL,
|
|
20
|
+
'ERROR': ERROR,
|
|
21
|
+
'WARN': WARNING,
|
|
22
|
+
'WARNING': WARNING,
|
|
23
|
+
'INFO': INFO,
|
|
24
|
+
'DEBUG': DEBUG,
|
|
25
|
+
'NOTSET': NOTSET,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_log_folder():
|
|
30
|
+
home_folder = os.getenv('HOME') or os.path.expanduser('~')
|
|
31
|
+
if not os.access(home_folder, os.W_OK):
|
|
32
|
+
home_folder = tempfile.gettempdir()
|
|
33
|
+
log_folder = os.path.join(home_folder, '.honeybee')
|
|
34
|
+
if not os.path.isdir(log_folder):
|
|
35
|
+
try:
|
|
36
|
+
os.mkdir(log_folder)
|
|
37
|
+
except OSError as e:
|
|
38
|
+
if e.errno != 17: # avoid race conditions between multiple tasks
|
|
39
|
+
raise OSError('Failed to create log folder: %s\n%s' % (log_folder, e))
|
|
40
|
+
return log_folder
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_log_level(level):
|
|
44
|
+
level = _name_to_level.get(level)
|
|
45
|
+
return level or logging.INFO
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_logger(name, filename='honeybee.log', file_log_level='DEBUG',
|
|
49
|
+
console_log_level='WARNING'):
|
|
50
|
+
"""Get a logger to be used for each module.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
name: Logger name. The good practice is to set it to __init__ from inside each
|
|
54
|
+
modules.
|
|
55
|
+
filename: Logger filename.Setting filename to None will remove the file handler
|
|
56
|
+
(Default: honeybee.log).
|
|
57
|
+
file_log_level: Log level for file handler as a string (Default: DEBUG).
|
|
58
|
+
console_log_level: Log level for stream handler as a string (Default: WARNING).
|
|
59
|
+
"""
|
|
60
|
+
logger = logging.getLogger(name)
|
|
61
|
+
|
|
62
|
+
# create a file handler to log debug and higher level logs
|
|
63
|
+
if filename:
|
|
64
|
+
log_file = os.path.join(_get_log_folder(), filename)
|
|
65
|
+
file_handler = TimedRotatingFileHandler(log_file, when='midnight')
|
|
66
|
+
file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
67
|
+
file_handler.setFormatter(file_format)
|
|
68
|
+
file_handler.setLevel(_get_log_level(file_log_level))
|
|
69
|
+
logger.addHandler(file_handler)
|
|
70
|
+
|
|
71
|
+
# create a console handler that only prints out errors and warnings
|
|
72
|
+
stream_handler = logging.StreamHandler()
|
|
73
|
+
stream_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
|
|
74
|
+
stream_handler.setFormatter(stream_format)
|
|
75
|
+
stream_handler.setLevel(_get_log_level(console_log_level))
|
|
76
|
+
|
|
77
|
+
logger.addHandler(stream_handler)
|
|
78
|
+
|
|
79
|
+
return logger
|