Exemplo n.º 1
0
    def test_1d_elimination_3d_2d_1d(self):
        """
        3d case with a single 1d 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]])

        gb = meshing.cart_grid([f1, f2], [2, 2, 2], **{'physdims': [1, 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)

            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)

        p = sps.linalg.spsolve(A, rhs)
        p_cond, _, _, _ = condensation.solve_static_condensation(\
                                                                 A, rhs, gb, dim=1)

        solver_coupler.split(gb, "pressure", p)
        solver_coupler.split(gb, "p_cond", p_cond)

        tol = 1e-5
        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)
Exemplo n.º 2
0
    def test_mpfa_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 = mpfa.Mpfa(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)
Exemplo n.º 3
0
    def atest_mpfa_coupling_2d_1d_bottom_top_dir(self):
        """
        Grid: 2 x 2 matrix + 2 x 1 fracture from left to right.
        Dirichlet + 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 = mpfa.Mpfa(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.SecondOrderTensor(
                3,
                np.ones(g.num_cells) * np.power(1e-3, g.dim < gb.dim_max()))
            param.set_tensor("flow", p)
            bound_faces = g.tags["domain_boundary_faces"].nonzero()[0]
            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[np.logical_or(top, bottom)] = ["dir"]

            bc_val = np.zeros(g.num_faces)
            bc_dir = bound_faces[np.logical_or(top, bottom)]
            bc_val[bc_dir] = g.face_centers[1, 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.19047619, 0., -0.19047619],
            [0., 4.19047619, -0.19047619],
            [-0.19047619, -0.19047619, 0.38095238],
        ])

        rhs_known = np.array([0., 4., 0.])

        rtol = 1e-6
        atol = rtol

        self.assertTrue(np.allclose(A.todense(), A_known, rtol, atol))
        self.assertTrue(np.allclose(rhs, rhs_known, rtol, atol))
Exemplo n.º 4
0
    def test_mpfa_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 = mpfa.Mpfa(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)
Exemplo n.º 5
0
    def time_disc(self):
        """
        Returns the time discretization.
        """
        class TimeDisc(mass_matrix.MassMatrix):
            def __init__(self, deltaT):
                self.deltaT = deltaT

            def matrix_rhs(self, g, data):
                ndof = g.num_cells
                aperture = data['param'].get_aperture()
                coeff = g.cell_volumes * aperture / self.deltaT

                factor_fluid = data['param'].fluid_specific_heat\
                             * data['param'].fluid_density\
                             * data['param'].porosity
                factor_rock = data['param'].rock_specific_heat\
                             * data['param'].rock_density\
                             * (1 - data['param'].porosity)
                factor = sps.dia_matrix((factor_fluid + factor_rock, 0),
                                        shape=(ndof, ndof))

                lhs = sps.dia_matrix((coeff, 0), shape=(ndof, ndof))
                rhs = np.zeros(ndof)
                return factor * lhs, factor * rhs

        single_dim_discr = TimeDisc(self.time_step())
        if self.is_GridBucket:
            time_discretization = coupler.Coupler(single_dim_discr)
        else:
            time_discretization = TimeDisc(self.time_step())
        return time_discretization
Exemplo n.º 6
0
            def __init__(self):
                self.physics = 'transport'

                self.discr = WeightedUpwindDisc()
                self.discr_ndof = self.discr.ndof
                self.coupling_conditions = WeightedUpwindCoupler(self.discr)

                self.solver = coupler.Coupler(self.discr,
                                              self.coupling_conditions)
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
    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)
Exemplo n.º 9
0
    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)
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
def darcy_dualVEM_coupling_example2(**kwargs):
    #######################
    # Simple 2d Darcy problem with known exact solution
    #######################
    np.set_printoptions(linewidth=999999, threshold=np.nan, precision=16)

    f_1 = np.array([[-1, 1, 1, -1], [0, 0, 0, 0], [-1, -1, 1, 1]])
    f_2 = np.array([[0, 0, 0, 0], [-1, 1, 1, -1], [-1.5, -1.5, .8, .8]])
    domain = {'xmin': -2, 'xmax': 2, 'ymin': -2, 'ymax': 2, 'zmin': -2, 'zmax':
              2}

#    mesh_size = {'mode': 'constant', 'value': 0.5, 'bound_value': 1}
    mesh_size = {'mode': 'constant', 'value': 5, 'bound_value': 10}
    mesh_size = {'mode': 'constant', 'value': 0.25, 'bound_value': 10}
    kwargs['mesh_size'] = mesh_size
    kwargs['gmsh_path'] = '~/gmsh/bin/gmsh'

    gb = meshing.simplex_grid([f_1, f_2], domain, **kwargs)
    gb.remove_nodes(lambda g: g.dim == gb.dim_max())

# It's not really working now the coarsening part with the gb
#    for g, _ in gb:
#        if g.dim != 1:
#            part = create_partition(tpfa_matrix(g))
#            gb.change_nodes({g: generate_coarse_grid(g, part)})
#
#    gb.compute_geometry(is_starshaped=True)

    print([g.num_faces for g, _ in gb])
    gb.assign_node_ordering()

    # Need to remove the boundary flag explicity from the fracture face,
    # because of the mix formulation
    internal_flag = FaceTag.FRACTURE
    [g.remove_face_tag_if_tag(FaceTag.BOUNDARY, internal_flag)
     for g, _ in gb if g.dim == gb.dim_max()]

    if kwargs['visualize']:
        plot_grid(gb, info="f", alpha=0)

    gb.add_node_props(['perm', 'source', 'bc', 'bc_val'])
    for g, d in gb:
        kxx = np.ones(g.num_cells)
        d['perm'] = tensor.SecondOrder(g.dim, kxx)
        d['source'] = np.zeros(g.num_cells)

        b_faces = g.get_boundary_faces()
        b_faces_dir = b_faces[np.bitwise_or(g.face_centers[1, b_faces] == -1,
                                            g.face_centers[0, b_faces] == -1)]

        b_faces_dir_cond = g.face_centers[0, b_faces_dir]

        b_faces_neu = np.setdiff1d(b_faces, b_faces_dir, assume_unique=True)
        b_faces = np.hstack((b_faces_dir, b_faces_neu))
        b_faces_label = np.hstack((['dir'] * b_faces_dir.size,
                                   ['neu'] * b_faces_neu.size))
        d['bc'] = bc.BoundaryCondition(g, b_faces, b_faces_label)
        d['bc_val'] = {'dir': b_faces_dir_cond,
                       'neu': np.zeros(b_faces_neu.size)}

    gb.add_edge_prop('kn')
    for e, d in gb.edges_props():
        g_l = gb.sorted_nodes_of_edge(e)[0]
        c = g_l.cell_centers[2, :] > -0.5
        d['kn'] = (np.ones(g_l.num_cells) + c.astype('float') * (-1 + 1e-2))

    solver = dual.DualVEM()
    coupling_conditions = dual_coupling.DualCoupling(solver)
    solver_coupler = coupler.Coupler(solver, coupling_conditions)
    A, b = solver_coupler.matrix_rhs(gb)

    up = sps.linalg.spsolve(A, b)
    solver_coupler.split(gb, "up", up)

    gb.add_node_props(["u", 'pressure', "P0u"])
    for g, d in gb:
        d["u"] = solver.extractU(g, d["up"])
        d['pressure'] = solver.extractP(g, d["up"])
        d["P0u"] = solver.projectU(g, d["u"], d)

    if kwargs['visualize']:
        plot_grid(gb, 'pressure', "P0u")

    export_vtk(gb, "grid", ['pressure', "P0u"])
Exemplo n.º 12
0
    def atest_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 = pp.meshing.cart_grid([f1, f2], [2, 2], **{"physdims": [1, 1]})
        # gb = pp.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 = pp.TpfaMixedDim()
        gb.add_node_props(["param"])
        a = 1e-2
        for g, d in gb:
            param = pp.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 = pp.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("flow",
                             pp.BoundaryCondition(g, bound_faces, labels))
                param.set_bc_val("flow", bc_val)
                # Transport
                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)

                param.set_bc("transport",
                             pp.BoundaryCondition(g, bound_faces, labels))
                param.set_bc_val("transport", bc_val)
            else:
                param.set_bc("transport",
                             pp.BoundaryCondition(g, np.empty(0), np.empty(0)))
                param.set_bc("flow",
                             pp.BoundaryCondition(g, np.empty(0), np.empty(0)))
            # Transport:
            source = g.cell_volumes * a_dim
            param.set_source("transport", source)

            d["param"] = param

        gb.add_edge_props("param")
        for e, d in gb.edges():
            g_h = gb.nodes_of_edge(e)[1]
            d["param"] = pp.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)

        # pp.fvutils.compute_discharges(gb)
        pp.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 = pp.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
        self.assertTrue(np.isclose(deltaT, deltaT_known, tol, tol))
        self.assertTrue((np.amax(np.absolute(U_r - U_known))) < tol)
        self.assertTrue((np.amax(np.absolute(rhs_u_r - rhs_known))) < tol)
        self.assertTrue((np.amax(np.absolute(theta_r - theta_known))) < tol)
Exemplo n.º 13
0
    def test_0d_elimination_two_0d_grids(self):
        """
        2d case involving two 0d grids.
        """
        f1 = np.array([[0, 1], [.5, .5]])
        f2 = np.array([[.5, .5], [0, 1]])
        f3 = np.array([[.25, .25], [0, 1]])

        gb = meshing.cart_grid([f1, f2, f3], [4, 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())
            #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)

        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)
Exemplo n.º 14
0
    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)
Exemplo n.º 15
0
def darcy_dualVEM_coupling_example2(**kwargs):
    #######################
    # Simple 2d Darcy problem with known exact solution
    #######################
    np.set_printoptions(linewidth=999999, threshold=np.nan, precision=16)

    f_1 = np.array([[-1, 1, 1, -1], [0, 0, 0, 0], [-1, -1, 1, 1]])
    f_2 = np.array([[0, 0, 0, 0], [-1, 1, 1, -1], [-1.5, -1.5, .8, .8]])
    domain = {
        "xmin": -2,
        "xmax": 2,
        "ymin": -2,
        "ymax": 2,
        "zmin": -2,
        "zmax": 2
    }

    kwargs = {
        "mesh_size_frac": .25,
        "mesh_size_bound": 10,
        "mesh_size_min": .02,
        "gmsh_path": "~/gmsh/bin/gmsh",
    }

    gb = meshing.simplex_grid([f_1, f_2], domain, **kwargs)
    gb.remove_nodes(lambda g: g.dim == gb.dim_max())

    # It's not really working now the coarsening part with the gb
    #    for g, _ in gb:
    #        if g.dim != 1:
    #            part = create_partition(tpfa_matrix(g))
    #            gb.change_nodes({g: generate_coarse_grid(g, part)})
    #
    #    gb.compute_geometry(is_starshaped=True)

    print([g.num_faces for g, _ in gb])
    gb.assign_node_ordering()

    if kwargs["visualize"]:
        plot_grid(gb, info="f", alpha=0)

    gb.add_node_props(["perm", "source", "bc", "bc_val"])
    for g, d in gb:
        kxx = np.ones(g.num_cells)
        d["perm"] = tensor.SecondOrderTensor(g.dim, kxx)
        d["source"] = np.zeros(g.num_cells)

        b_faces = g.tags["domain_boundary_faces"].nonzero()[0]
        b_faces_dir = b_faces[np.bitwise_or(g.face_centers[1, b_faces] == -1,
                                            g.face_centers[0, b_faces] == -1)]

        b_faces_dir_cond = g.face_centers[0, b_faces_dir]

        b_faces_neu = np.setdiff1d(b_faces, b_faces_dir, assume_unique=True)
        b_faces = np.hstack((b_faces_dir, b_faces_neu))
        b_faces_label = np.hstack(
            (["dir"] * b_faces_dir.size, ["neu"] * b_faces_neu.size))
        d["bc"] = bc.BoundaryCondition(g, b_faces, b_faces_label)
        d["bc_val"] = {
            "dir": b_faces_dir_cond,
            "neu": np.zeros(b_faces_neu.size)
        }

    gb.add_edge_prop("kn")
    for e, d in gb.edges_props():
        g_l = gb.sorted_nodes_of_edge(e)[0]
        c = g_l.cell_centers[2, :] > -0.5
        d["kn"] = np.ones(g_l.num_cells) + c.astype("float") * (-1 + 1e-2)

    solver = dual.DualVEM()
    coupling_conditions = dual_coupling.DualCoupling(solver)
    solver_coupler = coupler.Coupler(solver, coupling_conditions)
    A, b = solver_coupler.matrix_rhs(gb)

    up = sps.linalg.spsolve(A, b)
    solver_coupler.split(gb, "up", up)

    gb.add_node_props(["u", "pressure", "P0u"])
    for g, d in gb:
        d["u"] = solver.extractU(g, d["up"])
        d["pressure"] = solver.extractP(g, d["up"])
        d["P0u"] = solver.projectU(g, d["u"], d)

    if kwargs["visualize"]:
        plot_grid(gb, "pressure", "P0u")

    export_vtk(gb, "grid", ["pressure", "P0u"])
Exemplo n.º 16
0
    gb = meshing.simplex_grid(f_set, domain, gmsh_path=path_to_gmsh)
    gb.assign_node_ordering()

    ################## Transport solver ##################

    print("Compute global matrix and rhs for the advection problem")
    gb_r, elimination_data = gb.duplicate_without_dimension(0)
    condensation.compute_elimination_fluxes(gb, gb_r, elimination_data)

    add_data_transport(gb)
    add_data_transport(gb_r)

    upwind_solver = upwind.Upwind()
    upwind_cc = upwind.UpwindCoupling(upwind_solver)
    coupler_solver = coupler.Coupler(upwind_solver, upwind_cc)
    U, rhs = coupler_solver.matrix_rhs(gb)
    U_r, rhs_r = coupler_solver.matrix_rhs(gb_r)

    deltaT = np.amin([upwind_solver.cfl(g, d) for g, d in gb])
    deltaT_r = np.amin([upwind_solver.cfl(g, d) for g, d in gb_r])

    T = deltaT * max(Nx, Ny) * 4

    gb.add_node_prop("deltaT", None, deltaT)
    gb_r.add_node_prop("deltaT", None, deltaT_r)

    mass_solver = mass_matrix.MassMatrix()
    coupler_solver = coupler.Coupler(mass_solver)
    M, _ = coupler_solver.matrix_rhs(gb)
    M_r, _ = coupler_solver.matrix_rhs(gb_r)
Exemplo n.º 17
0
    def atest_0d_elimination_two_0d_grids(self):
        """
        2d case involving two 0d grids.
        """
        f1 = np.array([[0, 1], [.5, .5]])
        f2 = np.array([[.5, .5], [0, 1]])
        f3 = np.array([[.25, .25], [0, 1]])

        gb = meshing.cart_grid([f1, f2, f3], [4, 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
        self.assertTrue((np.amax(np.absolute(p - p_cond))) < tol)
        self.assertTrue(
            np.sum(error.error_L2(g, d["pressure"], d["p_cond"]) for g, d in gb) < tol
        )