def __init__(self, json_file_path: str) -> None: """ Initialize the plant loop and all components on it. :param json_file_path: Path to the JSON input file """ self.start_time = dt.datetime.now() # process inputs self.ip = InputProcessor(json_file_path) try: # setup output processor self.op = OutputProcessor( self.ip.input_dict['simulation']['output-path'], self.ip.input_dict['simulation']['output-csv-name']) except KeyError: # paths were not provided. apply default paths. self.op = OutputProcessor(os.getcwd(), 'out.csv') # init plant-level variables self.demand_inlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.demand_outlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.supply_inlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.supply_outlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.end_sim_time = self.ip.input_dict['simulation']['runtime'] # set the time step # can only set the time steps per hour or the time step try: self.time_step = num_ts_per_hour_to_sec_per_ts( self.ip.input_dict['simulation']['time-steps-per-hour']) except KeyError: try: self.time_step = self.ip.input_dict['simulation']['time-step'] except KeyError: raise KeyError( "'simulation' object must contain either 'time-steps-per-hour' or 'time-step' field." ) self.demand_comps = [] self.supply_comps = [] # initialize plant loop components self.initialize_plant_loop_topology()
def add_instance(method): fpath = os.path.dirname(os.path.abspath(__file__)) data_str = '../../../glhe/profiles/external_data/GSHP-GLHE_USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.csv' data_path = os.path.normpath(os.path.join(fpath, data_str)) d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': method, 'value': 10, 'name': 'my name', 'path': data_path, 'start-time': 1, 'end-time': 10, 'amplitude': 100, 'offset': 100, 'period': 10, 'synthetic-method': 'symmetric' }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return make_load_profile(d['load-profile'][0], ip, op)
def test_constant_flow(self): d = {'flow-profile': [{'flow-profile-type': 'constant', 'name': 'my name', 'value': 1}]} temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') tst = make_flow_profile(d['flow-profile'][0], ip, op) self.assertIsInstance(tst, ConstantFlow)
def test_fail(self): d = {'flow-profile': [{'flow-profile-type': 'constant', 'name': 'my name', 'value': 1}]} temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') with self.assertRaises(ValueError) as _: make_flow_profile({'flow-profile-type': 'not-a-type'}, ip, op)
def add_instance(path): d = {'fluid': {'fluid-type': 'water'}, 'load-profile': [{'load-profile-type': 'external', 'name': 'my name', 'path': path}]} temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return ExternalLoad(d['load-profile'][0], ip, op)
def add_instance(): d = { 'flow-profile': [{ 'flow-profile-type': 'constant', 'name': 'my name', 'value': 0.1 }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return ConstantFlow(d['flow-profile'][0], ip, op)
def add_instance(): d = { 'fluid': { 'fluid-type': 'water' }, 'soil': { "name": "dirt", "conductivity": 2.7, "density": 2500, "specific-heat": 880 }, 'grout-definitions': [{ 'name': 'standard grout', 'conductivity': 0.744, 'density': 1500, 'specific-heat': 800 }], 'pipe-definitions': [{ 'name': '32 mm SDR-11 HDPE', 'outer-diameter': 0.0334, 'inner-diameter': 0.0269, 'conductivity': 0.389, 'density': 950, 'specific-heat': 1900 }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') d_seg = { 'length': 7.62, 'diameter': 0.114, 'segment-name': 0, 'grout-def-name': 'standard grout', 'pipe-def-name': '32 mm sdr-11 hdpe' } return SingleUTubeGroutedSegment(d_seg, ip, op)
def add_instance(): temp_dir = tempfile.mkdtemp() temp_data = os.path.join(temp_dir, 'temp_data.csv') with open(temp_data, 'w') as f: f.write('Date/Time, Meas. Total Power [W], mdot [kg/s], temperature[C]\n' '2018-01-01 00:00:00, 1, 1, 1\n' '2018-01-01 01:00:00, 2, 2, 2\n' '2018-01-01 02:00:00, 3, 3, 3\n' '2018-01-01 03:00:00, 4, 4, 4\n') d = {'temperature-profile': [{'temperature-profile-type': 'external', 'name': 'my name', 'path': temp_data}]} temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return ExternalTemps(d['temperature-profile'][0], ip, op)
def test_external_flow(self): fpath = os.path.dirname(os.path.abspath(__file__)) rel_path = '../../../glhe/profiles/external_data/GSHP-GLHE_USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.csv' d = { 'flow-profile': [{'flow-profile-type': 'external', 'name': 'my name', 'path': os.path.join(fpath, rel_path)}]} temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') tst = make_flow_profile(d['flow-profile'][0], ip, op) self.assertIsInstance(tst, ExternalFlow)
def add_instance(): d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': 'constant', 'name': 'my name', 'value': 4000 }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return ConstantLoad(d['load-profile'][0], ip, op)
def add_instance(method): d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': 'synthetic', 'name': 'my name', 'amplitude': 1000, 'synthetic-method': method }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return SyntheticLoad(d['load-profile'][0], ip, op)
def add_instance(): inputs = {'pipe-definitions': [{ 'name': '32 mm sdr-11 hdpe', 'outer-diameter': 0.0334, 'inner-diameter': 0.0269, 'conductivity': 0.4, 'density': 950, 'specific-heat': 1900}], 'fluid': {'fluid-type': 'water'}, 'pipe': [ {'pipe-def-name': '32 mm sdr-11 hdpe', 'name': 'pipe 1', 'length': 100}]} temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, inputs) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return Pipe(inputs['pipe'][0], ip, op)
def add_instance(): d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': 'single-impulse', 'name': 'my name', 'value': 1000, 'start-time': 0, 'end-time': 200 }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return PulseLoad(d['load-profile'][0], ip, op)
def add_instance(): d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': 'sinusoid', 'name': 'my name', 'amplitude': 1, 'offset': 0, 'period': 2 * pi }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return SinusoidLoad(d['load-profile'][0], ip, op)
def test_fail(self): d = { 'fluid': { 'fluid-type': 'water' }, 'load-profile': [{ 'load-profile-type': 'constant', 'value': 10, 'name': 'my name' }] } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') make_load_profile(d['load-profile'][0], ip, op) with self.assertRaises(ValueError) as _: make_load_profile({'load-profile-type': 'not-a-method'}, ip, op)
def add_instance(): f_path = os.path.dirname(os.path.abspath(__file__)) d = { "borehole-definitions": [{ "borehole-type": "single-grouted", "length": 76.2, "diameter": 0.114, "grout-def-name": "standard grout", "name": "borehole type 1", "pipe-def-name": "26 mm SDR-11 HDPE", "segments": 10, "shank-spacing": 0.0469 }], "borehole": [{ "name": "bh 1", "borehole-def-name": "borehole type 1", "location": { "x": 0, "y": 0, "z": 0 } }], "flow-profile": [{ "name": "constant 0.3", "flow-profile-type": "constant", "value": 0.3 }], "fluid": { "fluid-type": "water" }, "ground-temperature-model": { "ground-temperature-model-type": "constant", "temperature": 16.1 }, "grout-definitions": [{ "name": "standard grout", "conductivity": 0.85, "density": 2500, "specific-heat": 1560 }], "load-profile": [{ "name": "constant 4000", "load-profile-type": "constant", "value": 4000 }], "ground-heat-exchanger": [{ "name": "GHE 1", "simulation-mode": "direct", "g-function-path": os.path.join(f_path, '..', '..', '..', 'validation', 'MFRTRT_EWT_g_functions', 'EWT_experimental_g_functions.csv'), "flow-paths": [{ "name": "path 1", "components": [{ "comp-type": "borehole", "name": "bh 1" }] }], "load-aggregation": { "method": "dynamic", "expansion-rate": 1.5, "number-bins-per-level": 9 } }], "pipe-definitions": [{ "name": "26 mm SDR-11 HDPE", "outer-diameter": 0.0267, "inner-diameter": 0.0218, "conductivity": 0.39, "density": 950, "specific-heat": 1900 }], "simulation": { "name": "Basic GLHE", "initial-temperature": 16.1, "time-step": 30, "runtime": 3600 }, "topology": { "demand-side": [{ "comp-type": "flow-profile", "name": "constant 0.3" }, { "comp-type": "load-profile", "name": "constant 4000" }], "supply-side": [{ "comp-type": "ground-heat-exchanger", "name": "GHE 1" }] }, "soil": { "name": "dirt", "conductivity": 2.7, "density": 2500, "specific-heat": 880 } } temp_dir = tempfile.mkdtemp() temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(f_path, 'out.csv') return GroundHeatExchangerSTS(d['ground-heat-exchanger'][0], ip, op)
class PlantLoop(object): Type = ComponentTypes.PlantLoop def __init__(self, json_file_path: str) -> None: """ Initialize the plant loop and all components on it. :param json_file_path: Path to the JSON input file """ self.start_time = dt.datetime.now() # process inputs self.ip = InputProcessor(json_file_path) try: # setup output processor self.op = OutputProcessor( self.ip.input_dict['simulation']['output-path'], self.ip.input_dict['simulation']['output-csv-name']) except KeyError: # paths were not provided. apply default paths. self.op = OutputProcessor(os.getcwd(), 'out.csv') # init plant-level variables self.demand_inlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.demand_outlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.supply_inlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.supply_outlet_temp = self.ip.input_dict['simulation'][ 'initial-temperature'] self.end_sim_time = self.ip.input_dict['simulation']['runtime'] # set the time step # can only set the time steps per hour or the time step try: self.time_step = num_ts_per_hour_to_sec_per_ts( self.ip.input_dict['simulation']['time-steps-per-hour']) except KeyError: try: self.time_step = self.ip.input_dict['simulation']['time-step'] except KeyError: raise KeyError( "'simulation' object must contain either 'time-steps-per-hour' or 'time-step' field." ) self.demand_comps = [] self.supply_comps = [] # initialize plant loop components self.initialize_plant_loop_topology() def initialize_plant_loop_topology(self) -> None: for comp in self.ip.input_dict['topology']['demand-side']: self.demand_comps.append( make_plant_loop_component(comp, self.ip, self.op)) for comp in self.ip.input_dict['topology']['supply-side']: self.supply_comps.append( make_plant_loop_component(comp, self.ip, self.op)) def simulate(self) -> bool: """ Do the entire time stepping simulation of the plant loop """ current_sim_time = 0 while True: self.do_one_time_step(current_sim_time, self.time_step) current_sim_time += self.time_step self.collect_outputs(current_sim_time) if current_sim_time >= self.end_sim_time: break self.op.write_to_file() print('Simulation time: {}'.format(dt.datetime.now() - self.start_time)) with open( '{}.txt'.format( os.path.join(self.op.output_dir, self.op.output_file[:-4])), 'w+') as f: f.write('Simulation time: {}\n'.format(dt.datetime.now() - self.start_time)) return True def do_one_time_step(self, sim_time: Union[int, float], time_step: Union[int, float]): """ Simulate one time step of the entire plant loop """ # update demand inlet node and initial conditions self.demand_inlet_temp = self.supply_outlet_temp response = SimulationResponse(sim_time, time_step, 0, self.demand_inlet_temp) # simulate demand components flow-wise for comp in self.demand_comps: response = comp.simulate_time_step(response) # update interface nodes self.demand_outlet_temp = response.temperature self.supply_inlet_temp = response.temperature # simulate supply components flow-wise for comp in self.supply_comps: response = comp.simulate_time_step(response) # supply outlet node self.supply_outlet_temp = response.temperature def report_outputs(self): d = { '{:s}:{:s}'.format(self.Type, 'Demand Inlet Temp. [C]'): self.demand_inlet_temp, '{:s}:{:s}'.format(self.Type, 'Demand Outlet Temp. [C]'): self.demand_outlet_temp, '{:s}:{:s}'.format(self.Type, 'Supply Inlet Temp. [C]'): self.supply_inlet_temp, '{:s}:{:s}'.format(self.Type, 'Supply Outlet Temp. [C]'): self.supply_outlet_temp } return d def collect_outputs(self, sim_time): # record current time d = {'Elapsed Time [s]': sim_time} # report outputs from the PlantLoop object d = merge_dicts(d, self.report_outputs()) # collect reports from demand components for comp in self.demand_comps: d = merge_dicts(d, comp.report_outputs()) # collect outputs from the supply components for comp in self.supply_comps: d = merge_dicts(d, comp.report_outputs()) # finalize collection by the OutputProcessor self.op.collect_output(d)
def add_instance(): temp_dir = tempfile.mkdtemp() with open(os.path.join(temp_dir, 'temp.csv'), 'w') as f: f.write( 'Date/Time,Heating Loads (W),Water Heating Loads (W),Outdoor Air Temperature (C)\n' ) f.write('1/1/2019 0:00,751.231087,0,4\n') f.write('1/1/2019 1:00,609.682528,60.515364,5.3\n') f.write('1/1/2019 2:00,728.634445,41.330207,6.2\n') f.write('1/1/2019 3:00,562.383158,42.178469,6.8\n') f.write('1/1/2019 4:00,685.067724,63.096246,7.2\n') f.write('1/1/2019 5:00,539.127476,43.947185,7.5\n') f.write('1/1/2019 6:00,663.467736,44.849591,7.5\n') f.write('1/1/2019 7:00,539.08215,165.88032,6.7\n') f.write('1/1/2019 8:00,692.252428,26.56684,6\n') f.write('1/1/2019 9:00,564.562993,888.906269,5.2\n') f.write('1/1/2019 10:00,670.844481,1230.286559,5.2\n') f.write('1/1/2019 11:00,453.722975,610.134925,5.2\n') f.write('1/1/2019 12:00,538.938447,771.268588,5.2\n') f.write('1/1/2019 13:00,460.832251,30.826198,4.6\n') f.write('1/1/2019 14:00,674.925154,51.852264,4.1\n') f.write('1/1/2019 15:00,583.467315,1515.140121,3.5\n') f.write('1/1/2019 16:00,769.103444,10851.59779,3.2\n') f.write('1/1/2019 17:00,621.861048,10852.40995,2.9\n') f.write('1/1/2019 18:00,807.407677,45000,2.6\n') f.write('1/1/2019 19:00,646.501964,1779.03981,2.5\n') f.write('1/1/2019 20:00,830.903352,157.21722,2.4\n') f.write('1/1/2019 21:00,661.800554,358.381625,2.3\n') f.write('1/1/2019 22:00,847.617722,38.695181,2.3\n') f.write('1/1/2019 23:00,675.803234,179.849569,2.2\n') inputs = { 'fluid': { 'fluid-type': 'PG', 'concentration': 35 }, 'swedish-heat-pump': [{ 'name': 'svenska varmmepumpe', 'max-heating-set-point': 55, 'min-heating-set-point': 30, 'water-heating-set-point': 60, 'outdoor-air-temperature-at-max-heating-set-point': -10, 'outdoor-air-temperature-at-min-heating-set-point': 20, 'immersion-heater-capacity': 7000, 'load-data-path': os.path.join(temp_dir, 'temp.csv'), 'capacity-coefficients': [8.536666667, -0.007266667, -0.00084, 0.263666667], 'coefficient-of-performance-coefficients': [7.641839817, -0.075098454, -0.000208441, 0.109423218], }] } temp_file = os.path.join(temp_dir, 'temp.json') write_json(temp_file, inputs) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return SwedishHP(inputs['swedish-heat-pump'][0], ip, op)
def add_instance(): d = { "borehole-definitions": [{ "borehole-type": "single-grouted", "length": 76.2, "diameter": 0.114, "grout-def-name": "standard grout", "name": "borehole type 1", "pipe-def-name": "26 mm SDR-11 HDPE", "segments": 10, "shank-spacing": 0.0469 }], "borehole": [{ "name": "bh 1", "borehole-def-name": "borehole type 1", "location": { "x": 0, "y": 0, "z": 0 } }], "fluid": { "fluid-type": "water" }, "grout-definitions": [{ "name": "standard grout", "conductivity": 0.85, "density": 2500, "specific-heat": 1560 }], "ground-heat-exchanger": [{ "name": "GHE 1", "simulation-mode": "direct", "g-function-path": "validation/MFRTRT_EWT_g_functions/EWT_experimental_g_functions.csv", "flow-paths": [{ "name": "path 1", "components": [{ "comp-type": "borehole", "name": "bh 1" }] }], "load-aggregation": { "method": "dynamic", "expansion-rate": 1.5, "number-bins-per-level": 9 } }], "pipe-definitions": [{ "name": "26 mm SDR-11 HDPE", "outer-diameter": 0.0267, "inner-diameter": 0.0218, "conductivity": 0.39, "density": 950, "specific-heat": 1900 }], "soil": { "name": "dirt", "conductivity": 2.7, "density": 2500, "specific-heat": 880 } } temp_dir = tempfile.mkdtemp() temp_file = norm(join(temp_dir, 'temp.json')) write_json(temp_file, d) ip = InputProcessor(temp_file) op = OutputProcessor(temp_dir, 'out.csv') return Path(d['ground-heat-exchanger'][0]['flow-paths'][0], ip, op)