diff --git a/PowerDiagram.py b/PowerDiagram.py index 89b5d12..d01e0b3 100644 --- a/PowerDiagram.py +++ b/PowerDiagram.py @@ -63,11 +63,32 @@ class Machine(object): outgoing_connections.append(conn) return outgoing_connections - def get_power_consumption(self): - power_consumption = self.power_consumption + def get_powered_machines(self): + powered_machines = {} + powered_machines[self.name] = self for conn in self.get_outgoing_connections(): - power_consumption += conn.get_power_consumption() - # print("machine %s : power_consumption += %f" % (self.name, conn.get_power_consumption())) + conn_powered_machines = conn.to_plug.machine.get_powered_machines() + for machine in conn_powered_machines.itervalues(): + if machine not in powered_machines.keys(): + powered_machines[machine.name] = machine + return powered_machines + + def get_power_consumption(self, worst_case_scenario=False): + """ + Returns the number of watts going through this 'machine' (which could just be a powerstrip) + + :param bool worst_case_scenario: if True, computes the number of watts going through this cable in the worst case scenario, in which this cable has to provide the power supply assumung all other backup powers are dead + """ + if worst_case_scenario: + # this machine has to provide the full power to all machine it powers, assuming all the power backup providers are dead + power_consumption = 0.0 + for machine in self.get_powered_machines().itervalues(): + power_consumption += machine.power_consumption + else: + power_consumption = self.power_consumption + for conn in self.get_outgoing_connections(): + power_consumption += conn.get_power_consumption(worst_case_scenario) + # print("machine %s : power_consumption += %f" % (self.name, conn.get_power_consumption())) return power_consumption def is_power_provider(self): @@ -124,14 +145,6 @@ class Plug(object): return capacity -# def get_power_consumption(self): -# power_consumption = 0.0 -# for conn in self.get_outgoing_connections(): -# power_consumption += conn.get_power_consumption() -# power_consumption += self.get_power_consumption() -# return self.from_plug.get_power_consumption() - - class Connection(object): """ a power cable connecting an input power plug to an output power plug @@ -181,14 +194,28 @@ class Connection(object): input_plug = from_machine.input_plugs[input_plug_names[0]] return input_plug.get_incoming_connection().get_power_provider() - def get_power_consumption(self): - # at the moment, this program doesn't handle redundant power supplies properly: - # the energy dragged by a power supply depends whether both power supplies are connnected to the same provider or not - if self.is_redundancy_cable(): - return 0.0 # consider secondary power supplies to drag 0 power + def get_power_consumption(self, worst_case_scenario=False): + """ + Returns the number of watts going through this cable + + :param bool worst_case_scenario: if True, computes the number of watts going through this cable in the worst case scenario, in which this cable has to provide the power supply assumung all other backup powers are dead + """ + to_machine = self.to_plug.machine + power_consumption = None + if worst_case_scenario: + if False: # self.is_redundancy_cable(): + power_consumption = 0.0 + else: + power_consumption = to_machine.get_power_consumption(worst_case_scenario) else: - return self.to_plug.machine.get_power_consumption() - + num_input_cables = 0 + for input_plug in to_machine.input_plugs.itervalues(): + input_cable = input_plug.get_incoming_connection() + assert input_cable + num_input_cables += 1 + assert num_input_cables > 0 + power_consumption = to_machine.get_power_consumption(worst_case_scenario) / num_input_cables + return power_consumption class PowerConfig(object): """ @@ -296,7 +323,7 @@ class PowerConfig(object): class CableColorer(object): - def get_cable_color(self, cable): + def get_cable_color(self, cable, worst_case_scenario): """ :param Connection cable: """ @@ -304,11 +331,11 @@ class CableColorer(object): class SimpleColorer(CableColorer): - def get_cable_color(self, cable): + def get_cable_color(self, cable, worst_case_scenario): """ :param Connection cable: """ - power_consumption = cable.get_power_consumption() + power_consumption = cable.get_power_consumption(worst_case_scenario) amperes = power_consumption / 220.0 capacity = cable.get_max_amperes() saturation = amperes / capacity @@ -332,11 +359,11 @@ class RampColorer(CableColorer): clamped_hotness = max(min(hotness, 1.0), 0.0) return "%f, 1.0, 0.8" % ((clamped_hotness) * 0.1 + 0.23) - def get_cable_color(self, cable): + def get_cable_color(self, cable, worst_case_scenario): """ :param Connection cable: """ - power_consumption = cable.get_power_consumption() + power_consumption = cable.get_power_consumption(worst_case_scenario) amperes = power_consumption / 220.0 capacity = cable.get_max_amperes() saturation = amperes / capacity @@ -357,14 +384,13 @@ class RampColorer(CableColorer): color = '/svg/red' # draw overloaded cables in red return color -def power_config_to_svg(power_config, svg_file_path): - +def power_config_to_svg(power_config, svg_file_path, worst_case_scenario=True): """ creates a svg diagram representing the input power configuration :param PowerConfig power_config: the input power config """ - graph = pygraphviz.AGraph() + graph = pygraphviz.AGraph(strict=False) # strict=False allows more than one connection between 2 nodes graph.graph_attr['overlap'] = 'false' graph.graph_attr['splines'] = 'true' graph.graph_attr['rankdir'] = 'LR' # to get hrizontal tree rather than vertical @@ -396,12 +422,30 @@ def power_config_to_svg(power_config, svg_file_path): if machine.name not in rack['machines']: rack['machines'].append(machine) + for machine in power_config.machines.itervalues(): + graph.add_node(machine.name) + node = graph.get_node(machine.name) + machine_total_power_consumption = int(machine.get_power_consumption(worst_case_scenario=worst_case_scenario)) + # node.attr['label'] = '%s (%d W)' % (machine.name, machine_total_power_consumption) + + node.attr['shape'] = 'plaintext' + + node.attr['label'] = '<\ +
%s | \ +%s W | \ +