Exemple #1
0
def main(kf, description, is_coarse=False, if_export=False):
    mesh_size = 0.045
    gb, domain = make_grid_bucket(mesh_size)
    # Assign parameters
    add_data(gb, domain, kf)

    # Choose and define the solvers and coupler
    solver_flow = pp.DualVEMMixedDim("flow")
    A_flow, b_flow = solver_flow.matrix_rhs(gb)

    solver_source = pp.DualSourceMixedDim("flow", coupling=[None])

    A_source, b_source = solver_source.matrix_rhs(gb)

    up = sps.linalg.spsolve(A_flow + A_source, b_flow + b_source)
    solver_flow.split(gb, "up", up)

    gb.add_node_props(["discharge", "pressure", "P0u"])
    solver_flow.extract_u(gb, "up", "discharge")
    solver_flow.extract_p(gb, "up", "pressure")
    solver_flow.project_u(gb, "discharge", "P0u")

    if if_export:
        save = pp.Exporter(gb, "vem", folder="vem_" + description)
        save.write_vtk(["pressure", "P0u"])
def main():

    mesh_size = np.power(2., -7)
    gb = create_gb(mesh_size)

    param = get_param()

    scheme = Scheme(gb)
    scheme.set_data(param)

    # exporter
    folder = "./case2/"
    save = pp.Exporter(gb, "case2", folder_name=folder+"solution_ml")
    vars_to_save = scheme.vars_to_save()

    # post process
    save.write_vtk(vars_to_save, time_step=0)

    for i in np.arange(param["time"]["num_steps"]):
        time = (i+1)*param["time"]["step"]

        print("processing", i, "step at time", time)

        # do one step of the splitting scheme
        scheme.one_step_splitting_scheme(time)

        # post process
        save.write_vtk(vars_to_save, time_step=time)

    time = np.arange(param["time"]["num_steps"]+1)*param["time"]["step"]
    save.write_pvd(time)
Exemple #3
0
def export(gb, folder):

    gb.add_node_props(["cell_volumes", "cell_centers"])
    for g, d in gb:
        d["cell_volumes"] = g.cell_volumes
        d["cell_centers"] = g.cell_centers

    save = pp.Exporter(gb, "sol", folder=folder)

    props = ["pressure", "cell_volumes", "cell_centers"]

    # extra properties, problem specific
    if all(gb.has_nodes_prop(gb.get_grids(), "low_zones")):
        gb.add_node_props("bottom_domain")
        for g, d in gb:
            d["bottom_domain"] = 1 - d["low_zones"]
        props.append("bottom_domain")

    if all(gb.has_nodes_prop(gb.get_grids(), "color")):
        props.append("color")

    if all(gb.has_nodes_prop(gb.get_grids(), "aperture")):
        props.append("aperture")

    save.write_vtk(props)
    def _export_vtu(self) -> None:
        self.exporter = pp.Exporter(
            self.gb,
            self.params["file_name"],
            folder_name=self.params["folder_name"] + "_vtu",
        )
        for g, d in self.gb:
            if g.dim == self.Nd:
                pad_zeros = np.zeros((3 - g.dim, g.num_cells))
                u = d[pp.STATE][self.displacement_variable].reshape(
                    (self.Nd, -1), order="F")
                u_exp = np.vstack((u, pad_zeros))
                d[pp.STATE]["u_exp"] = u_exp
                d[pp.STATE]["u_global"] = u_exp
                d[pp.STATE]["traction_exp"] = np.zeros(
                    d[pp.STATE]["u_exp"].shape)
            elif g.dim == (self.Nd - 1):
                pad_zeros = np.zeros((2 - g.dim, g.num_cells))
                g_h = self.gb.node_neighbors(g)[0]
                data_edge = self.gb.edge_props((g, g_h))

                u_mortar_local = self.reconstruct_local_displacement_jump(
                    data_edge,
                    d["tangential_normal_projection"],
                    from_iterate=False)
                u_exp = np.vstack((u_mortar_local, pad_zeros))
                d[pp.STATE]["u_exp"] = u_exp

                traction = d[pp.STATE][self.contact_traction_variable].reshape(
                    (self.Nd, -1), order="F")
                d[pp.STATE]["traction_exp"] = np.vstack((traction, pad_zeros))
        export_fields = ["u_exp", "traction_exp"]
        self.exporter.write_vtu(export_fields)
    def __init__(self, gb, folder, tol):

        self.model = "flow"
        self.gb = gb
        self.data = None
        self.assembler = None

        # discretization operator name
        self.discr_name = "flux"
        self.discr = pp.RT0(self.model)

        self.mass_name = "mass"
        self.mass = pp.MixedMassMatrix(self.model)

        self.coupling_name = self.discr_name + "_coupling"
        self.coupling = pp.RobinCoupling(self.model, self.discr)

        self.source_name = "source"
        self.source = pp.DualScalarSource(self.model)

        # master variable name
        self.variable = "flow_variable"
        self.mortar = "lambda_" + self.variable

        # post process variables
        self.pressure = "pressure"
        self.flux = "darcy_flux"  # it has to be this one
        self.P0_flux = "P0_darcy_flux"

        # tolerance
        self.tol = tol

        # exporter
        self.save = pp.Exporter(self.gb, "solution", folder=folder)
Exemple #6
0
    def test_import_single_gb(self):
        folder = "../../geometry/mesh_test_porepy/meshconuna/"
        gb = import_gb(folder, 2, num_frac=1)
        for g, d in gb:
            d[pp.STATE] = {}

        pp.Exporter(gb, "grid").write_vtk()
Exemple #7
0
def main(kf, description, multi_point, if_export=False):
    mesh_size = 0.045
    gb, domain = make_grid_bucket(mesh_size)
    # Assign parameters
    add_data(gb, domain, kf, mesh_size)

    # Choose discretization and define the solver
    if multi_point:
        solver = pp.MpfaMixedDim("flow")
    else:
        solver = pp.TpfaMixedDim("flow")

    # Discretize
    A, b = solver.matrix_rhs(gb)

    # Solve the linear system
    p = sps.linalg.spsolve(A, b)

    # Store the solution
    gb.add_node_props(["pressure"])
    solver.split(gb, "pressure", p)

    if if_export:
        save = pp.Exporter(gb, "fv", folder="fv_" + description)
        save.write_vtk(["pressure"])
def main():
    gb = import_gb("cut", 2)

    param = get_param()

    scheme = Scheme(gb)
    scheme.set_data(param)

    # exporter
    save = pp.Exporter(gb, "case5", folder_name="solution")
    vars_to_save = scheme.vars_to_save()

    # post process
    scheme.extract()
    save.write_vtk(vars_to_save, time_step=0)

    for i in np.arange(param["time"]["num_steps"]):

        print("processing", i, "step at time", i * param["time"]["step"])

        # do one step of the splitting scheme
        scheme.one_step_splitting_scheme()

        # post process
        time = param["time"]["step"] * (i + 1)
        save.write_vtk(vars_to_save, time_step=time)

    time = np.arange(param["time"]["num_steps"] + 1) * param["time"]["step"]
    save.write_pvd(time)
Exemple #9
0
    def test_import_single_grid(self):
        folder = "../../geometry/mesh_test_porepy/mesh_senzafrattura/"
        fname = "_bulk"
        g = import_grid(folder, fname, 2)
        pp.Exporter(g, "grid").write_vtk()

        pp.plot_grid(g, info="c", alpha=0)
        print(g)
def export_mortar_grid(g,
                       mg,
                       data_edge,
                       uc,
                       Tc,
                       key,
                       key_m,
                       *vargs,
                       time_step=None,
                       **kwargs):
    """
    Export the displacement jumps and mortar variable on the mortar grid.
    """
    # Get subcell topology and mappings to sub mortar grid
    s_t = pp.fvutils.SubcellTopology(g)
    sgn_bnd_hf, slv_2_mrt_nd, mstr_2_mrt_nd = utils.get_mappings(g, mg, s_t)

    # Get mortar mappings for faces also
    mg_f2c = data_edge['mortar_grid_f2c']
    slavef2mortarc_nd = sps.kron(mg_f2c.slave_to_mortar_int(), sps.eye(g.dim))
    hf2f = pp.fvutils.map_hf_2_f(g=g)

    # First get face valued vectors (from subface values)
    Tcc, ucc = utils.subface_to_face_mortar(g, mg, data_edge, Tc, uc)
    t_id = [0, 1]
    n_id = [2]
    M_inv, _ = utils.normal_tangential_rotations(g, mg)
    M = utils.inverse_3dmatrix(M_inv)
    tc1 = M[:, 0, :]
    tc2 = M[:, 1, :]
    nc = M[:, 2, :]

    # Then get the tangential and normal components
    T_hat = np.sum(M_inv * Tc, axis=1)

    Tc_tau = T_hat[t_id[0]] * tc1 + T_hat[t_id[1]] * tc2
    Tc_n = T_hat[n_id] * nc
    Tcc_tau = slavef2mortarc_nd * hf2f * slv_2_mrt_nd.T * Tc_tau.ravel('F')
    Tcc_tau = Tcc_tau.reshape((g.dim, -1), order='F')
    Tcc_n = slavef2mortarc_nd * hf2f * slv_2_mrt_nd.T * Tc_n.ravel('F')
    Tcc_n = Tcc_n.reshape((g.dim, -1), order='F')

    # Sanity check
    assert np.allclose(Tcc_tau + Tcc_n, Tcc)

    # Export face values
    mg_plot = mg_f2c.side_grids['mortar_grid']

    exporter = pp.Exporter(mg_plot, *vargs, **kwargs)
    exporter.write_vtk(
        {
            'Ttau': Tcc_tau / mg_f2c.cell_volumes,
            'Tn': Tcc_n / mg_f2c.cell_volumes,
            '[u]': ucc
        },
        time_step=time_step)
Exemple #11
0
def export(gb, x, name, solver_flow):

    solver_flow.split(gb, "up", x)

    gb.add_node_props("pressure")
    solver_flow.extract_p(gb, "up", "pressure")
    solver_flow.extract_u(gb, "up", "discharge")
    solver_flow.project_u(gb, "discharge", "P0u")

    save = pp.Exporter(gb, "rt0", folder=name)
    save.write_vtk(["pressure", "P0u"])
Exemple #12
0
    def init_viz(self, overwrite=False):
        """ Initialize visualization.
        Will only create a new object if none exists.
        Alternatively, the existing exporter can be overwritten using 'overwrite'.

        """
        if (self.viz is None) or overwrite:
            # g3 = self.gb.grids_of_dimension(self.gb.dim_max())[0]
            self.viz = pp.Exporter(self.gb,
                                   name="test_biot",
                                   folder=self.viz_folder_name)
def export_nodal_values(g, mg, data_node, u, p, Tc, key, key_m, *vargs,
                        **kwargs):
    """
    Extrapolate the cell centered displacements to the nodes and export to vtk.
    """
    u_n = utils.construct_nodal_values(g, mg, data_node, u, p, Tc, key, key_m)
    # Export
    if g.dim == 2:
        u_n_exp = np.vstack((u_n, np.zeros(u_n.shape[1])))
    else:
        u_n_exp = u_n
    exporter = pp.Exporter(g, *vargs, **kwargs)
    exporter.write_vtk({"u": u_n_exp}, point_data=True)
Exemple #14
0
    def __init__(
        self,
        gb,
        physics="transport",
        time_step=1.0,
        end_time=1.0,
        callback=None,
        **kwargs
    ):
        self._gb = gb
        self.is_GridBucket = isinstance(self._gb, pp.GridBucket)
        self.physics = physics
        self._data = kwargs.get("data", dict())
        self._time_step = time_step
        self._end_time = end_time

        self.callback = callback

        # A hack to make parabolic work with different number of mortars
        # I.e., if we have only advective or only diffusive, we have 1
        # set of mortars, while if we have both advective and diffusive we have
        # two sets
        self.advective_term = True
        self.diffusive_term = True
        discs = self.space_disc()
        if not isinstance(discs, tuple):
            discs = [discs]

        self.advective_term = False
        self.diffusive_term = False
        for d in discs:
            if isinstance(d, pp.Upwind) or isinstance(d, pp.UpwindMixedDim):
                self.advective_term = True
            if isinstance(d, pp.Tpfa) or isinstance(d, pp.TpfaMixedDim):
                self.diffusive_term = True

        self._set_data()

        self._solver = self.solver()

        logger.info("Create exporter")
        tic = time.time()
        file_name = kwargs.get("file_name", "solution")
        folder_name = kwargs.get("folder_name", "results")
        self.exporter = pp.Exporter(self._gb, file_name, folder_name)
        logger.info("Done. Elapsed time: " + str(time.time() - tic))

        self.x_name = "solution"
        self._time_disc = self.time_disc()
Exemple #15
0
    def set_viz(self):
        """ Set exporter for visualization """
        self.viz = pp.Exporter(self.gb, file_name=self.file_name, folder_name=self.viz_folder_name)
        # list of time steps to export with visualization.

        self.u_exp = 'u_exp'
        self.traction_exp = 'traction_exp'
        self.normal_frac_u = 'normal_frac_u'
        self.tangential_frac_u = 'tangential_frac_u'

        self.export_fields = [
            self.u_exp,
            self.traction_exp,
            self.normal_frac_u,
            self.tangential_frac_u,
        ]
Exemple #16
0
def export(gb, folder):

    props = ["cell_volumes", "cell_centers"]
    gb.add_node_props(props)
    for g, d in gb:
        d["cell_volumes"] = g.cell_volumes
        d["cell_centers"] = g.cell_centers

    # extra properties
    if all(gb.has_nodes_prop(gb.get_grids(), "pressure")):
        props.append("pressure")

    if all(gb.has_nodes_prop(gb.get_grids(), "P0u")):
        props.append("P0u")

    save = pp.Exporter(gb, "sol", folder=folder)
    save.write_vtk(props)
    def prepare_simulation(self) -> None:
        """Is run prior to a time-stepping scheme. Use this to initialize
        discretizations, export for visualization, linear solvers etc.

        """
        self.create_grid()
        self._Nd = self.gb.dim_max()
        self._set_parameters()
        self._assign_variables()
        self._assign_discretizations()
        self._initial_condition()
        self._discretize()
        self._initialize_linear_solver()

        g_max = self._nd_grid()
        self.viz = pp.Exporter(g_max,
                               file_name="mechanics",
                               folder_name=self.viz_folder_name)
Exemple #18
0
def _export_flow(gb, partition, folder):

    for g, d in gb:
        d[pp.STATE]["is_low"] = d["is_low"] * np.ones(g.num_cells)
        d[pp.STATE]["frac_num"] = d["frac_num"] * np.ones(g.num_cells)

    # in the case of partition
    for g, d in gb:
        if g.dim == 2 and partition:
            g_old, subdiv = partition[g]
            d[pp.STATE]["pressure"] = d[pp.STATE]["pressure"][subdiv]
            d[pp.STATE]["is_low"] = d[pp.STATE]["is_low"][subdiv]
            d[pp.STATE]["frac_num"] = d[pp.STATE]["frac_num"][subdiv]
            gb.update_nodes({g: g_old})
            break

    save = pp.Exporter(gb, "sol", folder=folder, binary=False)
    save.write_vtk(["pressure", "is_low", "frac_num"])
Exemple #19
0
def main(kf, is_coarse=False):

    mesh_size = 0.045
    gb, domain = make_grid_bucket(mesh_size)

    # Assign parameters
    add_data(gb, domain, kf)

    # Choose and define the solvers and coupler
    solver_flow = pp.DualVEMMixedDim("flow")
    A, b = solver_flow.matrix_rhs(gb)
    up = sps.linalg.spsolve(A, b)
    solver_flow.split(gb, "up", up)

    gb.add_node_props(["discharge", "pressure", "P0u"])
    solver_flow.extract_u(gb, "up", "discharge")
    solver_flow.extract_p(gb, "up", "pressure")
    solver_flow.project_u(gb, "discharge", "P0u")

    save = pp.Exporter(gb, "vem", folder="vem_ref")
    save.write_vtk(["pressure", "P0u"])
Exemple #20
0
    def prepare_simulation(self):
        """ Is run prior to a time-stepping scheme. Use this to initialize
        discretizations, linear solvers etc.

        TODO: Should the arguments be solver_options and **kwargs (for everything else?)

        TODO: Examples needed

        """
        self.create_grid()
        self.Nd = self.gb.dim_max()
        self.set_parameters()
        self.assign_variables()
        self.assign_discretizations()
        self.initial_condition()
        self.discretize()
        self.initialize_linear_solver()

        g_max = self._nd_grid()
        self.viz = pp.Exporter(
            g_max, file_name="mechanics", folder_name=self.viz_folder_name
        )
def advdiff(gb, param, model_flow):

    model = "transport"

    model_data_adv, model_data_diff = data.advdiff(gb, model, model_flow,
                                                   param)

    # discretization operator names
    adv_id = "advection"
    diff_id = "diffusion"

    # variable names
    variable = "scalar"
    mortar_adv = "lambda_" + variable + "_" + adv_id
    mortar_diff = "lambda_" + variable + "_" + diff_id

    # discretization operatr
    discr_adv = pp.Upwind(model_data_adv)
    discr_diff = pp.Tpfa(model_data_diff)

    coupling_adv = pp.UpwindCoupling(model_data_adv)
    coupling_diff = pp.RobinCoupling(model_data_diff, discr_diff)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {
            variable: {
                adv_id: discr_adv,
                diff_id: discr_diff
            }
        }

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {
            mortar_adv: {
                "cells": 1
            },
            mortar_diff: {
                "cells": 1
            }
        }

        d[pp.COUPLING_DISCRETIZATION] = {
            adv_id: {
                g_slave: (variable, adv_id),
                g_master: (variable, adv_id),
                e: (mortar_adv, coupling_adv)
            },
            diff_id: {
                g_slave: (variable, diff_id),
                g_master: (variable, diff_id),
                e: (mortar_diff, coupling_diff)
            }
        }

    # setup the advection-diffusion problem
    assembler = pp.Assembler()
    logger.info(
        "Assemble the advective and diffusive terms of the transport problem")
    A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    # mass term
    mass_id = "mass"
    discr_mass = pp.MassMatrix(model_data_adv)

    for g, d in gb:
        d[pp.PRIMARY_VARIABLES] = {variable: {"cells": 1}}
        d[pp.DISCRETIZATION] = {variable: {mass_id: discr_mass}}

    gb.remove_edge_props(pp.COUPLING_DISCRETIZATION)

    for e, d in gb.edges():
        g_slave, g_master = gb.nodes_of_edge(e)
        d[pp.PRIMARY_VARIABLES] = {
            mortar_adv: {
                "cells": 1
            },
            mortar_diff: {
                "cells": 1
            }
        }

    logger.info("Assemble the mass term of the transport problem")
    M, _, _, _ = assembler.assemble_matrix_rhs(gb)
    logger.info("done")

    # Perform an LU factorization to speedup the solver
    #IE_solver = sps.linalg.factorized((M + A).tocsc())

    # time loop
    logger.info("Prepare the exporting")
    save = pp.Exporter(gb, "solution", folder=param["folder"])
    logger.info("done")
    variables = [variable, param["pressure"], param["P0_flux"]]

    x = np.ones(A.shape[0]) * param["initial_advdiff"]
    logger.info("Start the time loop with " + str(param["n_steps"]) + " steps")
    for i in np.arange(param["n_steps"]):
        #x = IE_solver(b + M.dot(x))
        logger.info("Solve the linear system for time step " + str(i))
        x = sps.linalg.spsolve(M + A, b + M.dot(x))
        logger.info("done")

        logger.info("Variable post-process")
        assembler.distribute_variable(gb, x, block_dof, full_dof)
        logger.info("done")

        logger.info("Export variable")
        save.write_vtk(variables, time_step=i)
        logger.info("done")

    save.write_pvd(np.arange(param["n_steps"]) * param["time_step"])
Exemple #22
0
def main():

    # tolerance in the computation
    tol = 1e-10

    # assign the flag for the low permeable fractures
    mesh_size = 0.5 * 1e-2
    tol_network = mesh_size
    mesh_kwargs = {
        "mesh_size_frac": mesh_size,
        "mesh_size_min": mesh_size / 20
    }

    # read and mark the original fracture network, the fractures id will be preserved
    file_name = "network.csv"
    domain = {"xmin": 0, "xmax": 1, "ymin": -1, "ymax": 1}
    network = pp.fracture_importer.network_2d_from_csv(file_name,
                                                       domain=domain)
    # set the original id
    network.tags["original_id"] = np.arange(network.num_frac, dtype=np.int)
    # save the original network
    network_original = network.copy()

    # set the condition, meaning if for a branch we solve problem with a < (1) or with > (0)
    # for simplicity we just set all equal
    network.tags["condition"] = np.ones(network.num_frac, dtype=np.int)

    flux_threshold = 0.15
    cond = lambda flux, op, tol=0: condition_interface(flux_threshold, flux,
                                                       op, tol)

    file_name = "case2"
    folder_name = "./non_linear/"
    variable_to_export = [
        Flow.pressure, Flow.P0_flux, "original_id", "condition"
    ]

    iteration = 0
    max_iteration = 50
    max_iteration_non_linear = 50
    max_err_non_linear = 1e-4
    okay = False
    while not okay:

        print("iteration", iteration)

        # create the grid bucket
        gb = network.mesh(mesh_kwargs,
                          dfn=True,
                          preserve_fracture_tags=["original_id", "condition"])

        # create the discretization
        discr = Flow(gb)

        # the mesh is changed as well as the interface, do not use the solution at previous step
        # initialize the non-linear algorithm by setting zero the flux which is equivalent to get
        # the Darcy solution at the first iteration
        for g, d in gb:
            d.update({pp.STATE: {}})
            d[pp.STATE].update({Flow.P0_flux: np.zeros((3, g.num_cells))})
            d[pp.STATE].update(
                {Flow.P0_flux + "_old": np.zeros((3, g.num_cells))})

        # non-linear problem solution with a fixed point strategy
        err_non_linear = max_err_non_linear + 1
        iteration_non_linear = 0
        while err_non_linear > max_err_non_linear and iteration_non_linear < max_iteration_non_linear:

            # solve the linearized problem
            discr.set_data(test_data())
            A, b = discr.matrix_rhs()
            x = sps.linalg.spsolve(A, b)
            discr.extract(x)

            # compute the exit condition
            all_flux = np.empty((3, 0))
            all_flux_old = np.empty((3, 0))
            all_cell_volumes = np.empty(0)
            for g, d in gb:
                # collect the current flux
                flux = d[pp.STATE][Flow.P0_flux]
                all_flux = np.hstack((all_flux, flux))
                # collect the old flux
                flux_old = d[pp.STATE][Flow.P0_flux + "_old"]
                all_flux_old = np.hstack((all_flux_old, flux_old))
                # collect the cell volumes
                all_cell_volumes = np.hstack(
                    (all_cell_volumes, g.cell_volumes))
                # save the old flux
                d[pp.STATE][Flow.P0_flux + "_old"] = flux

            # compute the error and normalize the result
            err_non_linear = np.sum(
                all_cell_volumes *
                np.linalg.norm(all_flux - all_flux_old, axis=0))
            norm_flux_old = np.sum(all_cell_volumes *
                                   np.linalg.norm(all_flux_old, axis=0))
            err_non_linear = err_non_linear / norm_flux_old if norm_flux_old != 0 else err_non_linear

            print("iteration non-linear problem", iteration_non_linear,
                  "error", err_non_linear)
            iteration_non_linear += 1

        # exporter
        save = pp.Exporter(gb, "sol_" + file_name, folder_name=folder_name)
        save.write_vtu(variable_to_export, time_step=iteration)

        # save the network points to check if we have reached convergence
        old_network_pts = network.pts

        # construct the new network such that the interfaces are respected
        network = detect_interface(gb, network, network_original, discr, cond,
                                   tol)
        # export the current network with the associated tags
        network_file_name = make_file_name(file_name, iteration)
        network.to_file(network_file_name,
                        data=network.tags,
                        folder_name=folder_name,
                        binary=False)

        # check if any point in the network has changed
        all_pts = np.hstack((old_network_pts, network.pts))
        distances = pp.distances.pointset(all_pts) > tol_network
        # consider only the block between the old and new points
        distances = distances[:old_network_pts.shape[1],
                              -network.pts.shape[1]:]
        # check if an old point has a point equal in the new set
        check = np.any(np.logical_not(distances), axis=0)

        if np.all(check) or iteration > max_iteration:
            okay = True
        iteration += 1

    save.write_pvd(np.arange(iteration), np.arange(iteration))
    write_network_pvd(file_name, folder_name, np.arange(iteration))
Exemple #23
0
def viscous_flow(disc, data, time_step_param):
    """
    Solve the coupled problem of fluid flow and temperature transport, where the
    viscosity is depending on the temperature.
    Darcy's law and mass conservation is solved for the fluid flow:
    u = -K/mu(T) grad p,   div u = 0,
    where mu(T) is a given temperature depending viscosity.
    The temperature is advective and diffusive:
    \partial phi T /\partial t + div (cu) -div (D grad c) = 0.
    
    A darcy type coupling is assumed between grids of different dimensions:
    lambda = -kn/mu(T) * (p^lower - p^higher),
    and similar for the diffusivity:
    lambda_c = -D * (c^lower - c^higher).

    Parameters:
    disc (discretization.ViscousFlow): A viscous flow discretization class
    data (data.ViscousData): a viscous flow data class

    Returns:
    None

    The solution is exported to vtk.
    """
    # Get information from data
    gb = data.gb
    flow_kw = data.flow_keyword
    tran_kw = data.transport_keyword

    # define shorthand notation for discretizations
    # Flow
    flux = disc.mat[flow_kw]["flux"]
    bound_flux = disc.mat[flow_kw]["bound_flux"]
    trace_p_cell = disc.mat[flow_kw]["trace_cell"]
    trace_p_face = disc.mat[flow_kw]["trace_face"]
    bc_val_p = disc.mat[flow_kw]["bc_values"]
    kn = disc.mat[flow_kw]["kn"]
    mu = data.viscosity

    # Transport
    diff = disc.mat[tran_kw]["flux"]
    bound_diff = disc.mat[tran_kw]["bound_flux"]
    trace_c_cell = disc.mat[tran_kw]["trace_cell"]
    trace_c_face = disc.mat[tran_kw]["trace_face"]
    bc_val_c = disc.mat[tran_kw]["bc_values"]
    Dn = disc.mat[tran_kw]["dn"]

    # Define projections between grids
    master2mortar, slave2mortar, mortar2master, mortar2slave = projection.mixed_dim_projections(
        gb)
    # And between cells and faces
    avg = projection.cells2faces_avg(gb)
    div = projection.faces2cells(gb)

    # Assemble geometric values
    mass_weight = disc.mat[tran_kw]["mass_weight"]
    cell_volumes = gb.cell_volumes() * mass_weight
    mortar_volumes = gb.cell_volumes_mortar()
    # mortar_area = mortar_volumes * (master2mortar * avg * specific_volume)

    # Define secondary variables:
    q_func = lambda p, c, lam: (
        (flux * p + bound_flux * bc_val_p) *
        (mu(avg * c))**-1 + bound_flux * mortar2master * lam)
    trace_p = lambda p, lam: trace_p_cell * p + trace_p_face * (lam + bc_val_p)
    trace_c = lambda c, lam_c: trace_c_cell * c + trace_c_face * (lam_c +
                                                                  bc_val_c)

    # Define discrete equations
    # Flow, conservation
    mass_conservation = lambda p, lam, q: (div * q - mortar2slave * lam)
    # Flow, coupling law
    coupling_law = lambda p, lam, c: (lam / kn / mortar_volumes + (
        slave2mortar * p - master2mortar * trace_p(p, mortar2master * lam)
    ) / mu((slave2mortar * c + master2mortar * avg * c) / 2))

    # Transport
    # Define upwind and diffusive discretizations
    upwind = lambda c, lam, q: (div * disc.upwind(c, q) + disc.mortar_upwind(
        c, lam, div, avg, master2mortar, slave2mortar, mortar2master,
        mortar2slave))

    diffusive = lambda c, lam_c: (div * (diff * c + bound_diff * (
        mortar2master * lam_c + bc_val_c)) - mortar2slave * lam_c)
    # Diffusive copuling law
    coupling_law_c = lambda c, lam_c: (lam_c / Dn / mortar_volumes +
                                       slave2mortar * c - master2mortar *
                                       trace_c(c, mortar2master * lam_c))
    # Tranpsort, conservation equation
    theta = 0.5
    transport = lambda lam, lam0, c, c0, lam_c, lam_c0, q, q0: (
        (c - c0) * (cell_volumes / dt) + theta *
        (upwind(c, lam, q) + diffusive(c, lam_c)) + (1 - theta) *
        (upwind(c0, lam0, q0) + (1 - theta) * diffusive(c0, lam_c0)))
    # Define ad variables
    print("Solve for initial condition")
    # We solve for inital pressure and mortar flux by fixing the temperature
    # to the initial value.
    c0 = np.zeros(gb.num_cells())
    lam_c0 = np.zeros(gb.num_mortar_cells())
    # Initial guess for the pressure and mortar flux
    p0_init = np.zeros(gb.num_cells())
    lam0_init = np.zeros(gb.num_mortar_cells())
    # Define Ad variables and set up equations
    p0, lam0 = ad.initAdArrays([p0_init, lam0_init])
    eq_init = ad.concatenate(
        (mass_conservation(p0, lam0,
                           q_func(p0, c0, lam0)), coupling_law(p0, lam0, c0)))
    # As the temperature is fixed, the system is linear, thus Newton's method converges
    # in one iteration
    sol_init = -sps.linalg.spsolve(eq_init.jac, eq_init.val)
    p0 = sol_init[:gb.num_cells()]
    lam0 = sol_init[gb.num_cells():]

    # Now that we have solved for initial condition, initalize full problem
    p, lam, c, lam_c = ad.initAdArrays([p0, lam0, c0, lam_c0])
    sol = np.hstack((p.val, lam.val, c.val, lam_c.val))
    q = q_func(p, c, lam)

    # define dofs indices
    p_ix = slice(gb.num_cells())
    lam_ix = slice(gb.num_cells(), gb.num_cells() + gb.num_mortar_cells())
    c_ix = slice(
        gb.num_cells() + gb.num_mortar_cells(),
        2 * gb.num_cells() + gb.num_mortar_cells(),
    )
    lam_c_ix = slice(
        2 * gb.num_cells() + gb.num_mortar_cells(),
        2 * gb.num_cells() + 2 * gb.num_mortar_cells(),
    )
    # solve system
    dt = time_step_param["dt"]
    t = 0
    k = 0
    exporter = pp.Exporter(gb, time_step_param["file_name"],
                           time_step_param["folder_name"])
    # Export initial condition
    viz.split_variables(gb, [p.val, c.val], ["pressure", "concentration"])
    exporter.write_vtk(["pressure", "concentration"], time_step=k)
    times = [0]
    # Store average concentration
    out_file_name = "res_avg_c/" + time_step_param["file_name"] + ".csv"
    os.makedirs(os.path.dirname(out_file_name), exist_ok=True)
    out_file = open(out_file_name, "w")
    out_file.write('time, average_c\n')
    viz.store_avg_concentration(gb, 0, "concentration", out_file)

    while t <= time_step_param["end_time"]:
        t += dt
        k += 1
        print("Solving time step: ", k, " dt: ", dt, " Time: ", t)
        p0 = p.val
        lam0 = lam.val
        c0 = c.val
        lam_c0 = lam_c.val
        q0 = q.val
        err = np.inf
        newton_it = 0
        sol0 = sol.copy()
        while err > 1e-9:
            newton_it += 1
            q = q_func(p, c, lam)
            equation = ad.concatenate((
                mass_conservation(p, lam, q),
                coupling_law(p, lam, c),
                transport(lam, lam0, c, c0, lam_c, lam_c0, q, q0),
                coupling_law_c(c, lam_c),
            ))
            err = np.max(np.abs(equation.val))
            if err < 1e-9:
                break
            print("newton iteration number: ", newton_it - 1, ". Error: ", err)
            sol = sol - sps.linalg.spsolve(equation.jac, equation.val)
            p.val = sol[p_ix]
            lam.val = sol[lam_ix]

            c.val = sol[c_ix]
            lam_c.val = sol[lam_c_ix]

            if err != err or newton_it > 10 or err > 10e10:
                # Reset
                print("failed Netwon, reducing time step")
                t -= dt / 2
                dt = dt / 2
                p.val = p0
                lam.val = lam0

                c.val = c0
                lam_c.val = lam_c0

                sol = sol0
                err = np.inf
                newton_it = 0
            # print(err)
        print("Converged Newton in : ", newton_it - 1, " iterations. Error: ",
              err)
        if newton_it < 3 and dt < time_step_param["max_dt"]:
            dt = dt * 2
        elif newton_it < 7 and dt < time_step_param["max_dt"]:
            dt *= 1.1

        viz.split_variables(gb, [p.val, c.val], ["pressure", "concentration"])

        exporter.write_vtk(["pressure", "concentration"], time_step=k)
        viz.store_avg_concentration(gb, t, "concentration", out_file)
        times.append(t)
    exporter.write_pvd(timestep=np.array(times))
    out_file.close()
 def set_viz(self):
     self.viz = pp.Exporter(
         self.gb,
         file_name=self.params.viz_file_name,
         folder_name=self.params.folder_name,
     )
def main():

    # tolerance in the computation
    tol = 1e-10

    # assign the flag for the low permeable fractures
    mesh_size = 0.5*1e-2
    tol_network = mesh_size
    mesh_kwargs = {"mesh_size_frac": mesh_size, "mesh_size_min": mesh_size / 20}

    # read and mark the original fracture network, the fractures id will be preserved
    file_name = "network.csv"
    domain = {"xmin": 0, "xmax": 1, "ymin": -1, "ymax": 1}
    network = pp.fracture_importer.network_2d_from_csv(file_name, domain=domain)
    # set the original id
    network.tags["original_id"] = np.arange(network.num_frac, dtype=np.int)
    # save the original network
    network_original = network.copy()

    # set the condition, meaning if for a branch we solve problem with a < (1) or with > (0)
    # for simplicity we just set all equal
    network.tags["condition"] = np.ones(network.num_frac, dtype=np.int)

    flux_threshold = 0.15
    cond = lambda flux, op, tol=0: condition_interface(flux_threshold, flux, op, tol)

    file_name = "case2"
    folder_name = "./linear/"
    variable_to_export = [Flow.pressure, Flow.P0_flux, "original_id", "condition"]

    iteration = 0
    max_iteration = 1e3
    okay = False
    while not okay:

        print("iteration", iteration)

        # create the grid bucket
        gb = network.mesh(mesh_kwargs, dfn=True, preserve_fracture_tags=["original_id", "condition"])

        # create the discretization
        discr = Flow(gb)
        discr.set_data(test_data())

        # problem solution
        A, b = discr.matrix_rhs()
        x = sps.linalg.spsolve(A, b)
        discr.extract(x)

        # exporter
        save = pp.Exporter(gb, "sol_" + file_name, folder_name=folder_name)
        save.write_vtu(variable_to_export, time_step=iteration)

        # save the network points to check if we have reached convergence
        old_network_pts = network.pts

        # construct the new network such that the interfaces are respected
        network = detect_interface(gb, network, network_original, discr, cond, tol)
        # export the current network with the associated tags
        network_file_name = make_file_name(file_name, iteration)
        network.to_file(network_file_name, data=network.tags, folder_name=folder_name, binary=False)

        # check if any point in the network has changed
        all_pts = np.hstack((old_network_pts, network.pts))
        distances = pp.distances.pointset(all_pts) > tol_network
        # consider only the block between the old and new points
        distances = distances[:old_network_pts.shape[1], -network.pts.shape[1]:]
        # check if an old point has a point equal in the new set
        check = np.any(np.logical_not(distances), axis=0)

        if np.all(check) or iteration > max_iteration:
            okay = True
        iteration += 1

    save.write_pvd(np.arange(iteration), np.arange(iteration))
    write_network_pvd(file_name, folder_name, np.arange(iteration))
            continue
        E0 = d['flow_data'].E0
        d['param'].set_aperture(E0 + d[name])


# # Set up solvers
# We are finally ready to define our solver objects and solve for flow and temperature. With all parameters defined, this is a relatively simple code:

# In[8]:

gb = create_grid()
g3 = gb.grids_of_dimension(3)[0]
data3 = gb.node_props(g3)

# Create an exporter object, and dump the grid
exporter = pp.Exporter(gb, 'low_pressure_stimulation', folder='results')
exporter.write_vtk()

# The resulting grid looks like this, after some manipulation in Paraview

# In[9]:

display(HTML("<img src='fig/mesh.png'>"))

# ### Define solvers
# The flow problem is dependent on time, and needs the time step as an argument. The mechanics and fracture deformation are both quasi-static, i.e., slip happens instantaneous when the Mohr-Colomb criterion is violated
#

# In[10]:

# Define the time stepping
def run_biot(setup):
    """
    Function for solving the time dependent Biot equations with a non-linear Coulomb
    contact condition on the fractures.
    
    There are some assumtions on the variable and discretization names given to the
    grid bucket:
        'u': The displacement variable
        'p': Fluid pressure variable
        'lam': The mortar variable
    Furthermore, the parameter keyword from the elasticity is assumed the same as the
    parameter keyword from the contact condition.

    In addition to the standard parameters for Biot we also require the following
    under the mechanics keyword (returned from setup.set_parameters):
        'friction_coeff' : The coefficient of friction
        'c' : The numerical parameter in the non-linear complementary function.
    and for the parameters under the fluid flow keyword:
        'time_step': time step of implicit Euler.

    Arguments:
        setup: A setup class with methods:
                set_parameters(g, data_node, mg, data_edge): assigns data to grid bucket.
                    Returns the keyword for the linear elastic parameters and a keyword
                    for the contact mechanics parameters.
                create_grid(): Create and return the grid bucket
                initial_condition(): Returns initial guess for 'u' and 'lam'.
            and attributes:
                out_name(): returns a string. The data from the simulation will be
                    written to the file 'res_data/' + setup.out_name and the vtk files
                    to 'res_plot/' + setup.out_name
                end_time: End time time of simulation.
    """
    gb = setup.create_grid()
    # Extract the grids we use
    dim = gb.dim_max()
    g = gb.grids_of_dimension(dim)[0]
    data_node = gb.node_props(g)
    data_edge = gb.edge_props((g, g))
    mg = data_edge['mortar_grid']

    # set parameters
    key_m, key_f = setup.set_parameters(g, data_node, mg, data_edge)
    # Short hand for some parameters
    F = data_edge[pp.PARAMETERS][key_m]['friction_coeff']
    c_num = data_edge[pp.PARAMETERS][key_m]['c']
    dt = data_node[pp.PARAMETERS][key_f]["time_step"]

    # Define rotations
    M_inv, nc = utils.normal_tangential_rotations(g, mg)

    # Set up assembler and get initial condition
    assembler = pp.Assembler()

    u0 = data_node[pp.PARAMETERS][key_m]['state']['displacement'].reshape(
        (g.dim, -1), order='F')
    p0 = data_node[pp.PARAMETERS][key_f]['state']
    Tc = data_edge[pp.PARAMETERS][key_m]['state'].reshape((g.dim, -1),
                                                          order='F')

    # Reconstruct displacement jump on fractures
    uc = reconstruct_mortar_displacement(u0,
                                         Tc,
                                         g,
                                         mg,
                                         data_node,
                                         data_edge,
                                         key_m,
                                         key_f,
                                         pressure=p0)
    uc0 = uc.copy()

    # Define function for splitting the global solution vector
    def split_solution_vector(x, block_dof, full_dof):
        # full_dof contains the number of dofs per block. To get a global ordering, use
        global_dof = np.r_[0, np.cumsum(full_dof)]

        # split global variable
        block_u = block_dof[(g, "u")]
        block_p = block_dof[(g, "p")]
        block_lam = block_dof[((g, g), "lam_u")]
        # Get the global displacement and pressure dofs
        u_dof = np.arange(global_dof[block_u], global_dof[block_u + 1])
        p_dof = np.arange(global_dof[block_p], global_dof[block_p + 1])
        lam_dof = np.arange(global_dof[block_lam], global_dof[block_lam + 1])

        # Plot pressure and displacements
        u = x[u_dof].reshape((g.dim, -1), order="F")
        p = x[p_dof]
        lam = x[lam_dof].reshape((g.dim, -1), order="F")
        return u, p, lam

    # prepare for time loop
    sol = None  # inital guess for Newton solver.
    T_contact = []
    u_contact = []
    save_sliding = []
    errors = []
    exporter = pp.Exporter(g, setup.out_name, 'res_plot')
    t = 0.0
    T = setup.end_time
    k = 0
    times = []
    newton_it = 0
    while t < T:
        t += dt
        k += 1
        print('Time step: ', k, '/', int(np.ceil(T / dt)))

        times.append(t)
        # Prepare for Newton
        counter_newton = 0
        converged_newton = False
        max_newton = 12
        newton_errors = []
        while counter_newton <= max_newton and not converged_newton:
            print('Newton iteration number: ', counter_newton, '/', max_newton)
            counter_newton += 1
            bf = F * np.clip(np.sum(nc *
                                    (-Tc + c_num * uc), axis=0), 0, np.inf)
            ducdt = (uc - uc0) / dt
            # Find the robin weight
            mortar_weight, robin_weight, rhs = contact_coulomb(
                Tc, ducdt, F, bf, c_num, c_num, M_inv)
            rhs = rhs.reshape((g.dim, -1), order='F')
            for i in range(mg.num_cells):
                robin_weight[i] = robin_weight[i] / dt
                rhs[:, i] = rhs[:, i] + robin_weight[i].dot(uc0[:, i])
            data_edge[pp.PARAMETERS][key_m]['robin_weight'] = robin_weight
            data_edge[pp.PARAMETERS][key_m]['mortar_weight'] = mortar_weight
            data_edge[pp.PARAMETERS][key_m]['robin_rhs'] = rhs.ravel('F')

            # Re-discretize and solve
            A, b, block_dof, full_dof = assembler.assemble_matrix_rhs(gb)
            print('max A: ', np.max(np.abs(A)))
            print('max A sum: ', np.max(np.sum(np.abs(A), axis=1)))
            print('min A sum: ', np.min(np.sum(np.abs(A), axis=1)))

            if A.shape[0] > 10000:
                sol, msg, err = solvers.fixed_stress(gb, A, b, block_dof,
                                                     full_dof, sol)
                if msg != 0:
                    # did not converge.
                    print('Iterative solver failed.')
            else:
                sol = sps.linalg.spsolve(A, b)

            # Split solution in the different variables
            u, p, Tc = split_solution_vector(sol, block_dof, full_dof)

            # Reconstruct displacement jump on mortar boundary
            uc = reconstruct_mortar_displacement(u,
                                                 Tc,
                                                 g,
                                                 mg,
                                                 data_node,
                                                 data_edge,
                                                 key_m,
                                                 key_f,
                                                 pressure=p)
            # Calculate the error
            if np.sum((u - u0)**2 * g.cell_volumes) / np.sum(
                    u**2 * g.cell_volumes) < 1e-10:
                converged_newton = True

            print('error: ', np.sum((u - u0)**2) / np.sum(u**2))
            newton_errors.append(np.sum((u - u0)**2) / np.sum(u**2))
            # Prepare for nect newton iteration
            u0 = u
            newton_it += 1

        errors.append(newton_errors)
        # Prepare for next time step
        uc0 = uc.copy()
        T_contact.append(Tc)
        u_contact.append(uc)

        mech_bc = data_node[pp.PARAMETERS][key_m]['bc_values'].copy()
        data_node[pp.PARAMETERS][key_m]['bc_values'] = setup.bc_values(
            g, t + dt, key_m)
        data_node[pp.PARAMETERS][key_f]['bc_values'] = setup.bc_values(
            g, t + dt, key_f)

        data_node[pp.PARAMETERS][key_m]["state"]["displacement"] = u.ravel(
            'F').copy()
        data_node[pp.PARAMETERS][key_m]["state"]["bc_values"] = mech_bc
        data_node[pp.PARAMETERS][key_f]["state"] = p.copy()
        data_edge[pp.PARAMETERS][key_m]["state"] = Tc.ravel('F').copy()

        if g.dim == 2:
            u_exp = np.vstack((u, np.zeros(u.shape[1])))
        elif g.dim == 3:
            u_exp = u.copy()
            m_exp_name = setup.out_name + "_mortar_grid"
            viz.export_mortar_grid(g,
                                   mg,
                                   data_edge,
                                   uc,
                                   Tc,
                                   key_m,
                                   key_m,
                                   m_exp_name,
                                   "res_plot",
                                   time_step=k)

        exporter.write_vtk({"u": u_exp, 'p': p}, time_step=k)

    exporter.write_pvd(np.array(times))
Exemple #28
0
    'mesh_size_bound': 40,
    'mesh_size_min': 1e-1
}

domain = {'xmin': 0, 'xmax': 700, 'ymin': 0, 'ymax': 600}
gb = pp.importer.dfm_2d_from_csv("network.csv", mesh_kwargs, domain)
gb.compute_geometry()
pp.coarsening.coarsen(gb, 'by_volume')
gb.assign_node_ordering()

# Assign parameters
add_data(gb, domain)

# Choose and define the solvers and coupler
solver_flow = pp.DualVEMMixedDim('flow')
A_flow, b_flow = solver_flow.matrix_rhs(gb)

solver_source = pp.DualSourceMixedDim('flow')
A_source, b_source = solver_source.matrix_rhs(gb)

up = sps.linalg.spsolve(A_flow + A_source, b_flow + b_source)
solver_flow.split(gb, "up", up)

gb.add_node_props(["discharge", 'pressure', "P0u"])
solver_flow.extract_u(gb, "up", "discharge")
solver_flow.extract_p(gb, "up", 'pressure')
solver_flow.project_u(gb, "discharge", "P0u")

save = pp.Exporter(gb, "vem", folder="vem")
save.write_vtk(['pressure', "P0u"])
equation_manager = pp.ad.EquationManager(gb, dof_manager)
p = equation_manager.merge_variables([(g, pressure_var) for g in grid_list])
p_m = p.previous_iteration()
p_n = p.previous_timestep()

#%% We let the density to be a non-linear function of the pressure
def rho(p):
    if isinstance(p, pp.ad.Ad_array):
        return rho_ref * pp.ad.exp(c * (p - p_ref))
    else:
        return rho_ref * np.exp(c * (p - p_ref))

rho_ad = pp.ad.Function(rho, name="density")

#%% Initialize exporter
exporter = pp.Exporter(gb, "compressible_1p", "out")
d[pp.STATE]["p_ex"] = p_ex(cc[0], cc[1], time * np.ones_like(cc[0]))
exporter.write_vtu(["p_ex", pressure_var], time_step=0)

#%% Declare AD operators and equations
assign_parameters(time)

div_ad = pp.ad.Divergence(grid_list)  # discrete diveregence
bound_ad = pp.ad.BoundaryCondition(param_key, grids=grid_list)  # boundary vals
dir_bound_ad = DirBC(bound_ad, grid_list)

source_ad = pp.ad.ParameterArray(param_key, "source", grids=grid_list) 
mass_ad = pp.ad.MassMatrixAd(param_key, grid_list)
mpfa_ad = pp.ad.MpfaAd(param_key, grid_list)
flux_inactive = mpfa_ad.flux * p_m + mpfa_ad.bound_flux * bound_ad
flux_active = mpfa_ad.flux * p + mpfa_ad.bound_flux * bound_ad
accumulation_ad = accum_active + accum_inactive

# Continuity equation
continuity_ad = accumulation_ad + dt * div_ad * flux_ad - dt * source_ad

# We need to keep track of the pressure traces
h_trace = mpfa_ad.bound_pressure_cell * h + mpfa_ad.bound_pressure_face * bound_ad
psi_trace = h_trace - z_fc

#%% Assemble the system of equations
eqs = pp.ad.Expression(continuity_ad, dof_manager)  # convert to expression
equation_manager.equations.clear()
equation_manager.equations.append(eqs)  # feed eq to the equation manager

#%% Initialize exporter
exporter = pp.Exporter(gb, "new_mexico", "out")
exporter.write_vtu([pressure_var], time_step=0)

#%% Time loop
total_iteration_counter = 0

# Time loop
for n in range(1, num_time_steps + 1):
    time += dt
    recompute_solution = True
    sat_faces = []
    control_faces = []
    d[pp.STATE]["water_table"] = np.zeros(g.num_cells)
    print("Current time: ", np.round(time, decimals=1))

    # Control Loop