def is_respected(self, comp: AbstractComponent, comp_port_id: int, ngbr: AbstractComponent, ngbr_port_id: int, field: Field) -> bool: flag = True wait_policy: List[List[int]] = ngbr.get_wait_policy(ngbr_port_id) if (wait_policy): if (self._stack.get(ngbr) is None): self._stack[ngbr] = ([ngbr_port_id], [field]) else: self._stack[ngbr][0].append(ngbr_port_id) self._stack[ngbr][1].append(field) # If more than one policy matches, take the first one flag = False i = 0 while (i < len(wait_policy) and not flag): port_count: List[int] = [ self._stack[ngbr][0].count(wait_port) for wait_port in wait_policy[i] ] if (0 not in port_count): flag = True self._stack_policy[ngbr] = wait_policy[i] i += 1 if (not flag): util.print_terminal( "Signal is waiting for fields " "arriving at other ports.", '') return flag
def _respect_waiting(self, comp: AbstractComponent, neighbor: AbstractComponent, port: int, field: Field, input_port: int) -> bool: flag = True wait_policy: List[List[int]] = neighbor.get_wait_policy(input_port) if (wait_policy): if (self._stack_waiting.get(neighbor) is None): self._stack_waiting[neighbor] = ([input_port], [field]) else: self._stack_waiting[neighbor][0].append(input_port) self._stack_waiting[neighbor][1].append(field) # If more than one policy matches, take the first one flag = False i = 0 while (i < len(wait_policy) and not flag): port_count = [ self._stack_waiting[neighbor][0].count(wait_port) for wait_port in wait_policy[i] ] if (0 not in port_count): flag = True self._stack_wait_policy[neighbor] = wait_policy[i] i += 1 if (not flag): util.print_terminal( "Signal is waiting for fields " "arriving at other ports.", '') return flag
def __str__(self) -> str: util.print_terminal("State of component '{}':".format(self.name)) for i in range(self._nbr_ports): print(self._ports[i]) return str()
def _print_computation_state(self, elapsed_time: float) -> None: str_to_print = ("Solved method(s) {} ({} steps) ".format( self._methods[0], self._steps[0])) for i in range(1, len(self._methods)): str_to_print += "and {} ({} steps) ".format( self._methods[i], self._steps[i]) str_to_print += "for {} km length in {} s".format( self._length, str(elapsed_time)) util.print_terminal(str_to_print, '')
def plot_graph(fig, resolution, fig_title, filename): if (fig_title is not None): fig.suptitle(fig_title, fontsize=16) fig.tight_layout() # Avoiding overlapping texts (legend) fig.set_size_inches(resolution[0]/fig.dpi, resolution[1]/fig.dpi) if (filename != ""): fig.savefig(filename, bbox_inches='tight') util.print_terminal("Graph has been saved on filename '{}'" .format(filename)) else: plt.show()
def __str__(self): if (self._comps): util.print_terminal("Structure of layout '{}':".format(self.name)) for comp in self._comps: for port_nbr in range(len(comp)): if (comp.get_neighbor(port_nbr) is not None): comp.print_port_state(port_nbr) else: util.print_terminal("Layout '{}' is empty".format(self.name)) return str()
def __str__(self): if (self._comps): util.print_terminal("Structure of layout '{}':".format(self.name)) for comp in self._comps: for port in comp: if (not port.is_free()): print(port) else: util.print_terminal("Layout '{}' is empty".format(self.name)) return str()
def _respect_coprop(self, comp: AbstractComponent, neighbor: AbstractComponent, port: int, field: Field, input_port: int) -> bool: """Check if need to wait for other copropagating fields.""" flag = True if (self._stack_coprop.get((comp, port)) is not None): self._stack_coprop[(comp, port)][1][0] -= 1 if (self._stack_coprop[(comp, port)][1][0] > 0): flag = False util.print_terminal("Signal is waiting for copropagating " "fields.", '') return flag
def is_respected(self, comp: AbstractComponent, comp_port_id: int, ngbr: AbstractComponent, ngbr_port_id: int, field: Field) -> bool: flag = True comp_port: Port = comp[comp_port_id] if (self._stack.get(comp_port) is not None): self._stack[comp_port][1][0] -= 1 if (self._stack[comp_port][1][0] > 0): flag = False util.print_terminal( "Signal is waiting for copropagating " "fields.", '') return flag
def _shooting_method(self, waves: Array[cst.NPFT], solvers: List[Solver], eqs: List[AbstractEquation], steps: int, step_method: STEP_METHOD_TYPE) -> Array[cst.NPFT]: # N.B.: take last equation to get criterion by defaults # -> need to handle different cases that might pop up def apply_ic(eqs, waves_init, end): res = np.zeros_like(waves_init) for eq in eqs: res = eq.initial_condition(waves_init, end) return res error_bound = self._error # First iteration for co-prop or counter prop scheme if (self._start_shooting_forward): waves_f = apply_ic(eqs, waves, False) waves_f = step_method(waves_f, solvers, steps, True, 1) else: waves_b = apply_ic(eqs, waves, True) waves_b = step_method(waves_b, solvers, steps, False, -2) waves_f = apply_ic(eqs, waves, False) waves_f = step_method(waves_f, solvers, steps, True, 1) # Start loop till convergence criterion is met cached_criterion = 0.0 error = error_bound * 1e10 while (error > error_bound): waves_f_back_up = waves_f waves_b = apply_ic(eqs, waves_f, True) waves_b = step_method(waves_b, solvers, steps, False, -2) waves_f = apply_ic(eqs, waves_b, False) waves_f = step_method(waves_f, solvers, steps, True, 1) new_cached_criterion = eqs[-1].get_criterion(waves_f, waves_b) old_error = error error = abs(cached_criterion - new_cached_criterion) util.print_terminal( "Shooting method is running and got error = {}".format(error), '') cached_criterion = new_cached_criterion if (old_error < error): util.warning_terminal( "Shooting method stopped before " "reaching error bound value as error is increasing.") error = 0.0 waves_f = waves_f_back_up return waves_f
def method_wrapper(self, *args, **kwargs): back_up_residual: float = self.residual res: bool = has_converged(self, *args, **kwargs) # Stop if divergence not accepted if (self._crt_iter and self.residual > back_up_residual): util.warning_terminal("Divergent method !") if (self.stop_if_divergent): res = True self._crt_iter += 1 # Stop if the maximum nbr of steps is reached if (not res and self._crt_iter >= self._max_nbr_iter): util.print_terminal("Maximum number of iterations reached.", '') res = True if (res): self.reset() return res
def __call__(self, domain: Domain, ports: List[int], fields: List[Field]) -> Tuple[List[int], List[Field]]: if (os.path.isfile(self._full_path_to_file) and self.add_fields): with open(self._full_path_to_file, 'ab') as file_container: pickle.dump(fields, file_container) util.print_terminal( "{} field(s) added to existing file '{}'.".format( len(fields), self.file_name)) else: with open(self._full_path_to_file, 'wb') as file_container: pickle.dump(fields, file_container) util.print_terminal( "{} field(s) added in new file '{}'.".format( len(fields), self.file_name)) return self.output_ports(ports), []
def _init_propagation(self, comp: AbstractComponent, output_port: int, output_field: Field) -> None: """Propagate one Field""" # Recording field ---------------------------------------------- if (comp.save or (comp in self._leaf_comps)): comp[output_port].save_field(output_field) # Propagate output_field to neighbors of comp ------------------ neighbor: Optional[AbstractPassComp] = None potential_neighbor = comp[output_port].ngbr_comp if (isinstance(potential_neighbor, AbstractPassComp)): # no starter neighbor = potential_neighbor if (neighbor is not None): input_port_neighbor = comp[output_port].ngbr_port if (not neighbor[input_port_neighbor].is_unidir()): if (neighbor.save): # Recording field neighbor[input_port_neighbor].save_field(output_field) # Valid propagation management ----------------------------- util.print_terminal( "Component '{}' has sent a signal from " "port {} to port {} of component '{}'.".format( comp.name, output_port, input_port_neighbor, neighbor.name)) input_ports_neighbor, output_fields = \ self._comply_with_constraints(comp, neighbor, output_port, output_field, input_port_neighbor) if (output_fields): # Constraints respected if (self._check_field_time_overlap(output_fields)): # Make sure time windows overlap if >1 field field_time_data = self._match_field_time(output_fields) # Send the fields into the component output_ports_neighbor, output_fields_neighbor =\ neighbor(self.domain, input_ports_neighbor, output_fields) # Reset original time window self._reset_field_time(output_fields, field_time_data) # Recursive function self._propagate(neighbor, output_ports_neighbor, output_fields_neighbor) else: # Time window of output_fields not overlapping util.warning_terminal( "Fields can not be accepted at " "the entrance of component '{}' as their time " "windows are not overlapping.".format( neighbor.name), '')
def _add_edge(self, comp_1: AbstractComponent, port_comp_1: int, comp_2: AbstractComponent, port_comp_2: int, unidir: bool = False) -> None: """Add a new edge in the Layout The edge can be either unidirectionnal or bidirectionnal. In case of bidirectionnal edge, only the first component is linked to the second one. Parameters ---------- comp_1 : AbstractComponent The first component of the edge. port_comp_1 : The port of the first component. comp_2 : AbstractComponent The second component of the edge. port_comp_2 : The port of the second component. unidir : If True, unidirectionnal link. """ # Adding new edge ---------------------------------------------- if (comp_1.is_port_free(port_comp_1) and comp_2.is_port_free(port_comp_2) and comp_1 != comp_2): self.add_comp(comp_1) self.add_comp(comp_2) comp_1.link_to(port_comp_1, comp_2, port_comp_2) if (unidir): # Undirected edge comp_2.link_to(port_comp_2, comp_1, cst.UNIDIR_PORT) else: # Directed edge comp_2.link_to(port_comp_2, comp_1, port_comp_1) # Edge can not be added ---------------------------------------- else: util.warning_terminal("Linking of component '{}' and component " "'{}' has encountered a problem, action aborted:" .format(comp_1.name, comp_2.name)) if (comp_1 == comp_2): util.print_terminal("Component '{}' can not be linked to " "itself".format(comp_1.name), '') else: comp_1.print_port_state(port_comp_1) comp_2.print_port_state(port_comp_2)
def _add_edge(self, port_1: Port, port_2: Port, unidir: bool = False) -> None: """Add a new edge in the Layout The edge can be either unidirectionnal or bidirectionnal. In case of unidirectionnal edge, only the first component is linked to the second one. Parameters ---------- port_1 : Port The first port of the edge. port_2 : Port The second port of the edge. unidir : If True, unidirectionnal link. """ # Adding new edge ---------------------------------------------- free_ports = port_1.is_free() and port_2.is_free() if (free_ports and port_1.comp != port_2.comp): self.add_comp(port_1.comp) self.add_comp(port_2.comp) port_1.link_to(port_2) if (unidir): # Undirected edge port_2.link_unidir_to(port_1) else: # Directed edge port_2.link_to(port_1) # Edge can not be added ---------------------------------------- else: util.warning_terminal( "Linking of component '{}' and component " "'{}' has encountered a problem, action aborted:".format( port_1.comp.name, port_2.comp.name)) if (port_1.comp == port_2.comp): util.print_terminal( "Component '{}' can not be linked to " "itself".format(port_1.comp.name), '') else: print(port_1) print(port_2)
def print_port_state(self, port_nbr: int) -> None: if (self.is_port_valid(port_nbr)): port_ = self._ports[port_nbr] if (port_ is None): util.print_terminal("Port {} of component '{}' is free." .format(port_nbr, self.name), '') else: if (port_[1] != cst.UNIDIR_PORT): util.print_terminal("Port {} of component '{}' is linked " "to port {} of component '{}'." .format(port_nbr, self.name, port_[1], port_[0].name), '') else: util.print_terminal("Port {} of component '{}' has an " "unidirectionnaly link from component '{}'." .format(port_nbr, self.name, port_[0].name), '')
def __str__(self) -> str: if (self._ngbr_comp is None): util.print_terminal( "Port {} of component '{}' is free.".format( self._port, self._comp.name), '') else: if (self._unidir): util.print_terminal( "Port {} of component '{}' has an " "unidirectionnal link from component '{}'.".format( self._port, self._comp.name, self._ngbr_comp.name), '') else: util.print_terminal( "Port {} of component '{}' is linked " "to port {} of component '{}'.".format( self._port, self._comp.name, self._ngbr_port, self._ngbr_comp.name), '') return str()
def _shooting_method( self, waves: np.ndarray, noises: np.ndarray, solvers: List[AbstractSolver], noise_solvers: List[Optional[AbstractSolver]], eqs: List[SOLVER_CALLABLE_TYPE], steps: int, step_method: STEP_METHOD_TYPE) -> Tuple[np.ndarray, np.ndarray]: """Run the shooting algorithm.""" if ((self._boundary_cond is not None) and (self._conv_checker is not None)): # Aliases for cleaner code forward = lambda waves, noises: self._forward_method( waves, noises, solvers, noise_solvers, eqs, steps, step_method, True) backward = lambda waves, noises: self._backward_method( waves, noises, solvers, noise_solvers, eqs, steps, step_method, True) apply_cond = lambda waves, noises, fiber_end:\ self._boundary_cond.apply_cond(waves, noises, fiber_end) get_input = lambda waves, noises, fiber_end:\ self._boundary_cond.get_input(waves, noises, fiber_end) get_output = lambda waves, waves_, noises, noises_:\ self._boundary_cond.get_output(waves, waves_, noises, noises_) has_converged = lambda waves, waves_, noises, noises_:\ self._conv_checker.has_converged(np.vstack((waves, waves_)), np.vstack((noises, noises_))) converged: bool = False first_iter: bool = True waves_b: np.ndarray # Backward propagating waves waves_f: np.ndarray # Forward propagating waves noises_b: np.ndarray # Backward propagating noises noises_f: np.ndarray # Forward propagating noises # Start loop till convergence criterion is met while (not converged): if (first_iter): waves_b, noises_b = get_input(waves, noises, True) first_iter = False else: waves_b, noises_b = apply_cond(waves_f, noises_f, True) waves_b, noises_b = backward(waves_b, noises_b) waves_f, noises_f = apply_cond(waves_b, noises_b, False) waves_f, noises_f = forward(waves_f, noises_f) converged = has_converged(waves_f, waves_b, noises_f, noises_b) util.print_terminal( "Shooting method is running and got " "residual = {}".format(self._conv_checker.residual), '') waves, noises = get_output(waves_f, waves_b, noises_f, noises_b) # Save channels and noises to storage if required if (self.save_all and self._channels.size): channels_f = self._channels[:(len(self._channels) // 2)] channels_b = self._channels[(len(self._channels) // 2):] noises_f = self._noises[:(len(self._noises) // 2)] noises_b = self._noises[(len(self._noises) // 2):] self._channels, self._noises = get_output( channels_f, channels_b, noises_f, noises_b) else: raise MissingInfoError( "Boundary condition and convergence " "checker must be provided for running shooting method.") return waves, noises
def animation2d(x_datas: np.ndarray, y_datas: np.ndarray, z_datas: Optional[np.ndarray] = None, x_label: Optional[str] = None, y_label: Optional[str] = None, x_range: Optional[Tuple[float, float]] = None, y_range: Optional[Tuple[float, float]] = None, line_styles: List[str] = ['-'], line_widths: List[float] = [1.], line_labels: Optional[List[Optional[str]]] = None, line_colors: Optional[List[str]] = None, line_opacities: List[float] = [0.2], plot_title: Optional[str] = None, fig_title: Optional[str] = None, filename: str = "", resolution: Tuple[float, float] = (1920., 1080.), interval: float = 100., repeat: bool = True, repeat_delay: float = 1000.) -> None: """Plot an 2D animation. Parameters ---------- x_datas : The data on the x axis. y_datas : The data on the y axis. z_datas : The data on the z axis, will be display as text x_label : The labels for each axis along the x axis. y_label : The labels for each axis along the y axis. x_range : The ranges for each axis along the x axis. y_range : The ranges for each axis along the y axis. line_styles : The linestyle of the line. line_widths : The linewidth of the line. line_labels : The labels for each line. line_colors : The color of each line. line_opacities : The opacity of each line. plot_title : The title of the animation. fig_title : The figure title. filename : The filename where to save the animation. If provided, the animation will be saved. resolution : The resolution with which to save the animation. interval : The interval in between each frame. repeat : Either to repeat the animation when it is displayed. repeat_delay : The delay in between each repetition. """ # N.B. if y_datas comes from field, np.ndarray is multidim # Initializing ----------------------------------------------------- fig = plt.gcf() ax = plt.axes() # Managing x and y labels ------------------------------------------ x_label_: Optional[str] x_label_ = check_axis_labels([x_label], axis_labels)[0] y_label_: Optional[str] y_label_ = check_axis_labels([y_label], axis_labels)[0] if (x_label_ is not None): plt.xlabel(x_label_) if (y_label_ is not None): plt.ylabel(y_label_) # Plot title ------------------------------------------------------- if (plot_title is not None): plt.title(plot_title) # Padding ---------------------------------------------------------- nbr_channels: int = 1 nbr_images: int = 1 y_datas_: np.ndarray x_datas_: np.ndarray if (y_datas.ndim == 3): # (channels, image, y_data) nbr_channels = y_datas.shape[0] nbr_images = y_datas.shape[1] if (x_datas.ndim < 2): x_datas_ = util.vstack_ndarray(np.array([x_datas]), nbr_images) x_datas_ = util.vstack_ndarray(np.array([x_datas_]), nbr_channels) elif (x_datas.ndim < 3): x_datas_ = util.vstack_ndarray(x_datas, nbr_images) x_datas_ = util.vstack_ndarray(np.array([x_datas_]), nbr_channels) else: # Should be ndim = 3 if (nbr_channels > x_datas.shape[0]): x_datas_ = util.vstack_ndarray([x_datas_], nbr_channels) else: x_datas_ = x_datas y_datas_ = y_datas elif (y_datas.ndim == 2): # (image, y_data) nbr_images = y_datas.shape[0] if (x_datas.ndim < 2): x_datas_ = util.vstack_ndarray(np.array([x_datas]), nbr_images) else: if (nbr_images > x_datas.shape[0]): x_datas_ = util.vstack_ndarray(x_datas, len(y_datas)) else: x_datas_ = x_datas y_datas_ = y_datas x_datas_ = np.array([x_datas_]) y_datas_ = np.array([y_datas_]) else: util.warning_terminal( "The y_datas must be at least two dimensional, " "shape can be (image, y_data) or (channels, image, y_data)") return None # Lines charact. management ---------------------------------------- line_styles = util.make_list(line_styles, nbr_channels) line_widths = util.make_list(line_widths, nbr_channels) line_opacities = util.make_list(line_opacities, nbr_channels) # Lables management ------------------------------------------------ line_labels = util.make_list(line_labels, nbr_channels, '') line_labels_: List[str] = [] if (line_labels is not None): for i in range(nbr_channels): crt_line_label = line_labels[i] if (crt_line_label is None or crt_line_label == ''): line_labels_.append("channel {}".format(i)) else: line_labels_.append(crt_line_label + " (ch.{})".format(i)) # Colors management ------------------------------------------------ if (line_colors is not None): line_colors_ = line_colors else: line_colors_ = linecolors # Line2D creation -------------------------------------------------- lines = [] for i in range(nbr_channels): line = ax.plot([], [], c=line_colors_[i % len(line_colors_)], ls=line_styles[i], label=line_labels_[i], lw=line_widths[i])[0] lines.append(line) plt.ticklabel_format(axis='both', style='sci', scilimits=(-2, 2)) if (line_labels is not None): plt.legend(loc="best") min_y = 0. max_y = 0. if (y_range is None): max_y = np.amax(y_datas_) max_y = max_y + 0.2 * max_y ax.set_ylim(0., max_y) else: max_y = y_range[1] ax.set_ylim(y_range[0], max_y) # Animation creation ----------------------------------------------- text_plot = [ax.text(0., 0., '', style='italic', fontsize=10)] fill_lines = [] for j, line in enumerate(lines): fill_lines.append(ax.fill_between([], [])) def update(i): mins: List[float] = [] maxs: List[float] = [] for j, line in enumerate(lines): # Browsing channels -> plots fill_lines[j].remove() line.set_data(x_datas_[j][i], y_datas_[j][i]) facecolor = line_colors_[j % len(line_colors_)] fill_lines[j] = ax.fill_between(x_datas_[j][i], y_datas_[j][i], alpha=line_opacities[j], facecolor=facecolor) mins.append(x_datas_[j][i][0]) maxs.append(x_datas_[j][i][-1]) if (x_range is None): min_x = min(mins) max_x = max(maxs) ax.set_xlim(min_x, max_x) else: min_x = x_range[0] max_x = x_range[1] ax.set_xlim(x_range[0], x_range[1]) if (z_datas is not None): x_pos = max_x - (max_x - min_x) * 0.1 y_pos = min_y + (max_y - min_y) * 0.1 text_plot[0].set_position((x_pos, y_pos)) text_plot[0].set_text("z = {} km".format(str(z_datas[i]))) return lines def init(): for line in lines: line.set_data([], []) return lines ani = animation.FuncAnimation(fig, update, frames=nbr_images, interval=interval, repeat=repeat, repeat_delay=repeat_delay, init_func=init) # Plotting / saving ------------------------------------------------ if (fig_title is not None): fig.suptitle(fig_title, fontsize=16) fig.tight_layout() # Avoiding overlapping texts (legend) fig.set_size_inches(resolution[0] / fig.dpi, resolution[1] / fig.dpi) if (filename != ""): ani.save(filename) util.print_terminal( "Graph has been saved on filename '{}'".format(filename)) fig.clf() else: plt.show()
def plot(x_datas: List[Array[float]], y_datas: List[Array[float]], x_labels: Optional[List[str]] = None, y_labels: Optional[List[str]] = None, x_ranges: Optional[List[float]] = None, y_ranges: Optional[List[float]] = None, plot_linestyles: List[str] = ['-'], plot_labels: List[Optional[Union[str, List[str]]]] = [None], plot_titles: Optional[List[str]] = None, plot_colors: Optional[List[str]] = None, plot_groups: Optional[List[int]] = None, split: Optional[bool] = None, opacity: float = 0.2, fig_title: Optional[str] = None, filename: str = ""): # N.B. if y_datas comes from field, np.ndarray is multidim # initializing ----------------------------------------------------- plt.clf() # Managing x and y labels ------------------------------------------ x_labels = check_xy_labels(x_labels, xy_labels) y_labels = check_xy_labels(y_labels, xy_labels) # Padding ---------------------------------------------------------- y_datas = util.make_list(y_datas) x_datas = util.make_list(x_datas, len(y_datas)) if (len(y_datas) < len(x_datas)): util.warning_terminal( "The number of y data must be equal or greater " "than the number of x data, graph creation aborted.") return None #x_datas, y_datas = util.pad_list_with_last_elem(x_datas, y_datas, True) x_labels = util.make_list(x_labels, len(x_datas)) y_labels = util.make_list(y_labels, len(y_datas)) x_ranges = util.make_list(x_ranges, len(x_datas)) y_ranges = util.make_list(y_ranges, len(y_datas)) plot_labels = util.make_list(plot_labels, len(x_datas)) plot_colors = util.make_list(plot_colors, len(x_datas)) plot_linestyles = util.make_list(plot_linestyles, len(x_datas)) plot_titles = util.make_list(plot_titles, len(x_datas), '') if (plot_groups is not None): plot_groups = util.make_list(plot_groups, len(x_datas)) # Preparing graph parameters if (split is None): if (plot_groups is None): nbr_graphs = 1 graphs = [[i for i in range(len(x_datas))]] else: nbr_graphs = max(plot_groups) + 1 graphs = [[] for i in range(nbr_graphs)] for i in range(len(plot_groups)): graphs[plot_groups[i]].append(i) else: if (split): nbr_graphs = len(x_datas) graphs = [[i] for i in range(len(x_datas))] else: nbr_graphs = 1 graphs = [[i for i in range(len(x_datas))]] plot_titles, graphs = util.pad_list_with_last_elem(plot_titles, graphs) # Nonexistent field management (no field recorded in component) for i in range(len(y_datas)): if (y_datas[i] is None): util.warning_terminal("Try to plot a nonexistent field!") y_datas[i] = np.zeros(0) x_datas[i] = np.zeros(0) # Plot graph ------------------------------------------------------- if (nbr_graphs < 4): nbr_row = nbr_graphs elif (nbr_graphs == 4): nbr_row = 2 else: nbr_row = 3 nbr_col = math.ceil(nbr_graphs / nbr_row) for i, graph in enumerate(graphs): plt_to_add = plt.subplot(nbr_row, nbr_col, i + 1) for plot in graph: add_single_plot(plt_to_add, x_datas[plot], y_datas[plot], x_labels[plot], y_labels[plot], x_ranges[plot], y_ranges[plot], plot_titles[i], plot_labels[plot], plot_linestyles[plot], plot_colors[plot], opacity) # Finalizing ------------------------------------------------------- if (fig_title is not None): plt.suptitle(fig_title, fontsize=16) plt.tight_layout() # Avoiding overlapping texts (legend) if (filename != ""): plt.savefig(filename) util.print_terminal( "Graph has been saved on filename '{}'".format(filename)) else: plt.show()
def print_propagation(self, comp: AbstractComponent, comp_port_id: int, ngbr: AbstractComponent, ngbr_port_id: int) -> None: util.print_terminal("Component '{}' has sent a signal from " "port {} to port {} of component '{}'.".format( comp.name, comp_port_id, ngbr_port_id, ngbr.name))