buildyn 1.0.0__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 (42) hide show
  1. buildyn/__init__.py +2 -0
  2. buildyn/buildyn.py +129 -0
  3. buildyn/converter/__init__.py +2 -0
  4. buildyn/converter/converter.py +35 -0
  5. buildyn/converter/converter_function.py +12 -0
  6. buildyn/distributions/__init__.py +1 -0
  7. buildyn/distributions/continuous/__init__.py +2 -0
  8. buildyn/distributions/continuous/continuous_distribution.py +5 -0
  9. buildyn/distributions/continuous/gauss_distribution.py +35 -0
  10. buildyn/distributions/discrete/__init__.py +2 -0
  11. buildyn/distributions/discrete/discrete_distribution.py +10 -0
  12. buildyn/distributions/discrete/random_choice.py +21 -0
  13. buildyn/distributions/distribution.py +13 -0
  14. buildyn/examples/builda/builda_fmu.py +104 -0
  15. buildyn/examples/builda/converter_functions/Component_configurator.py +119 -0
  16. buildyn/examples/builda/converter_functions/Component_properties_calculator.py +167 -0
  17. buildyn/examples/builda/converter_functions/Link_resolver.py +28 -0
  18. buildyn/examples/builda/converter_functions/Miscellaneous_handler.py +21 -0
  19. buildyn/examples/builda/converter_functions/Model_compatibility_layer.py +42 -0
  20. buildyn/examples/builda/converter_functions/NaiveConverterFunction.py +30 -0
  21. buildyn/examples/builda/converter_functions/Nominal_cooling_power_calculator.py +597 -0
  22. buildyn/examples/builda/converter_functions/Nominal_heating_power_calculator.py +54 -0
  23. buildyn/examples/builda/converter_functions/RC_Distribution_Configurator.py +80 -0
  24. buildyn/examples/builda/converter_functions/Zone_dimensions_calculator.py +66 -0
  25. buildyn/examples/builda/converter_functions/__init__.py +10 -0
  26. buildyn/fmu.py +345 -0
  27. buildyn/walker/__init__.py +2 -0
  28. buildyn/walker/fixed/__init__.py +2 -0
  29. buildyn/walker/fixed/constant_walker.py +16 -0
  30. buildyn/walker/fixed/poisson_walker.py +57 -0
  31. buildyn/walker/interval_walker.py +32 -0
  32. buildyn/walker/random/__init__.py +2 -0
  33. buildyn/walker/random/ramp_walker.py +31 -0
  34. buildyn/walker/random/random_walker.py +24 -0
  35. buildyn/walker/random/sinusoidal_walker.py +54 -0
  36. buildyn/walker/walker.py +8 -0
  37. buildyn-1.0.0.dist-info/METADATA +105 -0
  38. buildyn-1.0.0.dist-info/RECORD +42 -0
  39. buildyn-1.0.0.dist-info/WHEEL +5 -0
  40. buildyn-1.0.0.dist-info/licenses/LICENSE +21 -0
  41. buildyn-1.0.0.dist-info/top_level.txt +2 -0
  42. notebooks/builda_fmu.py +104 -0
buildyn/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .fmu import FMU
2
+ from .buildyn import BuilDyn
buildyn/buildyn.py ADDED
@@ -0,0 +1,129 @@
1
+ from buildyn.fmu import FMU
2
+ from typing import Dict
3
+ from buildyn.walker.walker import Walker
4
+ from buildyn.walker.interval_walker import IntervalWalker
5
+ from buildyn.distributions.distribution import Distribution
6
+ from buildyn.distributions.discrete.discrete_distribution import DiscreteDistribution
7
+
8
+ from copy import copy
9
+ import itertools
10
+
11
+ class BuilDyn:
12
+
13
+ def __init__(self,
14
+ fmu: FMU,
15
+ observables: list = []
16
+ ):
17
+
18
+ self.variation_distributions: Dict[str, Distribution] = dict()
19
+
20
+ self.walker_distributions: Dict[str, IntervalWalker | DiscreteDistribution] = dict()
21
+
22
+ self.fmu: FMU = fmu
23
+
24
+ self.observables = observables
25
+
26
+
27
+ def add_variation_distribution(self, variable: str, distribution: Distribution):
28
+
29
+ self.variation_distributions[variable] = distribution
30
+
31
+
32
+ def add_walker_distribution(self, variable: str, distribution: IntervalWalker | DiscreteDistribution):
33
+
34
+ self.walker_distributions[variable] = distribution
35
+
36
+
37
+ def sample_one(self,
38
+ start_time: int = 0,
39
+ stop_time: int = 86_400,
40
+ step_size: int = 900):
41
+
42
+
43
+ # Sample one fmu with random variation
44
+ fmu = self.sample_one_fmu()
45
+
46
+ # Sample the walker from the correpnding walker distributions
47
+ walker: Dict[str, Walker] = dict()
48
+
49
+ for param, walker_dist in self.walker_distributions.items():
50
+
51
+ if isinstance(walker_dist, IntervalWalker):
52
+
53
+ walker[param] = walker_dist
54
+ continue
55
+
56
+ walker[param] = walker_dist.sample_one()
57
+
58
+ res = fmu.simulate(
59
+ start_time=start_time,
60
+ stop_time=stop_time,
61
+ step_size=step_size,
62
+ observables=self.observables,
63
+ walker=walker
64
+ )
65
+
66
+ return res
67
+
68
+
69
+ def sample_one_fmu(self):
70
+
71
+ fmu = self.fmu.__copy__()
72
+
73
+ fmu_initial_variables = dict()
74
+
75
+ # Sample the variations from the corresponding distributions
76
+ for param, distirbution in self.variation_distributions.items():
77
+
78
+ variable_value = distirbution.sample_one()
79
+
80
+ fmu_initial_variables[param] = variable_value
81
+
82
+ fmu.set_initial_variables(variables=fmu_initial_variables)
83
+
84
+ return fmu
85
+
86
+
87
+ def sample_all_fmus(self):
88
+
89
+ all_fmus = []
90
+ all_samples = {}
91
+
92
+ # Check if all distributions in this class are Discrete, else it would not be possible to really sample all.
93
+
94
+ for variable, distribution in self.variation_distributions.items():
95
+
96
+ if not isinstance(distribution, DiscreteDistribution):
97
+
98
+ return TypeError(f"Sampling all FMUs in not possible because {distribution.__class__.__name__} is not a discrete distribution.")
99
+
100
+ all_samples[variable] = distribution.sample_all()
101
+
102
+ keys = list(all_samples.keys())
103
+ values = list(all_samples.values())
104
+
105
+ # Making the cartesian product of the sample_all
106
+ for combination in itertools.product(*values):
107
+
108
+ variation_dict = dict(zip(keys, combination))
109
+
110
+ fmu = copy(self.fmu)
111
+ fmu.set_initial_variables(variation_dict)
112
+
113
+ all_fmus.append(fmu)
114
+
115
+ return all_fmus
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
@@ -0,0 +1,2 @@
1
+ from .converter_function import ConverterFunction
2
+ from .converter import Converter
@@ -0,0 +1,35 @@
1
+ from buildyn.converter.converter_function import ConverterFunction
2
+
3
+ class Converter:
4
+
5
+ def __init__(self):
6
+
7
+ self.converter_functions: set[ConverterFunction] = []
8
+
9
+ # For variables that should be used in the variation step of an fmu.
10
+ self.converter_variables: dict[str, str | bool | float | int] = {}
11
+
12
+
13
+ def add_converter_function(self, converter_function: ConverterFunction = None):
14
+
15
+ if not converter_function:
16
+ return
17
+
18
+ self.converter_functions.append(converter_function)
19
+
20
+
21
+ def get_converter_functions(self) -> list[ConverterFunction]:
22
+
23
+ return self.converter_functions
24
+
25
+
26
+ def update_converter_variables(self, d: dict[str, str | bool | float | int]):
27
+
28
+ self.converter_variables.update(d)
29
+
30
+
31
+ def get_converter_variables(self) -> dict[str, str | bool | float | int]:
32
+
33
+ return self.converter_variables
34
+
35
+
@@ -0,0 +1,12 @@
1
+ from abc import ABC
2
+
3
+ class ConverterFunction(ABC):
4
+
5
+ def __init__(self):
6
+
7
+ pass
8
+
9
+
10
+ def convert(self, var_dict: dict):
11
+
12
+ return NotImplementedError("Function convert not implemented in this ConverterFunction. Please override this method first.")
@@ -0,0 +1 @@
1
+ from .distribution import Distribution
@@ -0,0 +1,2 @@
1
+ from .continuous_distribution import ContinuousDistribution
2
+ from .gauss_distribution import GaussDistribution
@@ -0,0 +1,5 @@
1
+ from buildyn.distributions.distribution import Distribution
2
+
3
+ class ContinuousDistribution(Distribution):
4
+
5
+ pass
@@ -0,0 +1,35 @@
1
+ from buildyn.distributions.continuous.continuous_distribution import ContinuousDistribution
2
+ import random
3
+
4
+ class GaussDistribution(ContinuousDistribution):
5
+
6
+ def __init__(self, mu, sigma, min: float = None, max: float = None):
7
+
8
+ super().__init__()
9
+
10
+ self.mu = mu
11
+ self.sigma = sigma
12
+ self.min = min
13
+ self.max = max
14
+
15
+
16
+ def sample_one(self):
17
+
18
+ # No bounds → return normally
19
+ if self.min is None and self.max is None:
20
+ return random.gauss(self.mu, self.sigma)
21
+
22
+ # Otherwise, keep sampling until value is within bounds
23
+ for _ in range(999):
24
+ value = random.gauss(self.mu, self.sigma)
25
+
26
+ if self.min is not None and value < self.min:
27
+ continue
28
+ if self.max is not None and value > self.max:
29
+ continue
30
+
31
+ return value
32
+
33
+ # We assume that the min-max is near-impossible to hit.
34
+ raise Exception(f"Gauss distribution: Not realistic with min {self.min} and max {self.max}")
35
+
@@ -0,0 +1,2 @@
1
+ from .discrete_distribution import DiscreteDistribution
2
+ from .random_choice import RandomChoiceDistribution
@@ -0,0 +1,10 @@
1
+ from abc import abstractmethod
2
+
3
+ from buildyn.distributions.distribution import Distribution
4
+
5
+ class DiscreteDistribution(Distribution):
6
+
7
+ @abstractmethod
8
+ def sample_all(self):
9
+
10
+ pass
@@ -0,0 +1,21 @@
1
+ from buildyn.distributions.discrete.discrete_distribution import DiscreteDistribution
2
+ import random
3
+
4
+ class RandomChoiceDistribution(DiscreteDistribution):
5
+
6
+ def __init__(self, choices: list | set):
7
+
8
+ super().__init__()
9
+
10
+ self.choices = choices
11
+
12
+
13
+ def sample_one(self):
14
+
15
+ return random.choice(self.choices)
16
+
17
+
18
+ def sample_all(self):
19
+
20
+ return self.choices
21
+
@@ -0,0 +1,13 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class Distribution(ABC):
4
+
5
+ @abstractmethod
6
+ def sample_one(self):
7
+
8
+ pass
9
+
10
+
11
+ def sample_multiple(self, n: int):
12
+
13
+ return [self.sample_one() for _ in range(n)]
@@ -0,0 +1,104 @@
1
+ from buildyn.converter import Converter
2
+ from buildyn.examples.builda.converter_functions.Component_configurator import Component_configurator
3
+ from buildyn.examples.builda.converter_functions.Link_resolver import Link_resolver
4
+ from buildyn.examples.builda.converter_functions.Miscellaneous_handler import Miscellaneous_handler
5
+ from buildyn.examples.builda.converter_functions.Model_compatibility_layer import Model_compatibility_layer
6
+ from buildyn.examples.builda.converter_functions.Nominal_cooling_power_calculator import Nominal_cooling_power_calculator
7
+ from buildyn.examples.builda.converter_functions.Nominal_heating_power_calculator import Nominal_heating_power_calculator
8
+ from buildyn.examples.builda.converter_functions.RC_Distribution_Configurator import RC_Distribution_Configurator
9
+ from buildyn.examples.builda.converter_functions.Zone_dimensions_calculator import Zone_dimensions_calculator
10
+ from buildyn.examples.builda.converter_functions.Component_properties_calculator import Component_properties_calculator
11
+
12
+
13
+ # Helper function to retrieve the pre-configured BuilDa FMU with all converter functions and default values set.
14
+ def get_configured_builda_fmu(internal_controller: bool = False):
15
+
16
+ converter = Converter()
17
+
18
+ # All the converter functiosn from BuilDa 2.0
19
+ converter_functions = [Link_resolver, Miscellaneous_handler, Model_compatibility_layer, Zone_dimensions_calculator, Component_configurator, RC_Distribution_Configurator, Component_properties_calculator, Nominal_heating_power_calculator, Nominal_cooling_power_calculator]
20
+
21
+ for cf in converter_functions:
22
+ converter.add_converter_function(cf())
23
+
24
+ converter_variables = {
25
+ "zone_length": 9.4125,
26
+ "zone_width": 8,
27
+ "floor_height": 3.04,
28
+ "n_floors": 2,
29
+ "fAWin_south": 0.14056,
30
+ "fAWin_west": 0.14056,
31
+ "fAWin_north": 0.14056,
32
+ "fAWin_east": 0.14056,
33
+ "fATransToAWindow": 0.9,
34
+ "fARoofToAFloor": 1.63612217795485,
35
+ "fAInt": 1.238235294117647,
36
+ "heatCapacity_furniture_per_m2": 2230,
37
+ "UExt": 0.665,
38
+ "heatCapacity_wall": 192000,
39
+ "UFloor": 0.514,
40
+ "heatCapacity_floor": 483840,
41
+ "UInt": 1,
42
+ "heatCapacity_internalWall": 145154,
43
+ "URoof": 0.402,
44
+ "heatCapacity_roof": 81240,
45
+ "UWin": 3.2,
46
+ "thermalZone.gWin": 0.7,
47
+ "heatRecoveryRate": 0,
48
+ "airChangeRate": 0.3,
49
+ "heatingCurve_steepness": 1,
50
+ "relative_heatPump_efficiency": 0.8,
51
+ "internalGainsConvectiveFraction": 0.4,
52
+ "heatingConvectiveFraction": 1,
53
+ "weaDat.fileName": "resources/Munich.mos",
54
+ "internalGain.fileName": "resources/NoActivity.txt",
55
+ "hygienicalWindowOpening.fileName": "resources/no_opening.txt",
56
+ "roomTempLowerSetpoint": 18,
57
+ "roomTempUpperSetpoint": 22,
58
+ #"UseInternalController": 0,
59
+ "extWall_C_distribution": "monolythic",
60
+ "floor_C_distribution": [478800, 5040, 0.001],
61
+ "roof_C_distribution": [22440, 58800, 0.001],
62
+ "extWall_R_distribution": "monolythic",
63
+ "floor_R_distribution": [0.0525, 0.0525, 0.1579, 0.0001],
64
+ "roof_R_distribution": [1.1085, 1.1085, 0.1, 0.0001],
65
+ "intWall_R_distribution": "monolythic",
66
+ "intWall_C_distribution": "monolythic",
67
+ "Rsi_extWall": 0.13333333333333333,
68
+ "Rsi_intWall": 0.13333333333333333,
69
+ "Rsi_floor": 0.17543859649122806,
70
+ "Rsi_roof": 0.1,
71
+ "Rse_extWall": 0.04,
72
+ "Rse_roof": 0.04,
73
+ "Rsi_window": 0.13333333333333333,
74
+ "Rse_window": 0.05,
75
+ "ta_min": None,
76
+ "ti_set": None
77
+ }
78
+
79
+ # Set the converter variables in the converter. This also updates previously set variables.
80
+ converter.update_converter_variables(converter_variables)
81
+
82
+ from buildyn import FMU
83
+ import json
84
+
85
+ # Example FMU from BuilDa 2.0
86
+ fmu_path = "resources/building.fmu"
87
+
88
+ # Initial variables from the BuilDa 2.0 FMU -> Needs extra variables here because the BuilDa FMU is weird. For other use-cases you don't have to do this.
89
+ with open("resources/fmu_state_dict.json", "r") as f:
90
+ start_variables = json.load(f)
91
+
92
+ start_variables.update({
93
+ "weaDat.filNam": "resources/Munich.mos",
94
+ "internalGain.fileName": "resources/NoActivity.txt",
95
+ "hygienicalWindowOpening.fileName": "resources/no_opening.txt",
96
+ "UseInternalController.k": 1 if internal_controller else 0
97
+ })
98
+
99
+ # FMU object from the buil_dyn package
100
+ fmu = FMU(fmu_file=fmu_path, init_values=start_variables)
101
+
102
+ fmu.set_converter(converter=converter)
103
+
104
+ return fmu
@@ -0,0 +1,119 @@
1
+ from buildyn.converter.converter_function import ConverterFunction
2
+ import pandas as pd
3
+
4
+
5
+ class Component_configurator(ConverterFunction):
6
+ '''
7
+ Sets up preconfigured wall construction profiles comprising U-Value,
8
+ heat capacity and R- and C-distributions.
9
+ Profiles include e.g., 'heavy', 'lightweight',
10
+ 'pumiceAndBrick', 'baloonFraming'
11
+ '''
12
+ def __init__(self):
13
+ super().__init__()
14
+ # Definition of Component_constructions_n3, only use, when number of elements n=3,
15
+ self.Component_constructions_n3={
16
+
17
+ "heavy":{ #from ashrae 140-2004 TC900
18
+ "UExt":0.512,
19
+ "heatCapacity_wall":145154,
20
+ "extWall_C_distribution":"heavy",
21
+ "extWall_R_distribution":"heavy",
22
+
23
+ "URoof":0.318,
24
+ "heatCapacity_roof":18169.944,
25
+ "roof_C_distribution":"heavy",
26
+ "roof_R_distribution":"heavy",
27
+ "UFloor":0.039,
28
+ "heatCapacity_floor":112000.00200000001,
29
+ "floor_C_distribution":"heavy",
30
+ "floor_R_distribution":"heavy",
31
+ },
32
+ "lightweight":{ #from ashrae 140-2004 TC600
33
+ "UExt":0.514,
34
+ "heatCapacity_wall":14534.28,
35
+ "extWall_C_distribution":"lightweight",
36
+ "extWall_R_distribution":"lightweight",
37
+
38
+ "URoof":0.318,
39
+ "heatCapacity_roof":18169.944,
40
+ "roof_C_distribution":"lightweight",
41
+ "roof_R_distribution":"lightweight",
42
+ "UFloor":0.039,
43
+ "heatCapacity_floor":29610.239999999998,
44
+ "floor_C_distribution":"lightweight",
45
+ "floor_R_distribution":"lightweight",
46
+
47
+ },
48
+
49
+
50
+ #wall constructrion according to:
51
+ # https://www.ubakus.de/u-wert-rechner/index.php?c=2&M0=132061I1&M1=132153I33&l1=0.23&r1=550&name1=Geschosshohe%20Porenbetonplatten&v1=f2f2f2&tex1=gf&M2=77i5&T_i=20&RH_i=50&Te=-5&RH_e=80&outside=0&bt=0&unorm=enev14alt&cq=2947871&name=AW%20Porenbeton%20Fassadenelemente%20GSB%2035%2C%2033%20cm%2C%20ab%201952&fz=14
52
+ "gasConcrete":{ #from ashrae 140-2004 TC600
53
+ "UExt":0.615,
54
+ "heatCapacity_wall":201500,
55
+ "extWall_C_distribution":"gasConcrete",
56
+ "extWall_R_distribution":"gasConcrete",
57
+ },
58
+
59
+
60
+ #wall constructrion according to:
61
+ # https://www.ubakus.de/u-wert-rechner/index.php?c=2&M0=199i15&M1=132261I24&v1=b7b7b7&tex1=0&M2=133477I2&M3=136921i115&v3=cc5c4a&tex3=vz2&T_i=20&RH_i=50&Te=-5&RH_e=80&outside=0&bt=0&Rsi=U&unorm=enev14alt&cq=2947497&name=AW%20Bims-Schwemmstein%2024%20cm%2C%20Schalenfuge%2FVZ-Vormauer%201200%20kg%2Fm%C2%B3%2C%20ab%201952&fz=14
62
+ "pumiceAndBrick":{
63
+ "UExt":0.9,
64
+ "heatCapacity_wall":333100,
65
+ "extWall_C_distribution":"pumiceAndBrick",
66
+ "extWall_R_distribution":"pumiceAndBrick",
67
+ },
68
+
69
+ #wall constructrion according to:
70
+ # https://www.ubakus.de/u-wert-rechner/index.php?c=2&M0=133859i6&M1=36i24&M2=137011i2&M3=86I6&M4=36I9&x4=-0.05&y4=0.2&w4=6&R4=60&M5=132403I3&v5=81674f&tex5=kork&M6=132657i3&M7=90i24&M8=36i24&y8=0&w8=4.8&R8=30&hz8=1&M9=119929i44&T_i=20&RH_i=50&Te=-5&RH_e=80&outside=0&bt=0&unorm=enev14alt&cq=2947513&name=AW%20Einsteins%20Sommerhaus%2C%20Holzrahmen%2012%20cm%2C%203%20cm%20Torfd%C3%A4mmung%2C%201929&fz=14
71
+ "baloonFraming":{
72
+ "UExt":0.732,
73
+ "heatCapacity_wall":37176,
74
+ "extWall_C_distribution":"baloonFraming",
75
+ "extWall_R_distribution":"baloonFraming",
76
+ },
77
+
78
+ ##Draft for additional Component_constructions_n3 profile:
79
+ # "templateWall":{
80
+ # "UExt":*value_of_template_wall*,
81
+ # "heatCapacity_wall":*value_of_template_wall*,
82
+ # "extWall_C_distribution":*C-Distribution_of_template_wall*,
83
+ # "extWall_R_distribution":*R-Distribution_of_template_wall*,
84
+ # add other expressions as needed...
85
+ # },
86
+ }
87
+
88
+ #add components defined in external files
89
+ import json,glob,os
90
+ for json_file in glob.glob("resources/componentConstructions/*json"):
91
+ new_components=json.load(open(json_file,"r"))
92
+ new_keys=set(new_components.keys()) - set(self.Component_constructions_n3.keys())
93
+ if len(new_keys)==0:
94
+ print(f"Nothing added from file {json_file}, as {list(new_components.keys())} already configured.")
95
+ for key in new_keys:
96
+ self.Component_constructions_n3.update({key:new_components[key]})
97
+
98
+
99
+
100
+
101
+
102
+ def convert(self, variable_dict):
103
+ tr=variable_dict
104
+ for key in tr.keys():
105
+ #check if configured parameter value of parameter key is within the
106
+ # Component construction profiles, indicating that an existing
107
+ # profile should be applied for configuration
108
+ if type(tr[key]) is str and tr[key] in self.Component_constructions_n3.keys():
109
+ try:
110
+ #replace formerly configured link to profile by corresponding
111
+ # value from profile
112
+ tr[key]=self.Component_constructions_n3[tr[key]] [key]
113
+ except KeyError:
114
+ #raises an error, if there is no value for the parameter configured
115
+ # in profile, except parameter is starting with '#'
116
+ if not(key.startswith("#")):
117
+ raise IndexError(f"""Could not read out value for parameter '{key}' on component profile '{tr[key]}'. There is none configured.""")
118
+ return tr
119
+