예제 #1
0
    def modify_mesh(self):
        self.mesh = gmsh_io.GmshIO()
        with open(self.tmp_msh_file, "r") as f:
            self.mesh.read(f)

        new_elements = {}
        for id, elm in self.mesh.elements.items():
            el_type, tags, nodes = elm
            if len(tags) < 2:
                raise Exception("Less then 2 tags.")
            dim = self.el_type_to_dim[el_type]
            shape_id = tags[1]
            shape_info = self.gmsh_shape_dist[ (dim, shape_id)]

            if not shape_info.free:
                continue
            region = self.regions[shape_info.i_reg]
            if not region.is_active(dim):
                continue
            assert region.dim == dim
            physical_id = shape_info.i_reg + 10000
            if region.name in self.mesh.physical:
                assert self.mesh.physical[region.name][0] == physical_id
            else:
                self.mesh.physical[region.name] = (physical_id, dim)
            assert (region.name[0] == '.') == (region.boundary)
            tags[0] = physical_id
            new_elements[id] = (el_type, tags, nodes)
        self.mesh.elements = new_elements
        self.msh_file = self.basename + ".msh"
        with open(self.msh_file, "w") as f:
            self.mesh.write_ascii(f)
        return self.mesh
예제 #2
0
def test_check_flat_quad():
    h = 0.005
    nodes = np.array([[0, 0, 0], [1, 1, 0], [0, 1, h], [1, 0, h]], dtype=float)
    mesh_io = gmsh_io.GmshIO()
    for inn, n in enumerate(nodes):
        mesh_io.nodes[inn] = n
    mesh_io.elements[0] = (4, (1, 2, 3), [0, 1, 2, 3])

    hm = heal_mesh.HealMesh(mesh_io)
    hm.gamma_tol = 0.01
    ele = hm._make_element(0)
    hm._check_flat_tetra(ele)
예제 #3
0
 def make_mesh(self):
     import geometry_2d as geom
     mesh_file = "mesh_{}.msh".format(self.basename)
     self.skip_decomposition = os.path.exists(mesh_file)
     self.make_fracture_network()
     if not self.skip_decomposition:
         gmsh_executable = self.config_dict["gmsh_executable"]
         g2d = geom.Geometry2d("mesh_" + self.basename, self.regions)
         g2d.add_compoud(self.decomp)
         g2d.make_brep_geometry()
         step_range = (self.mesh_step * 0.9, self.mesh_step * 1.1)
         g2d.call_gmsh(gmsh_executable, step_range)
         self.mesh = g2d.modify_mesh()
     else:
         self.mesh = gmsh_io.GmshIO()
         with open(mesh_file, "r") as f:
             self.mesh.read(f)
예제 #4
0
def test_fracture_neighbors(config_dict):
    """
    Function that tests finding fracture neighbors.
    It outputs mesh data - level per element.
    :param config_dict:
    :return:
    """
    setup_dir(config_dict, clean=True)
    mesh_repo = config_dict.get('mesh_repository', None)
    if mesh_repo:
        healed_mesh = sample_mesh_repository(mesh_repo)
        config_fracture_regions(config_dict["fracture_regions"])
    else:
        fractures = generate_fractures(config_dict)
        # plot_fr_orientation(fractures)
        healed_mesh = prepare_mesh(config_dict, fractures)
        print("Created mesh: " + os.path.basename(healed_mesh))

    mesh = gmsh_io.GmshIO(healed_mesh)
    fracture_neighbors = find_fracture_neigh(mesh, ["fr"], n_levels=3)

    ele_ids = np.array(list(mesh.elements.keys()), dtype=float)
    ele_ids_map = dict()
    for i in range(len(ele_ids)):
        ele_ids_map[ele_ids[i]] = i

    data = -1 * np.ones(shape=(len(ele_ids), 1))

    for eid, lev in fracture_neighbors:
        data[ele_ids_map[eid]] = lev

    # Separate base from extension
    mesh_name, extension = os.path.splitext(healed_mesh)
    # Initial new name
    new_mesh_name = os.path.join(os.curdir, mesh_name + "_data" + extension)

    with open(new_mesh_name, "w") as fout:
        mesh.write_ascii(fout)
        mesh.write_element_data(fout, ele_ids, 'data', data)
예제 #5
0
def prepare_th_input(config_dict):
    """
    Prepare FieldFE input file for the TH simulation.
    :param config_dict: Parsed config.yaml. see key comments there.
    """
    # pass
    # we have to read region names from the input mesh
    # input_mesh = gmsh_io.GmshIO(config_dict['hm_params']['mesh'])
    #
    # is_bc_region = {}
    # for name, (id, _) in input_mesh.physical.items():
    #     unquoted_name = name.strip("\"'")
    #     is_bc_region[id] = (unquoted_name[0] == '.')

    # read mesh and mechanichal output data
    # mechanics_output = os.path.join(config_dict['hm_params']["output_dir"], 'mechanics.msh')
    mechanics_output = 'output_01_hm/mechanics.msh'

    # hm = heal_mesh.HealMesh.read_mesh(mechanics_output, node_tol=1e-4)
    # hm.heal_mesh(gamma_tol=0.01)
    # hm.stats_to_yaml(mechanics_output + "_heal_stats.yaml")
    # hm.write()
    # hm.healed_mesh_name

    mesh = gmsh_io.GmshIO(mechanics_output)
    # map eid to the element position in the array
    ele_ids = np.array(list(mesh.elements.keys()), dtype=float)
    ele_ids_map = dict()
    for i in range(len(ele_ids)):
        ele_ids_map[ele_ids[i]] = i

    init_fr_cs = float(config_dict['hm_params']['fr_cross_section'])
    init_fr_K = float(config_dict['hm_params']['fr_conductivity'])
    init_bulk_K = float(config_dict['hm_params']['bulk_conductivity'])
    min_fr_cross_section = float(config_dict['th_params']['min_fr_cross_section'])
    max_fr_cross_section = float(config_dict['th_params']['max_fr_cross_section'])

    # read cross-section from HM model
    time_idx = 1
    time, field_cs = mesh.element_data['cross_section_updated'][time_idx]
    # cut small and large values of cross-section
    cs = np.maximum(np.array([v[0] for v in field_cs.values()]), min_fr_cross_section)
    cs = np.minimum(cs, max_fr_cross_section)

    # IMPORTANT - we suppose that the output mesh has the same ELEMENT NUMBERING as the input mesh
    # get fracture regions ids
    orig_mesh = gmsh_io.GmshIO(config_dict["th_params"]["mesh"])
    fr_regs = orig_mesh.get_reg_ids_by_physical_names(config_dict["fracture_regions"], 2)
    fr_indices = orig_mesh.get_elements_of_regions(fr_regs)
    # find bulk elements neighboring to the fractures
    fr_n_levels = config_dict["th_params"]["increased_bulk_cond_levels"]
    fracture_neighbors = find_fracture_neigh(orig_mesh, fr_regs, n_levels=fr_n_levels)

    # create and fill conductivity field
    # set all values to initial bulk conductivity
    K = init_bulk_K * np.ones(shape=(len(ele_ids_map),1))
    # increase conductivity in fractures due to power law
    for eid in fr_indices:
        i = ele_ids_map[eid]
        K[i] = init_fr_K * (cs[i] / init_fr_cs) ** 2
    # increase the bulk conductivity in the vicinity of the fractures
    level_factor = [10**(fr_n_levels - i) for i in range(fr_n_levels)]
    for eid, lev in fracture_neighbors:
        K[ele_ids_map[eid]] = init_bulk_K * level_factor[lev]

    # get cs and K on fracture elements only
    cs_fr = np.array([cs[ele_ids_map[i]] for i in fr_indices])
    k_fr = np.array([K[ele_ids_map[i]] for i in fr_indices])

    # compute cs and K statistics and write it to a file
    fr_param = {}
    avg = float(np.average(cs_fr))
    median = float(np.median(cs_fr))
    interquantile = float(1.5 * (np.quantile(cs_fr, 0.75) - np.quantile(cs_fr, 0.25)))
    fr_param["fr_cross_section"] = {"avg": avg, "median": median, "interquantile": interquantile}

    avg = float(np.average(k_fr))
    median = float(np.median(k_fr))
    interquantile = float(1.5 * (np.quantile(k_fr, 0.75) - np.quantile(k_fr, 0.25)))
    fr_param["fr_conductivity"] = {"avg": avg, "median": median, "interquantile": interquantile}

    with open('fr_param_output.yaml', 'w') as outfile:
        yaml.dump(fr_param, outfile, default_flow_style=False)

    # mesh.write_fields('output_hm/th_input.msh', ele_ids, {'conductivity': K})
    th_input_file = 'th_input.msh'
    with open(th_input_file, "w") as fout:
        mesh.write_ascii(fout)
        mesh.write_element_data(fout, ele_ids, 'conductivity', K)
        mesh.write_element_data(fout, ele_ids, 'cross_section_updated', cs[:, None])
예제 #6
0
    def effective_tensor_from_bulk(self):
        """
        :param bulk_regions: mapping reg_id -> tensor_group_id, groups of regions for which the tensor will be computed.
        :return: {group_id: conductivity_tensor} List of effective tensors.
        """
        bulk_regions = self.reg_to_group
        out_mesh = gmsh_io.GmshIO()
        with open(os.path.join(self.basename, "flow_fields.msh"), "r") as f:
            out_mesh.read(f)
        time_idx = 0
        time, field_cs = out_mesh.element_data['cross_section'][time_idx]
        ele_reg_vol = {
            eid: (tags[0] - 10000, self.element_volume(out_mesh, nodes))
            for eid, (tele, tags, nodes) in out_mesh.elements.items()
        }

        assert len(field_cs) == len(ele_reg_vol)
        velocity_field = out_mesh.element_data['velocity_p0']

        loads = self.pressure_loads
        group_idx = {
            group_id: i_group
            for i_group, group_id in enumerate(set(bulk_regions.values()))
        }
        n_groups = len(group_idx)
        group_labels = n_groups * ['_']
        for reg_id, group_id in bulk_regions.items():
            i_group = group_idx[group_id]
            old_label = group_labels[i_group]
            new_label = self.regions[reg_id].name
            group_labels[i_group] = old_label if len(old_label) > len(
                new_label) else new_label

        n_directions = len(loads)
        flux_response = np.zeros((n_groups, n_directions, 2))
        area = np.zeros((n_groups, n_directions))
        print("Averaging velocities ...")
        for i_time, (time, velocity) in velocity_field.items():
            for eid, ele_vel in velocity.items():
                reg_id, vol = ele_reg_vol[eid]
                cs = field_cs[eid][0]
                volume = cs * vol
                i_group = group_idx[bulk_regions[reg_id]]
                flux_response[i_group,
                              i_time, :] += -(volume * np.array(ele_vel[0:2]))
                area[i_group, i_time] += volume
        flux_response /= area[:, :, None]
        cond_tensors = {}
        print("Fitting tensors ...")
        for group_id, i_group in group_idx.items():
            flux = flux_response[i_group]
            # least square fit for the symmetric conductivity tensor
            rhs = flux.flatten()
            # columns for the tensor values: C00, C01, C11
            pressure_matrix = np.zeros((len(rhs), 3))
            for i_load, (p0, p1) in enumerate(loads):
                i0 = 2 * i_load
                i1 = i0 + 1
                pressure_matrix[i0] = [p0, p1, 0]
                pressure_matrix[i1] = [0, p0, p1]
            C = np.linalg.lstsq(pressure_matrix, rhs, rcond=None)[0]
            cond_tn = np.array([[C[0], C[1]], [C[1], C[2]]])
            if i_group < 10:
                # if flux.shape[0] < 5:
                print("Plot tensor for eid: ", group_id)
                print("Fluxes: \n", flux)
                print("pressures: \n", loads)
                print("cond: \n", cond_tn)
                self.plot_effective_tensor(
                    flux, cond_tn, self.basename + "_" + group_labels[i_group])
                #print(cond_tn)
            cond_tensors[group_id] = cond_tn
        self.cond_tensors = cond_tensors
        return cond_tensors
예제 #7
0
    def elementwise_mesh(self, coarse_mesh, mesh_step, bounding_polygon):
        import geometry_2d as geom
        from bgem.polygons.plot_polygons import plot_decomp_segments

        mesh_file = "mesh_{}.msh".format(self.basename)
        if os.path.exists(mesh_file):
            # just initialize reg_to_group map
            self.skip_decomposition = True

        self.mesh_step = mesh_step
        self.none_reg = self.add_region('none', dim=-1)
        # centers of macro elements

        self.reg_to_group = {
        }  # bulk and fracture region id to coarse element id
        g2d = geom.Geometry2d("mesh_" + self.basename, self.regions,
                              bounding_polygon)
        for eid, (tele, tags, nodes) in coarse_mesh.elements.items():
            # eid = 319
            # (tele, tags, nodes) = coarse_mesh.elements[eid]
            #print("Geometry for eid: ", eid)
            if tele != 2:
                continue
            prefix = "el_{:03d}_".format(eid)
            outer_polygon = np.array(
                [coarse_mesh.nodes[nid][:2] for nid in nodes])
            # set mesh step to maximal height of the triangle
            area = np.linalg.norm(
                np.cross(outer_polygon[1] - outer_polygon[0],
                         outer_polygon[2] - outer_polygon[0]))

            self.mesh_step = min(
                self.mesh_step,
                area / np.linalg.norm(outer_polygon[1] - outer_polygon[0]))
            self.mesh_step = min(
                self.mesh_step,
                area / np.linalg.norm(outer_polygon[2] - outer_polygon[1]))
            self.mesh_step = min(
                self.mesh_step,
                area / np.linalg.norm(outer_polygon[0] - outer_polygon[2]))

            self.group_positions[eid] = np.mean(outer_polygon, axis=0)
            #edge_sizes = np.linalg.norm(outer_polygon[:, :] - np.roll(outer_polygon, -1, axis=0), axis=1)
            #diam = np.max(edge_sizes)

            bulk_reg = self.add_region(prefix + "bulk_2d_",
                                       dim=2,
                                       mesh_step=self.mesh_step)
            self.reg_to_group[bulk_reg.id] = eid
            # create regions
            # outer polygon
            normals = []
            shifts = []
            if eid == 1353:
                print("break")
            pd, side_regions = self.init_decomposition(outer_polygon,
                                                       bulk_reg,
                                                       tol=self.mesh_step *
                                                       0.8)
            for i_side, side_reg in enumerate(side_regions):
                side_reg.name = "." + prefix + side_reg.name[1:]
                side_reg.sub_reg.name = "." + prefix + side_reg.sub_reg.name[1:]
                self.reg_to_group[side_reg.id] = eid
                normals.append(side_reg.normal)
                shifts.append(side_reg.normal @ outer_polygon[i_side])
            self.side_regions.extend(side_regions)

            # extract fracture lines larger then the mesh step
            fracture_lines = self.fractures.get_lines(self.fr_range)
            line_candidates = {}
            for i_fr, (p0, p1) in fracture_lines.items():
                for n, d in zip(normals, shifts):
                    sgn0 = n @ p0 - d > 0
                    sgn1 = n @ p1 - d > 0
                    #print(sgn0, sgn1)
                    if sgn0 and sgn1:
                        break
                else:
                    line_candidates[i_fr] = (p0, p1)
                    #print("Add ", i_fr)
                #plot_decomp_segments(pd, [p0, p1])

            pd, fr_regions = self.add_fractures(pd, line_candidates, eid)
            for reg in fr_regions:
                reg.name = prefix + reg.name
                self.reg_to_group[reg.id] = eid
            if not self.skip_decomposition:
                g2d.add_compoud(pd)

        if self.skip_decomposition:
            self.mesh = gmsh_io.GmshIO()
            with open(mesh_file, "r") as f:
                self.mesh.read(f)
            return

        g2d.make_brep_geometry()
        step_range = (self.mesh_step * 0.9, self.mesh_step * 1.1)
        gmsh_executable = self.config_dict["gmsh_executable"]
        g2d.call_gmsh(gmsh_executable, step_range)
        self.mesh = g2d.modify_mesh()