Esempio n. 1
0
    def _solve(self, setup):
        pp.run_stationary_model(setup, {"convergence_tol": 1e-10})
        gb = setup.gb

        nd = gb.dim_max()

        g2 = gb.grids_of_dimension(2)[0]
        g1 = gb.grids_of_dimension(1)[0]

        d_m = gb.edge_props((g1, g2))
        d_1 = gb.node_props(g1)

        mg = d_m["mortar_grid"]

        u_mortar = d_m[pp.STATE][setup.mortar_displacement_variable]
        contact_force = d_1[pp.STATE][setup.contact_traction_variable]

        displacement_jump_global_coord = (mg.mortar_to_slave_avg(nd=nd) *
                                          mg.sign_of_mortar_sides(nd=nd) *
                                          u_mortar)
        projection = d_m["tangential_normal_projection"]

        project_to_local = projection.project_tangential_normal(
            int(mg.num_cells / 2))
        u_mortar_local = project_to_local * displacement_jump_global_coord
        u_mortar_local_decomposed = u_mortar_local.reshape((2, -1), order="F")

        contact_force = contact_force.reshape((2, -1), order="F")

        return u_mortar_local_decomposed, contact_force
def test_compare_run_mech_and_run_mech_by_filter_term():
    """ This test runs pure mechanics by running the test
    'test_mechanics_class_methods.test_decomposition_of_stress()'
    for the hydrostatic case. Then, it runs the test
    'test_run_mechanics_term_by_filter()'.

    The goal is to compare the output of these two methods and ensure they
    are the same.
    """
    # 1. Prepare parameters
    stress = gts.stress_tensor()
    # We set up hydrostatic stress
    hydrostatic = np.mean(np.diag(stress)) * np.ones(stress.shape[0])
    stress = np.diag(hydrostatic)
    no_shearzones = None
    gravity = False  # No gravity effects
    params = {
        "stress": stress,
        "shearzone_names": no_shearzones,
        "_gravity_bc": gravity,
        "_gravity_src": gravity,
    }

    # Storage folder
    this_method_name = test_compare_run_mech_and_run_mech_by_filter_term.__name__
    now_as_YYMMDD = pendulum.now().format("YYMMDD")
    _folder_root = f"{this_method_name}/{now_as_YYMMDD}"

    # 1. --- Setup ContactMechanicsISC ---
    setup_mech = test_util.prepare_setup(
        model=gts.ContactMechanicsISC,
        path_head=f"{_folder_root}/test_mech",
        params=params,
        prepare_simulation=False,
        setup_loggers=True,
    )
    setup_mech.create_grid()

    # 2. --- Setup BiotReduceToMechanics ---
    params2 = test_util.prepare_params(
        path_head=f"{_folder_root}/test_biot_reduce_to_mech",
        params=params,
        setup_loggers=False,
    )
    setup_biot = BiotReduceToMechanics(params=params2)

    # Recreate the same mesh as for the above setup
    path_to_gb_msh = f"{setup_mech.viz_folder_name}/gmsh_frac_file.msh"
    gb2 = pp.fracture_importer.dfm_from_gmsh(path_to_gb_msh,
                                             dim=3,
                                             network=setup_mech._network)
    setup_biot.set_grid(gb2)

    # 3. --- Run simulations ---
    nl_params = {}

    # Run ContactMechanicsISC
    pp.run_stationary_model(setup_mech, nl_params)

    # Run BiotReduceToMechanics
    pp.run_time_dependent_model(setup_biot, nl_params)

    # --- Compare results ---
    def get_u(_setup):
        gb = _setup.gb
        g = gb.grids_of_dimension(3)[0]
        d = gb.node_props(g)
        u = d["state"]["u"].reshape((3, -1), order="F")
        return u

    u_mech = get_u(setup_mech)
    u_biot = get_u(setup_biot)
    assert np.isclose(
        np.sum(np.abs(u_mech - u_biot)),
        0.0), ("Running mechanics or biot (only discretize mechanics "
               "term should return same result.")
    return setup_mech, setup_biot
def test_decomposition_of_stress(setup='normal_shear'):
    """ Test the solutions acquired when decomposing stress to
    purely compressive and purely rotational components.

    --- Setup ---
    A: 1. Get the stress tensor and split in diagonal and off-diagonal components.
    B: 1. Get the stress tensor and split in hydrostatic and deviatoric components.
    --
    2. Acquire solutions for each split tensor and the full tensor separately (3 cases).
    3. Compare solutions quantitatively (linearity of solution) and qualitatively (Paraview)

    Parameters
    ----------
    setup : str : {'normal_shear', 'hydrostatic'}
        Type of setup.
        'normal_shear' simply separates the normal and shear components
        'hydrostatic' separates hydrostatic and deviatoric stresses
    """

    # Import stress tensor
    stress = gts.isc_modelling.stress_tensor()

    if setup == 'normal_shear':
        # Get normal and shear stresses
        normal_stress = np.diag(np.diag(stress).copy())
        shear_stress = stress - normal_stress
        fname_n = 'normal_stress'
        fname_s = 'shear_stress'
    elif setup == 'hydrostatic':
        # Get hydrostatic and deviatoric stresses
        hydrostatic = np.mean(np.diag(stress)) * np.ones(stress.shape[0])
        normal_stress = np.diag(hydrostatic)
        shear_stress = stress - normal_stress
        fname_n = 'hydrostatic_stress'
        fname_s = 'deviatoric_stress'
    else:
        raise ValueError(f"Did not recognise input setup={setup}")

    # 1. Full stress tensor
    this_method_name = test_decomposition_of_stress.__name__
    now_as_YYMMDD = pendulum.now().format("YYMMDD")
    _folder_root = f"{this_method_name}/{now_as_YYMMDD}/no_gravity/{setup}"
    gravity = False
    no_shearzones = None
    params = {
        "shearzone_names": no_shearzones,
        "stress": stress,
        "_gravity_bc": gravity,
        "_gravity_src": gravity,
    }
    setup = test_util.prepare_setup(
        model=gts.ContactMechanicsISC,
        path_head=f"{_folder_root}",
        params=params,
        prepare_simulation=False,
        setup_loggers=True,
    )
    setup.create_grid()

    # -- Safely copy the grid generated above --
    # Ensures the implicit in-place variable changes across grid_buckets (gb.copy() is insufficient)
    # Get the grid_bucket .msh path
    path_to_gb_msh = f"{setup.viz_folder_name}/gmsh_frac_file.msh"
    # Re-create the grid buckets
    gb_n = pp.fracture_importer.dfm_from_gmsh(path_to_gb_msh,
                                              dim=3,
                                              network=setup._network)
    gb_s = pp.fracture_importer.dfm_from_gmsh(path_to_gb_msh,
                                              dim=3,
                                              network=setup._network)

    # 1. Pure normal stress / hydrostatic stress
    params_n = params.update({'stress': normal_stress})
    setup_n = test_util.prepare_setup(
        model=gts.ContactMechanicsISC,
        path_head=f"{_folder_root}/{fname_n}",
        params=params_n,
        prepare_simulation=False,
        setup_loggers=False,
    )
    setup_n.set_grid(gb_n)

    # 2. Pure shear stress / deviatoric stress
    params_s = params.update({"stress": shear_stress})
    setup_s = test_util.prepare_setup(
        model=gts.ContactMechanicsISC,
        path_head=f"{_folder_root}/{fname_s}",
        params=params_s,
        prepare_simulation=False,
        setup_loggers=False,
    )
    setup_s.set_grid(gb_s)

    # --- Run simulations ---
    params_nl = {}  # Use default Newton solver parameters

    # 1. Full stress tensor
    pp.run_stationary_model(setup, params_nl)

    # 2. Pure normal stress
    pp.run_stationary_model(setup_n, params_nl)

    # 3. Pure shear stress
    pp.run_stationary_model(setup_s, params_nl)

    # --- Compare results ---
    def get_u(_setup):
        gb = _setup.gb
        g = gb.grids_of_dimension(3)[0]
        d = gb.node_props(g)
        u = d['state']['u'].reshape((3, -1), order='F')
        return u

    return get_u(setup), get_u(setup_n), get_u(setup_s), [
        setup, setup_n, setup_s
    ]
        "folder_name": folder_name,
        "inclination": np.pi / 2,
        "poisson": 0.3,
        "boundary_traction": 1e-4,
        "simplex": simplex,
        "n_cells": [nx, nx, 4],
        "prepare_umfpack": False,
    }

    if not os.path.exists(folder_name):
        os.makedirs(folder_name)

    for i, nu in enumerate(poisson_ratios):
        params["poisson"] = nu
        for j, h in enumerate(mesh_sizes):
            params["mesh_args"] = {
                "mesh_size_frac": h,
                "mesh_size_bound": 3 * h,
            }
            m = SneddonSIFTest(params)
            # Also compute mode II SIFs:
            m._is_tensile = False
            pp.run_stationary_model(m, params)
            all_errors[i, j] = m.compute_sifs_and_errors()
    data = {
        "all_errors": all_errors,
        "poisson_ratios": poisson_ratios,
        "mesh_sizes": mesh_sizes,
    }
    write_pickle(data, folder_name + "/all_errors")
Esempio n. 5
0
def convergence_study():
    """ Perform a convergence study of a given problem setup.
    """

    # 1. Step: Create n grids by uniform refinement.
    # 2. Step: for grid i in list of n grids:
    # 2. a. Step: Set up the mechanics model.
    # 2. b. Step: Solve the mechanics problem.
    # 2. c. Step: Keep the grid (with solution data)
    # 3. Step: Let the finest grid be the reference solution.
    # 4. Step: For every other grid:
    # 4. a. Step: Map the solution to the fine grid, and compute error.
    # 5. Step: Compute order of convergence, etc.

    # -----------------
    # --- ARGUMENTS ---
    # -----------------
    viz_folder_name = Path(
        os.path.abspath(__file__)).parent / "results/mech_convergence_2test"
    if not os.path.exists(viz_folder_name):
        os.makedirs(viz_folder_name, exist_ok=True)

    shearzone_names = ["S1_1", "S1_2", "S1_3", "S3_1", "S3_2"]

    mesh_size = 10
    mesh_args = {  # A very coarse grid
        "mesh_size_frac": mesh_size,
        "mesh_size_min": mesh_size,
        "mesh_size_bound": mesh_size,
    }

    bounding_box = {
        "xmin": -6,
        "xmax": 80,
        "ymin": 55,
        "ymax": 150,
        "zmin": 0,
        "zmax": 50,
    }

    # 1. Step: Create n grids by uniform refinement.
    gb_list = create_isc_domain(
        viz_folder_name=viz_folder_name,
        shearzone_names=shearzone_names,
        bounding_box=bounding_box,
        mesh_args=mesh_args,
        n_refinements=1,
    )

    scales = {
        'scalar_scale': 1,
        'length_scale': 1,
    }
    solver = 'direct'

    # ---------------------------
    # --- PHYSICAL PARAMETERS ---
    # ---------------------------

    stress = stress_tensor()

    # ----------------------
    # --- SET UP LOGGING ---
    # ----------------------
    print(viz_folder_name / "results.log")
    logger = __setup_logging(viz_folder_name)

    logger.info(
        f"Preparing setup for mechanics convergence study on {pendulum.now().to_atom_string()}"
    )
    logger.info(f"Reporting on {len(gb_list)} grid buckets.")
    logger.info(f"Visualization folder path: \n {viz_folder_name}")
    logger.info(f"Mesh arguments for coarsest grid: \n {mesh_args}")
    logger.info(f"Bounding box: \n {bounding_box}")
    logger.info(f"Variable scaling: \n {scales}")
    logger.info(f"Solver type: {solver}")
    logger.info(f"Stress tensor: \n {stress}")

    # -----------------------
    # --- SETUP AND SOLVE ---
    # -----------------------

    newton_options = {  # Parameters for Newton solver.
        "max_iterations": 10,
        "convergence_tol": 1e-10,
        "divergence_tol": 1e5,
    }
    logger.info(f"Options for Newton solver: \n {newton_options}")

    from GTS.isc_modelling.mechanics import ContactMechanicsISCWithGrid
    for gb in gb_list:
        setup = ContactMechanicsISCWithGrid(
            viz_folder_name,
            'main_run',
            'linux',
            mesh_args,
            bounding_box,
            shearzone_names,
            scales,
            stress,
            solver,
            gb,
        )

        logger.info("Setup complete. Starting simulation")
        pp.run_stationary_model(setup, params=newton_options)
        logger.info("Simulation complete. Exporting solution.")

    return gb_list