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
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)
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)
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)
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])
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
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()