def run(self, inputSetup): """Run a preprocessing task. :param obj inputSetup: inputSetup object. :return: None """ # --------------------------------------------------------------- # Obtain the MPI environment # --------------------------------------------------------------- parEnv = MPIEnvironment() # Start timer Timers()["Preprocessing"].start() # --------------------------------------------------------------- # Preprocessing (sequential task) # --------------------------------------------------------------- if (parEnv.rank == 0): # Parameters shortcut (for code legibility) model = inputSetup.model run = inputSetup.run output = inputSetup.output out_dir = output.get('directory_scratch') # Compute number of dofs per element basis_order = run.get('nord') num_dof_in_element = np.int(basis_order * (basis_order + 2) * (basis_order + 3) / 2) if (model.get('mode') == 'csem'): mode = 'csem' elif (model.get('mode') == 'mt'): mode = 'mt' # Get data model data_model = model.get(mode) # --------------------------------------------------------------- # Import mesh file # --------------------------------------------------------------- mesh_file = model.get('mesh') # Import mesh mesh = meshio.read(mesh_file) # Number of elements size = mesh.cells[0][1][:].shape nElems = size[0] # --------------------------------------------------------------- # Preprocessing nodal coordinates # --------------------------------------------------------------- Print.master(' Nodal coordinates') # Build coordinates in PETGEM format where each row # represent the xyz coordinates of the 4 tetrahedral element num_dimensions = 3 num_nodes_per_element = 4 data = mesh.points[mesh.cells[0][1][:], :] data = data.reshape(nElems, num_dimensions * num_nodes_per_element) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], data) # Build path to save the file out_path = out_dir + '/nodes.dat' # Write PETGEM nodes in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Remove temporal matrix del matrix # --------------------------------------------------------------- # Preprocessing mesh connectivity # --------------------------------------------------------------- Print.master(' Mesh connectivity') # Get matrix dimensions size = mesh.cells[0][1][:].shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], mesh.cells[0][1][:]) # Build path to save the file out_path = out_dir + '/meshConnectivity.dat' # Write PETGEM connectivity in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Remove temporal matrix del matrix # --------------------------------------------------------------- # Preprocessing edges connectivity # --------------------------------------------------------------- Print.master(' Edges connectivity') # Compute edges elemsE, edgesNodes = computeEdges(mesh.cells[0][1][:], nElems) nEdges = edgesNodes.shape[0] # Get matrix dimensions size = elemsE.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], elemsE) # Build path to save the file out_path = out_dir + '/edges.dat' # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Remove temporal matrix del matrix # Reshape edgesNodes and save num_nodes_per_edge = 2 num_edges_per_element = 6 data = np.array((edgesNodes[elemsE[:], :]), dtype=np.float) data = data.reshape(nElems, num_nodes_per_edge * num_edges_per_element) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], data) # Build path to save the file out_path = out_dir + '/edgesNodes.dat' # Write PETGEM edgesNodes in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Remove temporal matrix del matrix # --------------------------------------------------------------- # Preprocessing faces connectivity # --------------------------------------------------------------- Print.master(' Faces connectivity') # Compute faces elemsF, facesN = computeFaces(mesh.cells[0][1][:], nElems) nFaces = facesN.shape[0] # Get matrix dimensions size = elemsF.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], elemsF) # Build path to save the file out_path = out_dir + '/faces.dat' # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Remove temporal matrix del matrix # --------------------------------------------------------------- # Preprocessing faces-edges connectivity # --------------------------------------------------------------- Print.master(' Faces-edges connectivity') facesE = computeFacesEdges(elemsF, elemsE, nFaces, nElems) num_faces_per_element = 4 num_edges_per_face = 3 data = np.array((facesE[elemsF[:], :]), dtype=np.float) data = data.reshape(nElems, num_faces_per_element * num_edges_per_face) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], data) # Build path to save the file out_path = out_dir + '/facesEdges.dat' # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) del matrix # --------------------------------------------------------------- # Preprocessing dofs connectivity # --------------------------------------------------------------- Print.master(' DOFs connectivity') # Compute degrees of freedom connectivity basis_order = run.get('nord') dofs, dof_edges, dof_faces, _, total_num_dofs = computeConnectivityDOFS( elemsE, elemsF, basis_order) # Get matrix dimensions size = dofs.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], dofs) # Build path to save the file out_path = out_dir + '/dofs.dat' # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) del matrix # --------------------------------------------------------------- # Preprocessing sigma model # --------------------------------------------------------------- Print.master(' Conductivity model') i_model = data_model.get('sigma') if (run.get('conductivity_from_file')): # Open sigma file sigma_file = i_model.get('file') fileID = h5py.File(sigma_file, 'r') # Read sigma file conductivityModel = fileID.get('data')[()] else: # Get physical groups elemsS = mesh.cell_data['gmsh:physical'][0] elemsS -= np.int(1) # 0-based indexing # Get horizontal sigma horizontal_sigma = i_model.get('horizontal') vertical_sigma = i_model.get('vertical') # Allocate conductivity array conductivityModel = np.zeros((nElems, 2), dtype=np.float) for i in np.arange(nElems): # Set horizontal sigma conductivityModel[i, 0] = horizontal_sigma[np.int(elemsS[i])] # Set vertical sigma conductivityModel[i, 1] = vertical_sigma[np.int(elemsS[i])] # Get matrix dimensions size = conductivityModel.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], conductivityModel) # Build path to save the file out_path = out_dir + '/conductivityModel.dat' # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) del matrix # --------------------------------------------------------------- # Preprocessing boundaries # --------------------------------------------------------------- Print.master(' Boundaries') # Compute boundary faces bFacesN, bFaces, nbFaces = computeBoundaryFaces(elemsF, facesN) # Build array with boundary dofs for csem mode (dirichlet BC) if (mode == 'csem'): # Compute boundary edges bEdges = computeBoundaryEdges(edgesNodes, bFacesN) # Compute dofs on boundaries _, indx_boundary_dofs = computeBoundaries( dofs, dof_edges, dof_faces, bEdges, bFaces, basis_order) # Build PETSc structures vector = createSequentialVectorWithArray(indx_boundary_dofs) # Build path to save the file out_path = out_dir + '/boundaries.dat' # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) del vector elif (mode == 'mt'): # Compute to what plane the boundary face belongs planeFace = computeFacePlane(mesh.points, bFaces, bFacesN) # Compute boundary elements bElems, numbElems = computeBoundaryElements( elemsF, bFaces, nFaces) if (nbFaces != numbElems): Print.master( ' Number of boundary faces is not consistent.') exit(-1) # Allocate data_boundaries = np.zeros((nbFaces, 53 + num_dof_in_element), dtype=np.float) # Fill tmp matrix with data for boundary faces for i in np.arange(nbFaces): # Get index of tetrahedral element (boundary element) iEle = bElems[i] # Get dofs of element container dofsElement = dofs[iEle, :] # Get indexes of nodes for i-boundary element and insert nodesBoundaryElement = mesh.cells[0][1][iEle, :] data_boundaries[i, 0:4] = nodesBoundaryElement # Get nodes coordinates for i-boundary element and insert coordEle = mesh.points[nodesBoundaryElement, :] coordEle = coordEle.flatten() data_boundaries[i, 4:16] = coordEle # Get indexes of faces for i-boundary element and insert facesBoundaryElement = elemsF[iEle, :] data_boundaries[i, 16:20] = facesBoundaryElement # Get edges indexes for faces in i-boundary element and insert edgesBoundaryFace = facesE[facesBoundaryElement, :] edgesBoundaryFace = edgesBoundaryFace.flatten() data_boundaries[i, 20:32] = edgesBoundaryFace # Get indexes of edges for i-boundary and insert edgesBoundaryElement = elemsE[iEle, :] data_boundaries[i, 32:38] = edgesBoundaryElement # Get node indexes for edges in i-boundary and insert edgesNodesBoundaryElement = edgesNodes[ edgesBoundaryElement, :] edgesNodesBoundaryElement = edgesNodesBoundaryElement.flatten( ) data_boundaries[i, 38:50] = edgesNodesBoundaryElement # Get plane face ifacetype = planeFace[i] data_boundaries[i, 50] = ifacetype # Get global face index localFaceIndex = bFaces[i] data_boundaries[i, 51] = localFaceIndex # Get sigma value sigmaEle = conductivityModel[iEle, 0] data_boundaries[i, 52] = sigmaEle # Get dofs for boundary element and insert dofsBoundaryElement = dofsElement data_boundaries[i, 53::] = dofsBoundaryElement # Get matrix dimensions size = data_boundaries.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray( size[0], size[1], data_boundaries) # Build path to save the file out_path = out_dir + '/boundaryElements.dat' # Write PETGEM receivers in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) del matrix del data_boundaries # --------------------------------------------------------------- # Preprocessing receivers # --------------------------------------------------------------- Print.master(' Receivers') # Open receivers_file receivers_file = model.get('receivers') fileID = h5py.File(receivers_file, 'r') # Read receivers receivers = fileID.get('data')[()] # Number of receivers if receivers.ndim == 1: nReceivers = 1 else: dim = receivers.shape nReceivers = dim[0] # Find out which tetrahedral element source point is in (only for csem mode) if (mode == 'csem'): # Allocate vector to save source data data_source = np.zeros(50 + num_dof_in_element, dtype=np.float) i_model = data_model.get('source') # Get source position i_source_position = np.asarray(i_model.get('position'), dtype=np.float) # Build Delaunay triangulation with nodes tri = Delaunay(mesh.points) # Overwrite Delaunay structure with mesh_file connectivity and points tri.simplices = mesh.cells[0][1][:].astype(np.int32) tri.vertices = mesh.cells[0][1][:].astype(np.int32) srcElem = tri.find_simplex(i_source_position, bruteforce=True, tol=1.e-12) # If srcElem=-1, source not located if srcElem < 0: Print.master( ' Source no located in the computational domain. Please, verify source position or improve the mesh quality.' ) exit(-1) # Build data for source insertion # Get indexes of nodes for srcElem and insert nodesSource = mesh.cells[0][1][srcElem, :] data_source[0:4] = nodesSource # Get nodes coordinates for srcElem and insert coordSource = mesh.points[nodesSource, :] coordSource = coordSource.flatten() data_source[4:16] = coordSource # Get indexes of faces for srcElem and insert facesSource = elemsF[srcElem, :] data_source[16:20] = facesSource # Get edges indexes for faces in srcElem and insert edgesFace = facesE[facesSource, :] edgesFace = edgesFace.flatten() data_source[20:32] = edgesFace # Get indexes of edges for srcElem and insert edgesSource = elemsE[srcElem, :] data_source[32:38] = edgesSource # Get node indexes for edges in srcElem and insert edgesNodesSource = edgesNodes[edgesSource, :] edgesNodesSource = edgesNodesSource.flatten() data_source[38:50] = edgesNodesSource # Get dofs for srcElem and insert dofsSource = dofs[srcElem, :] data_source[50::] = dofsSource # Get matrix dimensions size = data_source.shape # Build PETSc structures vector = createSequentialVectorWithArray(data_source) # Build path to save the file out_path = out_dir + '/source.dat' # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) del vector # --------------------------------------------------------------- # Sparsity pattern # --------------------------------------------------------------- # Setup valence for each basis order (adding a small percentage to keep safe) valence = np.array([50, 200, 400, 800, 1400, 2500]) # Build nnz pattern for each row nnz = np.full((total_num_dofs), valence[basis_order - 1], dtype=np.int) # Build PETSc structures vector = createSequentialVectorWithArray(nnz) # Build path to save the file out_path = out_dir + '/nnz.dat' # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Print mesh statistics # --------------------------------------------------------------- Print.master(' ') Print.master(' Mesh statistics') Print.master(' Mesh file: {0:12}'.format( str(model.get('mesh')))) Print.master(' Number of elements: {0:12}'.format( str(nElems))) Print.master(' Number of faces: {0:12}'.format( str(nFaces))) Print.master(' Number of edges: {0:12}'.format( str(nEdges))) Print.master(' Number of dofs: {0:12}'.format( str(total_num_dofs))) if (mode == 'csem'): Print.master(' Number of boundaries: {0:12}'.format( str(len(indx_boundary_dofs)))) # --------------------------------------------------------------- # Print data model # --------------------------------------------------------------- Print.master(' ') Print.master(' Model data') Print.master(' Modeling mode: {0:12}'.format(str(mode))) i_sigma = data_model.get('sigma') if (run.get('conductivity_from_file')): Print.master(' Conductivity file: {0:12}'.format( i_sigma.get('file'))) else: Print.master(' Horizontal conductivity: {0:12}'.format( str(i_sigma.get('horizontal')))) Print.master(' Vertical conductivity: {0:12}'.format( str(i_sigma.get('vertical')))) if (mode == 'csem'): i_source = data_model.get('source') Print.master(' Source:') Print.master(' - Frequency (Hz): {0:12}'.format( str(i_source.get('frequency')))) Print.master(' - Position (xyz): {0:12}'.format( str(i_source.get('position')))) Print.master(' - Azimuth: {0:12}'.format( str(i_source.get('azimuth')))) Print.master(' - Dip: {0:12}'.format( str(i_source.get('dip')))) Print.master(' - Current: {0:12}'.format( str(i_source.get('current')))) Print.master(' - Length: {0:12}'.format( str(i_source.get('length')))) else: Print.master(' Frequency (Hz): {0:12}'.format( str(data_model.get('frequency')))) Print.master(' Polarization: {0:12}'.format( str(data_model.get('polarization')))) Print.master(' Vector basis order: {0:12}'.format( str(basis_order))) Print.master(' Receivers file: {0:12}'.format( str(model.get('receivers')))) Print.master(' Number of receivers: {0:12}'.format( str(nReceivers))) Print.master(' VTK output: {0:12}'.format( str(output.get('vtk')))) Print.master(' Cuda support: {0:12}'.format( str(run.get('cuda')))) Print.master(' Output directory: {0:12}'.format( str(output.get('directory')))) Print.master(' Scratch directory: {0:12}'.format( str(output.get('directory_scratch')))) # Stop timer Timers()["Preprocessing"].stop() # Apply barrier for MPI tasks alignement parEnv.comm.barrier() return
def create_alpha_mask(points, distance_limit, resolution_x=1000, resolution_y=1000, visualization=True): """ Creates interpolation grid, then masks over the alpha shape spanned up by points and defined by distance_limit. @params: points - Required : points spanning up alpha shape distance_limit - Required : distance threshold for removing Delaunay simplices resolution_x - Optional : resolution for grid in x, default is 1000 resolution_y - Optional : resolution for grid in y, default is 1000 visualization - Optional : boolean for visualizing result, default is False Returns: grid_mask : An array containing 1 for cells inside, and 0 for cells outside """ import numpy as np from scipy.spatial import Delaunay from matplotlib.collections import LineCollection import matplotlib.path as mplPath #---------------------------------------------------------------------- # Create Grid #---------------------------------------------------------------------- # Create meshgrid xi = np.transpose( np.linspace(min(points[:, 0]), max(points[:, 0]), resolution_x)) yi = np.transpose( np.linspace(min(points[:, 1]), max(points[:, 1]), resolution_y)) X, Y = np.meshgrid(xi, yi) # Reshape into vector gridpoints_x = np.reshape(X, resolution_x * resolution_y) gridpoints_y = np.reshape(Y, resolution_x * resolution_y) # Combine into gridpoints array gridpoints = np.transpose(np.asarray((gridpoints_x, gridpoints_y))) #---------------------------------------------------------------------- # Create Alpha Shape #---------------------------------------------------------------------- # Start Delaunay triangulation tri = Delaunay(points) # Auxiliary function for plotting, if required if visualization == True: import matplotlib.pyplot as plt edges = set() edge_points = [] def add_edge(i, j): """Add a line between the i-th and j-th points, if not in the list already""" if (i, j) in edges or (j, i) in edges: # already added return edges.add((i, j)) edge_points.append(points[[i, j]]) # Remove simplices outside of distance_limit simplex_flag = np.zeros(len(tri.simplices[:, 0])) # Flags bad simplices counter = 0 for ia, ib, ic in tri.vertices: # ia, ib, ic = indices of corner points of the triangle if np.sqrt((points[ia,0]-points[ib,0])**2+(points[ia,1]-points[ib,1])**2) < distance_limit and \ np.sqrt((points[ia,0]-points[ic,0])**2+(points[ia,1]-points[ic,1])**2) < distance_limit and \ np.sqrt((points[ib,0]-points[ic,0])**2+(points[ib,1]-points[ic,1])**2) < distance_limit: # do nothing simplex_flag[counter] = 0 else: # simplex has at least one side larger than threshold, flag it simplex_flag[counter] = 1 counter += 1 tri.simplices = tri.simplices[simplex_flag == 0, :] # Remove bad simplices tri.vertices = tri.vertices[simplex_flag == 0, :] # Remove bad simplices # Visualize, if requested if visualization == True: # Mark all remaining simplices for ia, ib, ic in tri.vertices: add_edge(ia, ib) add_edge(ib, ic) add_edge(ic, ia) # Draw them lines = LineCollection(edge_points) plt.figure() plt.gca().add_collection(lines) plt.plot(points[:, 0], points[:, 1], 'o') #---------------------------------------------------------------------- # Mask over Alpha Shape #---------------------------------------------------------------------- # Prepare point flag flag_gridpoints = np.zeros(len(gridpoints[:, 0]), dtype=np.int) # Evaluate gridpoints for sim in range(len(tri.simplices[:, 0])): # Print progress bar cv = sim mv = len(tri.simplices[:, 0]) - 1 print('\r%s |%s| %s%% %s' % ('Masking: ', '\033[33m' + '█' * int(50 * cv // mv) + '-' * (50 - int(50 * cv // mv)) + '\033[0m', ("{0:." + str(1) + "f}").format(100 * (cv / float(mv))), ' Complete'), end='\r') # Create simplex path bbPath = mplPath.Path( np.array([ points[tri.simplices[sim, 0], :], points[tri.simplices[sim, 1], :], points[tri.simplices[sim, 2], :], points[tri.simplices[sim, 0], :] ])) # Flag points that are inside this simplex for gridpts in range(len(gridpoints[:, 0])): if flag_gridpoints[ gridpts] == 0: # only process points not already allocated if bbPath.contains_point( (gridpoints[gridpts, 0], gridpoints[gridpts, 1])) == True: flag_gridpoints[gridpts] = 1 # Plot, if required if visualization == True: plt.scatter(gridpoints[flag_gridpoints == 1, 0], gridpoints[flag_gridpoints == 1, 1], color='g') plt.scatter(gridpoints[flag_gridpoints == 0, 0], gridpoints[flag_gridpoints == 0, 1], color='r') # Reshape flag_gridpoints into a 2D array global grid_mask grid_mask = np.reshape(flag_gridpoints, (resolution_y, resolution_x)) # Return result return grid_mask
# --------------------------------------------------------------- # Preprocessing receivers # --------------------------------------------------------------- Print.master(' Receivers') # Setup receivers receivers = np.vstack((inline, broadside)) # Number of receivers nReceivers = receivers.shape[0] # Build Delaunay triangulation with nodes tri = Delaunay(nodes) # Overwrite Delaunay structure with mesh_file connectivity and points tri.simplices = elemsN.astype(np.int32) tri.vertices = elemsN.astype(np.int32) # Find out which tetrahedral element points are in recvElems = tri.find_simplex(receivers, bruteforce=True, tol=1.e-12) # Determine if all receiver points were found idx = np.where(np.logical_or(recvElems > nElems, recvElems < 0))[0] # If idx is not empty, there are receivers outside the domain if idx.size != 0: Print.master( ' The following receivers were not located and will not be taken into account ' + str(idx)) # Update number of receivers nReceivers = nReceivers - len(idx)
def fieldInterpolator(solution_vector, nodes, elemsN, elemsE, edgesN, elemsF, facesE, dof_connectivity, points, inputSetup): """Interpolate electromagnetic field for a set of 3D points. :param ndarray-petsc solution_vector: vector field to be interpolated :param ndarray nodes: nodal coordinates :param ndarray elemsN: elements-node connectivity with dimensions = (number_elements, 4) :param ndarray elemsE: elements-edge connectivity with dimensions = (number_elements, 6) :param ndarray edgesN: edge-node connectivity with dimensions = (number_edges, 2) :param ndarray elemsF: element-faces connectivity with dimensions = (number_elements, 4) :param ndarray facesE: face-edges connectivity with dimensions = (number_faces, 3) :param ndarray dof_connectivity: local/global dofs list for elements, dofs index on edges, dofs index on faces, dofs index on volumes, total number of dofs :param ndarray points: point coordinates :param obj inputSetup: inputSetup object. :return: electromagnetic fields for a set of 3D points :rtype: ndarray and int """ # --------------------------------------------------------------- # Initialization # --------------------------------------------------------------- # Parameters shortcut (for code legibility) model = inputSetup.model run = inputSetup.run basis_order = run.get('nord') if (model.get('mode') == 'csem'): mode = 'csem' data_model = model.get(mode) # Get data model frequency = data_model.get('source').get('frequency') elif (model.get('mode') == 'mt'): mode = 'mt' data_model = model.get(mode) # Get data model frequency = data_model.get('frequency') omega = frequency * 2. * np.pi mu = 4. * np.pi * 1e-7 Const = np.sqrt(-1. + 0.j) * omega * mu # Number of elements size = elemsN.shape nElems = size[0] # Number of nodes #size = nodes.shape #nNodes = size[0] # Num dof per element num_dof_in_element = np.int(basis_order * (basis_order + 2) * (basis_order + 3) / 2) # Number of points if points.ndim == 1: nPoints = 1 else: dim = points.shape nPoints = dim[0] # Find where receivers are located tri = Delaunay(nodes) # Overwrite Delaunay structure with mesh_file connectivity and points tri.simplices = elemsN.astype(np.int32) tri.vertices = elemsN.astype(np.int32) # Find out which tetrahedral element points are in points_in_elements = tri.find_simplex(points, bruteforce=True, tol=1.e-12) # Determine if all points were found idx = np.where( np.logical_or(points_in_elements > nElems, points_in_elements < 0))[0] # If idx is not empty, there are points outside the domain if idx.size != 0: Print.master( ' The following receivers were not located and will not be taken into account ' + str(idx)) # Update number of receivers nPoints = nPoints - len(idx) if nPoints == 0: Print.master( ' No point has been found. Nothing to do. Aborting') exit(-1) # Remove idx from points matrix points = np.delete(points, idx, axis=0) # Remove idx from points_in_elements points_in_elements = np.delete(points_in_elements, idx, axis=0) indx_ele = points_in_elements # Allocate array fields = np.zeros((nPoints, 6), dtype=np.complex) # Interpolate electromagnetic field for all points for i in np.arange(nPoints): # Get element index iEle = indx_ele[i] # Get dofs of element container dofsEle = dof_connectivity[iEle, :] # Get receiver coordinates coordPoints = points[i, :] # Get indexes of nodes for iEle nodesEle = elemsN[iEle, :] # Get nodes coordinates for iEle coordEle = nodes[nodesEle, :] # Get indexes of faces for iEle facesEle = elemsF[iEle, :] # Get edges indexes for faces edgesFace = facesE[facesEle, :] # Get indexes of edges for iEle edgesEle = elemsE[iEle, :] # Get node indexes for edges in i and insert edgesNodesEle = edgesN[edgesEle, :] # Compute jacobian for iEle jacobian, invjacobian = computeJacobian(coordEle) # Compute global orientation for iEle edge_orientation, face_orientation = computeElementOrientation( edgesEle, nodesEle, edgesNodesEle, edgesFace) # Transform xyz source position to XiEtaZeta coordinates (reference tetrahedral element) XiEtaZeta = tetrahedronXYZToXiEtaZeta(coordEle, coordPoints) # Compute basis for i basis, curl_basis = computeBasisFunctions(edge_orientation, face_orientation, jacobian, invjacobian, basis_order, XiEtaZeta) # Get global dofs from x vector realField = np.real( solution_vector.getValues(dofsEle.astype(PETSc.IntType))) imagField = np.imag( solution_vector.getValues(dofsEle.astype(PETSc.IntType))) for j in np.arange(num_dof_in_element): # Exyz[k] = Exyz[k] + real_part*basis + imag_part*basis fields[i, 0] += realField[j] * basis[0, j] + np.sqrt( -1. + 0.j) * imagField[j] * basis[0, j] fields[i, 1] += realField[j] * basis[1, j] + np.sqrt( -1. + 0.j) * imagField[j] * basis[1, j] fields[i, 2] += realField[j] * basis[2, j] + np.sqrt( -1. + 0.j) * imagField[j] * basis[2, j] # Hxyz[k] = Hxyz[k] + real_part*curl_basis + imag_part*curl_basis fields[i, 3] += realField[j] * curl_basis[0, j] + np.sqrt( -1. + 0.j) * imagField[j] * curl_basis[0, j] fields[i, 4] += realField[j] * curl_basis[1, j] + np.sqrt( -1. + 0.j) * imagField[j] * curl_basis[1, j] fields[i, 5] += realField[j] * curl_basis[2, j] + np.sqrt( -1. + 0.j) * imagField[j] * curl_basis[2, j] # Following Maxwell equations, apply constant factor to compute magnetic field fields[:, 3::] /= Const return fields
def run(self, setup): """Run a preprocessing task. :param obj setup: inputSetup object. :return: None """ # --------------------------------------------------------------- # Initialization # --------------------------------------------------------------- # Start timer Timers()["Preprocessing"].start() # Parameters shortcut (for code legibility) model = setup.model output = setup.output # Obtain the MPI environment parEnv = MPIEnvironment() # --------------------------------------------------------------- # Import mesh file (gmsh format) # --------------------------------------------------------------- # Read nodes nodes, _ = readGmshNodes(model.mesh_file) # Read connectivity elemsN, nElems = readGmshConnectivity(model.mesh_file) # --------------------------------------------------------------- # Preprocessing nodal coordinates # --------------------------------------------------------------- Print.master(' Nodal coordinates') # Build coordinates in PETGEM format where each row # represent the xyz coordinates of the 4 tetrahedral element num_dimensions = 3 num_nodes_per_element = 4 data = np.array((nodes[elemsN[:], :]), dtype=np.float) data = data.reshape(nElems, num_dimensions*num_nodes_per_element) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], data) # Build path to save the file out_path = output.directory_scratch + '/nodes.dat' if parEnv.rank == 0: # Write PETGEM nodes in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing mesh connectivity # --------------------------------------------------------------- Print.master(' Mesh connectivity') # Get matrix dimensions size = elemsN.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], elemsN) # Build path to save the file out_path = output.directory_scratch + '/meshConnectivity.dat' if parEnv.rank == 0: # Write PETGEM connectivity in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing edges connectivity # --------------------------------------------------------------- Print.master(' Edges connectivity') # Compute edges elemsE, edgesNodes = computeEdges(elemsN, nElems) nEdges = edgesNodes.shape[0] # Get matrix dimensions size = elemsE.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], elemsE) # Build path to save the file out_path = output.directory_scratch + '/edges.dat' if parEnv.rank == 0: # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Reshape edgesNodes and save num_nodes_per_edge = 2 num_edges_per_element = 6 data = np.array((edgesNodes[elemsE[:], :]), dtype=np.float) data = data.reshape(nElems, num_nodes_per_edge*num_edges_per_element) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], data) # Build path to save the file out_path = output.directory_scratch + '/edgesNodes.dat' if parEnv.rank == 0: # Write PETGEM edgesNodes in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing faces connectivity # --------------------------------------------------------------- Print.master(' Faces connectivity') # Compute faces elemsF, facesN = computeFaces(elemsN, nElems) nFaces = facesN.shape[0] # Get matrix dimensions size = elemsF.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], elemsF) # Build path to save the file out_path = output.directory_scratch + '/faces.dat' if parEnv.rank == 0: # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing faces-edges connectivity # --------------------------------------------------------------- Print.master(' Faces-edges connectivity') N = invConnectivity(elemsF, nFaces) if nElems != 1: N = np.delete(N, 0, axis=1) # Allocate facesE = np.zeros((nFaces, 3), dtype=np.int) # Compute edges list for each face for i in np.arange(nFaces): iEle = N[i, 0] edgesEle = elemsE[iEle,:] facesEle = elemsF[iEle,:] kFace = np.where(facesEle == i)[0] if kFace == 0: # Face 1 facesE[facesEle[kFace],:] = [edgesEle[0], edgesEle[1], edgesEle[2]] elif kFace == 1: # Face 2 facesE[facesEle[kFace],:] = [edgesEle[0], edgesEle[4], edgesEle[3]] elif kFace == 2: # Face 3 facesE[facesEle[kFace],:] = [edgesEle[1], edgesEle[5], edgesEle[4]] elif kFace == 3: # Face 4 facesE[facesEle[kFace],:] = [edgesEle[2], edgesEle[5], edgesEle[3]] num_faces_per_element = 4 num_edges_per_face = 3 data = np.array((facesE[elemsF[:], :]), dtype=np.float) data = data.reshape(nElems, num_faces_per_element*num_edges_per_face) # Get matrix dimensions size = data.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], data) # Build path to save the file out_path = output.directory_scratch + '/facesEdges.dat' if parEnv.rank == 0: # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing dofs connectivity # --------------------------------------------------------------- Print.master(' DOFs connectivity') # Compute degrees of freedom connectivity dofs, dof_edges, dof_faces, _, total_num_dofs = computeConnectivityDOFS(elemsE,elemsF,model.basis_order) # Get matrix dimensions size = dofs.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], dofs) # Build path to save the file out_path = output.directory_scratch + '/dofs.dat' if parEnv.rank == 0: # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing boundaries # --------------------------------------------------------------- Print.master(' Boundaries') # Compute boundary faces bFacesN, bFaces = computeBoundaryFaces(elemsF, facesN) # Compute boundary edges bEdges = computeBoundaryEdges(edgesNodes, bFacesN) # Compute dofs on boundaries _, indx_boundary_dofs = computeBoundaries(dofs, dof_edges, dof_faces, bEdges, bFaces, model.basis_order); # Build PETSc structures vector = createSequentialVectorWithArray(indx_boundary_dofs) # Build path to save the file out_path = output.directory_scratch + '/boundaries.dat' if parEnv.rank == 0: # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing sigma model # --------------------------------------------------------------- Print.master(' Conductivity model') # Read element's tag elemsS, nElems = readGmshPhysicalGroups(model.mesh_file) # Build conductivity arrays conductivityModel = np.zeros((nElems, 2), dtype=np.float) for i in np.arange(nElems): # Set horizontal sigma conductivityModel[i, 0] = model.sigma_horizontal[np.int(elemsS[i])] # Set vertical sigma conductivityModel[i, 1] = model.sigma_vertical[np.int(elemsS[i])] # Get matrix dimensions size = conductivityModel.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], conductivityModel) # Build path to save the file out_path = output.directory_scratch + '/conductivityModel.dat' if parEnv.rank == 0: # Write PETGEM edges in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Preprocessing receivers # --------------------------------------------------------------- Print.master(' Receivers') # Open receivers_file fileID = h5py.File(model.receivers_file, 'r') # Read receivers receivers = fileID.get('data')[()] # Number of receivers if receivers.ndim == 1: nReceivers = 1 else: dim = receivers.shape nReceivers = dim[0] # Build Delaunay triangulation with nodes tri = Delaunay(nodes) # Overwrite Delaunay structure with mesh_file connectivity and points tri.simplices = elemsN.astype(np.int32) tri.vertices = elemsN.astype(np.int32) # Find out which tetrahedral element points are in recvElems = tri.find_simplex(receivers, bruteforce=True, tol=1.e-12) # Find out which tetrahedral element source point is in srcElem = tri.find_simplex(model.src_position, bruteforce=True, tol=1.e-12) # Determine if all receiver points were found idx = np.where(np.logical_or(recvElems>nElems, recvElems<0))[0] # If idx is not empty, there are receivers outside the domain if idx.size != 0: Print.master(' The following receivers were not located and will not be taken into account ' + str(idx)) # Update number of receivers nReceivers = nReceivers - len(idx) if nReceivers == 0: Print.master(' No receiver has been found. Nothing to do. Aborting') exit(-1) # Remove idx from receivers matrix receivers = np.delete(receivers, idx, axis=0) # Remove idx from recvElems recvElems = np.delete(recvElems, idx, axis=0) # If srcElem is empty, source not located if srcElem == 0: Print.master(' Source no located in the computational domain. Please, improve the mesh quality') exit(-1) # Compute number of dofs per element num_dof_in_element = np.int(model.basis_order*(model.basis_order+2)*(model.basis_order+3)/2) # Allocate data_receiver = np.zeros((nReceivers, 53+num_dof_in_element), dtype=np.float) # Fill tmp matrix with receiver positions, element coordinates and # nodal indexes for i in np.arange(nReceivers): # If there is one receiver if nReceivers == 1: # Get index of tetrahedral element (receiver container) iEle = recvElems # Get dofs of element container dofsElement = dofs[iEle] # If there are more than one receivers else: # Get index of tetrahedral element (receiver container) iEle = recvElems[i] # Get dofs of element container dofsElement = dofs[iEle, :] # Get indexes of nodes for iand insert nodesReceiver = elemsN[iEle, :] data_receiver[i, 0:4] = nodesReceiver # Get nodes coordinates for i and insert coordEle = nodes[nodesReceiver, :] coordEle = coordEle.flatten() data_receiver[i, 4:16] = coordEle # Get indexes of faces for i and insert facesReceiver = elemsF[iEle, :] data_receiver[i, 16:20] = facesReceiver # Get edges indexes for faces in i and insert edgesReceiver = facesE[facesReceiver, :] edgesReceiver = edgesReceiver.flatten() data_receiver[i, 20:32] = edgesReceiver # Get indexes of edges for i and insert edgesReceiver = elemsE[iEle, :] data_receiver[i, 32:38] = edgesReceiver # Get node indexes for edges in i and insert edgesNodesReceiver = edgesNodes[edgesReceiver, :] edgesNodesReceiver = edgesNodesReceiver.flatten() data_receiver[i, 38:50] = edgesNodesReceiver # Get receiver coordinates coordReceiver = receivers[i,: ] data_receiver[i, 50:53] = coordReceiver # Get dofs for srcElem and insert dofsReceiver = dofsElement data_receiver[i, 53::] = dofsReceiver # Get matrix dimensions size = data_receiver.shape # Build PETSc structures matrix = createSequentialDenseMatrixWithArray(size[0], size[1], data_receiver) # Build path to save the file out_path = output.directory_scratch + '/receivers.dat' if parEnv.rank == 0: # Write PETGEM receivers in PETSc format writeParallelDenseMatrix(out_path, matrix, communicator=PETSc.COMM_SELF) # Compute number of dofs per element num_dof_in_element = np.int(model.basis_order*(model.basis_order+2)*(model.basis_order+3)/2) # Build data for source insertion vector = np.zeros(50+num_dof_in_element, dtype=np.float) # Get indexes of nodes for srcElem and insert nodesSource = elemsN[srcElem, :] vector[0:4] = nodesSource # Get nodes coordinates for srcElem and insert coordSource = nodes[nodesSource, :] coordSource = coordSource.flatten() vector[4:16] = coordSource # Get indexes of faces for srcElem and insert facesSource = elemsF[srcElem, :] vector[16:20] = facesSource # Get edges indexes for faces in srcElem and insert edgesFace = facesE[facesSource, :] edgesFace = edgesFace.flatten() vector[20:32] = edgesFace # Get indexes of edges for srcElem and insert edgesSource = elemsE[srcElem, :] vector[32:38] = edgesSource # Get node indexes for edges in srcElem and insert edgesNodesSource = edgesNodes[edgesSource, :] edgesNodesSource = edgesNodesSource.flatten() vector[38:50] = edgesNodesSource # Get dofs for srcElem and insert dofsSource = dofs[srcElem,:] vector[50::] = dofsSource # Build PETSc structures vector = createSequentialVectorWithArray(vector) # Build path to save the file out_path = output.directory_scratch + '/source.dat' if parEnv.rank == 0: # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Sparsity pattern # --------------------------------------------------------------- # Setup valence for each basis order (adding a small percentage to keep safe) valence = np.array([50, 200, 400, 800, 1400, 2500]) # Build nnz pattern for each row nnz = np.full((total_num_dofs), valence[model.basis_order-1], dtype=np.int) # Build PETSc structures vector = createSequentialVectorWithArray(nnz) # Build path to save the file out_path = output.directory_scratch + '/nnz.dat' if parEnv.rank == 0: # Write PETGEM nodes in PETSc format writePetscVector(out_path, vector, communicator=PETSc.COMM_SELF) # --------------------------------------------------------------- # Print mesh statistics # --------------------------------------------------------------- Print.master(' ') Print.master(' Mesh statistics') Print.master(' Number of elements: {0:12}'.format(str(nElems))) Print.master(' Number of faces: {0:12}'.format(str(nFaces))) Print.master(' Number of edges: {0:12}'.format(str(nEdges))) Print.master(' Number of dofs: {0:12}'.format(str(total_num_dofs))) Print.master(' Number of boundaries: {0:12}'.format(str(len(indx_boundary_dofs)))) # --------------------------------------------------------------- # Print data model # --------------------------------------------------------------- Print.master(' ') Print.master(' Model data') Print.master(' Number of materials: {0:12}'.format(str(np.max(elemsS)+1))) Print.master(' Vector basis order: {0:12}'.format(str(model.basis_order))) Print.master(' Frequency (Hz): {0:12}'.format(str(model.frequency))) Print.master(' Source position (xyz): {0:12}'.format(str(model.src_position))) Print.master(' Source azimuth: {0:12}'.format(str(model.src_azimuth))) Print.master(' Source dip: {0:12}'.format(str(model.src_dip))) Print.master(' Source current: {0:12}'.format(str(model.src_current))) Print.master(' Source length: {0:12}'.format(str(model.src_length))) Print.master(' Sigma horizontal: {0:12}'.format(str(model.sigma_horizontal))) Print.master(' Sigma vertical: {0:12}'.format(str(model.sigma_vertical))) Print.master(' Number of receivers: {0:12}'.format(str(nReceivers))) # Apply barrier for MPI tasks alignement parEnv.comm.barrier() # Stop timer Timers()["Preprocessing"].stop()