def diffusive_disc(self): 'Discretization of term \nabla K \nabla T' if self.is_GridBucket: diffusive_discr = tpfa.TpfaMixedDim(physics=self.physics) else: diffusive_discr = tpfa.Tpfa(physics=self.physics) return diffusive_discr
def flux_disc(self): if self.mp: return mpfa.MpfaMixedDim(physics=self.physics) elif self.mix: return MixedDiscretization(self.physics) else: return tpfa.TpfaMixedDim(physics=self.physics)
def test_tpfa_matching_grids_no_flow(self): gb = self.set_grids(N=[1, 2], num_nodes_mortar=2, num_nodes_1d=2) self.set_param_flow(gb, no_flow=True) solver_flow = tpfa.TpfaMixedDim("flow") A_flow, b_flow = solver_flow.matrix_rhs(gb) p = sps.linalg.spsolve(A_flow, b_flow) self.assertTrue(np.all(p[:3] == 1)) self.assertTrue(np.all(p[3:] == 0))
def solve_tpfa(gb, folder): # Choose and define the solvers and coupler solver_flow = tpfa.TpfaMixedDim("flow") A_flow, b_flow = solver_flow.matrix_rhs(gb) solver_source = source.IntegralMixedDim("flow") A_source, b_source = solver_source.matrix_rhs(gb) p = sps.linalg.spsolve(A_flow + A_source, b_flow + b_source) solver_flow.split(gb, "pressure", p) save = Exporter(gb, "sol", folder=folder) save.write_vtk(["pressure"])
def test_tpfa_matching_grids_refine_2d_uniform_flow(self): kn = 1e4 gb = self.set_grids(N=[2, 2], num_nodes_mortar=2, num_nodes_1d=2) self.set_param_flow(gb, no_flow=False, kn=kn) solver_flow = tpfa.TpfaMixedDim("flow") A_flow, b_flow = solver_flow.matrix_rhs(gb) p = sps.linalg.spsolve(A_flow, b_flow) solver_flow.split(gb, "pressure", p) g_2d = gb.grids_of_dimension(2)[0] p_2d = gb.node_props(g_2d, "pressure") # NOTE: This will not be entirely correct due to impact of normal permeability at fracture self.assertTrue(np.allclose(p_2d, g_2d.cell_centers[1], rtol=1e-4)) g_1d = gb.grids_of_dimension(1)[0] p_1d = gb.node_props(g_1d, "pressure") # NOTE: This will not be entirely correct, self.assertTrue(np.allclose(p_1d, g_1d.cell_centers[1]))
def main(kf, description, multi_point, if_export=False): # Define the geometry and produce the meshes mesh_kwargs = {} mesh_size = 0.045 mesh_kwargs['mesh_size'] = { 'mode': 'constant', 'value': mesh_size, 'bound_value': mesh_size } domain = {'xmin': 0, 'xmax': 1, 'ymin': 0, 'ymax': 1} file_name = 'network_geiger.csv' write_network(file_name) gb = importer.dfm_2d_from_csv(file_name, mesh_kwargs, domain) gb.compute_geometry() gb.assign_node_ordering() # Assign parameters add_data(gb, domain, kf, mesh_size) # Choose discretization and define the solver if multi_point: solver = mpfa.MpfaMixedDim('flow') else: solver = tpfa.TpfaMixedDim('flow') # Discretize A, b = solver.matrix_rhs(gb) # Solve the linear system p = sps.linalg.spsolve(A, b) # Store the solution gb.add_node_props(['pressure']) solver.split(gb, 'pressure', p) if if_export: save = Exporter(gb, "fv", folder="fv_" + description) save.write_vtk(['pressure'])
def flux_disc(self): if self.multi_point: return mpfa.MpfaMixedDim(physics=self.physics) else: return tpfa.TpfaMixedDim(physics=self.physics)
for g, d in gb: bound_faces = g.tags['domain_boundary_faces'].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] left = bound_face_centers[0, :] < domain['xmin'] + tol flow_rate = d['u'][bound_faces[left]] total_flow_rate += np.sum(flow_rate) print("total flow rate", total_flow_rate) exporter.export_vtk(gb, 'darcy', ['pressure', "P0u"], folder=export_folder) ################################################################# physics = 'transport' advection = upwind.UpwindMixedDim(physics) diffusion = tpfa.TpfaMixedDim(physics) mass = mass_matrix.MassMatrixMixedDim(physics) invMass = mass_matrix.InvMassMatrixMixedDim(physics) # Assign parameters add_data_advection_diffusion(gb, domain, tol, a) T = 1 deltaT = 0.01 gb.add_node_prop('deltaT', prop=deltaT) U, rhs_u = advection.matrix_rhs(gb) D, rhs_d = diffusion.matrix_rhs(gb) M, _ = mass.matrix_rhs(gb) OF = advection.outflow(gb)
def test_upwind_2d_1d_cross_with_elimination(self): """ Simplest possible elimination scenario, one 0d-grid removed. Check on upwind matrix, rhs, solution and time step estimate. Full solution included (as comments) for comparison purposes if test breaks. """ f1 = np.array([[0, 1], [.5, .5]]) f2 = np.array([[.5, .5], [0, 1]]) domain = {'xmin': 0, 'ymin': 0, 'xmax': 1, 'ymax': 1} mesh_size = 0.4 mesh_kwargs = {} mesh_kwargs['mesh_size'] = { 'mode': 'constant', 'value': mesh_size, 'bound_value': mesh_size } gb = meshing.cart_grid([f1, f2], [2, 2], **{'physdims': [1, 1]}) #gb = meshing.simplex_grid( [f1, f2],domain,**mesh_kwargs) gb.compute_geometry() gb.assign_node_ordering() # Enforce node orderning because of Python 3.5 and 2.7. # Don't do it in general. cell_centers_1 = np.array([[7.50000000e-01, 2.500000000e-01], [5.00000000e-01, 5.00000000e-01], [-5.55111512e-17, 5.55111512e-17]]) cell_centers_2 = np.array([[5.00000000e-01, 5.00000000e-01], [7.50000000e-01, 2.500000000e-01], [-5.55111512e-17, 5.55111512e-17]]) for g, d in gb: if g.dim == 1: if np.allclose(g.cell_centers, cell_centers_1): d['node_number'] = 1 elif np.allclose(g.cell_centers, cell_centers_2): d['node_number'] = 2 else: raise ValueError('Grid not found') tol = 1e-3 solver = tpfa.TpfaMixedDim() gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) a_dim = np.power(a, gb.dim_max() - g.dim) aperture = np.ones(g.num_cells) * a_dim param.set_aperture(aperture) kxx = np.ones(g.num_cells) * np.power(1e3, g.dim < gb.dim_max()) p = tensor.SecondOrder(3, kxx, kyy=kxx, kzz=kxx) param.set_tensor('flow', p) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] right = bound_face_centers[0, :] > 1 - tol left = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[right] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[right] bc_neu = bound_faces[left] bc_val[bc_dir] = g.face_centers[0, bc_dir] bc_val[bc_neu] = -g.face_areas[bc_neu] * a_dim param.set_bc('flow', bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val('flow', bc_val) # Transport: source = g.cell_volumes * a_dim param.set_source("transport", source) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] left = bound_face_centers[0, :] < tol right = bound_face_centers[0, :] > 1 - tol bottom = bound_face_centers[1, :] < tol top = bound_face_centers[1, :] > 1 - tol labels = np.array(['neu'] * bound_faces.size) labels[np.logical_or(np.logical_or(left, right), np.logical_or(top, bottom))] = ['dir'] bc_val = np.zeros(g.num_faces) #bc_dir = bound_faces[np.logical_or(left, right)] #bc_val[bc_dir] = 1 param.set_bc('transport', bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val('transport', bc_val) d['param'] = param gb.add_edge_prop('param') for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] d['param'] = Parameters(g_h) A, rhs = solver.matrix_rhs(gb) # p = sps.linalg.spsolve(A,rhs) _, p_red, _, _ = condensation.solve_static_condensation(A, rhs, gb, dim=0) dim_to_remove = 0 gb_r, elimination_data = gb.duplicate_without_dimension(dim_to_remove) condensation.compute_elimination_fluxes(gb, gb_r, elimination_data) solver.split(gb_r, "pressure", p_red) # fvutils.compute_discharges(gb) fvutils.compute_discharges(gb_r) #------Transport------# advection_discr = upwind.Upwind(physics="transport") advection_coupling_conditions = upwind.UpwindCoupling(advection_discr) advection_coupler = coupler.Coupler(advection_discr, advection_coupling_conditions) U_r, rhs_u_r = advection_coupler.matrix_rhs(gb_r) _, rhs_src_r = IntegralMixedDim(physics='transport').matrix_rhs(gb_r) rhs_u_r = rhs_u_r + rhs_src_r deltaT = np.amin( gb_r.apply_function(advection_discr.cfl, advection_coupling_conditions.cfl).data) theta_r = sps.linalg.spsolve(U_r, rhs_u_r) U_known, rhs_known, theta_known, deltaT_known = known_for_elimination() tol = 1e-7 assert (np.isclose(deltaT, deltaT_known, tol, tol)) assert ((np.amax(np.absolute(U_r - U_known))) < tol) assert ((np.amax(np.absolute(rhs_u_r - rhs_known))) < tol) assert ((np.amax(np.absolute(theta_r - theta_known))) < tol)
def flux_disc(self): if self.is_GridBucket: return tpfa.TpfaMixedDim(physics=self.physics) else: return tpfa.Tpfa(physics=self.physics)
def test_tpfa_fluxes_2d_1d_left_right_dir_neu(self): """ Grid: 2 x 2 cells in matrix + 2 cells in the fracture from left to right. Dirichlet + inflow + no-flow, conductive fracture. Tests pressure solution and fluxes. """ f = np.array([[0, 1], [.5, .5]]) gb = meshing.cart_grid([f], [2, 2], **{'physdims': [1, 1]}) gb.compute_geometry() gb.assign_node_ordering() tol = 1e-3 solver = tpfa.TpfaMixedDim(physics='flow') gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) a_dim = np.power(a, gb.dim_max() - g.dim) aperture = np.ones(g.num_cells) * a_dim param.set_aperture(aperture) p = tensor.SecondOrder( 3, np.ones(g.num_cells) * np.power(1e-3, g.dim < gb.dim_max())) param.set_tensor('flow', p) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] right = bound_face_centers[0, :] > 1 - tol left = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[right] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[right] bc_neu = bound_faces[left] bc_val[bc_dir] = g.face_centers[0, bc_dir] bc_val[bc_neu] = -g.face_areas[bc_neu] * a_dim param.set_bc('flow', bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val('flow', bc_val) d['param'] = param gb.add_edge_prop('param') for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] d['param'] = Parameters(g_h) A, rhs = solver.matrix_rhs(gb) p = sps.linalg.spsolve(A, rhs) solver.split(gb, "pressure", p) fvutils.compute_discharges(gb) p_known = np.array([ 1.7574919, 1.25249747, 1.7574919, 1.25249747, 1.25250298, 1.80993337 ]) # Known discharges d_0, d_1 = fluxes_2d_1d_left_right_dir_neu() rtol = 1e-6 atol = rtol for _, d in gb: if d['node_number'] == 0: assert np.allclose(d['discharge'], d_0, rtol, atol) if d['node_number'] == 1: assert np.allclose(d['discharge'], d_1, rtol, atol) assert np.allclose(p, p_known, rtol, atol)
def test_tpfa_fluxes_2d_1d_cross_with_elimination(self): f1 = np.array([[0, 1], [.5, .5]]) f2 = np.array([[.5, .5], [0, 1]]) domain = {'xmin': 0, 'ymin': 0, 'xmax': 1, 'ymax': 1} mesh_size = 0.4 mesh_kwargs = {} mesh_kwargs['mesh_size'] = { 'mode': 'constant', 'value': mesh_size, 'bound_value': mesh_size } gb = meshing.cart_grid([f1, f2], [2, 2], **{'physdims': [1, 1]}) #gb = meshing.simplex_grid( [f1, f2],domain,**mesh_kwargs) gb.compute_geometry() gb.assign_node_ordering() # Enforce node orderning because of Python 3.5 and 2.7. # Don't do it in general. cell_centers_1 = np.array([[7.50000000e-01, 2.500000000e-01], [5.00000000e-01, 5.00000000e-01], [-5.55111512e-17, 5.55111512e-17]]) cell_centers_2 = np.array([[5.00000000e-01, 5.00000000e-01], [7.50000000e-01, 2.500000000e-01], [-5.55111512e-17, 5.55111512e-17]]) for g, d in gb: if g.dim == 1: if np.allclose(g.cell_centers, cell_centers_1): d['node_number'] = 1 elif np.allclose(g.cell_centers, cell_centers_2): d['node_number'] = 2 else: raise ValueError('Grid not found') tol = 1e-3 solver = tpfa.TpfaMixedDim('flow') gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) a_dim = np.power(a, gb.dim_max() - g.dim) aperture = np.ones(g.num_cells) * a_dim param.set_aperture(aperture) kxx = np.ones(g.num_cells) * np.power(1e3, g.dim < gb.dim_max()) p = tensor.SecondOrder(3, kxx, kyy=kxx, kzz=kxx) param.set_tensor('flow', p) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] right = bound_face_centers[0, :] > 1 - tol left = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[right] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[right] bc_neu = bound_faces[left] bc_val[bc_dir] = g.face_centers[0, bc_dir] bc_val[bc_neu] = -g.face_areas[bc_neu] * a_dim param.set_bc('flow', bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val('flow', bc_val) d['param'] = param gb.add_edge_prop('param') for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] d['param'] = Parameters(g_h) A, rhs = solver.matrix_rhs(gb) p = sps.linalg.spsolve(A, rhs) p = sps.linalg.spsolve(A, rhs) p_cond, p_red, _, _ = condensation.solve_static_condensation(\ A, rhs, gb, dim=0) solver.split(gb, "p_cond", p_cond) solver.split(gb, "pressure", p) # Make a copy of the grid bucket without the 0d grid dim_to_remove = 0 gb_r, elimination_data = gb.duplicate_without_dimension(dim_to_remove) # Compute the flux discretization on the new edges condensation.compute_elimination_fluxes(gb, gb_r, elimination_data) # Compute the discharges from the flux discretizations and computed pressures solver.split(gb_r, "pressure", p_red) fvutils.compute_discharges(gb) fvutils.compute_discharges(gb_r) # Known discharges d_0, d_1, d_2 = fluxes_2d_1d_cross_with_elimination() # Check node fluxes, ... rtol = 1e-6 atol = rtol for g, d in gb: if d['node_number'] == 0: assert np.allclose(d['discharge'], d_0, rtol, atol) if d['node_number'] == 1: assert np.allclose(d['discharge'], d_1, rtol, atol) if d['node_number'] == 2: assert np.allclose(d['discharge'], d_2, rtol, atol) for g, d in gb_r: if d['node_number'] == 0: assert np.allclose(d['discharge'], d_0, rtol, atol) if d['node_number'] == 1: assert np.allclose(d['discharge'], d_1, rtol, atol) if d['node_number'] == 2: assert np.allclose(d['discharge'], d_2, rtol, atol) # ... edge fluxes ... d_01, d_10, d_02, d_20, d_13, d_23 = coupling_fluxes_2d_1d_cross_no_el( ) for e, data in gb.edges_props(): g1, g2 = gb.sorted_nodes_of_edge(e) pa = data['param'] node_numbers = gb.nodes_prop([g2, g1], 'node_number') if pa is not None: if node_numbers == (0, 1): assert np.allclose( data['discharge'], d_01, rtol, atol) or \ np.allclose( data['discharge'], d_10, rtol, atol) if node_numbers == (0, 2): assert np.allclose( data['discharge'], d_02, rtol, atol) or \ np.allclose( data['discharge'], d_20, rtol, atol) if node_numbers == (1, 3): assert np.allclose(data['discharge'], d_13, rtol, atol) if node_numbers == (2, 3): assert np.allclose(data['discharge'], d_23, rtol, atol) d_11, d_21, d_22 = coupling_fluxes_2d_1d_cross_with_el() for e, data in gb_r.edges_props(): g1, g2 = gb_r.sorted_nodes_of_edge(e) pa = data['param'] node_numbers = gb_r.nodes_prop([g2, g1], 'node_number') if pa is not None: if node_numbers == (0, 1): assert np.allclose( data['discharge'], d_01, rtol, atol) or \ np.allclose( data['discharge'], d_10, rtol, atol) if node_numbers == (0, 2): assert np.allclose( data['discharge'], d_02, rtol, atol) or \ np.allclose( data['discharge'], d_20, rtol, atol) if node_numbers == (1, 1): assert np.allclose(data['discharge'], d_11, rtol, atol) if node_numbers == (2, 1): assert np.allclose(data['discharge'], d_21, rtol, atol) if node_numbers == (2, 2): assert np.allclose(data['discharge'], d_22, rtol, atol) # ... and pressures tol = 1e-10 assert ((np.amax(np.absolute(p - p_cond))) < tol) assert (np.sum( error.error_L2(g, d['pressure'], d['p_cond']) for g, d in gb) < tol)