Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@


.DS_Store

# environment variables:
Expand All @@ -7,6 +8,9 @@
# virtual environment:
.venv/

# vscode user settings:
.vscode/launch.json

# cache files:
__pycache__/
.pytest_cache
Expand Down
1 change: 1 addition & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ max-line-length=80
# see: https://github.com/google/sbsim/issues/43
ignore-long-lines=(?x)(
^\s*(\#\ )?<?https?://\S+>?$| # Ignore long URLs
^.*\[[^\]]+\]\(\s*(?:https?://|\/|(?:\.{1,2}\/|\S+\/)*)\S*\s*\).*$| # Ignore long markdown links in docstrings (including relative links)
^\s*(from\s+\S+\s+)?import\s+.+$| # Ignore import statements
.*(pytype:|pylint:|fmt:|TODO:).* # Ignore lines containing pragma comments
)
Expand Down
4 changes: 4 additions & 0 deletions docs/api/simulator/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@

::: smart_control.simulator.building_utils

::: smart_control.simulator.building_radiation_utils
options:
members_order: source

::: smart_control.simulator.thermal_diffuser_utils
12 changes: 12 additions & 0 deletions docs/assets/javascripts/mathjax_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
window.MathJax = {
tex: {
inlineMath: [['\\(', '\\)']],
displayMath: [['\\[', '\\]']],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};
13 changes: 13 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ markdown_extensions:
#- pymdownx.snippets
- pymdownx.superfences

# MATHJAX EQUATIONS CONFIG, PART 1 OF 2
# https://mrkeo.github.io/reference/mathjax/
# https://squidfunk.github.io/mkdocs-material/reference/math/#mathjax-mkdocsyml
# https://www.mathjax.org/
- pymdownx.arithmatex:
generic: true

extra_javascript:
# MATHJAX EQUATIONS CONFIG, PART 2 OF 2
- assets/javascripts/mathjax_config.js
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js

plugins:
- search

Expand Down
211 changes: 176 additions & 35 deletions smart_control/simulator/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import numpy as np

from smart_control.simulator import base_convection_simulator
from smart_control.simulator import building_radiation_utils
from smart_control.simulator import building_utils
from smart_control.simulator import constants
from smart_control.simulator import thermal_diffuser_utils
Expand All @@ -28,6 +29,22 @@ class MaterialProperties:
density: float


@gin.configurable
@dataclasses.dataclass
class RadiationProperties:
"""Holds the radiative properties for a material.

Args:
alpha (float): absorptivity
epsilon (float): emissivity
tau (float): transmittance
"""

alpha: float = 0.0 # absorptivity
epsilon: float = 0.0 # emissivity
tau: float = 0.0 # transmittance


def _check_room_sizes(matrix_shape: Shape2D, room_shape: Shape2D):
"""Raises a ValueError if room_shape is not compatible with matrix_shape.

Expand Down Expand Up @@ -259,7 +276,7 @@ def _construct_cv_type_array(
) -> np.ndarray:
"""Fills once the CV type matrix and save it.

In the original imlementation,
In the original implementation,
the sweep() function would call the get_cv_type() function every time,
repeating logic that only needed to be computed once and saved.

Expand Down Expand Up @@ -390,7 +407,7 @@ class Building(BaseSimulatorBuilding):
length of the building.
temp: The current temp in K of each control volume.
conductivity: Thermal conductivity in of each control volume W/m/K.
heat_capacity: Thermal heat cpacity of each control volume in J/kg/K.
heat_capacity: Thermal heat capacity of each control volume in J/kg/K.
density: Material density in kg/m3 of each control volume.
input_q: Heat energy applied (sign indicates heating/cooling) at the CV in W
(J/s).
Expand All @@ -399,6 +416,7 @@ class Building(BaseSimulatorBuilding):
volume.
cv_type: a matrix noting whether each CV is outside air, interior space, or
a wall. cv_type will be used in the sweep() function.

"""

def __init__(
Expand Down Expand Up @@ -633,6 +651,9 @@ def __init__(
inside_air_properties: MaterialProperties,
inside_wall_properties: MaterialProperties,
building_exterior_properties: MaterialProperties,
inside_air_radiative_properties: RadiationProperties | None = None,
inside_wall_radiative_properties: RadiationProperties | None = None,
building_exterior_radiative_properties: RadiationProperties | None = None,
zone_map: Optional[np.ndarray] = None,
zone_map_filepath: Optional[str] = None,
floor_plan: Optional[np.ndarray] = None,
Expand All @@ -652,6 +673,10 @@ def __init__(
inside_air_properties: MaterialProperties for interior air.
inside_wall_properties: MaterialProperties for interior walls.
building_exterior_properties: MaterialProperties for building's exterior.
inside_air_radiative_properties: RadiationProperties for interior air.
inside_wall_radiative_properties: RadiationProperties for interior walls.
building_exterior_radiative_properties: RadiationProperties for building's
exterior.
zone_map: an np.ndarray noting where the VAV zones are.
zone_map_filepath: a string of where to find the zone_map in CNS. Note
that the user requires only to provide one of either zone_map_filepath
Expand All @@ -673,40 +698,9 @@ def __init__(
self._convection_simulator = convection_simulator
self._reset_temp_values = reset_temp_values

# below is new code, to derive necessary artifacts from the floor plan.
# TODO(spangher): neaten code by turning the next twenty lines into a
# private method.

if floor_plan is None and floor_plan_filepath is None:
raise ValueError(
"Both floor_plan and floor_plan_filepath cannot be None."
)

elif floor_plan is None and floor_plan_filepath:
self.floor_plan = building_utils.read_floor_plan_from_filepath(
floor_plan_filepath
)

elif floor_plan is not None and floor_plan_filepath is None:
self.floor_plan = floor_plan

else:
raise ValueError("floor_plan and floor_plan_filepath ")
self._set_floor_plan(floor_plan, floor_plan_filepath)

if zone_map_filepath is None and zone_map is None:
raise ValueError("please provide a zone_map_filepath or a zone_map")

if zone_map_filepath is not None and zone_map is not None:
raise ValueError(
"You have provided both zone_map_filepath and a zone_map"
)

if zone_map is not None and zone_map_filepath is None:
self._zone_map = zone_map

if zone_map is None and zone_map_filepath is not None:
zone_map = building_utils.read_floor_plan_from_filepath(zone_map_filepath)
self._zone_map = zone_map
self._set_zone_map(zone_map, zone_map_filepath)

(self._room_dict, exterior_walls, interior_walls, self._exterior_space) = (
building_utils.construct_building_data_types(
Expand Down Expand Up @@ -757,8 +751,140 @@ def __init__(
self.neighbors = self._calculate_neighbors()
self.len_neighbors = self._calculate_length_of_neighbors()

# Beginning of radiation-related calculation
self.indexed_floor_plan = (
self._exterior_space.copy()
+ exterior_walls.copy()
+ interior_walls.copy()
)
self.interior_wall_idx = [
(r, c)
for r in range(self.indexed_floor_plan.shape[0])
for c in range(self.indexed_floor_plan.shape[1])
if self.indexed_floor_plan[r, c] == -3
]
self.interior_wall_mask = (
self.indexed_floor_plan == constants.INTERIOR_WALL_VALUE_IN_FUNCTION
)
self.interior_wall_index = np.full(self.indexed_floor_plan.shape, -1)
self.interior_wall_index[self.interior_wall_mask] = np.arange(
np.sum(self.interior_wall_mask)
)
self.interior_wall_VF = building_radiation_utils.get_VF( # pylint: disable=invalid-name
self.indexed_floor_plan
)

# breakpoint()
self._set_radiative_properties(
inside_air_radiative_properties,
inside_wall_radiative_properties,
building_exterior_radiative_properties,
exterior_walls, # do we want to use self.exterior_walls?
interior_walls, # do we want to use self.interior_walls?
)

self.reset()

def _set_floor_plan(
self,
floor_plan: Optional[np.ndarray] = None,
floor_plan_filepath: Optional[str] = None,
):

if floor_plan is None and floor_plan_filepath is None:
raise ValueError("Please provide a floor_plan or a floor_plan_filepath")

elif floor_plan is not None and floor_plan_filepath is not None:
raise ValueError(
"Provide either a floor_plan or a floor_plan_filepath, but not both."
)

elif floor_plan_filepath is not None:
self.floor_plan = building_utils.read_floor_plan_from_filepath(
floor_plan_filepath
)

elif floor_plan is not None:
self.floor_plan = floor_plan

def _set_zone_map(
self,
zone_map: Optional[np.ndarray] = None,
zone_map_filepath: Optional[str] = None,
):
if zone_map is None and zone_map_filepath is None:
raise ValueError("Please provide a zone_map or a zone_map_filepath")

elif zone_map is not None and zone_map_filepath is not None:
raise ValueError(
"Provide either a zone_map or a zone_map_filepath, but not both."
)

elif zone_map_filepath is not None:
self.zone_map = building_utils.read_floor_plan_from_filepath(
zone_map_filepath
)

elif zone_map is not None:
self.zone_map = zone_map

def _set_radiative_properties(
self,
inside_air_radiative_properties: RadiationProperties | None,
inside_wall_radiative_properties: RadiationProperties | None,
building_exterior_radiative_properties: RadiationProperties | None,
exterior_walls,
interior_walls,
):

# radiative properties
# by default, all radiative properties are 0.0
self.inside_wall_radiative_properties = (
inside_wall_radiative_properties
or RadiationProperties(epsilon=0.0, alpha=0.0, tau=0.0)
)

self.building_exterior_radiative_properties = (
building_exterior_radiative_properties
or RadiationProperties(epsilon=0.0, alpha=0.0, tau=0.0)
)
self.inside_air_radiative_properties = (
inside_air_radiative_properties
or RadiationProperties(epsilon=0.0, alpha=0.0, tau=0.0)
)

# emissivity
self._epsilon = _assign_interior_and_exterior_values(
exterior_walls=exterior_walls,
interior_walls=interior_walls,
interior_wall_value=self.inside_wall_radiative_properties.epsilon,
exterior_wall_value=self.building_exterior_radiative_properties.epsilon,
interior_and_exterior_space_value=self.inside_air_radiative_properties.epsilon, # pylint: disable=line-too-long
)
# absorptivity
self._alpha = _assign_interior_and_exterior_values(
exterior_walls=exterior_walls,
interior_walls=interior_walls,
interior_wall_value=self.inside_wall_radiative_properties.alpha,
exterior_wall_value=self.building_exterior_radiative_properties.alpha,
interior_and_exterior_space_value=self.inside_air_radiative_properties.alpha, # pylint: disable=line-too-long
)
# transmittance
self._tau = _assign_interior_and_exterior_values(
exterior_walls=exterior_walls,
interior_walls=interior_walls,
interior_wall_value=self.inside_wall_radiative_properties.tau,
exterior_wall_value=self.building_exterior_radiative_properties.tau,
interior_and_exterior_space_value=self.inside_air_radiative_properties.tau, # pylint: disable=line-too-long
)
self._epsilon_vector = self._epsilon[self.interior_wall_mask]
self.A_tilde_inv = building_radiation_utils.calculate_A_tilde_inv( # pylint: disable=invalid-name
self._epsilon_vector, self.interior_wall_VF
)
self.IFAinv = building_radiation_utils.calculate_IFAinv( # pylint: disable=invalid-name
self.interior_wall_VF, self.A_tilde_inv
)

@property
def density(self) -> np.ndarray:
return self._density
Expand Down Expand Up @@ -892,3 +1018,18 @@ def apply_thermal_power_zone(self, zone_name: str, power: float): # pylint: dis
def apply_convection(self) -> None:
if self._convection_simulator is not None:
self._convection_simulator.apply_convection(self._room_dict, self.temp)

# Radiative heat transfer
def apply_longwave_interior_radiative_heat_transfer(
self, temperature_estimates: np.ndarray
) -> np.ndarray:
"""
Applies long-wave interior radiative heat transfer.

This function calculates the net radiative heat flux and radiosity for each
interior wall.
"""
q_lwx = building_radiation_utils.net_radiative_heatflux_function_of_T(
temperature_estimates[self.interior_wall_mask], self.IFAinv
)
return q_lwx
Loading
Loading