def test_upwind_example1(self, if_export=False): ####################### # Simple 2d upwind problem with implicit Euler scheme in time ####################### T = 1 Nx, Ny = 10, 1 g = structured.CartGrid([Nx, Ny], [1, 1]) g.compute_geometry() advect = upwind.Upwind("transport") param = Parameters(g) dis = advect.discharge(g, [1, 0, 0]) b_faces = g.get_all_boundary_faces() bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size) bc_val = np.hstack(([1], np.zeros(g.num_faces - 1))) param.set_bc("transport", bc) param.set_bc_val("transport", bc_val) data = {'param': param, 'discharge': dis} data['deltaT'] = advect.cfl(g, data) U, rhs = advect.matrix_rhs(g, data) M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data) conc = np.zeros(g.num_cells) # Perform an LU factorization to speedup the solver IE_solver = sps.linalg.factorized((M + U).tocsc()) # Loop over the time Nt = int(T / data['deltaT']) time = np.empty(Nt) folder = 'example1' save = Exporter(g, "conc_IE", folder) for i in np.arange(Nt): # Update the solution # Backward and forward substitution to solve the system conc = IE_solver(M.dot(conc) + rhs) time[i] = data['deltaT'] * i if if_export: save.write_vtk({"conc": conc}, time_step=i) if if_export: save.write_pvd(time) known = np.array([ 0.99969927, 0.99769441, 0.99067741, 0.97352474, 0.94064879, 0.88804726, 0.81498958, 0.72453722, 0.62277832, 0.51725056 ]) assert np.allclose(conc, known)
def test_upwind_2d_beta_positive(self): f = np.array([[2, 2], [0, 2]]) gb = meshing.cart_grid([f], [4, 2]) gb.assign_node_ordering() gb.compute_geometry() solver = upwind.UpwindMixedDim('transport') gb.add_node_props(['param']) for g, d in gb: param = Parameters(g) aperture = np.ones(g.num_cells)*np.power(1e-2, gb.dim_max() - g.dim) param.set_aperture(aperture) d['discharge'] = solver.discr.discharge(g, [2, 0, 0], aperture) bf = g.get_boundary_faces() bc = BoundaryCondition(g, bf, bf.size * ['neu']) param.set_bc('transport', bc) d['param'] = param # Assign coupling discharge gb.add_edge_prop('param') for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] discharge = gb.node_prop(g_h,'discharge') d['param'] = Parameters(g_h) d['discharge'] = discharge M = solver.matrix_rhs(gb)[0].todense() M_known = np.array([[ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0.], [-2, 2, 0, 0, 0, 0, 0, 0, 0, 0.], [ 0, 0, 2, 0, 0, 0, 0, 0, 0, -2.], [ 0, 0, -2, 0, 0, 0, 0, 0, 0, 0.], [ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0.], [ 0, 0, 0, 0, -2, 2, 0, 0, 0, 0.], [ 0, 0, 0, 0, 0, 0, 2, 0, -2, 0.], [ 0, 0, 0, 0, 0, 0, -2, 0, 0, 0.], [ 0, 0, 0, 0, 0, -2, 0, 0, 2, 0.], [ 0, -2, 0, 0, 0, 0, 0, 0, 0, 2.]]) rtol = 1e-15 atol = rtol assert np.allclose(M, M_known, rtol, atol)
def test_mono_equals_multi(self): """ test that the mono_dimensional elliptic solver gives the same answer as the grid bucket elliptic """ g = CartGrid([10, 10]) g.compute_geometry() gb = meshing.cart_grid([], [10, 10]) param_g = Parameters(g) def bc_val(g): left = g.face_centers[0] < 1e-6 right = g.face_centers[0] > 10 - 1e-6 bc_val = np.zeros(g.num_faces) bc_val[left] = -1 bc_val[right] = 1 return bc_val def bc_labels(g): bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] left = bound_face_centers[0] < 1e-6 right = bound_face_centers[0] > 10 - 1e-6 labels = np.array(['neu'] * bound_faces.size) labels[np.logical_or(right, left)] = 'dir' bc_labels = bc.BoundaryCondition(g, bound_faces, labels) return bc_labels param_g.set_bc_val('flow', bc_val(g)) param_g.set_bc('flow', bc_labels(g)) gb.add_node_props(['param']) for sub_g, d in gb: d['param'] = Parameters(sub_g) d['param'].set_bc_val('flow', bc_val(g)) d['param'].set_bc('flow', bc_labels(sub_g)) problem_mono = elliptic.EllipticModel(g, {'param': param_g}) problem_mult = elliptic.EllipticModel(gb) p_mono = problem_mono.solve() p_mult = problem_mult.solve() assert np.allclose(p_mono, p_mult)
def test_upwind_example0(self, if_export=False): ####################### # Simple 2d upwind problem with explicit Euler scheme in time ####################### T = 1 Nx, Ny = 4, 1 g = structured.CartGrid([Nx, Ny], [1, 1]) g.compute_geometry() advect = upwind.Upwind("transport") param = Parameters(g) dis = advect.discharge(g, [1, 0, 0]) b_faces = g.get_all_boundary_faces() bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size) bc_val = np.hstack(([1], np.zeros(g.num_faces - 1))) param.set_bc("transport", bc) param.set_bc_val("transport", bc_val) data = {'param': param, 'discharge': dis} data['deltaT'] = advect.cfl(g, data) U, rhs = advect.matrix_rhs(g, data) OF = advect.outflow(g, data) M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data) conc = np.zeros(g.num_cells) M_minus_U = M - U invM, _ = mass_matrix.InvMassMatrix().matrix_rhs(g, data) # Loop over the time Nt = int(T / data['deltaT']) time = np.empty(Nt) folder = 'example0' production = np.zeros(Nt) save = Exporter(g, "conc_EE", folder) for i in np.arange(Nt): # Update the solution production[i] = np.sum(OF.dot(conc)) conc = invM.dot((M_minus_U).dot(conc) + rhs) time[i] = data['deltaT'] * i if if_export: save.write_vtk({"conc": conc}, time_step=i) if if_export: save.write_pvd(time) known = 1.09375 assert np.sum(production) == known
def test_zero_force(self): """ test that nothing moves if nothing is touched """ g = self.gb3d.grids_of_dimension(3)[0] data = {'param': Parameters(g)} bound = bc.BoundaryCondition(g, g.get_boundary_faces(), 'dir') data['param'].set_bc('mechanics', bound) solver = mpsa.FracturedMpsa() A, b = solver.matrix_rhs(g, data) u = np.linalg.solve(A.A, b) T = solver.traction(g, data, u) assert np.all(np.abs(u) < 1e-10) assert np.all(np.abs(T) < 1e-10)
def add_data_advection(gb, domain, tol): for g, d in gb: param = d['param'] source = np.zeros(g.num_cells) param.set_source("transport", source) param.set_porosity(1) param.set_discharge(d['discharge']) bound_faces = g.tags['domain_boundary_faces'].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] top = bound_face_centers[2, :] > domain['zmax'] - tol bottom = bound_face_centers[2, :] < domain['zmin'] + tol boundary = np.logical_or(top, bottom) labels = np.array(['neu'] * bound_faces.size) labels[boundary] = ['dir'] bc_val = np.zeros(g.num_faces) bc_val[bound_faces[bottom]] = 1 param.set_bc("transport", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("transport", bc_val) else: param.set_bc("transport", BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param # Assign coupling discharge gb.add_edge_prop('param') for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] discharge = gb.node_prop(g_h, 'param').get_discharge() d['param'] = Parameters(g_h) d['param'].set_discharge(discharge)
def test_upwind_example2(self, if_export=False): ####################### # Simple 2d upwind problem with explicit Euler scheme in time coupled with # a Darcy problem ####################### T = 2 Nx, Ny = 10, 10 folder = 'example2' def funp_ex(pt): return -np.sin(pt[0]) * np.sin(pt[1]) - pt[0] g = structured.CartGrid([Nx, Ny], [1, 1]) g.compute_geometry() param = Parameters(g) # Permeability perm = tensor.SecondOrderTensor(g.dim, kxx=np.ones(g.num_cells)) param.set_tensor("flow", perm) # Source term param.set_source("flow", np.zeros(g.num_cells)) # Boundaries b_faces = g.get_all_boundary_faces() bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size) bc_val = np.zeros(g.num_faces) bc_val[b_faces] = funp_ex(g.face_centers[:, b_faces]) param.set_bc("flow", bc) param.set_bc_val("flow", bc_val) # Darcy solver data = {'param': param} solver = vem_dual.DualVEM("flow") D_flow, b_flow = solver.matrix_rhs(g, data) solver_source = vem_source.DualSource('flow') D_source, b_source = solver_source.matrix_rhs(g, data) up = sps.linalg.spsolve(D_flow + D_source, b_flow + b_source) p, u = solver.extract_p(g, up), solver.extract_u(g, up) P0u = solver.project_u(g, u, data) save = Exporter(g, "darcy", folder) if if_export: save.write_vtk({'pressure': p, "P0u": P0u}) # Discharge dis = u # Boundaries bc = BoundaryCondition(g, b_faces, ['dir'] * b_faces.size) bc_val = np.hstack(([1], np.zeros(g.num_faces - 1))) param.set_bc("transport", bc) param.set_bc_val("transport", bc_val) data = {'param': param, 'discharge': dis} # Advect solver advect = upwind.Upwind("transport") U, rhs = advect.matrix_rhs(g, data) data['deltaT'] = advect.cfl(g, data) M, _ = mass_matrix.MassMatrix().matrix_rhs(g, data) conc = np.zeros(g.num_cells) M_minus_U = M - U invM, _ = mass_matrix.InvMassMatrix().matrix_rhs(g, data) # Loop over the time Nt = int(T / data['deltaT']) time = np.empty(Nt) save.change_name("conc_darcy") for i in np.arange(Nt): # Update the solution conc = invM.dot((M_minus_U).dot(conc) + rhs) time[i] = data['deltaT'] * i if if_export: save.write_vtk({"conc": conc}, time_step=i) if if_export: save.write_pvd(time) known = \ np.array([9.63168200e-01, 8.64054875e-01, 7.25390695e-01, 5.72228235e-01, 4.25640080e-01, 2.99387331e-01, 1.99574336e-01, 1.26276876e-01, 7.59011550e-02, 4.33431230e-02, 3.30416807e-02, 1.13058617e-01, 2.05372538e-01, 2.78382057e-01, 3.14035373e-01, 3.09920132e-01, 2.75024694e-01, 2.23163145e-01, 1.67386939e-01, 1.16897527e-01, 1.06111312e-03, 1.11951850e-02, 3.87907727e-02, 8.38516119e-02, 1.36617802e-01, 1.82773271e-01, 2.10446545e-01, 2.14651936e-01, 1.97681518e-01, 1.66549151e-01, 3.20751341e-05, 9.85780113e-04, 6.07062715e-03, 1.99393042e-02, 4.53237556e-02, 8.00799828e-02, 1.17199623e-01, 1.47761481e-01, 1.64729339e-01, 1.65390555e-01, 9.18585872e-07, 8.08267622e-05, 8.47227168e-04, 4.08879583e-03, 1.26336029e-02, 2.88705048e-02, 5.27841497e-02, 8.10459333e-02, 1.07956484e-01, 1.27665318e-01, 2.51295298e-08, 6.29844122e-06, 1.09361990e-04, 7.56743783e-04, 3.11384414e-03, 9.04446601e-03, 2.03443897e-02, 3.75208816e-02, 5.89595194e-02, 8.11457277e-02, 6.63498510e-10, 4.73075468e-07, 1.33728945e-05, 1.30243418e-04, 7.01905707e-04, 2.55272292e-03, 6.96686157e-03, 1.52290448e-02, 2.78607282e-02, 4.40402650e-02, 1.71197497e-11, 3.47118057e-08, 1.57974045e-06, 2.13489614e-05, 1.48634295e-04, 6.68104990e-04, 2.18444135e-03, 5.58646819e-03, 1.17334966e-02, 2.09744728e-02, 4.37822313e-13, 2.52373622e-09, 1.83589660e-07, 3.40553325e-06, 3.02948532e-05, 1.66504215e-04, 6.45119867e-04, 1.90731440e-03, 4.53436628e-03, 8.99977737e-03, 1.12627412e-14, 1.84486857e-10, 2.13562387e-08, 5.39492977e-07, 6.08223906e-06, 4.05535296e-05, 1.84731221e-04, 6.25871542e-04, 1.66459389e-03, 3.59980231e-03]) assert np.allclose(conc, known)
def test_0d_elimination_2d_1d_cross(self): """ Simplest case possible: 2d case with two fractures intersecting in a single 0d grid at the center of the domain. """ f1 = np.array([[0, 1], [.5, .5]]) f2 = np.array([[.5, .5], [0, 1]]) gb = meshing.cart_grid([f1, f2], [2, 2], **{'physdims': [1, 1]}) gb.compute_geometry() gb.assign_node_ordering() tol = 1e-3 solver = tpfa.Tpfa() 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.SecondOrderTensor(3, kxx, kyy=kxx, kzz=kxx) param.set_tensor('flow', p) bound_faces = g.tags['domain_boundary_faces'].nonzero()[0] if bound_faces.size != 0: 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(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) else: param.set_bc("flow", bc.BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) p = sps.linalg.spsolve(A, rhs) p_cond, _, _, _ = condensation.solve_static_condensation(A, rhs, gb, dim=0) solver_coupler.split(gb, 'pressure', p) solver_coupler.split(gb, "p_cond", p_cond) 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)
def add_data_darcy(gb, domain, tol): gb.add_node_props(["param", "is_tangent"]) apert = 1e-2 km = 7.5 * 1e-11 kf_t = 1e-5 * km kf_n = 1e-5 * km for g, d in gb: param = Parameters(g) rock = g.dim == gb.dim_max() kxx = km if rock else kf_t d["is_tangential"] = True perm = tensor.SecondOrderTensor(g.dim, kxx * np.ones(g.num_cells)) param.set_tensor("flow", perm) param.set_source("flow", np.zeros(g.num_cells)) param.set_aperture(np.power(apert, gb.dim_max() - g.dim)) bound_faces = g.tags["domain_boundary_faces"].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] top = bound_face_centers[1, :] > domain["ymax"] - tol bottom = bound_face_centers[1, :] < domain["ymin"] + tol left = bound_face_centers[0, :] < domain["xmin"] + tol right = bound_face_centers[0, :] > domain["xmax"] - tol boundary = np.logical_or(left, right) labels = np.array(["neu"] * bound_faces.size) labels[boundary] = ["dir"] bc_val = np.zeros(g.num_faces) bc_val[bound_faces[left]] = 30 * 1e6 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d["param"] = param # Assign coupling permeability gb.add_edge_prop("kn") for e, d in gb.edges_props(): g = gb.sorted_nodes_of_edge(e)[0] d["kn"] = kf_n / gb.node_prop(g, "param").get_aperture()
def compute_discharges(gb, physics='flow', d_name='discharge', p_name='pressure', data=None): """ Computes discharges over all faces in the entire grid /grid bucket given pressures for all nodes, provided as node properties. Parameter: gb: grid bucket with the following data fields for all nodes/grids: 'flux': Internal discretization of fluxes. 'bound_flux': Discretization of boundary fluxes. 'pressure': Pressure values for each cell of the grid (overwritten by p_name). 'bc_val': Boundary condition values. and the following edge property field for all connected grids: 'coupling_flux': Discretization of the coupling fluxes. physics (string): defaults to 'flow'. The physic regime d_name (string): defaults to 'discharge'. The keyword which the computed discharge will be stored by in the dictionary. p_name (string): defaults to 'pressure'. The keyword that the pressure field is stored by in the dictionary data (dictionary): defaults to None. If gb is mono-dimensional grid the data dictionary must be given. If gb is a multi-dimensional grid, this variable has no effect Returns: gb, the same grid bucket with the added field 'discharge' added to all node data fields. Note that the fluxes between grids will be added only at the gb edge, not at the node fields. The sign of the discharges correspond to the directions of the normals, in the edge/coupling case those of the higher grid. For edges beteween grids of equal dimension, there is an implicit assumption that all normals point from the second to the first of the sorted grids (gb.sorted_nodes_of_edge(e)). """ if not isinstance(gb, GridBucket): pa = data['param'] if data.get('flux') is not None: dis = data['flux'] * data[p_name] + data['bound_flux'] \ * pa.get_bc_val(physics) else: dis = np.zeros(g.num_faces) data[d_name] = dis return for g, d in gb: if g.dim > 0: pa = d['param'] if d.get('flux') is not None: dis = d['flux'] * d[p_name] + d['bound_flux'] \ * pa.get_bc_val(physics) else: dis = np.zeros(g.num_faces) d[d_name] = dis for e, d in gb.edges(): # According to the sorting convention, g2 is the higher dimensional grid, # the one to who's faces the fluxes correspond g1, g2 = gb.nodes_of_edge(e) try: pa = d['param'] except KeyError: pa = Parameters(g2) d['param'] = pa if g1.dim != g2.dim and d['face_cells'] is not None: coupling_flux = gb.edge_props(e, 'coupling_flux') pressures = [gb.node_props(g, p_name) for g in [g2, g1]] dis = coupling_flux * np.concatenate(pressures) d[d_name] = dis elif g1.dim == g2.dim and d['face_cells'] is not None: # g2 is now only the "higher", but still the one defining the faces # (cell-cells connections) in the sense that the normals are assumed # outward from g2, "pointing towards the g1 cells". Note that in # general, there are g2.num_cells x g1.num_cells connections/"faces". cc = d['face_cells'] cells_1, cells_2 = cc.nonzero() coupling_flux = gb.edge_props(e, 'coupling_flux') pressures = [gb.node_props(g, p_name) for g in [g2, g1]] p2 = pressures[0][cells_2] p1 = pressures[1][cells_1] contribution_2 = np.multiply(coupling_flux[cc], p2) contribution_1 = np.multiply(coupling_flux[cc], p1) dis = contribution_2 - contribution_1 # Store flux at the edge only. This means that the flux will remain # zero in the data of both g1 and g2 d[d_name] = np.ravel(dis)
def test_background_stress_default(self): p = Parameters(self.g) self.assertTrue(np.allclose(p.background_stress_mechanics, 0)) for name in p.known_physics: self.assertTrue(np.allclose(p.get_background_stress(name), 0))
def add_data(gb, domain, solver, case): if case == 1: kf = 1e4 else: kf = 1e-4 data = {"domain": domain, "aperture": 1e-4, "km": 1, "kf": kf} if_solver = solver == "vem" or solver == "rt0" or solver == "p1" if_p1 = solver == "p1" gb.add_node_props(["param", "is_tangential"]) for g, d in gb: param = Parameters(g) if g.dim == 3: kxx = np.ones(g.num_cells) * data["km"] perm = pp.SecondOrderTensor(3, kxx=kxx) else: kxx = np.ones(g.num_cells) * data["kf"] if if_solver: if g.dim == 2: perm = pp.SecondOrderTensor(g.dim, kxx=kxx, kyy=kxx, kzz=1) elif g.dim == 1: perm = pp.SecondOrderTensor(g.dim, kxx=kxx, kyy=1, kzz=1) else: # g.dim == 0 perm = pp.SecondOrderTensor(g.dim, kxx=kxx, kyy=1, kzz=1) else: perm = pp.SecondOrderTensor(3, kxx=kxx) param.set_tensor("flow", perm) aperture = np.power(data["aperture"], gb.dim_max() - g.dim) param.set_aperture(aperture * np.ones(g.num_cells)) param.set_source("flow", np.zeros(g.num_cells)) if if_p1: # for P1 a different handling of the boundary conditions bound_nodes = g.get_boundary_nodes() if bound_nodes.size == 0: bc = pp.BoundaryConditionNode(g, np.empty(0), np.empty(0)) bc_val = np.empty(0) else: p_press, b_in, b_out = b_pressure_node(g) labels = np.array(["neu"] * bound_nodes.size) labels[p_press] = "dir" bc_val = np.zeros(g.num_nodes) bc_val[bound_nodes[b_in]] = 1 bc_val[bound_nodes[b_out]] = -1 param.set_bc_val("flow", bc_val) bc = pp.BoundaryConditionNode(g, bound_nodes, labels) else: bound_faces = g.tags["domain_boundary_faces"].nonzero()[0] if bound_faces.size == 0: bc = BoundaryCondition(g, np.empty(0), np.empty(0)) param.set_bc("flow", bc) else: p_press, b_in, b_out = b_pressure(g) labels = np.array(["neu"] * bound_faces.size) labels[p_press] = "dir" bc_val = np.zeros(g.num_faces) bc_val[bound_faces[b_in]] = 1 bc_val[bound_faces[b_out]] = -1 param.set_bc_val("flow", bc_val) bc = BoundaryCondition(g, bound_faces, labels) param.set_bc("flow", bc) d["is_tangential"] = True d["param"] = param gb.add_edge_props("kn") for e, d in gb.edges(): g_l = gb.nodes_of_edge(e)[0] mg = d["mortar_grid"] check_P = mg.low_to_mortar_avg() kxx = data["kf"] gamma = np.power( check_P * gb.node_props(g_l, "param").get_aperture(), 1. / (gb.dim_max() - g_l.dim), ) d["kn"] = kxx * np.ones(mg.num_cells) / gamma
def new_coupling_fluxes(gb_old, gb_el, neighbours_old, neighbours_el, node_old): """ Adds new coupling_flux data fields to the new gb edges arising through the removal of one node. Idea: set up a condensation for the local system of old coupling_fluxes for the removed nodes and its n_neighbours neighbour nodes/grids. """ neighbours_old = gb_old.sort_multiple_nodes(neighbours_old) neighbours_el = gb_el.sort_multiple_nodes(neighbours_el) n_cells_l = node_old.num_cells n_neighbours = len(neighbours_old) # Initialize coupling matrix (see coupler.py, matrix_rhs) all_cc = np.empty((n_neighbours + 1, n_neighbours + 1), dtype=np.object) pos_i = 0 for g_i in neighbours_old: pos_j = 0 for g_j in neighbours_old: all_cc[pos_i, pos_j] = sps.coo_matrix( (g_i.num_cells, g_j.num_cells)) pos_j += 1 all_cc[pos_i, n_neighbours] = sps.coo_matrix( (g_i.num_cells, node_old.num_cells)) all_cc[n_neighbours, pos_i] = sps.coo_matrix( (node_old.num_cells, g_i.num_cells)) pos_i += 1 all_cc[n_neighbours, n_neighbours] = sps.coo_matrix( (node_old.num_cells, node_old.num_cells)) dofs = np.zeros(n_neighbours) # Assemble original system: for i in range(n_neighbours): cc = gb_old.edge_props((neighbours_old[i], node_old), 'coupling_discretization') idx = np.ix_([i, n_neighbours], [i, n_neighbours]) all_cc[idx] += cc dofs[i] = cc[0][0].shape[0] global_idx = np.r_[0, np.cumsum(dofs)].astype(int) all_cc = sps.bmat(all_cc, 'csr') # Eliminate "node" n_dof = all_cc.shape[0] to_be_eliminated = np.zeros(n_dof, dtype=bool) to_be_eliminated[range(n_dof - n_cells_l, n_dof)] = True all_cc, _, _, _, _ = eliminate_dofs(all_cc, np.zeros(n_dof), to_be_eliminated) # Extract the new coupling fluxes from the eliminated system and map to # faces of the first grid for i, g_0 in enumerate(neighbours_el): id_0 = slice(global_idx[i], global_idx[i + 1]) # Get the internal contribution (grids that have an internal hole after # the elimination), to be added to the node g_0. This contribution # is found at the off-diagonal part of the diagonal blocks cc_00 = all_cc.tocsr()[id_0, :].tocsc()[:, id_0] # Keep only one connection, the one from the "first/higher" cell(s) to # the "second/lower". Fluxes from higher to lower, so entries should be # positive (coming from off-diagonal, they are now negative) c_f = -np.triu(cc_00.todense(), k=1) # Check whether there is an internal hole in the grid. If so, add # connections between the cells on either side if not np.allclose(c_f, 0, 1e-10, 1e-12): cell_cells = np.array(c_f > 0, dtype=bool) # The fluxes c_f*p go from cells_1 to cells_2: # c_1, c_2, _ = sparse.find(cell_cells) gb_el.add_edge([g_0, g_0], cell_cells) d_edge = gb_el.edge_props([g_0, g_0]) d_edge['coupling_flux'] = sps.csr_matrix(c_f) d_edge['param'] = Parameters(g_0) # Get the contribution between different grids for j in range(i + 1, n_neighbours): g_1 = neighbours_el[j] id_1 = slice(global_idx[j], global_idx[j + 1]) cc_01 = all_cc.tocsr()[id_0, :].tocsc()[:, id_1] gb_el.add_edge_props('coupling_flux', [[g_0, g_1]]) gb_el.edge_props([g_0, g_1])['coupling_flux'] = -cc_01
def test_non_zero_bc_val(self): """ We mixed bc_val on domain boundary and fracture displacement in x-direction. """ frac = np.array([[1,1,1], [1,2,1], [2,2,1], [2,1,1]]).T physdims = np.array([3,3,2]) g = meshing.cart_grid([frac], [3,3,2], physdims=physdims).grids_of_dimension(3)[0] data = {'param': Parameters(g)} # Define boundary conditions bc_val = np.zeros((g.dim, g.num_faces)) frac_slip = np.zeros((g.dim, g.num_faces)) frac_bnd = g.has_face_tag(FaceTag.FRACTURE) dom_bnd = g.has_face_tag(FaceTag.DOMAIN_BOUNDARY) frac_slip[0, frac_bnd] = np.ones(np.sum(frac_bnd)) bc_val[:, dom_bnd] = g.face_centers[:, dom_bnd] bound = bc.BoundaryCondition(g, g.get_boundary_faces(), 'dir') data['param'].set_bc('mechanics', bound) data['param'].set_bc_val('mechanics', bc_val.ravel('F')) data['param'].set_slip_distance(frac_slip.ravel('F')) solver = mpsa.FracturedMpsa() A, b = solver.matrix_rhs(g, data) u = np.linalg.solve(A.A, b) u_f = solver.extract_frac_u(g, u) u_c = solver.extract_u(g, u) u_c = u_c.reshape((3, -1), order='F') # Test traction frac_faces = g.frac_pairs frac_left = frac_faces[0] frac_right = frac_faces[1] T = solver.traction(g, data, u) T = T.reshape((3, -1),order='F') T_left = T[:, frac_left] T_right = T[:, frac_right] assert np.allclose(T_left, T_right) # we have u_lhs - u_rhs = 1 so u_lhs should be positive mid_ind = int(round(u_f.size/2)) u_left = u_f[:mid_ind] u_right = u_f[mid_ind:] true_diff = np.atleast_2d(np.array([1,0,0])).T u_left = u_left.reshape((3, -1), order='F') u_right = u_right.reshape((3, -1), order='F') assert np.all(np.abs(u_left - u_right - true_diff) < 1e-10) # should have a positive displacement for all cells assert np.all(u_c > 0)
def add_data_darcy(gb, domain, tol, a): gb.add_node_props(['param']) kf = 1e4 for g, d in gb: param = Parameters(g) kxx = np.ones(g.num_cells) * np.power(kf, g.dim < gb.dim_max()) perm = tensor.SecondOrderTensor(g.dim, kxx) param.set_tensor("flow", perm) param.set_source("flow", np.zeros(g.num_cells)) aperture = np.power(a, gb.dim_max() - g.dim) param.set_aperture(np.ones(g.num_cells) * aperture) bound_faces = g.tags['domain_boundary_faces'].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] top = bound_face_centers[1, :] > domain['ymax'] - tol bottom = bound_face_centers[1, :] < domain['ymin'] + tol left = bound_face_centers[0, :] < domain['xmin'] + tol right = bound_face_centers[0, :] > domain['xmax'] - tol boundary = np.logical_or(left, right) labels = np.array(['neu'] * bound_faces.size) labels[boundary] = ['dir'] bc_val = np.zeros(g.num_faces) bc_val[bound_faces[right]] = 1 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param # Assign coupling permeability gb.add_edge_prop('kn') for e, d in gb.edges_props(): gn = gb.nodes_of_edge(e) aperture = np.power(a, gb.dim_max() - gn[0].dim) d['kn'] = np.ones(gn[0].num_cells) / aperture * kf
def add_data(gb, domain, direction, tol): """ Define the permeability, apertures, boundary conditions """ gb.add_node_props(["param", "Aavatsmark_transmissibilities"]) for g, d in gb: param = Parameters(g) d["Aavatsmark_transmissibilities"] = True if g.dim == 2: # Permeability kxx = np.ones(g.num_cells) param.set_tensor("flow", tensor.SecondOrder(3, kxx)) # Source term param.set_source("flow", np.zeros(g.num_cells)) # Boundaries bound_faces = g.get_boundary_faces() if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] if direction == "left_right": left = bound_face_centers[0, :] < domain["xmin"] + tol right = bound_face_centers[0, :] > domain["xmax"] - tol bc_dir = np.logical_or(left, right) bc_one = right elif direction == "bottom_top": bottom = bound_face_centers[2, :] < domain["zmin"] + tol top = bound_face_centers[2, :] > domain["zmax"] - tol bc_dir = np.logical_or(top, bottom) bc_one = top elif direction == "back_front": back = bound_face_centers[1, :] < domain["ymin"] + tol front = bound_face_centers[1, :] > domain["ymax"] - tol bc_dir = np.logical_or(back, front) bc_one = front labels = np.array(["neu"] * bound_faces.size) labels[bc_dir] = "dir" bc_val = np.zeros(g.num_faces) bc_val[bound_faces[bc_one]] = 1 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d["param"] = param gb.add_edge_props(["param", "Aavatsmark_transmissibilities"]) for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] d["param"] = Parameters(g_h) d["Aavatsmark_transmissibilities"] = True
def _set_data(self): if "param" not in self._data: self._data["param"] = Parameters(self.grid())
def add_data(gb, tol): """ Define the permeability, apertures, boundary conditions """ gb.add_node_props(['param', 'Aavatsmark_transmissibilities']) for g, d in gb: param = Parameters(g) d['Aavatsmark_transmissibilities'] = True if g.dim == 2: # Permeability kxx = np.ones(g.num_cells) param.set_tensor("flow", tensor.SecondOrder(g.dim, kxx)) # Source term param.set_source("flow", np.zeros(g.num_cells)) # Boundaries bound_faces = g.get_domain_boundary_faces() if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] bottom = bound_face_centers[1, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[bottom] = 'dir' bc_val = np.zeros(g.num_faces) mask = bound_face_centers[0, :] < tol bc_val[bound_faces[np.logical_and(bottom, mask)]] = 1 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param # Assign coupling discharge gb.add_edge_props(['param', 'Aavatsmark_transmissibilities']) for e, d in gb.edges_props(): g_h = gb.sorted_nodes_of_edge(e)[1] d['param'] = Parameters(g_h) d['Aavatsmark_transmissibilities'] = True
def test_tpfa_coupling_2d_1d_left_right_dir(self): """ Grid: 2 x 2 cells in matrix + 2 cells in the fracture from left to right. Dirichlet + no-flow, conductive fracture. """ 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.Tpfa(physics='flow') gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) aperture = np.ones(g.num_cells)*np.power(a, gb.dim_max() - g.dim) param.set_aperture(aperture) p = tensor.SecondOrder(3,np.ones(g.num_cells)* np.power(1e3, g.dim<gb.dim_max())) param.set_tensor('flow', p) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] left = bound_face_centers[0, :] > 1 - tol right = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[np.logical_or(left, right)] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[np.logical_or(left, right)] bc_val[bc_dir] = g.face_centers[0,bc_dir] param.set_bc(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) A_known = np.array( [[ 4.99996, -1. , 0. , 0. , 0. , -1.99996], [ -1. , 4.99996, 0. , 0. , -1.99996, 0. ], [ 0. , 0. , 4.99996, -1. , 0. , -1.99996], [ 0. , 0. , -1. , 4.99996, -1.99996, 0. ], [ 0. , -1.99996, 0. , -1.99996, 63.99992, -20. ], [ -1.99996, 0. , -1.99996, 0. , -20. , 63.99992]]) rhs_known = np.array([ 0., 2., 0., 2., 40., 0.]) rtol = 1e-6 atol = rtol assert np.allclose(A.todense(), A_known, rtol, atol) assert np.allclose(rhs, rhs_known, rtol, atol)
def test_fluid_compr_assertion(self): p = Parameters(self.g) with self.assertRaises(ValueError): p.set_fluid_compr(-1)
def add_data(gb, domain, kf): """ Define the permeability, apertures, boundary conditions """ gb.add_node_props(['param']) tol = 1e-5 a = 1e-3 for g, d in gb: param = Parameters(g) # Permeability kxx = np.ones(g.num_cells) * np.power(kf, g.dim < gb.dim_max()) if g.dim == 2: perm = tensor.SecondOrderTensor(3, kxx=kxx, kyy=kxx, kzz=1) else: perm = tensor.SecondOrderTensor(3, kxx=kxx, kyy=1, kzz=1) if g.dim == 1: R = cg.project_line_matrix(g.nodes, reference=[1, 0, 0]) perm.rotate(R) param.set_tensor("flow", perm) # Source term param.set_source("flow", np.zeros(g.num_cells)) # Assign apertures aperture = np.power(a, gb.dim_max() - g.dim) param.set_aperture(np.ones(g.num_cells) * aperture) # Boundaries bound_faces = g.tags['domain_boundary_faces'].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] bottom_corner = np.logical_and(bound_face_centers[0, :] < 0.1, bound_face_centers[1, :] < 0.1) top_corner = np.logical_and(bound_face_centers[0, :] > 0.9, bound_face_centers[1, :] > 0.9) labels = np.array(['neu'] * bound_faces.size) dir_faces = np.logical_or(bottom_corner, top_corner) labels[dir_faces] = 'dir' bc_val = np.zeros(g.num_faces) bc_val[bound_faces[bottom_corner]] = 1 bc_val[bound_faces[top_corner]] = -1 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param # Assign coupling permeability gb.add_edge_prop('kn') for e, d in gb.edges_props(): g = gb.sorted_nodes_of_edge(e)[0] d['kn'] = kf / gb.node_prop(g, 'param').get_aperture()
def test_tpfa_coupling_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 as well as matrix and rhs. """ 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.Tpfa(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(1e3, 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(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) A_known = np.array(\ [[ 2.99996, -1. , 0. , 0. , 0. , -1.99996], [ -1. , 4.99996, 0. , 0. , -1.99996, 0. ], [ 0. , 0. , 2.99996, -1. , 0. , -1.99996], [ 0. , 0. , -1. , 4.99996, -1.99996, 0. ], [ 0. , -1.99996, 0. , -1.99996, 63.99992, -20. ], [ -1.99996, 0. , -1.99996, 0. , -20. , 23.99992]] ) rhs_known = np.array([ 5.00000000e-01, 2.00000000e+00, 5.00000000e-01, 2.00000000e+00, 4.00000000e+01, 1.00000000e-02]) p_known = np.array([ 1.21984244, 1.05198918, 1.21984244, 1.05198918, 1.02005108, 1.05376576]) p = sps.linalg.spsolve(A, rhs) rtol = 1e-6 atol = rtol assert np.allclose(A.todense(), A_known, rtol, atol) assert np.allclose(rhs, rhs_known, rtol, atol) assert np.allclose(p, p_known, rtol, atol)
def edge_params(gb): 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)
def test_tpfa_coupling_2d_1d_left_right_cross_dir_neu(self): f1 = np.array([[0, 2], [.5, .5]]) f2 = np.array([[.5, .5], [0, 2]]) gb = meshing.cart_grid( [f1, f2], [2, 2], **{'physdims': [1, 1]}) 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.Tpfa() 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()) #print(kxx, 'dim', g.dim) p = tensor.SecondOrder(3,kxx,kyy=kxx,kzz=kxx) #print(p.perm) 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(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) A_known, rhs_known = matrix_rhs_for_2d_1d_cross() rtol = 1e-6 atol = rtol assert np.allclose(A.todense(), A_known, rtol, atol) assert np.allclose(rhs, rhs_known, rtol, atol)
def add_data(gb, tol): """ Define the permeability, apertures, boundary conditions """ gb.add_node_props(["param"]) # Aavatsmark_transmissibilities only for tpfa intra-dimensional coupling for g, d in gb: d["Aavatsmark_transmissibilities"] = True if g.dim < 2: continue param = Parameters(g) # Permeability kxx = np.array([perm(*pt) for pt in g.cell_centers.T]) param.set_tensor("flow", tensor.SecondOrderTensor(3, kxx)) # Source term frac_id = d["frac_id"][0] source = np.array([source_f[frac_id](*pt) for pt in g.cell_centers.T]) param.set_source("flow", g.cell_volumes * source) # Boundaries bound_faces = g.tags["domain_boundary_faces"].nonzero()[0] if bound_faces.size != 0: bound_face_centers = g.face_centers[:, bound_faces] labels = np.array(["dir"] * bound_faces.size) bc_val = np.zeros(g.num_faces) bc = [sol_f[frac_id](*pt) for pt in bound_face_centers.T] bc_val[bound_faces] = np.array(bc) param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d["param"] = param gb.add_edge_prop("Aavatsmark_transmissibilities") for _, d in gb.edges_props(): d["Aavatsmark_transmissibilities"] = True
def test_tpfa_coupling_3d_2d_1d_0d_dir(self): f1 = np.array([[ 0, 1, 1, 0], [ 0, 0, 1, 1], [.5, .5, .5, .5]]) f2 = np.array([[.5, .5, .5, .5], [ 0, 1, 1, 0], [ 0, 0, 1, 1]]) f3 = np.array([[ 0, 1, 1, 0], [.5, .5, .5, .5], [ 0, 0, 1, 1]]) gb = meshing.cart_grid([f1, f2, f3], [2, 2, 2], **{'physdims': [1, 1, 1]}) gb.compute_geometry() gb.assign_node_ordering() # Remove flag for dual cell_centers1 = np.array([[ 0.25 , 0.75 , 0.25 , 0.75], [ 0.25 , 0.25 , 0.75 , 0.75], [ 0.5 , 0.5 , 0.5 , 0.5 ]]) cell_centers2 = np.array([[ 0.5 , 0.5 , 0.5 , 0.5 ], [ 0.25 , 0.25 , 0.75 , 0.75], [ 0.75 , 0.25 , 0.75 , 0.25]]) cell_centers3 = np.array([[ 0.25 , 0.75 , 0.25 , 0.75], [ 0.5 , 0.5 , 0.5 , 0.5 ], [ 0.25 , 0.25 , 0.75 , 0.75]]) cell_centers4 = np.array([[ 0.5 ], [ 0.25], [ 0.5 ]]) cell_centers5 = np.array([[ 0.5 ], [ 0.75], [ 0.5 ]]) cell_centers6 = np.array([[ 0.75], [ 0.5 ], [ 0.5 ]]) cell_centers7 = np.array([[ 0.25], [ 0.5 ], [ 0.5 ]]) cell_centers8 = np.array([[ 0.5 ], [ 0.5 ], [ 0.25]]) cell_centers9 = np.array([[ 0.5 ], [ 0.5 ], [ 0.75]]) for g, d in gb: if np.allclose(g.cell_centers[:, 0], cell_centers1[:, 0]): d['node_number'] = 1 elif np.allclose(g.cell_centers[:, 0], cell_centers2[:, 0]): d['node_number'] = 2 elif np.allclose(g.cell_centers[:, 0], cell_centers3[:, 0]): d['node_number'] = 3 elif np.allclose(g.cell_centers[:, 0], cell_centers4[:, 0]): d['node_number'] = 4 elif np.allclose(g.cell_centers[:, 0], cell_centers5[:, 0]): d['node_number'] = 5 elif np.allclose(g.cell_centers[:, 0], cell_centers6[:, 0]): d['node_number'] = 6 elif np.allclose(g.cell_centers[:, 0], cell_centers7[:, 0]): d['node_number'] = 7 elif np.allclose(g.cell_centers[:, 0], cell_centers8[:, 0]): d['node_number'] = 8 elif np.allclose(g.cell_centers[:, 0], cell_centers9[:, 0]): d['node_number'] = 9 else: pass tol = 1e-3 solver = tpfa.Tpfa() gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) aperture = np.ones(g.num_cells)*np.power(a, gb.dim_max() - g.dim) param.set_aperture(aperture) p = tensor.SecondOrder(3,np.ones(g.num_cells)* np.power(1e3, g.dim<gb.dim_max())) param.set_tensor('flow', p) bound_faces = g.get_boundary_faces() bound_face_centers = g.face_centers[:, bound_faces] left = bound_face_centers[0, :] > 1 - tol right = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[np.logical_or(left, right)] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[np.logical_or(left, right)] bc_val[bc_dir] = g.face_centers[0,bc_dir] param.set_bc(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) A_known, rhs_known, p_known = \ matrix_rhs_pressure_for_test_tpfa_coupling_3d_2d_1d_0d() p = sps.linalg.spsolve(A, rhs) rtol = 1e-6 atol = rtol assert np.allclose(A.todense(), A_known, rtol, atol) assert np.allclose(rhs, rhs_known, rtol, atol) assert np.allclose(p, p_known, rtol, atol)
def add_data(gb, domain, kf): """ Define the permeability, apertures, boundary conditions """ gb.add_node_props(['param']) tol = 1e-5 a = 1e-4 for g, d in gb: param = Parameters(g) # Permeability kxx = np.ones(g.num_cells) * np.power(kf, g.dim < gb.dim_max()) if g.dim == 2: perm = tensor.SecondOrderTensor(3, kxx=kxx, kyy=kxx, kzz=1) else: perm = tensor.SecondOrderTensor(3, kxx=kxx, kyy=1, kzz=1) if g.dim == 1: R = cg.project_line_matrix(g.nodes, reference=[1, 0, 0]) perm.rotate(R) param.set_tensor("flow", perm) # Source term param.set_source("flow", np.zeros(g.num_cells)) # Assign apertures aperture = np.power(a, gb.dim_max() - g.dim) param.set_aperture(np.ones(g.num_cells) * aperture) # Boundaries 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 right = bound_face_centers[0, :] > domain['xmax'] - tol labels = np.array(['neu'] * bound_faces.size) labels[right] = 'dir' bc_val = np.zeros(g.num_faces) bc_val[bound_faces[left]] = -aperture \ * g.face_areas[bound_faces[left]] bc_val[bound_faces[right]] = 1 param.set_bc("flow", BoundaryCondition(g, bound_faces, labels)) param.set_bc_val("flow", bc_val) else: param.set_bc("flow", BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param # Assign coupling permeability gb.add_edge_prop('kn') for e, d in gb.edges_props(): gn = gb.sorted_nodes_of_edge(e) aperture = np.power(a, gb.dim_max() - gn[0].dim) d['kn'] = np.ones(gn[0].num_cells) * kf / aperture
def test_tpfa_coupling_2d_1d_bottom_top_dir_neu(self): """ Grid: 1 x 2 cells in matrix + 1 cell in the fracture from left to right. Dirichlet + inflow + no-flow, blocking fracture. """ f = np.array([[0, 1], [.5, .5]]) gb = meshing.cart_grid( [f], [1, 2], **{'physdims': [1, 1]}) gb.compute_geometry() gb.assign_node_ordering() tol = 1e-3 solver = tpfa.Tpfa(physics='flow') solver = tpfa.Tpfa(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] top = bound_face_centers[1, :] > 1 - tol bottom = bound_face_centers[1, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[bottom] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[bottom] bc_neu = bound_faces[top] bc_val[bc_dir] = g.face_centers[1,bc_dir] bc_val[bc_neu] = -g.face_areas[bc_neu]*a_dim param.set_bc(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) A_known = np.array([[ 4.19047619, 0. , -0.19047619], [ 0. , 0.19047619, -0.19047619], [-0.19047619, -0.19047619, 0.38095238]]) rhs_known = np.array([0, 1, 0]) rtol = 1e-6 atol = rtol assert np.allclose(A.todense(), A_known, rtol, atol) assert np.allclose(rhs, rhs_known, rtol, atol)
def test_no_dynamics_2d(self): g_list = setup_grids.setup_2d() for g in g_list: discr = biot.Biot() bound_faces = g.get_all_boundary_faces() bound = bc.BoundaryCondition( g, bound_faces.ravel("F"), ["dir"] * bound_faces.size ) mu = np.ones(g.num_cells) c = tensor.FourthOrderTensor(g.dim, mu, mu) k = tensor.SecondOrderTensor(g.dim, np.ones(g.num_cells)) bound_val = np.zeros(g.num_faces) param = Parameters(g) param.set_bc("flow", bound) param.set_bc("mechanics", bound) param.set_tensor("flow", k) param.set_tensor("mechanics", c) param.set_bc_val("mechanics", np.tile(bound_val, g.dim)) param.set_bc_val("flow", bound_val) param.porosity = np.ones(g.num_cells) param.biot_alpha = 1 data = {"param": param, "inverter": "python", "dt": 1} A, b = discr.matrix_rhs(g, data) sol = np.linalg.solve(A.todense(), b) self.assertTrue(np.isclose(sol, np.zeros(g.num_cells * (g.dim + 1))).all())
def test_0d_elimination_3d_2d_1d_0d(self): """ 3d case with a single 0d grid. """ f1 = np.array([[0, 1, 1, 0], [0, 0, 1, 1], [.5, .5, .5, .5]]) f2 = np.array([[.5, .5, .5, .5], [0, 1, 1, 0], [0, 0, 1, 1]]) f3 = np.array([[0, 1, 1, 0], [.5, .5, .5, .5], [0, 0, 1, 1]]) gb = meshing.cart_grid([f1, f2, f3], [2, 2, 2], **{'physdims': [1, 1, 1]}) gb.compute_geometry() gb.assign_node_ordering() cell_centers1 = np.array([[0.25, 0.75, 0.25, 0.75], [0.25, 0.25, 0.75, 0.75], [0.5, 0.5, 0.5, 0.5]]) cell_centers2 = np.array([[0.5, 0.5, 0.5, 0.5], [0.25, 0.25, 0.75, 0.75], [0.75, 0.25, 0.75, 0.25]]) cell_centers3 = np.array([[0.25, 0.75, 0.25, 0.75], [0.5, 0.5, 0.5, 0.5], [0.25, 0.25, 0.75, 0.75]]) cell_centers4 = np.array([[0.5], [0.25], [0.5]]) cell_centers5 = np.array([[0.5], [0.75], [0.5]]) cell_centers6 = np.array([[0.75], [0.5], [0.5]]) cell_centers7 = np.array([[0.25], [0.5], [0.5]]) cell_centers8 = np.array([[0.5], [0.5], [0.25]]) cell_centers9 = np.array([[0.5], [0.5], [0.75]]) for g, d in gb: if np.allclose(g.cell_centers[:, 0], cell_centers1[:, 0]): d['node_number'] = 1 elif np.allclose(g.cell_centers[:, 0], cell_centers2[:, 0]): d['node_number'] = 2 elif np.allclose(g.cell_centers[:, 0], cell_centers3[:, 0]): d['node_number'] = 3 elif np.allclose(g.cell_centers[:, 0], cell_centers4[:, 0]): d['node_number'] = 4 elif np.allclose(g.cell_centers[:, 0], cell_centers5[:, 0]): d['node_number'] = 5 elif np.allclose(g.cell_centers[:, 0], cell_centers6[:, 0]): d['node_number'] = 6 elif np.allclose(g.cell_centers[:, 0], cell_centers7[:, 0]): d['node_number'] = 7 elif np.allclose(g.cell_centers[:, 0], cell_centers8[:, 0]): d['node_number'] = 8 elif np.allclose(g.cell_centers[:, 0], cell_centers9[:, 0]): d['node_number'] = 9 else: pass tol = 1e-3 solver = tpfa.Tpfa() gb.add_node_props(['param']) a = 1e-2 for g, d in gb: param = Parameters(g) aperture = np.ones(g.num_cells) * np.power(a, gb.dim_max() - g.dim) param.set_aperture(aperture) p = tensor.SecondOrderTensor( 3, np.ones(g.num_cells) * np.power(1e3, g.dim < gb.dim_max())) param.set_tensor('flow', p) 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, :] > 1 - tol right = bound_face_centers[0, :] < tol labels = np.array(['neu'] * bound_faces.size) labels[np.logical_or(left, right)] = ['dir'] bc_val = np.zeros(g.num_faces) bc_dir = bound_faces[np.logical_or(left, right)] bc_val[bc_dir] = g.face_centers[0, bc_dir] param.set_bc(solver, bc.BoundaryCondition(g, bound_faces, labels)) param.set_bc_val(solver, bc_val) else: param.set_bc("flow", bc.BoundaryCondition(g, np.empty(0), np.empty(0))) d['param'] = param coupling_conditions = tpfa.TpfaCoupling(solver) solver_coupler = coupler.Coupler(solver, coupling_conditions) A, rhs = solver_coupler.matrix_rhs(gb) p = sps.linalg.spsolve(A, rhs) p_cond, _, _, _ = condensation.solve_static_condensation(A, rhs, gb, dim=0) solver_coupler.split(gb, 'pressure', p) solver_coupler.split(gb, "p_cond", p_cond) 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)