def run_one_level(net, level): """ """ g = top.graphs_by_level_as_dict(net)[level] gas = Chemical("natural gas", T=net.T_GRND, P=net.LEVELS[level]) loads = _scaled_loads_as_dict(net) p_ops = _operating_pressures_as_dict(net) p_nodes_i, m_dot_pipes_i, m_dot_nodes_i, gas = run_linear(net, level) x0 = np.concatenate((p_nodes_i, m_dot_pipes_i, m_dot_nodes_i)) x0 = np.clip(x0, a_min=1e-1, a_max=None) x0 *= np.random.normal(loc=1, scale=0.1, size=len(x0)) i_mat = create_incidence(g) leng = np.array([data["L_m"] for _, _, data in g.edges(data=True)]) diam = np.array([data["D_m"] for _, _, data in g.edges(data=True)]) materials = np.array([data["mat"] for _, _, data in g.edges(data=True)]) eps = np.array([fluids.material_roughness(m) for m in materials]) res = fsolve(_eq_model, x0, args=(i_mat, g, leng, diam, eps, gas, loads, p_ops, gas.P)) p_nodes = res[:len(g.nodes)] * gas.P m_dot_pipes = res[len(g.nodes):len(g.nodes) + len(g.edges)] * M_DOT_REF m_dot_nodes = res[len(g.nodes) + len(g.edges):] * M_DOT_REF return p_nodes, m_dot_pipes, m_dot_nodes, gas
def multiply_pressure_matrix_to_check(self): self.res_check = 0 # check for pressure conservation for each level sorted_levels = sorted(self.net.levels.items(), key=operator.itemgetter(1)) for level, value in sorted_levels: if level in self.net.bus["level"].unique(): # get network self.level = level netnx = self.net.netnx_all[level] level_value = self.net.levels[level] fluid_type = Chemical("natural gas", T=self.net.temperature, P=level_value + self.net.p_atm) # get network component for this level (not all component just part of it) self._compute_i_mat() self.bus_level = self.net.bus.loc[self.net.bus['level'] == level, :] self.load_level = self.net.load.loc[ self.net.load["bus"].isin(self.bus_level.index), :] self._scaled_loads() self._create_node_mass() # get data for this level materials = self.net.get_data_by_edge(level, "mat") roughness = np.array( [fluids.material_roughness(m) for m in materials]) leng = self.net.get_data_by_edge(level, "L_m") diam = self.net.get_data_by_edge(level, "D_m") name_pipe = self.net.get_data_by_edge(level, "name") m_dot_pipes = self.net.res_pipe.loc[name_pipe, "m_dot_kg/s"].values p_nodes = self.net.res_bus.loc[np.array(netnx.nodes), "p_Pa"].values # make the matrix multiplication (should be null) self._i_mat_for_pressure() p_loss = _dp_from_m_dot_vec(m_dot_pipes, leng, diam, roughness, fluid_type) * (-1) p_loss = np.append(p_loss, [level_value] * len(self.ind_feeder)) self.res_check += sum(self.mat_pres.dot(p_nodes) - p_loss)
def _run_sim(net, level="BP", t_grnd=10 + 273.15): g = top.graphs_by_level_as_dict(net)[level] gas = Chemical('natural gas', T=t_grnd, P=net.LEVELS[level]) material = fluids.nearest_material_roughness('steel', clean=True) eps = fluids.material_roughness(material) x0 = _init_variables(g, net.LEVELS[level]) i_mat = _i_mat(g) leng = np.array([data["L_m"] for _, _, data in g.edges(data=True)]) diam = np.array([data["D_m"] for _, _, data in g.edges(data=True)]) load = _scaled_loads_as_dict(net) p_nom = _p_nom_feed_as_dict(net) logging.debug("SIM {}".format(level)) logging.debug("LOADS {}".format(load)) logging.debug("P_NOM {}".format(p_nom)) res = fsolve(_eq_model, x0, args=(i_mat, g, leng, diam, eps, gas, load, p_nom)) p_nodes = np.round(res[:len(g.nodes)], 1) m_dot_pipes = np.round(res[len(g.nodes):len(g.nodes) + len(g.edges)], 6) m_dot_nodes = np.round(res[len(g.nodes) + len(g.edges):], 6) p_nodes = {n: p_nodes[i] for i, n in enumerate(g.nodes)} m_dot_pipes = { data["name"]: m_dot_pipes[i] for i, (_, _, data) in enumerate(g.edges(data=True)) } m_dot_nodes = {n: m_dot_nodes[i] for i, n in enumerate(g.nodes)} return p_nodes, m_dot_pipes, m_dot_nodes, gas
def test_dp_from_m_dot(): gas = Chemical('natural gas', T=10 + 273.15, P=4.5E5) material = fluids.nearest_material_roughness('steel', clean=True) eps = fluids.material_roughness(material) assert round( sim._dp_from_m_dot_vec(0.005, 100, 0.05, eps, gas).tolist(), 1) == 61.8
def run_sim_by_level(self, level): """ computes the gas simulation for one pressure level. :param level: the considered pressure level :return: a pandasgas network """ # gas parameter self.level = level level_value = self.net.levels[level] fluid_type = Chemical("natural gas", T=self.net.temperature, P=level_value * self.net.corr_pnom + self.net.p_atm) # select network component for this pressure level self._select_component_for_this_level() # get the data by edge for this level materials = self.net.get_data_by_edge(level, "mat") roughness = np.array([fluids.material_roughness(m) for m in materials]) leng = self.net.get_data_by_edge(level, "L_m") diam = self.net.get_data_by_edge(level, "D_m") # add load (with the load linked to a station of a lower pressure level) and give these masses to the nodes self._scaled_loads() m_dot_nodes = self._create_node_mass() # compute incidence matrix (so a matrix which says which node are connected to which edge) self._compute_i_mat() row0 = self.i_mat.shape[0] col0 = self.i_mat.shape[1] if self.net.solver_option['disp']: print('incidence matrix: done.') # modify i_mat so that the unknown linked with the solver are on the left side of the "equation" self._i_mat_with_feeder() # get null space for the mass (so that the space with all possible solutions form the matrix) self._qr_null() nullity_mass = self.z_i_mat.shape[1] # how many freedom degrees # get one solution to the equation representing mass conservation res = lsqr(self.mat_mass, m_dot_nodes, atol=self.net.solver_option['tol_mat_mass'], btol=self.net.solver_option['tol_mat_mass']) sol0 = res[0] if self.net.solver_option['disp']: print('find null space for the mass equation: done.') # obtain the pseudo inverse matrix for the pressure equation (so the matrix which find the closest solution) self._i_mat_for_pressure() pinv_pres = pinv(self.mat_pres) p_noms = [level_value] * len(self.ind_feeder) if self.net.solver_option['disp']: print( 'find pseudo-inverse matrix for the pressure equation: done.') # if we have more than one possibility as solution, minimize if nullity_mass > 0: m0 = np.random.rand(nullity_mass) args_mass = (self.z_i_mat, sol0, self.net.v_max, diam, row0, col0, leng, roughness, fluid_type, pinv_pres, p_noms, self.mat_pres, self.mat_mass, m_dot_nodes, self.net.solver_option) options = { 'maxiter': self.net.solver_option['maxiter'], 'disp': self.net.solver_option['disp'] } _compute_mass_and_pres.niter = 0 # attach a variable to a function # As we have more than on solution for the masss equation, we test many of them to find the one choice # which fits the pressure equation. res = minimize(_compute_mass_and_pres, m0, method='SLSQP', args=args_mass, options=options) # all solution are the "basic" solution + residual, cf. linear algebra. sol = sol0 + self.z_i_mat.dot(res.x) else: sol = sol0 # separate the result m_dot_pipes = sol[:col0] m_dot_nodes[self.ind_feeder] = sol[col0:] # compute load and velocity v, load_pipes = self._v_from_m_dot(diam, m_dot_pipes, fluid_type) # compute pressure p_loss = _dp_from_m_dot_vec(m_dot_pipes, leng, diam, roughness, fluid_type) * (-1) p_loss = np.append(p_loss, p_noms) p_nodes = pinv_pres.dot(p_loss) if nullity_mass > 0 and self.net.solver_option['disp']: _print_minimize_state(p_nodes, res.fun, _compute_mass_and_pres.niter) # transfer output to self.net self._transfer_output_to_net(p_nodes, m_dot_nodes, v, load_pipes, m_dot_pipes)