def update_values(self, intercomm_dictionary = {}): log_file = self.logger.handlers[0].baseFilename n_oct = self._n_oct o_ranges = self._mat.getOwnershipRange() b_bound = self._b_bound grid = self._proc_g # Upper bound octree's id contained. up_id_octree = o_ranges[0] + n_oct # Octree's ids contained. ids_octree_contained = range(o_ranges[0], up_id_octree) # Calling "allgather" to obtain data from the corresponding grid, # onto the intercommunicators created, not the intracommunicators. # http://www.mcs.anl.gov/research/projects/mpi/mpi-standard/mpi-report-1.1/node114.htm#Node117 # http://mpitutorial.com/tutorials/mpi-broadcast-and-collective-communication/ # http://www.linux-mag.com/id/1412/ for key, intercomm in intercomm_dictionary.items(): # Extending a list with the lists obtained by the other processes # of the corresponding intercommunicator. self._edg.extend(intercomm.allgather(self._edl)) self._res_g.extend(intercomm.allgather(self._res_l)) # Residual evaluation... for index, dictionary in enumerate(self._res_g): for center, solution_value in dictionary.items(): local_idx = self._octree.get_point_owner_idx(center) global_idx = local_idx + o_ranges[0] if global_idx in ids_octree_contained: center_cell_container = self._octree.get_center(local_idx)[:2] location = utilities.points_location(center, center_cell_container) neigh_centers, neigh_values = ([] for i in range(0, 2)) (neigh_centers, neigh_values) = self.find_right_neighbours(location , local_idx, o_ranges[0]) bilinear_value = utilities.bil_interp(center , neigh_centers, neigh_values) insert_mode = PETSc.InsertMode.INSERT_VALUES value = bilinear_value - solution_value self._res.setValue(global_idx, value , insert_mode) self._res.assemblyBegin() self._res.assemblyEnd() # "self.__temp_data_global" will be a list of same structures of data, # after the "allgather" call; these structures are dictionaries. for index, dictionary in enumerate(self._edg): for key, center in dictionary.items(): (x_center, y_center) = center into_background = True ghost_boundary = False if len(key) == 3: ghost_boundary = True # We are onto grids of the first level. if grid: local_idx = self._octree.get_point_owner_idx((x_center, y_center)) # We are onto the background grid. else: if key[2] == 0: x_center = x_center - key[3] if key[2] == 1: x_center = x_center + key[3] if key[2] == 2: y_center = y_center - key[3] if key[2] == 3: y_center = y_center + key[3] into_background = utilities.check_into_square((x_center, y_center) , b_bound , self.logger , log_file) if into_background: # The function "get_point_owner_idx" wants only one argument # so we are passing it a tuple. local_idx = self._octree.get_point_owner_idx((x_center, y_center)) # Is this "else" useful? For me no. else: local_idx = self._octree.get_point_owner_idx(center) global_idx = local_idx + o_ranges[0] if global_idx in ids_octree_contained: # Appending a tuple containing the grid number and # the corresponding octant index. if ghost_boundary: self._eil.append((key[0], key[1], key[2])) else: self._eil.append((key[0], key[1])) if into_background: center_cell_container = self._octree.get_center(local_idx)[:2] location = utilities.points_location((x_center, y_center), center_cell_container) neigh_centers, neigh_values = ([] for i in range(0, 2)) (neigh_centers, neigh_values) = self.find_right_neighbours(location , local_idx, o_ranges[0]) solution_value = utilities.bil_interp((x_center, y_center) , neigh_centers, neigh_values) else: solution_value = ExactSolution2D.ExactSolution2D.solution(x_center, y_center) self._evl.append(solution_value) # Updating data for each process into "self.__intra_extra_indices_global" # and "self.__intra_extra_values_global", calling "allgather" to obtain # data from the corresponding grid onto the intercommunicators created, # not the intracommunicators. for key, intercomm in intercomm_dictionary.items(): self._eig.extend(intercomm.allgather(self._eil)) self._evg.extend(intercomm.allgather(self._evl)) for index, values in enumerate(self._eig): for position, value in enumerate(values): # Check if the global index belong to the process. if value[1] in ids_octree_contained: # Check if we are onto the right grid. if value[0] == self._proc_g: intra_extra_value = self._evg[index][position] # Background grid. if grid == 0: insert_mode = PETSc.InsertMode.INSERT_VALUES # Here "insert_mode" does not affect nothing. if len(value) == 3: self._e_array_gb.setValue(value[1], intra_extra_value, insert_mode) else: self._e_array.setValue(value[1] , intra_extra_value, insert_mode) else: insert_mode = PETSc.InsertMode.ADD_VALUES self._e_array.setValue(value[1] , intra_extra_value, insert_mode) self._e_array.assemblyBegin() self._e_array.assemblyEnd() self._e_array_gb.assemblyBegin() self._e_array_gb.assemblyEnd() # Resetting structures used for the "allgather" functions. self.init_e_structures() self.logger.info("Updated inter_extra_array for comm \"" + str(self._comm.Get_name()) + "\" and rank \"" + str(self._comm.Get_rank()) + "\" of grid \"" + str(self._proc_g) + "\":\n" + str(self._e_array.getArray()))
def set_b_c(self): """Method to set boundary conditions for the current problem.""" penalization = self._pen log_file = self.logger.handlers[0].baseFilename b_bound = self._b_bound grid = self._proc_g n_oct = self._n_oct nfaces = glob.nfaces # \"getOwnershipRange()\" gives us the local ranges of the matrix owned # by the current process. o_ranges = self._mat.getOwnershipRange() h = self._h h2 = h * h is_background = False overlapping = self._over_l # If we are onto the grid \"0\", we are onto the background grid. if not grid: is_background = True b_indices, b_values = ([] for i in range(0, 2))# Boundary indices/values b_centers, b_faces = ([] for i in range(0, 2)) # Boundary centers/faces for octant in xrange(0, n_oct): # Global index of the current local octant \"octant\". g_octant = o_ranges[0] + octant py_oct = self._octree.get_octant(octant) center = self._octree.get_center(octant)[:2] for face in xrange(0, nfaces): # If we have an edge on the boundary. if self._octree.get_bound(py_oct, face): b_indices.append(g_octant) b_faces.append(face) b_centers.append(center) b_values = self.eval_b_c(b_centers, b_faces) b_values = b_values.tolist() if is_background: if overlapping: self.over_adds(b_centers, b_faces , b_values , b_indices) # Grids not of the background: equal to number >= 1. else: for i, center in enumerate(b_centers): # Check if foreground grid is inside the background one. check = utilities.check_into_square(center , b_bound , self.logger, log_file) if check: # Can't use list as dictionary's keys. # http://stackoverflow.com/questions/7257588/why-cant-i-use-a-list-as-a-dict-key-in-python # https://wiki.python.org/moin/DictionaryKeys key = (grid , # Grid (0 is for the background grid) b_indices[i], # Global index of the octant b_faces[i] , # Boundary face h) # Edge's length # We store the centers of the cells on the boundary. self._edl.update({key : center}) b_values[i] = self._e_array.getValue(b_indices[i]) # Residual evaluation... sol_value = self._sol.getValue(b_indices[i]) self._res_l.update({tuple(center) : sol_value}) dups = collections.defaultdict(list) for i, e in enumerate(b_indices): dups[e].append(i) # Popped elements. p_els = 0 for k, v in sorted(dups.iteritems()): if len(v) >= 2: for i in range(1, len(v)): b_indices.pop(v[i] - p_els) b_values.pop(v[i] - p_els) p_els = p_els + 1 b_values[:] = [b_value * (-1/h2) for b_value in b_values] insert_mode = PETSc.InsertMode.ADD_VALUES self._rhs.setValues(b_indices, b_values , insert_mode) # ATTENTION!! Non using these functions will give you an unassembled # vector PETSc. self._rhs.assemblyBegin() self._rhs.assemblyEnd() msg = "Set boundary conditions" extra_msg = "of grid \"" + str(self._proc_g) + "\"" self.log_msg(msg , "info", extra_msg)