idfpy 25.2.2__tar.gz → 25.2.3__tar.gz
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.
- {idfpy-25.2.2 → idfpy-25.2.3}/PKG-INFO +1 -1
- idfpy-25.2.3/idfpy/ext/construction/__init__.py +7 -0
- idfpy-25.2.3/idfpy/ext/construction/functions.py +78 -0
- idfpy-25.2.3/idfpy/ext/construction/mixins.py +38 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/constructions.py +3 -1
- {idfpy-25.2.2 → idfpy-25.2.3}/pyproject.toml +1 -1
- idfpy-25.2.3/tests/test_ext_construction.py +136 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/.github/workflows/publish-pypi.yml +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/.github/workflows/release-version.yml +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/.github/workflows/sync-energyplus.yml +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/.gitignore +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/.vscode/launch.json +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/LICENSE +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/README.md +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/benchmarks/bench_idf.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/__main__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/cli.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/field_parser.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/model_generator.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/schema_parser.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/template_filters.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/templates/idf_model_py.jinja2 +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/templates/init_py.jinja2 +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/templates/init_pyi.jinja2 +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/templates/ref_meta_py.jinja2 +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/codegen/templates/refs_py.jinja2 +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/ext/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/ext/geometry/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/ext/geometry/functions.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/ext/geometry/mixins.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/idf.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/__init__.pyi +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/_base.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/_errors.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/_metadata.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/_ref_meta.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/_refs.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/advanced_construction.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/air_distribution.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/availability_managers.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/coils.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/condensers.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/curves.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/daylighting.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/demand_limiting.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/economics.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/electric_load.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/ems.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/evap_coolers.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/external_interface.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/fans.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/faults.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/fluids.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/hvac_design.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/hvac_templates.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/internal_gains.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/location.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/misc.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/node_branch.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/outputs.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/plant_control.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/plant_equipment.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/pumps.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/python_plugins.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/refrigeration.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/room_air.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/schedules.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/setpoint_managers.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/simulation.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/solar.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/thermal_zones.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/unitary.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/user_defined.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/water_heaters.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/water_systems.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_airflow.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_controls.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_equipment.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_forced_air.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_radiative.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/models/zone_terminals.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/py.typed +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/sim/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/sim/_runner.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/sim/config.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/idfpy/sim/result.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/__init__.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test.idf +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_api_unification.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_epjson_doe.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_ext.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_merge_dict.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_metadata.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_models.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_ref_system.py +0 -0
- {idfpy-25.2.2 → idfpy-25.2.3}/tests/test_typing_check.py +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Material classification and layer resolution for layered constructions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Final
|
|
6
|
+
|
|
7
|
+
from idfpy.models.constructions import (
|
|
8
|
+
WindowMaterialBlind,
|
|
9
|
+
WindowMaterialGas,
|
|
10
|
+
WindowMaterialGasMixture,
|
|
11
|
+
WindowMaterialGlazing,
|
|
12
|
+
WindowMaterialGlazingGroupThermochromic,
|
|
13
|
+
WindowMaterialGlazingRefractionExtinctionMethod,
|
|
14
|
+
WindowMaterialScreen,
|
|
15
|
+
WindowMaterialShade,
|
|
16
|
+
WindowMaterialSimpleGlazingSystem,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from idfpy.models._base import IDFBaseModel
|
|
21
|
+
from idfpy.models.constructions import Construction
|
|
22
|
+
|
|
23
|
+
# Window-material layer types accepted by ``Construction`` layer fields.
|
|
24
|
+
WINDOW_MATERIAL_TYPES: Final = (
|
|
25
|
+
WindowMaterialBlind,
|
|
26
|
+
WindowMaterialGas,
|
|
27
|
+
WindowMaterialGasMixture,
|
|
28
|
+
WindowMaterialGlazing,
|
|
29
|
+
WindowMaterialGlazingGroupThermochromic,
|
|
30
|
+
WindowMaterialGlazingRefractionExtinctionMethod,
|
|
31
|
+
WindowMaterialScreen,
|
|
32
|
+
WindowMaterialShade,
|
|
33
|
+
WindowMaterialSimpleGlazingSystem,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def is_window_material(material: IDFBaseModel) -> bool:
|
|
38
|
+
"""Whether ``material`` is a window-material layer (glazing, gas or shading)."""
|
|
39
|
+
return isinstance(material, WINDOW_MATERIAL_TYPES)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def construction_layers(construction: Construction) -> list[IDFBaseModel]:
|
|
43
|
+
"""Resolve the layers of a bound construction.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
construction: Construction bound to an IDF container.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Materials from outside to inside; repeated names yield repeated
|
|
50
|
+
entries and empty layer fields are skipped.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
RuntimeError: If the construction is not bound to an IDF.
|
|
54
|
+
LookupError: If a layer name does not resolve to any material.
|
|
55
|
+
"""
|
|
56
|
+
c = construction
|
|
57
|
+
slots = (
|
|
58
|
+
(c.outside_layer, c.outside_layer_ref),
|
|
59
|
+
(c.layer_2, c.layer_2_ref),
|
|
60
|
+
(c.layer_3, c.layer_3_ref),
|
|
61
|
+
(c.layer_4, c.layer_4_ref),
|
|
62
|
+
(c.layer_5, c.layer_5_ref),
|
|
63
|
+
(c.layer_6, c.layer_6_ref),
|
|
64
|
+
(c.layer_7, c.layer_7_ref),
|
|
65
|
+
(c.layer_8, c.layer_8_ref),
|
|
66
|
+
(c.layer_9, c.layer_9_ref),
|
|
67
|
+
(c.layer_10, c.layer_10_ref),
|
|
68
|
+
)
|
|
69
|
+
layers: list[IDFBaseModel] = []
|
|
70
|
+
for name, material in slots:
|
|
71
|
+
if not name:
|
|
72
|
+
continue
|
|
73
|
+
if material is None:
|
|
74
|
+
raise LookupError(
|
|
75
|
+
f'Construction {c.name!r} references unknown material {name!r}'
|
|
76
|
+
)
|
|
77
|
+
layers.append(material)
|
|
78
|
+
return layers
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Layer access and classification mixin for ``Construction``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from idfpy.models._base import IDFBaseModel
|
|
9
|
+
from idfpy.models.constructions import Construction
|
|
10
|
+
|
|
11
|
+
# ``functions`` imports the window-material classes from
|
|
12
|
+
# ``idfpy.models.constructions``, which itself imports this mixin; the
|
|
13
|
+
# imports below are deferred to break that cycle.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConstructionLayersMixin:
|
|
17
|
+
"""Ordered layer access and window/opaque classification."""
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def layers(self: Construction) -> list[IDFBaseModel]:
|
|
21
|
+
"""Materials from outside to inside (see ``construction_layers``)."""
|
|
22
|
+
from .functions import construction_layers
|
|
23
|
+
|
|
24
|
+
return construction_layers(self)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def is_window_construction(self: Construction) -> bool:
|
|
28
|
+
"""Whether every layer is a window material (glazing, gas or shading)."""
|
|
29
|
+
from .functions import construction_layers, is_window_material
|
|
30
|
+
|
|
31
|
+
return all(is_window_material(m) for m in construction_layers(self))
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def is_opaque_construction(self: Construction) -> bool:
|
|
35
|
+
"""Whether no layer is a window material."""
|
|
36
|
+
from .functions import construction_layers, is_window_material
|
|
37
|
+
|
|
38
|
+
return not any(is_window_material(m) for m in construction_layers(self))
|
|
@@ -11,6 +11,8 @@ from typing import TYPE_CHECKING, Any, ClassVar, Literal # noqa: F401
|
|
|
11
11
|
|
|
12
12
|
from pydantic import Field
|
|
13
13
|
|
|
14
|
+
from idfpy.ext.construction.mixins import ConstructionLayersMixin
|
|
15
|
+
|
|
14
16
|
from ._base import IDFBaseModel
|
|
15
17
|
from ._refs import (
|
|
16
18
|
BivariateFunctionsRef,
|
|
@@ -107,7 +109,7 @@ class WindowMaterialGlazingGroupThermochromicTemperatureDataItem(IDFBaseModel):
|
|
|
107
109
|
return idf._resolve_forward(v, ['GlazingMaterialName'])
|
|
108
110
|
|
|
109
111
|
|
|
110
|
-
class Construction(IDFBaseModel):
|
|
112
|
+
class Construction(ConstructionLayersMixin, IDFBaseModel):
|
|
111
113
|
"""Start with outside layer and work your way to the inside layer Up to 10
|
|
112
114
|
layers total, 8 for windows Enter the material name for each layer"""
|
|
113
115
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Tests for the construction ext plugin: layer resolution and classification."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import idfpy.models as models
|
|
8
|
+
from idfpy import IDF
|
|
9
|
+
from idfpy.ext.construction.functions import is_window_material
|
|
10
|
+
from idfpy.models._ref_meta import REF_PROVIDERS
|
|
11
|
+
from idfpy.models.constructions import (
|
|
12
|
+
Construction,
|
|
13
|
+
Material,
|
|
14
|
+
WindowMaterialGas,
|
|
15
|
+
WindowMaterialGlazing,
|
|
16
|
+
WindowMaterialSimpleGlazingSystem,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
OPAQUE_LAYER_TYPES = {
|
|
20
|
+
'Material',
|
|
21
|
+
'Material:AirGap',
|
|
22
|
+
'Material:InfraredTransparent',
|
|
23
|
+
'Material:NoMass',
|
|
24
|
+
'Material:RoofVegetation',
|
|
25
|
+
}
|
|
26
|
+
WINDOW_LAYER_TYPES = {
|
|
27
|
+
'WindowMaterial:Blind',
|
|
28
|
+
'WindowMaterial:Gas',
|
|
29
|
+
'WindowMaterial:GasMixture',
|
|
30
|
+
'WindowMaterial:Glazing',
|
|
31
|
+
'WindowMaterial:Glazing:RefractionExtinctionMethod',
|
|
32
|
+
'WindowMaterial:GlazingGroup:Thermochromic',
|
|
33
|
+
'WindowMaterial:Screen',
|
|
34
|
+
'WindowMaterial:Shade',
|
|
35
|
+
'WindowMaterial:SimpleGlazingSystem',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _layer_material_classes() -> dict[str, type[models.IDFBaseModel]]:
|
|
40
|
+
layer_types = {
|
|
41
|
+
object_type
|
|
42
|
+
for object_type, fields in REF_PROVIDERS.items()
|
|
43
|
+
if any('MaterialName' in groups for _, groups in fields)
|
|
44
|
+
}
|
|
45
|
+
classes = (getattr(models, name) for name in models.__all__)
|
|
46
|
+
return {
|
|
47
|
+
cls.idf_object_type(): cls
|
|
48
|
+
for cls in classes
|
|
49
|
+
if isinstance(cls, type)
|
|
50
|
+
and issubclass(cls, models.IDFBaseModel)
|
|
51
|
+
and getattr(cls, '_idf_object_type', None) in layer_types
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.fixture
|
|
56
|
+
def idf() -> IDF:
|
|
57
|
+
idf = IDF()
|
|
58
|
+
idf.add(
|
|
59
|
+
Material(
|
|
60
|
+
name='Brick',
|
|
61
|
+
roughness='Rough',
|
|
62
|
+
thickness=0.1,
|
|
63
|
+
conductivity=0.9,
|
|
64
|
+
density=1900.0,
|
|
65
|
+
specific_heat=800.0,
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
idf.add(
|
|
69
|
+
WindowMaterialGlazing(
|
|
70
|
+
name='Clear3mm', optical_data_type='SpectralAverage', thickness=0.003
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
idf.add(WindowMaterialGas(name='Air13mm', gas_type='Air', thickness=0.013))
|
|
74
|
+
idf.add(
|
|
75
|
+
WindowMaterialSimpleGlazingSystem(
|
|
76
|
+
name='SGS', u_factor=2.5, solar_heat_gain_coefficient=0.4
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
return idf
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _add(idf: IDF, name: str, *layers: str) -> Construction:
|
|
83
|
+
fields = ['outside_layer', *(f'layer_{i}' for i in range(2, 11))]
|
|
84
|
+
construction = Construction(name=name, **dict(zip(fields, layers, strict=False)))
|
|
85
|
+
idf.add(construction)
|
|
86
|
+
return construction
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class TestIsWindowMaterial:
|
|
90
|
+
def test_partition_of_layer_material_types(self):
|
|
91
|
+
classes = _layer_material_classes()
|
|
92
|
+
assert set(classes) == OPAQUE_LAYER_TYPES | WINDOW_LAYER_TYPES
|
|
93
|
+
|
|
94
|
+
window = {
|
|
95
|
+
t for t, cls in classes.items() if is_window_material(cls.model_construct())
|
|
96
|
+
}
|
|
97
|
+
assert window == WINDOW_LAYER_TYPES
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TestLayers:
|
|
101
|
+
def test_order_and_repeats(self, idf: IDF):
|
|
102
|
+
construction = _add(idf, 'Dbl', 'Clear3mm', 'Air13mm', 'Clear3mm')
|
|
103
|
+
glass = idf.get(WindowMaterialGlazing, 'Clear3mm')
|
|
104
|
+
gas = idf.get(WindowMaterialGas, 'Air13mm')
|
|
105
|
+
assert construction.layers == [glass, gas, glass]
|
|
106
|
+
|
|
107
|
+
def test_unknown_material_raises(self, idf: IDF):
|
|
108
|
+
construction = _add(idf, 'Broken', 'Brick', 'Missing')
|
|
109
|
+
with pytest.raises(
|
|
110
|
+
LookupError, match="'Broken' references unknown material 'Missing'"
|
|
111
|
+
):
|
|
112
|
+
_ = construction.layers
|
|
113
|
+
|
|
114
|
+
def test_unbound_raises(self):
|
|
115
|
+
construction = Construction(name='Loose', outside_layer='Brick')
|
|
116
|
+
with pytest.raises(RuntimeError):
|
|
117
|
+
_ = construction.layers
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class TestClassification:
|
|
121
|
+
@pytest.mark.parametrize(
|
|
122
|
+
('layers', 'is_window', 'is_opaque'),
|
|
123
|
+
[
|
|
124
|
+
(('Brick',), False, True),
|
|
125
|
+
(('SGS',), True, False),
|
|
126
|
+
(('Clear3mm', 'Air13mm', 'Clear3mm'), True, False),
|
|
127
|
+
(('Brick', 'Clear3mm'), False, False),
|
|
128
|
+
(('Clear3mm', 'Brick'), False, False),
|
|
129
|
+
],
|
|
130
|
+
)
|
|
131
|
+
def test_window_and_opaque(
|
|
132
|
+
self, idf: IDF, layers: tuple[str, ...], is_window: bool, is_opaque: bool
|
|
133
|
+
):
|
|
134
|
+
construction = _add(idf, 'C', *layers)
|
|
135
|
+
assert construction.is_window_construction is is_window
|
|
136
|
+
assert construction.is_opaque_construction is is_opaque
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|