def test_simulate_time_step(self): tst = self.add_instance() res = tst.simulate_time_step(SimulationResponse(0, 10, 0, 10)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 10) self.assertEqual(res.flow_rate, 0) self.assertAlmostEqual(res.temperature, 10, delta=0.1) res = tst.simulate_time_step(SimulationResponse(0, 10, 0.1, 10)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 10) self.assertEqual(res.flow_rate, 0.1) self.assertAlmostEqual(res.temperature, 19.5, delta=0.1)
def test_simulate_time_step(self): tst = self.add_instance() tol = 0.01 response = SimulationResponse(0, 3600, 0.3, 20) response = tst.simulate_time_step(response) self.assertAlmostEqual(response.temperature, 19.44, delta=tol) response = SimulationResponse(3600 * 16, 3600, 0.3, 20) response = tst.simulate_time_step(response) self.assertAlmostEqual(response.temperature, 12.87, delta=tol) response = SimulationResponse(3600 * 18, 3600, 0.3, 20) response = tst.simulate_time_step(response) self.assertAlmostEqual(response.temperature, 12.87, delta=tol)
def test_simulate_time_step(self): tst = self.add_instance() res = tst.simulate_time_step(SimulationResponse(0, 3600, 1, 10)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 3600) self.assertEqual(res.flow_rate, 1) self.assertEqual(res.temperature, 2)
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 test_simulate_time_step(self): tol = 0.01 tst = self.add_instance('symmetric') res = tst.simulate_time_step(SimulationResponse(0, 60, 0, 20)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 60) self.assertEqual(res.flow_rate, 0) self.assertEqual(res.temperature, 20) res = tst.simulate_time_step(SimulationResponse(0, 60, 0.2, 20)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 60) self.assertEqual(res.flow_rate, 0.2) self.assertAlmostEqual(res.temperature, 20, delta=tol)
def simulate_time_step(self, inputs: SimulationResponse) -> SimulationResponse: time = inputs.time dt = inputs.time_step flow_rate = inputs.flow_rate inlet_temp = inputs.temperature # model prioritizes water heating above space heating # so these must be done in order self.calc_wtr_htg(time, inlet_temp) self.calc_htg(time, inlet_temp) # collect totals self.hp_rtf = self.wtr_htg_rtf + self.htg_rtf self.heat_extraction = -self.wtr_htg_heat_extraction - self.htg_heat_extraction cp = self.fluid.get_cp(inlet_temp) outlet_temp = inlet_temp + self.heat_extraction / (flow_rate * cp) response = SimulationResponse(time, dt, flow_rate, outlet_temp, hp_src_heat_rate=self.heat_extraction) # update report variables self.htg_tot = self.htg + self.wtr_htg self.imm_elec_tot = self.htg_imm_elec + self.wtr_htg_imm_elec self.flow_rate = flow_rate self.inlet_temperature = inlet_temp self.outlet_temperature = outlet_temp self.odt = self.oda_temps.get_value(time) return response
def simulate_time_step(self, inputs: SimulationResponse) -> SimulationResponse: if inputs.bh_wall_temp: response = SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, inputs.temperature, inputs.bh_wall_temp) else: response = SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, inputs.temperature) for comp in self.components: response = comp.simulate_time_step(response) # update report variables self.flow_rate = inputs.flow_rate self.inlet_temperature = inputs.temperature self.outlet_temperature = response.temperature return response
def simulate_time_step(self, inputs: SimulationResponse) -> SimulationResponse: time = inputs.time time_step = inputs.time_step flow_rate = inputs.flow_rate inlet_temp = inputs.temperature bh_wall_temp = inputs.bh_wall_temp r_12, r_b = self.calc_direct_coupling_resistance(inlet_temp, flow_rate=flow_rate) seg_inputs = {'boundary-temperature': bh_wall_temp, 'rb': r_b, 'flow-rate': flow_rate, 'dc-resist': r_12} self.pipe_1.simulate_time_step(SimulationResponse(time, time_step, flow_rate, inlet_temp)) for _ in range(self.num_iterations): for idx, seg in enumerate(self.segments): if idx == 0: seg_inputs['inlet-1-temp'] = self.pipe_1.outlet_temperature seg_inputs['inlet-2-temp'] = self.segments[idx + 1].get_outlet_2_temp() elif idx == self.num_segments: seg_inputs['inlet-1-temp'] = self.segments[idx - 1].get_outlet_1_temp() else: seg_inputs['inlet-1-temp'] = self.segments[idx - 1].get_outlet_1_temp() seg_inputs['inlet-2-temp'] = self.segments[idx + 1].get_outlet_2_temp() seg.simulate_time_step(time_step, seg_inputs) self.pipe_2.simulate_time_step(SimulationResponse(time, time_step, flow_rate, self.get_outlet_temp())) # update report variables self.inlet_temperature = inlet_temp self.outlet_temperature = self.pipe_2.outlet_temperature cp = self.fluid.get_cp(inlet_temp) self.heat_rate = flow_rate * cp * (inlet_temp - self.outlet_temperature) self.heat_rate_bh = self.get_heat_rate_bh() return SimulationResponse(time, time_step, flow_rate, self.get_outlet_temp())
def simulate_time_step(self, inputs: SimulationResponse) -> SimulationResponse: time = inputs.time time_step = inputs.time_step flow = inputs.flow_rate inlet_temp = inputs.temperature # TODO: update bh wall temp # self.bh_wall_temperature = self.soil.get_temp(time, self.h) self.bh_wall_temperature = self.soil.get_temp( time, self.h) + self.calc_bh_wall_temp_rise(time, time_step) # TODO: distribute flow properly path_inlet_conditions = SimulationResponse(inputs.time, inputs.time_step, flow, inlet_temp, self.bh_wall_temperature) path_responses = [] for path in self.paths: path_responses.append( path.simulate_time_step(path_inlet_conditions)) outlet_temp = self.mix_paths(path_responses) # update report variables # TODO: generalize first-law computations everywhere cp = self.fluid.get_cp(inlet_temp) self.heat_rate = flow * cp * (inlet_temp - outlet_temp) self.heat_rate_bh = self.get_heat_rate_bh() self.inlet_temperature = inputs.temperature self.outlet_temperature = outlet_temp # normalized borehole wall heat transfer rate (W/m) q = self.heat_rate_bh / (self.h * self.num_bh) # energy (J/m) self.energy = q * time_step return SimulationResponse(inputs.time, inputs.time_step, flow, outlet_temp)
def simulate_time_step(self, inputs: SimulationResponse): self.inlet_temp = inputs.temperature flow_rate = inputs.flow_rate if flow_rate == 0: return inputs specific_heat = self.ip.props_mgr.fluid.get_cp(self.inlet_temp) self.outlet_temp = self.load / (flow_rate * specific_heat) + self.inlet_temp return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temp)
def test_simulate_time_step(self): 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]\n' '2018-01-01 00:00:00, 1, 1\n' '2018-01-01 01:00:00, 2, 2\n' '2018-01-01 02:00:00, 3, 3\n' '2018-01-01 03:00:00, 4, 4\n') tst = self.add_instance(temp_data) res = tst.simulate_time_step(SimulationResponse(0, 10, 0, 10)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 10) self.assertEqual(res.flow_rate, 0) self.assertAlmostEqual(res.temperature, 10, delta=0.1) res = tst.simulate_time_step(SimulationResponse(0, 10, 0.00001, 10)) self.assertEqual(res.time, 0) self.assertEqual(res.time_step, 10) self.assertEqual(res.flow_rate, 0.00001) self.assertAlmostEqual(res.temperature, 33.9, delta=0.1)
def simulate_time_step(self, inputs: SimulationResponse): flow_rate = inputs.flow_rate if flow_rate == 0: return inputs t = inputs.time dt = inputs.time_step inlet_temp = inputs.temperature self.load = self.amplitude * sin(2 * pi * (t + dt) / self.period) + self.offset specific_heat = self.ip.props_mgr.fluid.get_cp(inlet_temp) self.outlet_temp = self.load / (flow_rate * specific_heat) + inlet_temp return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temp)
def simulate_time_step(self, inputs: SimulationResponse): if self.start_time <= inputs.time + inputs.time_step < self.end_time: flow_rate = inputs.flow_rate if flow_rate == 0: return inputs inlet_temp = inputs.temperature specific_heat = self.ip.props_mgr.fluid.get_cp(inlet_temp) self.outlet_temp = self.load / (flow_rate * specific_heat) + inlet_temp return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temp) else: self.load = 0 return inputs
def test_simulate_time_step(self): tst = self.add_instance() tol = 0.01 self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(0, 100, 0.1, 25)).temperature, 20, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(100, 100, 0.1, 25)).temperature, 20, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(200, 100, 0.1, 25)).temperature, 20, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(300, 100, 0.1, 25)).temperature, 20, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(400, 100, 0.1, 25)).temperature, 20, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(500, 100, 0.1, 25)).temperature, 22.63, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(600, 100, 0.1, 25)).temperature, 24.34, delta=tol) self.assertAlmostEqual(tst.simulate_time_step(SimulationResponse(700, 100, 0.1, 25)).temperature, 24.87, delta=tol)
def simulate_time_step(self, inputs: SimulationResponse): return SimulationResponse(inputs.time, inputs.time_step, self.flow_rate, inputs.temperature)
def generate_g_b(self, flow_rate=0.5): q = 10 # W/m flow_rate = flow_rate flow_rate_path = flow_rate / self.num_paths # kg/s temperature = self.ip.init_temp() # C d_ave_bh = { 'average-borehole': self.average_bh(), 'name': 'average-borehole', 'borehole-type': 'single-grouted' } ave_bh = make_borehole(d_ave_bh, self.ip, self.op) dt = 30 times = range(0, SEC_IN_DAY + dt, dt) q_tot = q * self.num_bh * self.h # W r_b = ave_bh.calc_bh_average_resistance(temperature, flow_rate_path) lntts_b = [] g_b = [] for t in times: cp = self.fluid.get_cp(temperature) temperature = temperature + q_tot / (flow_rate * cp) response = SimulationResponse(t, dt, flow_rate, temperature) temperature = self.simulate_time_step(response).temperature t_out = self.outlet_temperature t_bh = self.bh_wall_temperature lntts_b.append(log((t + dt) / self.ts)) g_b.append((t_out - t_bh) / (q * r_b)) # check for convergence err = (g_b[-1] - g_b[-2]) / (lntts_b[-1] - lntts_b[-2]) t = times[-1] end_time = self.ip.input_dict['simulation']['runtime'] while err > 0.02: t += dt cp = self.fluid.get_cp(temperature) temperature = temperature + q_tot / (flow_rate * cp) response = SimulationResponse(t, dt, flow_rate, temperature) temperature = self.simulate_time_step(response).temperature t_out = self.outlet_temperature t_bh = self.bh_wall_temperature lntts_b.append(log((t + dt) / self.ts)) g_b.append((t_out - t_bh) / (q * r_b)) err = (g_b[-1] - g_b[-2]) / (lntts_b[-1] - lntts_b[-2]) if t > end_time: break # add point at end time if end_time > t: lntts_b.append(log(end_time / self.ts)) g_b.append(g_b[-1]) self.lntts_b, self.g_b = resample_g_functions(lntts_b, g_b, lntts_interval=0.1) write_arrays_to_csv(os.path.join(self.op.output_dir, 'g_b.csv'), [self.lntts_b, self.g_b])
def simulate_time_step(self, inputs: SimulationResponse) -> SimulationResponse: """ Simulate the temperature response of an adiabatic pipe with internal fluid mixing. Rees, S.J. 2015. 'An extended two-dimensional borehole heat exchanger model for simulation of short and medium timescale thermal response.' Renewable Energy. 83: 518-526. Skoglund, T, and P. Dejmek. 2007. 'A dynamic object-oriented model for efficient simulation of fluid dispersion in turbulent flow with varying fluid properties.' Chem. Eng. Sci.. 62: 2168-2178. Bischoff, K.B., and O. Levenspiel. 1962. 'Fluid dispersion--generalization and comparision of mathematical models--II; Comparison of models.' Chem. Eng. Sci.. 17: 257-264. :param inputs: inlet conditions :return: outlet conditions """ # iteration constants num_cells = self.num_pipe_cells m_dot = inputs.flow_rate inlet_temp = inputs.temperature time = inputs.time dt_tot = inputs.time_step if dt_tot > 0: re = self.m_dot_to_re(m_dot, inlet_temp) r_p = self.inner_radius l = self.length # total transit time tau = self.calc_transit_time(m_dot, inlet_temp) # Rees Eq. 18 # Peclet number peclet = 1 / (2 * r_p / l * (3.e7 * re**-2.1 + 1.35 * re**-0.125)) # Rees Eq. 17 # transit time for ideal-mixed cells tau_n = tau * sqrt(2 / (num_cells * peclet)) # transit time for plug-flow cell tau_0 = tau - num_cells * tau_n # volume flow rate v_dot = m_dot / self.fluid.get_rho(inlet_temp) # volume for ideal-mixed cells v_n = tau_n * v_dot # check for sub-stepping # limit maximum step to 10% of the transit time if (dt_tot / tau) > 0.10: num_sub_steps = ceil(dt_tot / tau) dt = dt_tot / num_sub_steps else: num_sub_steps = 1 dt = dt_tot steps = [dt] * num_sub_steps t_sub = time # setup tri-diagonal equations a = np.full(num_cells - 1, -v_dot) b = np.full(num_cells, v_n / dt + v_dot) b[0] = 1 c = np.full(num_cells - 1, 0) for _ in steps: d = np.full(num_cells, v_n / dt) * self.cell_temps if self.apply_transit_delay: self.log_inlet_temps(inlet_temp, t_sub + dt) d[0] = self.plug_flow_outlet_temp(t_sub + dt - tau_0) else: d[0] = inlet_temp # solve for cell temps self.cell_temps = tdma_1(a, b, c, d) # update time t_sub += dt # save outlet temp self.outlet_temperature = self.cell_temps[-1] if hasattr(inputs, 'bh_wall_temp'): return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temperature, inputs.bh_wall_temp) else: return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temperature)
def simulate_time_step(self, inputs: SimulationResponse): self.flow_rate = self.get_value(inputs.time + inputs.time_step) return SimulationResponse(inputs.time, inputs.time_step, self.flow_rate, inputs.temperature)
def simulate_time_step(self, inputs: SimulationResponse): time = inputs.time dt = inputs.time_step flow_rate = inputs.flow_rate inlet_temp = inputs.temperature # per bh variables flow_rate_path = flow_rate / self.num_paths # aggregate load from previous time # load aggregation method takes care of what happens during iterations self.load_agg.aggregate(time, self.energy) # solve for outlet temperature g = self.load_agg.get_g_value(dt) g_b = self.load_agg.get_g_b_value(dt, flow_rate_path) resist_b = self.ave_bh.calc_bh_average_resistance( temperature=inlet_temp, flow_rate=flow_rate) hist_g, hist_g_b = self.load_agg.calc_temporal_superposition( dt, flow_rate_path) c_1 = self.c_0 * hist_g + resist_b * hist_g_b hist_x_ghe = 0 if self.cross_ghe_present: for x_ghe in self.cross_ghe: x_ghe.simulate_time_step(dt, time) hist_x_ghe += x_ghe.load_agg.calc_temporal_superposition(dt) c_1 += self.c_0 * hist_x_ghe c_2 = (self.c_0 * g + resist_b * g_b) cp = self.fluid.get_cp(inlet_temp) c_3 = (flow_rate_path * cp) / self.h q_prev = self.load_agg.get_q_prev() soil_temp = self.soil.get_temp(time, self.h) outlet_temp = (soil_temp + c_2 * c_3 * inlet_temp - c_2 * q_prev + c_1) / (1 + c_2 * c_3) # total heat transfer rate (W) q_tot = flow_rate * cp * (inlet_temp - outlet_temp) # normalized heat transfer rate (W/m) self.q = q_tot / (self.h * self.num_bh) # energy (J/m) self.energy = self.q * dt # set report variables self.inlet_temperature = inlet_temp self.outlet_temperature = outlet_temp self.heat_rate = q_tot self.resist_b = resist_b self.bh_wall_temperature = soil_temp + self.c_0 * (hist_g + hist_x_ghe) self.resist_b_eff = self.ave_bh.calc_bh_effective_resistance_uhf( temperature=inlet_temp, flow_rate=flow_rate) return SimulationResponse(inputs.time, inputs.time_step, inputs.flow_rate, self.outlet_temperature)