Skip to content
Merged
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
2 changes: 1 addition & 1 deletion process/core/caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def _call_models_once(self, xc: np.ndarray):
self.models.availability.run(output=False)

# Water usage in secondary cooling system
self.models.water_use.run(output=False)
self.models.water_use.run()

# Costs model
"""Cost switch values
Expand Down
2 changes: 0 additions & 2 deletions process/core/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
from process.data_structure.tfcoil_variables import init_tfcoil_variables
from process.data_structure.times_variables import init_times_variables
from process.data_structure.vacuum_variables import init_vacuum_variables
from process.data_structure.water_usage_variables import init_watuse_variables
from process.models.stellarator.initialization import st_init


Expand Down Expand Up @@ -288,7 +287,6 @@ def init_all_module_vars():
init_pulse_variables()
init_rebco_variables()
init_reinke_variables()
init_watuse_variables()
init_cs_fatigue_variables()
init_blanket_library()
init_dcll_module()
Expand Down
10 changes: 9 additions & 1 deletion process/core/io/data_structure_dicts.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,14 +403,22 @@ def get_dicts():
dict_module_entry = {}
variable_types = {}

# Check whether to get the initial value from the global data structure
# or some dataclass
object_containing_initial_values = (
module
if not hasattr(module, "CREATE_DICTS_FROM_DATACLASS")
else module.CREATE_DICTS_FROM_DATACLASS()
)

# get the variable names and initial values
for node in ast.walk(module_tree):
if isinstance(node, ast.AnnAssign):
# for each variable in the file, get the initial value
# (either is None, or value initialised in init_variables fn)
# set default to be None if variable is not being initialised eg if you
# just have `example_double: float` instead of `example_double: float = None`
initial_value = getattr(module, node.target.id)
initial_value = getattr(object_containing_initial_values, node.target.id)
# JSON doesn't like np arrays
if type(initial_value) is np.ndarray:
initial_value = initial_value.tolist()
Expand Down
36 changes: 36 additions & 0 deletions process/core/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import abc
from dataclasses import dataclass, fields

from process.data_structure.water_usage_variables import WaterUseData

initialise_later = object()


@dataclass(kw_only=True)
class DataStructure:
water_use: WaterUseData = initialise_later

def __post_init__(self):
for f in fields(self):
if getattr(self, f.name) is initialise_later:
setattr(self, f.name, f.type())


class Model(abc.ABC):
data: DataStructure

@abc.abstractmethod
def run(self) -> None:
"""Run the model.

The run method is resposible for 'running' the model, ensuring it updates the data
structure with variables that subsequent models will require.
"""

@abc.abstractmethod
def output(self) -> None:
"""Output model data.

This method will always be called after run method and should output the model data to the
output files.
"""
2 changes: 1 addition & 1 deletion process/core/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def write(models, _outfile):
models.power.output_power_profiles_over_time()

# Water usage in secondary cooling system
models.water_use.run(output=True)
models.water_use.output()

# stop capturing warnings so that Outfile does not end up with
# a lot of non-model logs
Expand Down
127 changes: 51 additions & 76 deletions process/data_structure/water_usage_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,79 +6,54 @@
https://www.thermal-engineering.org/what-is-latent-heat-of-vaporization-definition/
"""

airtemp: float = None
"""ambient air temperature (degrees Celsius)"""

watertemp: float = None
"""water temperature (degrees Celsius)"""

windspeed: float = None
"""wind speed (m/s)"""

waterdens: float = None
"""density of water (kg/m3)
for simplicity, set to static value applicable to water at 21 degC
"""

latentheat: float = None
"""latent heat of vaporization (J/kg)
for simplicity, set to static value applicable at 1 atm (100 kPa) air pressure
"""

volheat: float = None
"""volumetric heat of vaporization (J/m3)"""

evapratio: float = None
"""evaporation ratio: ratio of the heat used to evaporate water
to the total heat discharged through the tower
"""

evapvol: float = None
"""evaporated volume of water (m3)"""

energypervol: float = None
"""input waste (heat) energy cooled per evaporated volume (J/m3)"""

volperenergy: float = None
"""volume evaporated by units of heat energy (m3/MJ)"""

waterusetower: float = None
"""total volume of water used in cooling tower (m3)"""

wateruserecirc: float = None
"""total volume of water used in recirculating system (m3)"""

wateruseonethru: float = None
"""total volume of water used in once-through system (m3)"""


def init_watuse_variables():
"""Initialise water variables"""
global \
airtemp, \
watertemp, \
windspeed, \
waterdens, \
latentheat, \
volheat, \
evapratio, \
evapvol, \
energypervol, \
volperenergy, \
waterusetower, \
wateruserecirc, \
wateruseonethru

airtemp = 15.0
watertemp = 5.0
windspeed = 4.0
waterdens = 998.02
latentheat = 2257000.0
volheat = 0.0
evapratio = 0.0
evapvol = 0.0
energypervol = 0.0
volperenergy = 0.0
waterusetower = 0.0
wateruserecirc = 0.0
wateruseonethru = 0.0
from dataclasses import dataclass


@dataclass
class WaterUseData:
airtemp: float = 15.0
"""ambient air temperature (degrees Celsius)"""
watertemp: float = 5.0
"""water temperature (degrees Celsius)"""
windspeed: float = 4.0
"""wind speed (m/s)"""
waterdens: float = 998.02
"""density of water (kg/m3)
for simplicity, set to static value applicable to water at 21 degC
"""
latentheat: float = 2257000.0
"""latent heat of vaporization (J/kg)
for simplicity, set to static value applicable at 1 atm (100 kPa) air pressure
"""
volheat: float = 0.0
"""volumetric heat of vaporization (J/m3)"""
evapratio: float = 0.0
"""evaporation ratio: ratio of the heat used to evaporate water
to the total heat discharged through the tower
"""

evapvol: float = 0.0
"""evaporated volume of water (m3)"""

energypervol: float = 0.0
"""input waste (heat) energy cooled per evaporated volume (J/m3)"""

volperenergy: float = 0.0
"""volume evaporated by units of heat energy (m3/MJ)"""

waterusetower: float = 0.0
"""total volume of water used in cooling tower (m3)"""

wateruserecirc: float = 0.0
"""total volume of water used in recirculating system (m3)"""

wateruseonethru: float = 0.0
"""total volume of water used in once-through system (m3)"""


# Another disgusting we may need to do in the transition period to support the dicts.
# Once all variables in the new data structure we can make the dicts from the DataStructure...
# and then in the long term put metadata on these classes and entierly remove the dicts
# In the meantime... the dicts will check each module for a '_CREATE_DICTS_FROM_DATACLASS' attribute
# and, if present, use this to create the dict ...
CREATE_DICTS_FROM_DATACLASS = WaterUseData
17 changes: 17 additions & 0 deletions process/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
vary_iteration_variables,
)
from process.core.log import logging_model_handler, show_errors
from process.core.model import DataStructure, Model
from process.core.process_output import OutputFileManager, oheadr
from process.core.scan import Scan
from process.models.availability import Availability
Expand Down Expand Up @@ -731,6 +732,8 @@ def __init__(self):

self.dcll = DCLL(fw=self.fw)

self.setup_data_structure()

@property
def costs(self) -> CostsProtocol:
if data_structure.cost_variables.cost_model == 0:
Expand All @@ -748,6 +751,20 @@ def costs(self) -> CostsProtocol:
def costs(self, value: CostsProtocol):
self._costs_custom = value

@property
def models(self) -> tuple[Model, ...]:
# At the moment, this property just returns models that implement the Model interface.
# Eventually every Model will comply and then this method can be used as the caller/outputter!
return (self.water_use,)

def setup_data_structure(self):
# This Models class should be replaced with a dataclass so we can
# iterate over the `fields`.
# This can be a disgusting temporary measure :(
data = DataStructure()
for model in self.models:
model.data = data


# setup handlers for writing to terminal (on warnings+)
# or writing to the log file (on info+)
Expand Down
Loading
Loading