Пример #1
0
 def test_sub_two_scalars(self):
     a = Ad_array(1, 0)
     b = Ad_array(3, 0)
     c = a - b
     self.assertTrue(c.val == -2 and c.jac == 0)
     self.assertTrue(a.val == 1 and a.jac == 0)
     self.assertTrue(b.val == 3 and a.jac == 0)
Пример #2
0
 def test_mul_scal_ad_scal(self):
     a = Ad_array(3, 0)
     b = Ad_array(2, 0)
     c = a * b
     self.assertTrue(c.val == 6 and c.jac == 0)
     self.assertTrue(a.val == 3 and a.jac == 0)
     self.assertTrue(b.val == 2 and b.jac == 0)
Пример #3
0
 def test_add_two_scalars(self):
     a = Ad_array(1, 0)
     b = Ad_array(-10, 0)
     c = a + b
     self.assertTrue(c.val == -9 and c.jac == 0)
     self.assertTrue(a.val == 1 and a.jac == 0)
     self.assertTrue(b.val == -10 and b.jac == 0)
Пример #4
0
 def test_sub_two_ad_variables(self):
     a = Ad_array(4, 1.0)
     b = Ad_array(9, 3)
     c = a - b
     self.assertTrue(np.allclose(c.val, -5) and np.allclose(c.jac, -2))
     self.assertTrue(a.val == 4 and np.allclose(a.jac, 1.0))
     self.assertTrue(b.val == 9 and b.jac == 3)
Пример #5
0
 def test_mul_ad_var_ad_var(self):
     a = Ad_array(3, 3)
     b = Ad_array(2, -4)
     c = a * b
     self.assertTrue(c.val == 6 and c.jac == -6)
     self.assertTrue(a.val == 3 and a.jac == 3)
     self.assertTrue(b.val == 2 and b.jac == -4)
Пример #6
0
 def test_copy_vector(self):
     a = Ad_array(np.ones((3, 1)), np.ones((3, 1)))
     b = a.copy()
     self.assertTrue(np.allclose(a.val, b.val))
     self.assertTrue(np.allclose(a.jac, b.jac))
     a.val[0] = 3
     a.jac[2] = 4
     self.assertTrue(np.allclose(b.val, np.ones((3, 1))))
     self.assertTrue(np.allclose(b.jac, np.ones((3, 1))))
Пример #7
0
 def test_copy_scalar(self):
     a = Ad_array(1, 0)
     b = a.copy()
     self.assertTrue(a.val == b.val)
     self.assertTrue(a.jac == b.jac)
     a.val = 2
     a.jac = 3
     self.assertTrue(b.val == 1)
     self.assertTrue(b.jac == 0)
Пример #8
0
def log(var):
    if not isinstance(var, Ad_array):
        return np.log(var)

    val = np.log(var.val)
    der = var.diagvec_mul_jac(1 / var.val)
    return Ad_array(val, der)
Пример #9
0
 def test_add_var_with_scal(self):
     a = Ad_array(3, 2)
     b = 3
     c = a + b
     self.assertTrue(np.allclose(c.val, 6) and np.allclose(c.jac, 2))
     self.assertTrue(a.val == 3 and np.allclose(a.jac, 2))
     self.assertTrue(b == 3)
Пример #10
0
def abs(var):
    if not isinstance(var, Ad_array):
        return np.abs(var)
    else:
        val = np.abs(var.val)
        jac = var.diagvec_mul_jac(sign(var))
        return Ad_array(val, jac)
Пример #11
0
def exp(var):
    if isinstance(var, Ad_array):
        val = np.exp(var.val)
        der = var.diagvec_mul_jac(np.exp(var.val))
        return Ad_array(val, der)
    else:
        return np.exp(var)
Пример #12
0
 def test_mul_ad_var_scal(self):
     a = Ad_array(3, 3)
     b = 3
     c = a * b
     self.assertTrue(c.val == 9 and c.jac == 9)
     self.assertTrue(a.val == 3 and a.jac == 3)
     self.assertTrue(b == 3)
Пример #13
0
 def test_sub_scal_with_var(self):
     a = Ad_array(3, 2)
     b = 3
     c = b - a
     self.assertTrue(np.allclose(c.val, 0) and np.allclose(c.jac, -2))
     self.assertTrue(a.val == 3 and a.jac == 2)
     self.assertTrue(b == 3)
Пример #14
0
 def test_sign_advar(self):
     a = Ad_array(np.array([1, -10, 3, -np.pi]), np.eye(4))
     sign = af.sign(a)
     self.assertTrue(np.all(sign == [1, -1, 1, -1]))
     self.assertTrue(
         np.allclose(a.val, [1, -10, 3, -np.pi]) and np.allclose(a.jac, np.eye(4))
     )
Пример #15
0
    def test_abs_advar(self):
        J = np.array(
            [[1, -1, -np.pi, 3], [0, 0, 0, 0], [1, 2, -3.2, 4], [4, 2, 300000, 1]]
        )
        a = Ad_array(np.array([1, -10, 3, -np.pi]), sps.csc_matrix(J))
        a_abs = af.abs(a)
        J_abs = np.array(
            [[1, -1, -np.pi, 3], [0, 0, 0, 0], [1, 2, -3.2, 4], [-4, -2, -300000, -1]]
        )

        self.assertTrue(
            np.allclose(
                J,
                np.array(
                    [
                        [1, -1, -np.pi, 3],
                        [0, 0, 0, 0],
                        [1, 2, -3.2, 4],
                        [4, 2, 300000, 1],
                    ]
                ),
            )
        )
        self.assertTrue(np.allclose(a_abs.val, [1, 10, 3, np.pi]))
        self.assertTrue(np.allclose(a_abs.jac.A, J_abs))
Пример #16
0
 def test_log_sparse_jac(self):
     val = np.array([1, 2, 3])
     J = sps.csc_matrix(np.array([[3, 2, 1], [5, 6, 1], [2, 3, 5]]))
     a = Ad_array(val, J)
     b = af.log(a)
     jac = np.dot(np.diag(1 / val), J.A)
     self.assertTrue(np.all(b.val == np.log(val)) and np.all(b.jac == jac))
Пример #17
0
    def test_full_jac(self):
        J1 = sps.csc_matrix(
            np.array([[1, 3, 5], [1, 5, 1], [6, 2, 4], [2, 4, 1], [6, 2, 1]]))
        J2 = sps.csc_matrix(np.array([[1, 2], [2, 5], [6, 0], [9, 9], [45,
                                                                       2]]))
        J = np.array([
            [1, 3, 5, 1, 2],
            [1, 5, 1, 2, 5],
            [6, 2, 4, 6, 0],
            [2, 4, 1, 9, 9],
            [6, 2, 1, 45, 2],
        ])

        a = Ad_array(np.array([1, 2, 3, 4, 5]),
                     J.copy())  # np.array([J1, J2]))

        self.assertTrue(np.sum(a.full_jac() != J) == 0)
Пример #18
0
    def test_mul_sps_advar(self):
        J = sps.csc_matrix(np.array([[1, 3, 1], [5, 0, 0], [5, 1, 2]]))
        x = Ad_array(np.array([1, 2, 3]), J)
        A = sps.csc_matrix(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
        f = A * x

        self.assertTrue(np.all(f.val == [14, 32, 50]))
        self.assertTrue(np.all(f.jac == A * J.A))
Пример #19
0
    def test_log_vector(self):
        val = np.array([1, 2, 3])
        J = sps.csc_matrix(np.array([[3, 2, 1], [5, 6, 1], [2, 3, 5]]))
        a = Ad_array(val, J)
        b = af.log(a)
        jac = sps.diags(1 / val) * J

        self.assertTrue(np.all(b.val == np.log(val)) and np.all(b.jac.A == jac))
Пример #20
0
    def test_mul_advar_vectors(self):
        Ja = sps.csc_matrix(np.array([[1, 3, 1], [5, 0, 0], [5, 1, 2]]))
        Jb = sps.csc_matrix(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
        a = Ad_array(np.array([1, 2, 3]), Ja)
        b = Ad_array(np.array([1, 1, 1]), Jb)
        A = sps.csc_matrix(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))

        f = A * a + b
        jac = A * Ja + Jb

        self.assertTrue(np.all(f.val == [15, 33, 51]))
        self.assertTrue(np.sum(f.full_jac() != A * Ja + Jb) == 0)
        self.assertTrue(
            np.sum(Ja != sps.csc_matrix(
                np.array([[1, 3, 1], [5, 0, 0], [5, 1, 2]]))) == 0)
        self.assertTrue(
            np.sum(Jb != sps.csc_matrix(
                np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))) == 0)
Пример #21
0
    def test_exp_vector(self):
        val = np.array([1, 2, 3])
        J = np.array([[3, 2, 1], [5, 6, 1], [2, 3, 5]])
        a = Ad_array(val, sps.csc_matrix(J))
        b = af.exp(a)
        jac = np.dot(np.diag(np.exp(val)), J)

        self.assertTrue(np.all(b.val == np.exp(val)) and np.all(b.jac == jac))
        self.assertTrue(np.all(J == np.array([[3, 2, 1], [5, 6, 1], [2, 3, 5]])))
Пример #22
0
def concatenate(variables, axis=0):
    vals = [var.val for var in variables]
    jacs = np.array([var.jac for var in variables])

    vals_stacked = np.concatenate(vals, axis=axis)
    jacs_stacked = []
    jacs_stacked = sps.vstack(jacs)

    return Ad_array(vals_stacked, jacs_stacked)
Пример #23
0
    def test_advar_mul_vec(self):
        x = Ad_array(np.array([1, 2, 3]), sps.diags([3, 2, 1]))
        A = np.array([1, 3, 10])
        f = x * A
        sol = np.array([1, 6, 30])
        jac = np.diag([3, 6, 10])

        self.assertTrue(np.all(f.val == sol) and np.all(f.jac == jac))
        self.assertTrue(
            np.all(x.val == np.array([1, 2, 3]))
            and np.all(x.jac == np.diag([3, 2, 1])))
Пример #24
0
    def test_mul_ad_var_mat(self):
        x = Ad_array(np.array([1, 2, 3]), sps.diags([3, 2, 1]))
        A = sps.csc_matrix(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
        f = x * A
        sol = np.array([30, 36, 42])
        jac = np.diag([3, 2, 1]) * A

        self.assertTrue(np.all(f.val == sol) and np.all(f.jac == jac))
        self.assertTrue(
            np.all(x.val == np.array([1, 2, 3])) and np.all(x.jac == np.diag([3, 2, 1]))
        )
        self.assertTrue(np.all(A == np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])))
Пример #25
0
    def test_log_scalar_times_ad_var(self):
        val = np.array([1, 2, 3])
        J = sps.diags(np.array([1, 1, 1]))
        a = Ad_array(val, J)
        c = 2
        b = af.log(c * a)
        jac = sps.diags(1 / val) * J

        self.assertTrue(
            np.allclose(b.val, np.log(c * val)) and np.allclose(b.jac.A, jac.A)
        )
        self.assertTrue(np.all(a.val == [1, 2, 3]) and np.all(a.jac.A == J.A))
Пример #26
0
 def test_advar_m_mul_vec_n(self):
     x = Ad_array(np.array([1, 2, 3]), sps.diags([3, 2, 1]))
     vec = np.array([1, 2])
     R = sps.csc_matrix(np.array([[1, 0, 1], [0, 1, 0]]))
     y = R * x
     z = y * vec
     Jy = np.array([[1, 0, 3], [0, 2, 0]])
     Jz = np.array([[1, 0, 3], [0, 4, 0]])
     self.assertTrue(np.all(y.val == [4, 2]))
     self.assertTrue(np.sum(y.full_jac().A - Jy) == 0)
     self.assertTrue(np.all(z.val == [4, 4]))
     self.assertTrue(np.sum(z.full_jac().A - Jz) == 0)
Пример #27
0
    def test_rpower_advar_vector_scalar(self):
        J = sps.csc_matrix(np.array([[1, 2], [2, 3], [0, 1]]))
        a = Ad_array(np.array([1, 2, 3]), J)
        b = 3**a
        bJac = np.array([
            [3 * np.log(3) * 1, 3 * np.log(3) * 2],
            [9 * np.log(3) * 2, 9 * np.log(3) * 3],
            [27 * np.log(3) * 0, 27 * np.log(3) * 1],
        ])

        self.assertTrue(np.all(b.val == [3, 9, 27]))
        self.assertTrue(np.all(b.jac.A == bJac))
Пример #28
0
 def test_div_advar_scalar(self):
     a = Ad_array(10, 6)
     b = 2
     c = a / b
     self.assertTrue(c.val == 5, c.jac == 2)
def conv_test(n):

    # Analytical solution
    def mandel_solution(g, Nx, Ny, times, F, B, nu_u, nu, c_f, mu_s):

        # Some needed parameters
        a = np.max(g.face_centers[0])  # a = Lx
        x_cntr = g.cell_centers[0][:Nx]  # [m] vector of x-centers
        y_cntr = g.cell_centers[1][::Nx]  # [m] vector of y-centers

        # Solutions to tan(x) - ((1-nu)/(nu_u-nu)) x = 0
        """
        This is somehow tricky, we have to solve the equation numerically in order to
        find all the positive solutions to the equation. Later we will use them to 
        compute the infinite sums. Experience has shown that 200 roots are more than enough to
        achieve accurate results. Note that we find the roots using the bisection method.
        """
        f = lambda x: np.tan(x) - (
            (1 - nu) /
            (nu_u - nu)) * x  # define the algebraic eq. as a lambda function
        n_series = 200  # number of roots
        a_n = np.zeros(n_series)  # initializing roots array
        x0 = 0  # initial point
        for i in range(0, len(a_n)):
            a_n[i] = opt.bisect(
                f,  # function
                x0 + np.pi / 4,  # left point 
                x0 + np.pi / 2 -
                10000 * 2.2204e-16,  # right point (a tiny bit less than pi/2)
                xtol=1e-30,  # absolute tolerance
                rtol=1e-15  # relative tolerance
            )
            x0 += np.pi  # apply a phase change of pi to get the next root

        # Creating dictionary to store analytical solutions
        mandel_sol = dict()
        mandel_sol['p'] = np.zeros((len(times), len(x_cntr)))
        mandel_sol['u_x'] = np.zeros((len(times), len(x_cntr)))
        mandel_sol['u_y'] = np.zeros((len(times), len(y_cntr)))
        mandel_sol['sigma_yy'] = np.zeros((len(times), len(x_cntr)))

        # Terms needed to compute the solutions (these are constants)
        p0 = (2 * F * B * (1 + nu_u)) / (3 * a)
        ux0_1 = ((F * nu) / (2 * mu_s * a))
        ux0_2 = -((F * nu_u) / (mu_s * a))
        ux0_3 = F / mu_s
        uy0_1 = (-F * (1 - nu)) / (2 * mu_s * a)
        uy0_2 = (F * (1 - nu_u) / (mu_s * a))
        sigma0_1 = -F / a
        sigma0_2 = (-2 * F * B * (nu_u - nu)) / (a * (1 - nu))
        sigma0_3 = (2 * F) / a

        # Saving solutions for the initial conditions
        mandel_sol['p'][0] = ((F * B * (1 + nu_u)) / (3 * a)) * np.ones(Nx)
        mandel_sol['u_x'][0] = (F * nu_u * x_cntr) / (2 * mu_s * a)
        mandel_sol['u_y'][0] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * y_cntr

        # Storing solutions for the subsequent time steps
        for ii in range(1, len(times)):

            # Analytical Pressures
            p_sum = 0
            for n in range(len(a_n)):
                p_sum += (((np.sin(a_n[n])) /
                           (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) *
                          (np.cos((a_n[n] * x_cntr) / a) - np.cos(a_n[n])) *
                          np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2)))

            mandel_sol['p'][ii] = p0 * p_sum

            # Analytical horizontal displacements
            ux_sum1 = 0
            ux_sum2 = 0
            for n in range(len(a_n)):
                ux_sum1 += ((np.sin(a_n[n]) * np.cos(a_n[n])) /
                            (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n])) *
                            np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2)))
                ux_sum2 += ((np.cos(a_n[n]) /
                             (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) *
                            np.sin(a_n[n] * (x_cntr / a)) * np.exp(
                                (-(a_n[n]**2) * c_f * times[ii]) / (a**2)))
            mandel_sol['u_x'][ii] = (
                ux0_1 + ux0_2 * ux_sum1) * x_cntr + ux0_3 * ux_sum2

            # Analytical vertical displacements
            uy_sum = 0
            for n in range(len(a_n)):
                uy_sum += (((np.sin(a_n[n]) * np.cos(a_n[n])) /
                            (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) *
                           np.exp((-(a_n[n]**2) * c_f * times[ii]) / (a**2)))
            mandel_sol['u_y'][ii] = (uy0_1 + uy0_2 * uy_sum) * y_cntr

            # Analitical vertical stress
            sigma_sum1 = 0
            sigma_sum2 = 0
            for n in range(len(a_n)):
                sigma_sum1 += (((np.sin(a_n[n])) /
                                (a_n[n] - (np.sin(a_n[n]) * np.cos(a_n[n])))) *
                               np.cos(a_n[n] * (x_cntr / a)) * np.exp(
                                   (-(a_n[n]**2) * c_f * times[ii]) / (a**2)))
                sigma_sum2 += (((np.sin(a_n[n]) * np.cos(a_n[n])) /
                                (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) *
                               np.exp(
                                   (-(a_n[n]**2) * c_f * times[ii]) / (a**2)))
            mandel_sol['sigma_yy'][ii] = (sigma0_1 + sigma0_2 * sigma_sum1) + (
                sigma0_3 * sigma_sum2)

        return mandel_sol

    # Computing the initial condition

    def get_mandel_init_cond(g, F, B, nu_u, mu_s):

        # Initialing pressure and displacement arrays
        p0 = np.zeros(g.num_cells)
        u0 = np.zeros(g.num_cells * 2)

        # Some needed parameters
        a = np.max(g.face_centers[0])  # a = Lx

        p0 = ((F * B * (1 + nu_u)) / (3 * a)) * np.ones(g.num_cells)
        u0[::2] = (F * nu_u * g.cell_centers[0]) / (2 * mu_s * a)
        u0[1::2] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * g.cell_centers[1]

        return p0, u0

    # Getting the time-dependent boundary condition

    def get_mandel_bc(g, y_max, times, F, B, nu_u, nu, c_f, mu_s):

        # Initializing top boundary array
        u_top = np.zeros((len(times), len(y_max)))

        # Some needed parameters
        a = np.max(g.face_centers[0])  # a = Lx
        b = np.max(g.face_centers[1])  # b = Ly
        y_top = g.face_centers[1][
            y_max]  # [m] y-coordinates at the top boundary

        # Solutions to tan(x) - ((1-nu)/(nu_u-nu)) x = 0
        """
        This is somehow tricky, we have to solve the equation numerically in order to
        find all the positive solutions to the equation. Later we will use them to 
        compute the infinite sums. Experience has shown that 200 roots are more than enough to
        achieve accurate results. Note that we find the roots using the bisection method.
        """
        f = lambda x: np.tan(x) - (
            (1 - nu) /
            (nu_u - nu)) * x  # define the algebraic eq. as a lambda function
        n_series = 200  # number of roots
        a_n = np.zeros(n_series)  # initializing roots array
        x0 = 0  # initial point
        for i in range(0, len(a_n)):
            a_n[i] = opt.bisect(
                f,  # function
                x0 + np.pi / 4,  # left point 
                x0 + np.pi / 2 -
                10000 * 2.2204e-16,  # right point (a tiny bit less than pi/2)
                xtol=1e-30,  # absolute tolerance
                rtol=1e-15  # relative tolerance
            )
            x0 += np.pi  # apply a phase change of pi to get the next root

        # Terms needed to compute the solutions (these are constants)
        uy0_1 = (-F * (1 - nu)) / (2 * mu_s * a)
        uy0_2 = (F * (1 - nu_u) / (mu_s * a))

        # For the initial condition:
        u_top[0] = ((-F * (1 - nu_u)) / (2 * mu_s * a)) * b

        for i in range(1, len(times)):
            # Analytical vertical displacements at the top boundary
            uy_sum = 0
            for n in range(len(a_n)):
                uy_sum += (((np.sin(a_n[n]) * np.cos(a_n[n])) /
                            (a_n[n] - np.sin(a_n[n]) * np.cos(a_n[n]))) *
                           np.exp((-(a_n[n]**2) * c_f * times[i]) / (a**2)))

            u_top[i] = (uy0_1 + uy0_2 * uy_sum) * y_top

        # Returning array of u_y at the top boundary
        return u_top

    # Getting mechanics boundary conditions

    def get_bc_mechanics(g, u_top, times, b_faces, x_min, x_max, west, east,
                         y_min, y_max, south, north):

        # Setting the tags at each boundary side for the mechanics problem
        labels_mech = np.array([None] * b_faces.size)
        labels_mech[west] = 'dir_x'  # roller
        labels_mech[east] = 'neu'  # traction free
        labels_mech[south] = 'dir_y'  # roller
        labels_mech[
            north] = 'dir_y'  # roller (with non-zero displacement in the vertical direction)

        # Constructing the bc object for the mechanics problem
        bc_mech = pp.BoundaryConditionVectorial(g, b_faces, labels_mech)

        # Constructing the boundary values array for the mechanics problem
        bc_val_mech = np.zeros((
            len(times),
            g.num_faces * g.dim,
        ))

        for i in range(len(times)):

            # West side boundary conditions (mech)
            bc_val_mech[i][2 * x_min] = 0  # [m]
            bc_val_mech[i][2 * x_min + 1] = 0  # [Pa]

            # East side boundary conditions (mech)
            bc_val_mech[i][2 * x_max] = 0  # [Pa]
            bc_val_mech[i][2 * x_max + 1] = 0  # [Pa]

            # South Side boundary conditions (mech)
            bc_val_mech[i][2 * y_min] = 0  # [Pa]
            bc_val_mech[i][2 * y_min + 1] = 0  # [m]

            # North Side boundary conditions (mech)
            bc_val_mech[i][2 * y_max] = 0  # [Pa]
            bc_val_mech[i][2 * y_max + 1] = u_top[i]  # [m]

        return bc_mech, bc_val_mech

    # Getting flow boundary conditions

    def get_bc_flow(g, b_faces, x_min, x_max, west, east, y_min, y_max, south,
                    north):

        # Setting the tags at each boundary side for the mechanics problem
        labels_flow = np.array([None] * b_faces.size)
        labels_flow[west] = 'neu'  # no flow
        labels_flow[east] = 'dir'  # constant pressure
        labels_flow[south] = 'neu'  # no flow
        labels_flow[north] = 'neu'  # no flow

        # Constructing the bc object for the flow problem
        bc_flow = pp.BoundaryCondition(g, b_faces, labels_flow)

        # Constructing the boundary values array for the flow problem
        bc_val_flow = np.zeros(g.num_faces)

        # West side boundary condition (flow)
        bc_val_flow[x_min] = 0  # [Pa]

        # East side boundary condition (flow)
        bc_val_flow[x_max] = 0  # [m^3/s]

        # South side boundary condition (flow)
        bc_val_flow[y_min] = 0  # [m^3/s]

        # North side boundary condition (flow)
        bc_val_flow[y_max] = 0  # [m^3/s]

        return bc_flow, bc_val_flow

    # ## Setting up the grid

    # In[7]:

    Nx = 40
    Ny = 40
    Lx = 100
    Ly = 10
    g = pp.CartGrid([Nx, Ny], [Lx, Ly])
    #g.nodes = g.nodes + 1E-7*np.random.randn(3, g.num_nodes)
    g.compute_geometry()
    V = g.cell_volumes

    # Physical parameters

    # Skeleton parameters
    mu_s = 2.475E+09  # [Pa] Shear modulus
    lambda_s = 1.65E+09  # [Pa] Lame parameter
    K_s = (2 / 3) * mu_s + lambda_s  # [Pa] Bulk modulus
    E_s = mu_s * ((9 * K_s) / (3 * K_s + mu_s))  # [Pa] Young's modulus
    nu_s = (3 * K_s - 2 * mu_s) / (2 * (3 * K_s + mu_s)
                                   )  # [-] Poisson's coefficient
    k_s = 100 * 9.869233E-13  # [m^2] Permeabiliy

    # Fluid parameters
    mu_f = 10.0E-3  # [Pa s] Dynamic viscosity

    # Porous medium parameters
    alpha_biot = 1.  # [m^2] Intrinsic permeability
    S_m = 6.0606E-11  # [1/Pa] Specific Storage
    K_u = K_s + (alpha_biot**2) / S_m  # [Pa] Undrained bulk modulus
    B = alpha_biot / (S_m * K_u)  # [-] Skempton's coefficient
    nu_u = (3 * nu_s + B *
            (1 - 2 * nu_s)) / (3 - B *
                               (1 - 2 * nu_s))  # [-] Undrained Poisson's ratio
    c_f = (2 * k_s * (B**2) * mu_s * (1 - nu_s) *
           (1 + nu_u)**2) / (9 * mu_f * (1 - nu_u) *
                             (nu_u - nu_s))  # [m^2/s] Fluid diffusivity

    # Creating second and fourth order tensors

    # Permeability tensor
    perm = pp.SecondOrderTensor(g.dim, k_s * np.ones(g.num_cells))
    # Stiffness matrix
    constit = pp.FourthOrderTensor(g.dim, mu_s * np.ones(g.num_cells),
                                   lambda_s * np.ones(g.num_cells))
    # Time parameters

    t0 = 0  # [s] Initial time
    tf = 100  # [s] Final simulation time
    tLevels = 100  # [-] Time levels
    times = np.linspace(t0, tf, tLevels + 1)  # [s] Vector of time evaluations
    dt = np.diff(times)  # [s] Vector of time steps

    # Boundary conditions pre-processing

    b_faces = g.tags['domain_boundary_faces'].nonzero()[0]

    # Extracting indices of boundary faces w.r.t g
    x_min = b_faces[g.face_centers[0, b_faces] < 0.0001]
    x_max = b_faces[g.face_centers[0, b_faces] > 0.9999 * Lx]
    y_min = b_faces[g.face_centers[1, b_faces] < 0.0001]
    y_max = b_faces[g.face_centers[1, b_faces] > 0.9999 * Ly]

    # Extracting indices of boundary faces w.r.t b_faces
    west = np.in1d(b_faces, x_min).nonzero()
    east = np.in1d(b_faces, x_max).nonzero()
    south = np.in1d(b_faces, y_min).nonzero()
    north = np.in1d(b_faces, y_max).nonzero()

    # Applied load and top boundary condition
    F_load = 6.8E+8  # [N/m] Applied load
    u_top = get_mandel_bc(g, y_max, times, F_load, B, nu_u, nu_s, c_f,
                          mu_s)  # [m] Vector of imposed vertical displacements

    # MECHANICS BOUNDARY CONDITIONS
    bc_mech, bc_val_mech = get_bc_mechanics(g, u_top, times, b_faces, x_min,
                                            x_max, west, east, y_min, y_max,
                                            south, north)
    # FLOW BOUNDARY CONDITIONS
    bc_flow, bc_val_flow = get_bc_flow(g, b_faces, x_min, x_max, west, east,
                                       y_min, y_max, south, north)

    # Initialiazing solution and solver dicitionaries

    # Solution dictionary
    sol = dict()
    sol['time'] = np.zeros(tLevels + 1, dtype=float)
    sol['displacement'] = np.zeros((tLevels + 1, g.num_cells * g.dim),
                                   dtype=float)
    sol['displacement_faces'] = np.zeros(
        (tLevels + 1, g.num_faces * g.dim * 2), dtype=float)
    sol['pressure'] = np.zeros((tLevels + 1, g.num_cells), dtype=float)
    sol['traction'] = np.zeros((tLevels + 1, g.num_faces * g.dim), dtype=float)
    sol['flux'] = np.zeros((tLevels + 1, g.num_faces), dtype=float)
    sol['iter'] = np.array([], dtype=int)
    sol['time_step'] = np.array([], dtype=float)
    sol['residual'] = np.array([], dtype=float)

    # Solver dictionary
    newton_param = dict()
    newton_param['tol'] = 1E-6  # maximum tolerance
    newton_param['max_iter'] = 20  # maximum number of iterations
    newton_param['res_norm'] = 1000  # initializing residual
    newton_param['iter'] = 1  # iteration

    # Discrete operators and discrete equations

    # Flow operators

    F = lambda x: biot_F * x  # Flux operator
    boundF = lambda x: biot_boundF * x  # Bound Flux operator
    compat = lambda x: biot_compat * x  # Compatibility operator (Stabilization term)
    divF = lambda x: biot_divF * x  # Scalar divergence operator

    # Mechanics operators

    S = lambda x: biot_S * x  # Stress operator
    boundS = lambda x: biot_boundS * x  # Bound Stress operator
    divU = lambda x: biot_divU * x  # Divergence of displacement field
    divS = lambda x: biot_divS * x  # Vector divergence operator
    gradP = lambda x: biot_divS * biot_gradP * x  # Pressure gradient operator
    boundDivU = lambda x: biot_boundDivU * x  # Bound Divergence of displacement operator
    boundUCell = lambda x: biot_boundUCell * x  # Contribution of displacement at cells -> Face displacement
    boundUFace = lambda x: biot_boundUFace * x  # Contribution of bc_mech at the boundaries -> Face displacement
    boundUPressure = lambda x: biot_boundUPressure * x  # Contribution of pressure at cells -> Face displacement

    # Discrete equations

    # Generalized Hooke's law
    T = lambda u, bc_val_mech: S(u) + boundS(bc_val_mech)

    # Momentum conservation equation (I)
    u_eq1 = lambda u, bc_val_mech: divS(T(u, bc_val_mech))

    # Momentum conservation equation (II)
    u_eq2 = lambda p: -gradP(p)

    # Darcy's law
    Q = lambda p: (1. / mu_f) * (F(p) + boundF(bc_val_flow))

    # Mass conservation equation (I)
    p_eq1 = lambda u, u_n, bc_val_mech, bc_val_mech_n: alpha_biot * (divU(
        u - u_n) + boundDivU(bc_val_mech - bc_val_mech_n))

    # Mass conservation equation (II)
    p_eq2 = lambda p, p_n, dt: (p - p_n) * S_m * V + divF(Q(
        p)) * dt + alpha_biot * compat(p - p_n)

    # Creating AD variables

    # Retrieve initial conditions
    p_init, u_init = get_mandel_init_cond(g, F_load, B, nu_u, mu_s)

    # Create displacement AD-variable
    u_ad = Ad_array(u_init.copy(), sps.diags(np.ones(g.num_cells * g.dim)))

    # Create pressure AD-variable
    p_ad = Ad_array(p_init.copy(), sps.diags(np.ones(g.num_cells)))

    # The time loop

    tt = 0  # time counter

    while times[tt] < times[-1]:

        ################################
        # Initializing data dictionary #
        ################################

        d = dict()  # initialize dictionary to store data

        ################################
        #  Creating the data objects   #
        ################################

        # Mechanics data object
        specified_parameters_mech = {
            "fourth_order_tensor": constit,
            "bc": bc_mech,
            "biot_alpha": 1.,
            "bc_values": bc_val_mech[tt],
            "mass_weight": S_m
        }

        pp.initialize_default_data(g, d, "mechanics",
                                   specified_parameters_mech)

        # Flow data object
        specified_parameters_flow = {
            "second_order_tensor": perm,
            "bc": bc_flow,
            "biot_alpha": 1.,
            "bc_values": bc_val_flow,
            "mass_weight": S_m,
            "time_step": dt[tt - 1]
        }

        pp.initialize_default_data(g, d, "flow", specified_parameters_flow)

        ################################
        #  CALLING MPFA/MPSA ROUTINES  #
        ################################

        # Biot discretization
        solver_biot = pp.Biot("mechanics", "flow")
        solver_biot.discretize(g, d)

        # Mechanics discretization matrices
        biot_S = d['discretization_matrices']['mechanics']['stress']
        biot_boundS = d['discretization_matrices']['mechanics']['bound_stress']
        biot_divU = d['discretization_matrices']['mechanics']['div_d']
        biot_gradP = d['discretization_matrices']['mechanics']['grad_p']
        biot_boundDivU = d['discretization_matrices']['mechanics'][
            'bound_div_d']
        biot_boundUCell = d['discretization_matrices']['mechanics'][
            'bound_displacement_cell']
        biot_boundUFace = d['discretization_matrices']['mechanics'][
            'bound_displacement_face']
        biot_boundUPressure = d['discretization_matrices']['mechanics'][
            'bound_displacement_pressure']
        biot_divS = pp.fvutils.vector_divergence(g)

        # Flow discretization matrices
        biot_F = d['discretization_matrices']['flow']['flux']
        biot_boundF = d['discretization_matrices']['flow']['bound_flux']
        biot_compat = d['discretization_matrices']['flow'][
            'biot_stabilization']
        biot_divF = pp.fvutils.scalar_divergence(g)

        ################################
        #  Saving Initial Condition    #
        ################################

        if times[tt] == 0:
            sol['pressure'][tt] = p_ad.val
            sol['displacement'][tt] = u_ad.val
            sol['displacement_faces'][tt] = (
                boundUCell(sol['displacement'][tt]) +
                boundUFace(bc_val_mech[tt]) +
                boundUPressure(sol['pressure'][tt]))
            sol['time'][tt] = times[tt]
            sol['traction'][tt] = T(u_ad.val, bc_val_mech[tt])
            sol['flux'][tt] = Q(p_ad.val)

        tt += 1  # increasing time counter

        ################################
        #  Solving the set of PDE's    #
        ################################

        # Displacement and pressure at the previous time step
        u_n = u_ad.val.copy()
        p_n = p_ad.val.copy()

        # Updating residual and iteration at each time step
        newton_param.update({'res_norm': 1000, 'iter': 1})

        # Newton loop
        while newton_param['res_norm'] > newton_param['tol'] and newton_param[
                'iter'] <= newton_param['max_iter']:

            # Calling equations
            eq1 = u_eq1(u_ad, bc_val_mech[tt])
            eq2 = u_eq2(p_ad)
            eq3 = p_eq1(u_ad, u_n, bc_val_mech[tt], bc_val_mech[tt - 1])
            eq4 = p_eq2(p_ad, p_n, dt[tt - 1])

            # Assembling Jacobian of the coupled system
            J_mech = np.hstack(
                (eq1.jac, eq2.jac))  # Jacobian blocks (mechanics)
            J_flow = np.hstack((eq3.jac, eq4.jac))  # Jacobian blocks (flow)
            J = sps.bmat(np.vstack((J_mech, J_flow)),
                         format='csc')  # Jacobian (coupled)

            # Determining residual of the coupled system
            R_mech = eq1.val + eq2.val  # Residual (mechanics)
            R_flow = eq3.val + eq4.val  # Residual (flow)
            R = np.hstack((R_mech, R_flow))  # Residual (coupled)

            y = sps.linalg.spsolve(J, -R)  #
            u_ad.val = u_ad.val + y[:g.dim * g.num_cells]  # Newton update
            p_ad.val = p_ad.val + y[g.dim * g.num_cells:]  #

            newton_param['res_norm'] = np.linalg.norm(R)  # Updating residual

            if newton_param['res_norm'] <= newton_param[
                    'tol'] and newton_param['iter'] <= newton_param['max_iter']:
                print('Iter: {} \t Error: {:.8f} [m]'.format(
                    newton_param['iter'], newton_param['res_norm']))
            elif newton_param['iter'] > newton_param['max_iter']:
                print('Error: Newton method did not converge!')
            else:
                newton_param['iter'] += 1

        ################################
        #      Saving the variables    #
        ################################
        sol['iter'] = np.concatenate(
            (sol['iter'], np.array([newton_param['iter']])))
        sol['residual'] = np.concatenate(
            (sol['residual'], np.array([newton_param['res_norm']])))
        sol['time_step'] = np.concatenate((sol['time_step'], dt))
        sol['pressure'][tt] = p_ad.val
        sol['displacement'][tt] = u_ad.val
        sol['displacement_faces'][tt] = (boundUCell(sol['displacement'][tt]) +
                                         boundUFace(bc_val_mech[tt]) +
                                         boundUPressure(sol['pressure'][tt]))
        sol['time'][tt] = times[tt]
        sol['traction'][tt] = T(u_ad.val, bc_val_mech[tt])
        sol['flux'][tt] = Q(p_ad.val)

    # Calling analytical solution

    sol_mandel = mandel_solution(g, Nx, Ny, times, F_load, B, nu_u, nu_s, c_f,
                                 mu_s)

    # Creating analytical and numerical results arrays

    p_num = (Lx * sol['pressure'][-1][:Nx]) / F
    p_ana = (Lx * sol_mandel['p'][-1]) / F

    # Returning values

    return p_num, p_ana
Пример #30
0
 def test_div_advar_advar(self):
     # a = x ^ 3: b = x^2: x = 2
     a = Ad_array(8, 12)
     b = Ad_array(4, 4)
     c = a / b
     self.assertTrue(c.val == 2 and np.allclose(c.jac, 1))