Example #1
0
def compute_nonwetting_influx(network, conductance, pressure, q_n):
    g_n = np.zeros(network.nr_t)
    ti_nw = (network.tubes.invaded == 1).nonzero()[0]
    g_n[ti_nw] = conductance[ti_nw]
    A_n = laplacian_from_network(network, weights=g_n)
    flux_in_nw = -A_n * pressure + q_n
    return flux_in_nw
Example #2
0
def reorder_network(network):
    A = laplacian_from_network(network)
    A = scipy_to_petsc_matrix(A)
    a_is, b_is = A.getOrdering(PETSc.Mat.OrderingType.RCM)
    a = np.asarray(a_is.getIndices())
    b = np.asarray(b_is.getIndices())
    assert np.all(a == b)
    permuted_network = SubNetwork(network, a)
    return permuted_network
Example #3
0
    def _general_absolute_permeability(self, coord, pi_inlet, pi_outlet):
        network = self.network
        tube_k_w = self.cond_computer.conductances_fully_wetting()

        pi_dirichlet = np.union1d(pi_inlet, pi_outlet)
        A = laplacian_from_network(network,
                                   weights=tube_k_w,
                                   ind_dirichlet=pi_dirichlet)
        rhs = np.zeros(network.nr_p)
        rhs[pi_inlet] = 1.0

        pressure = petsc_solve(A * 1e20, rhs * 1e20, tol=1e-12)

        mu_w = self.fluid_properties["mu_w"]
        self.total_flux_one_phase = flux_into_pores(network, pressure,
                                                    tube_k_w, pi_inlet)

        coord_max = np.min(coord)
        coord_min = np.max(coord)

        return mu_w * np.abs(self.total_flux_one_phase) * (
            coord_max - coord_min)**2 / self.network_vol
Example #4
0
    def _general_effective_nonwetting_permeability(self, coord, pi_inlet,
                                                   pi_outlet):
        network = self.network
        tube_k_n, tube_k_w = self.cond_computer.conductances_two_phase()

        p_conn_inlet, t_conn_inlet = graph_algs.get_pore_and_tube_nonwetting_connectivity_to_pore_list(
            network, pi_inlet)
        is_nwett_pore_outlet_conn_to_inlet = np.any(
            p_conn_inlet[pi_outlet] == 1)

        if not is_nwett_pore_outlet_conn_to_inlet:
            kr_n_eff = 0.0
        else:
            pi_dirichlet = reduce(np.union1d,
                                  (pi_inlet, pi_outlet,
                                   (p_conn_inlet == 0).nonzero()[0]))
            A = laplacian_from_network(network,
                                       weights=tube_k_n,
                                       ind_dirichlet=pi_dirichlet)

            rhs = np.zeros(network.nr_p)
            rhs[pi_inlet] = 1.0

            pressure = petsc_solve(A * 1e20, rhs * 1e20, tol=1e-12)

            mu_n = self.fluid_properties["mu_n"]
            total_flux_nwett = flux_into_pores(network, pressure, tube_k_n,
                                               pi_inlet)

            coord_max = np.min(coord)
            coord_min = np.max(coord)

            kr_n_eff = mu_n * np.abs(total_flux_nwett) * (
                coord_max - coord_min)**2 / self.network_vol

        return kr_n_eff
Example #5
0
def run():

    # Create network
    try:
        network = PoreNetwork.load("benchmark_network.pkl")

    except IOError:
        network = unstructured_network_delaunay(20000, quasi_2d=True)
        #network = structured_network(40, 20, 2)
        network.save("benchmark_network.pkl")

    tubes = network.tubes
    pores = network.pores

    # load simulation settings
    mu_w = sim_settings['fluid_properties']["mu_w"]
    mu_n = sim_settings['fluid_properties']["mu_n"]
    gamma = sim_settings['fluid_properties']["gamma"]

    ds_out = 0.01
    s_target = 0.01
    n_out = 0

    # set boundary conditions
    pores.invaded[network.pi_list_face[WEST]] = 1
    pores.sat[:] = 0.0
    q_n = np.zeros(network.nr_p)
    q_n[network.
        pi_list_face[WEST]] = sim_settings['dynamic']['q_n_inlet'] / len(
            network.pi_list_face[WEST])
    q = q_n

    # Compute tube entry pressure and conductances
    entry_pressure = 2 * gamma / network.tubes.r
    tube_conductances = compute_conductance(tubes.r, tubes.l, mu_w)

    pressure = np.zeros(network.nr_p)
    sf = 1.e20  # scaling factor

    # TODO: unblock interface pore only if time-step is zero!

    try:
        pores.sat[network.pi_list_face[WEST]] = 0.01

        for niter in xrange(1000000):
            # Ensure pores at the inlet are invaded and outlet is always empty
            pores.invaded[network.pi_list_face[WEST]] = 1
            tubes.invaded[tubes_within_pore_set(
                network, network.pi_list_face[WEST])] = 1

            pores.sat[network.pi_list_face[EAST]] = 0.0

            # Update tube conductance
            ti_drained = (tubes.invaded == 1).nonzero()[0]
            ti_imbibed = (tubes.invaded == 0).nonzero()[0]
            tube_conductances[:] = 0.0
            # tubes.invaded[tubes.invaded==2] = 0
            tube_conductances[ti_drained] = compute_conductance(
                tubes.r[ti_drained], tubes.l[ti_drained], mu_n)
            tube_conductances[ti_imbibed] = compute_conductance(
                tubes.r[ti_imbibed], tubes.l[ti_imbibed], mu_w)

            for _ in xrange(3):
                event = False

                # Unblock Tubes
                while True:
                    # Solve Pressure
                    A = laplacian_from_network(
                        network,
                        tube_conductances,
                        ind_dirichlet=network.pi_list_face[EAST])
                    pressure = petsc_solve(A * sf,
                                           q * sf,
                                           x0=pressure,
                                           tol=1e-10)
                    pores.p_n[:] = pressure
                    assert not np.any(np.isnan(pressure))

                    # Compute unblocked tubes
                    ti_list_unblocked = get_unblocked_tubes(network)
                    print "num of unblocked tubes:", len(ti_list_unblocked)

                    if len(ti_list_unblocked) == 0:
                        break

                    event = True
                    network.tubes.invaded[ti_list_unblocked] = 0

                # Block tubes
                while True:
                    # Solve pressure
                    A = laplacian_from_network(
                        network,
                        tube_conductances,
                        ind_dirichlet=network.pi_list_face[EAST])

                    pi_list_blocked = (A.diagonal() == 0).nonzero()[0]
                    for pi_blocked in pi_list_blocked:
                        fixed_blocked_pore(network, tube_conductances, mu_n,
                                           pi_blocked)
                        A = laplacian_from_network(
                            network,
                            tube_conductances,
                            ind_dirichlet=network.pi_list_face[EAST])

                    pressure = petsc_solve(A * sf,
                                           q * sf,
                                           x0=pressure,
                                           tol=1e-10)
                    pores.p_n[:] = pressure
                    assert not np.any(np.isnan(pressure))

                    # Compute blocked throats
                    ti_list_blocked = get_blocked_tubes(
                        network, pressure, entry_pressure)
                    print "num of blocked tubes", len(ti_list_blocked)

                    for ti_blocked in ti_list_blocked:
                        tube_conductances[ti_blocked] = 0.0
                        tubes.invaded[ti_blocked] = 2
                        assert np.sum(network.pores.invaded[
                            network.edgelist[ti_blocked]]) > 0

                    if len(ti_list_blocked) == 0:
                        break

                    event = True

                # Drain tubes
                while True:
                    # Solve pressure
                    A = laplacian_from_network(
                        network,
                        weights=tube_conductances,
                        ind_dirichlet=network.pi_list_face[EAST])
                    pressure = petsc_solve(A * sf,
                                           q * sf,
                                           x0=pressure,
                                           tol=1e-10)
                    network.pores.p_n[:] = pressure
                    assert not np.any(np.isnan(pressure))

                    # Compute drained throats
                    ti_list_drained = get_drained_tubes(
                        network, pressure, entry_pressure)
                    # print "length of drain list", len(ti_list_drained)

                    if len(ti_list_drained) == 0:
                        break

                    for ti_drained in ti_list_drained[0:2 *
                                                      len(ti_list_drained) /
                                                      3 + 1]:
                        drain_tube(network, ti_drained, tube_conductances,
                                   mu_n)
                    event = True

                # Imbibe Tubes
                while True:
                    # Solve pressure
                    A = laplacian_from_network(
                        network,
                        weights=tube_conductances,
                        ind_dirichlet=network.pi_list_face[EAST])

                    pressure = petsc_solve(A * sf,
                                           q * sf,
                                           x0=pressure,
                                           tol=1e-10)
                    network.pores.p_n[:] = pressure

                    assert not np.any(np.isnan(pressure))

                    # Compute imbibed throats
                    ti_list_imbibed = get_imbibed_tubes(network, pressure)
                    # print "len imbibed list", len(ti_list_imbibed)

                    if len(ti_list_imbibed) == 0:
                        break

                    ti_imbibed = ti_list_imbibed[0]

                    network.tubes.invaded[ti_imbibed] = 0
                    pi_ngh_1, pi_ngh_2 = network.edgelist[ti_imbibed]

                    print "imbibing tube:", ti_imbibed
                    if (pores.sat[pi_ngh_1] < 0.001) and np.all(
                            tubes.invaded[network.ngh_tubes[pi_ngh_1]] == 0):
                        network.pores.invaded[pi_ngh_1] = 0
                        print "imbibed pore:", pi_ngh_1

                    if (pores.sat[pi_ngh_2] < 0.001) and np.all(
                            tubes.invaded[network.ngh_tubes[pi_ngh_2]] == 0):
                        network.pores.invaded[pi_ngh_2] = 0
                        print "imbibed pore:", pi_ngh_2

                    tube_conductances[ti_imbibed] = compute_conductance(
                        tubes.r[ti_imbibed], tubes.l[ti_imbibed], mu_w)
                    event = True

                if not event:
                    break

            A = laplacian_from_network(
                network,
                weights=tube_conductances,
                ind_dirichlet=network.pi_list_face[EAST])
            pressure = petsc_solve(A * sf, q * sf, x0=pressure, tol=1e-12)
            network.pores.p_n[:] = pressure

            #  Update saturation
            flux_n = compute_nonwetting_influx(network, tube_conductances,
                                               pressure, q_n)
            dt_drain, dt_imb = compute_timestep(network, flux_n)
            dt = min(dt_drain, dt_imb)

            if dt_drain == 0:
                print "simulation stuck"
                ti_blocked_all = (tubes.invaded == 2).nonzero()[0]
                if len(ti_blocked_all) > 0:
                    print "unblocking largest tube"
                    ti_largest = ti_blocked_all[np.argmax(
                        tubes.r[ti_blocked_all])]
                    assert tubes.invaded[ti_largest] == 2
                    drain_tube(network, ti_largest, tube_conductances, mu_n)
                    assert np.all(tube_conductances[tubes.invaded == 1] > 0.0)

            network.pores.sat = update_sat(network, flux_n, dt)

            sat_network = np.sum(network.pores.sat *
                                 network.pores.vol) / np.sum(network.pores.vol)

            if sat_network > s_target:
                network.pores.p_n[:] = pressure
                print "Number of throats invaded:", niter
                network.save("network_history/network" + str(n_out).zfill(5) +
                             ".pkl")
                s_target += ds_out
                n_out += 1
                network.export_to_vtk("test" + str(n_out).zfill(3))

            if niter % 1 == 0:
                print "saturation is:", sat_network

    except KeyboardInterrupt:
        pass
Example #6
0
    def __update_saturation_implicit(self, dt):
        eps_sat = 1.e-4
        logger.debug("Solving fully implicit")
        network = self.network
        print "solving fully implicit"

        def residual_saturation(p_w, p_c, sat, dt):
            p_n = p_w + p_c
            residual = (sat - network.pores.sat) + (A_n * p_n - self.q_n) * dt / network.pores.vol
            return residual

        def residual_pressure(p_w, p_c):
            rhs = -A_n * p_c + self.q_n + self.q_w
            rhs[pi_dirichlet] = 0.0
            ref_residual = norm(A * (rhs / A.diagonal()) - rhs, ord=np.inf)
            residual_normalized = (A*p_w - rhs)/ref_residual
            return residual_normalized

        pi_dirichlet = ((self.q_n + self.q_w) == 0.0).nonzero()[0][0]

        # Assume that the conductances do not change and are fixed
        A = laplacian_from_network(network, weights=network.tubes.k_n + network.tubes.k_w, ind_dirichlet=pi_dirichlet)
        A_n = laplacian_from_network(network, weights=network.tubes.k_n)

        p_w = np.copy(network.pores.p_w)
        sat = np.copy(network.pores.sat)

        ksp = get_petsc_ksp(A=A * 1e20, ksptype="minres", max_it=10000, tol=1e-9)

        logger.debug("Starting iteration")

        p_c = DynamicCapillaryPressureComputer.sat_to_pc_func(network.pores.sat, network.pores.r)

        while True:
            for iter in xrange(200):
                # Solve for pressure

                rhs = -A_n * p_c + self.q_n + self.q_w
                rhs[pi_dirichlet] = 0.0

                p_w[:] = petsc_solve_from_ksp(ksp, rhs*1e20, x=p_w, tol=1e-9)

                p_n = p_w + p_c
                # Solve for saturation
                if iter == 0:
                    damping = 1.
                if iter > 0:
                    damping = 0.4
                if iter > 10:
                    damping = 0.1
                if iter > 20:
                    damping = 0.055
                sat = (1-damping)*sat + damping * (network.pores.sat + (self.q_n - A_n * p_n) * dt / network.pores.vol)
                if np.min(sat) < 0.0:
                    print "saturation undershoot decreasing time-step slightly"
                    dt *= 0.5

                if np.max(sat) > 1.0:
                    print "saturation overshoot"

                sat = np.maximum(sat, 0.0)
                sat = np.minimum(sat, 0.99999999999)

                p_c = DynamicCapillaryPressureComputer.sat_to_pc_func(sat, network.pores.r)
                res_pw = residual_pressure(p_w, p_c)
                res_sat = residual_saturation(p_w, p_c, sat, dt)

                linf_res_pw = norm(res_pw, ord=np.inf)
                linf_res_sat = norm(res_sat, ord=np.inf)

                if iter % 10 == 0:
                    print "iteration %d \t sat res: %g \t press res %g"%(iter, linf_res_sat, linf_res_pw)

                if iter > 3 and linf_res_sat > 1000:
                    break

                if iter > 10 and linf_res_sat > 1.0:
                    break

                if linf_res_sat < eps_sat and linf_res_pw < 1e-5:
                    break

            if linf_res_sat < eps_sat and linf_res_pw < 1e-5:
                print "Iteration converged"
                print "iteration %d \t sat res: %g \t press res %g" % (iter, linf_res_sat, linf_res_pw)
                network.pores.sat[:] = sat
                network.pores.p_w[:] = p_w
                network.pores.p_n[:] = p_n
                network.pores.p_c[:] = p_c
                assert np.all(sat <= 1.0)
                print "Leaving implicit loop"
                break
            else:
                p_w = np.copy(network.pores.p_w)
                sat = np.copy(network.pores.sat)
                p_c = DynamicCapillaryPressureComputer.sat_to_pc_func(sat, network.pores.r)
                dt *= 0.5
                print "decreasing timestep to", dt

        print "timestep is", dt
        return dt