Commit 2d3cda50 authored by Bouknight, Sedrick's avatar Bouknight, Sedrick
Browse files

Merge branch 'refactor-single-fmu-dict' into 'main'

Returns a single fmu output dict to TickData

See merge request !62
parents ed9de3f9 e0f078d9
Loading
Loading
Loading
Loading
+12 −14
Original line number Diff line number Diff line
@@ -206,7 +206,7 @@ class ThermoFluidsModel:
        return fmu_inputs


    def calculate_pue(self, cooling_input, datacenter_output, cep_output):
    def calculate_pue(self, cooling_input, cooling_output):
        """
        Calculate the Power Usage Effectiveness (PUE) of the data center.

@@ -230,13 +230,13 @@ class ThermoFluidsModel:
            return np.array(value_in_kw) * 1e3 if value_in_kw is not None else 0.0

        # Convert values from kW to Watts using the utility function
        W_HTWPs = convert_to_watts(cep_output.get(W_HTWPs_KEY))
        W_CTWPs = convert_to_watts(cep_output.get(W_CTWPs_KEY))
        W_CTs = convert_to_watts(cep_output.get(W_CTs_KEY))
        W_HTWPs = convert_to_watts(cooling_output.get(W_HTWPs_KEY))
        W_CTWPs = convert_to_watts(cooling_output.get(W_CTWPs_KEY))
        W_CTs = convert_to_watts(cooling_output.get(W_CTs_KEY))

        # Get the sum of the work done by all CDU pumps
        W_CDUPs = sum(
            convert_to_watts(datacenter_output.get(f'simulator[1].datacenter[1].computeBlock[{idx+1}].cdu[1].summary.W_flow_CDUP_kW'))
            convert_to_watts(cooling_output.get(f'simulator[1].datacenter[1].computeBlock[{idx+1}].cdu[1].summary.W_flow_CDUP_kW'))
            for idx in range(NUM_CDUS)
        )

@@ -283,22 +283,20 @@ class ThermoFluidsModel:
        self.fmu.doStep(currentCommunicationPoint=current_time, communicationStepSize=step_size)

        # Initialize dictionaries for cooling input, datacenter output, and CEP output
        cooling_input = {v.name: self.fmu.getReal([v.valueReference])[0] for v in self.inputs}
        datacenter_output = {v.name: self.fmu.getReal([v.valueReference])[0] for v in self.outputs if "datacenter" in v.name}
        cep_output = {v.name: self.fmu.getReal([v.valueReference])[0] for v in self.outputs if "centralEnergyPlant" in v.name}
        cooling_inputs = {v.name: self.fmu.getReal([v.valueReference])[0] for v in self.inputs}
        cooling_outputs = {v.name: self.fmu.getReal([v.valueReference])[0] for v in self.outputs}

        # Calculate PUE
        pue = self.calculate_pue(cooling_input, datacenter_output, cep_output)
        pue = self.calculate_pue(cooling_inputs, cooling_outputs)

        # Append time to each dictionary
        cooling_input['time'] = current_time
        datacenter_output['time'] = current_time
        cep_output['time'] = current_time
        cooling_inputs['time'] = current_time
        cooling_outputs['pue'] = pue

        # Append the combined results to the history
        self.fmu_history.append({**cooling_input, **datacenter_output, **cep_output})
        self.fmu_history.append({**cooling_inputs, **cooling_outputs})

        return cooling_input, datacenter_output, cep_output, pue
        return cooling_inputs, cooling_outputs

    def terminate(self):
        """
+6 −10
Original line number Diff line number Diff line
@@ -81,9 +81,7 @@ class TickData:
    g_flops_w: float
    system_util: float
    fmu_inputs: Optional[dict]
    fmu_datacenter_outputs: Optional[dict]
    fmu_cep_outputs: Optional[dict]
    pue: Optional[float]
    fmu_outputs: Optional[dict]


def get_utilization(trace, time_quanta_index):
@@ -315,7 +313,7 @@ class Scheduler:

        # Render the updated layout
        power_df = None
        cooling_inputs, datacenter_outputs, cep_outputs, pue = None, None, None, None
        cooling_inputs, cooling_outputs = None, None

        # Update power history every 15s
        if self.current_time % POWER_UPDATE_FREQ == 0:
@@ -339,7 +337,7 @@ class Scheduler:
                # FMU inputs are N powers and the wetbulb temp
                fmu_inputs = self.cooling_model.generate_fmu_inputs(runtime_values, \
                             uncertainties=self.power_manager.uncertainties)
                cooling_inputs, datacenter_outputs, cep_outputs, pue = \
                cooling_inputs, cooling_outputs =\
                    self.cooling_model.step(self.current_time, fmu_inputs, FMU_UPDATE_FREQ)
                
                # Get a dataframe of the power data
@@ -347,9 +345,9 @@ class Scheduler:

                if self.layout_manager:
                    self.layout_manager.update_powertemp_array(power_df, \
                               datacenter_outputs, pue, pflops, gflop_per_watt, \
                               cooling_outputs, pflops, gflop_per_watt, \
                               system_util, uncertainties=self.power_manager.uncertainties)
                    self.layout_manager.update_pressflow_array(datacenter_outputs)
                    self.layout_manager.update_pressflow_array(cooling_outputs)

        if self.current_time % UI_UPDATE_FREQ == 0:
            # Get a dataframe of the power data
@@ -373,9 +371,7 @@ class Scheduler:
            g_flops_w = gflop_per_watt,
            system_util = system_util,
            fmu_inputs = cooling_inputs,
            fmu_datacenter_outputs = datacenter_outputs,
            fmu_cep_outputs = cep_outputs,
            pue = pue
            fmu_outputs = cooling_outputs,
        )

        self.current_time += 1
+7 −7
Original line number Diff line number Diff line
@@ -163,10 +163,10 @@ class LayoutManager:
        # Update the layout
        self.layout["status"].update(Panel(Align(table, align="center"), title="Scheduler Stats"))

    def update_pressflow_array(self, datacenter_outputs):
    def update_pressflow_array(self, cooling_outputs):
        columns = ["Output", "Average Value"]

        datacenter_df = self.get_datacenter_df(datacenter_outputs)
        datacenter_df = self.get_datacenter_df(cooling_outputs)

        # List of keys to include in the table
        relevant_keys = [
@@ -187,7 +187,7 @@ class LayoutManager:
        self.add_table_rows(table, data)
        self.layout["pressflow"].update(Panel(table))

    def get_datacenter_df(self, datacenter_outputs):
    def get_datacenter_df(self, cooling_outputs):
        # Initialize data dictionary with keys from FMU_COLUMN_MAPPING
        data = {key: [] for key in FMU_COLUMN_MAPPING.keys()}
        
@@ -197,7 +197,7 @@ class LayoutManager:
            
            # Append data to the corresponding lists dynamically using FMU_COLUMN_MAPPING keys
            for key in FMU_COLUMN_MAPPING.keys():
                data[key].append(datacenter_outputs.get(compute_block_key + key))
                data[key].append(cooling_outputs.get(compute_block_key + key))
        
        # Convert to DataFrame
        df = pd.DataFrame(data)
@@ -205,7 +205,7 @@ class LayoutManager:
        return df


    def update_powertemp_array(self, power_df, datacenter_outputs, pue, pflops, gflop_per_watt, system_util, uncertainties=False):
    def update_powertemp_array(self, power_df, cooling_outputs, pflops, gflop_per_watt, system_util, uncertainties=False):
        """
        Updates the displayed power and temperature table with the provided data.

@@ -222,7 +222,7 @@ class LayoutManager:
        # Updated cooling keys to include temperature instead of pressure
        cooling_keys = ["T_prim_s_C", "T_prim_r_C", "T_sec_s_C", "T_sec_r_C"]

        datacenter_df = self.get_datacenter_df(datacenter_outputs)
        datacenter_df = self.get_datacenter_df(cooling_outputs)

        # Create column headers with appropriate styles
        columns = [f"{col} (kW)" if col != "CDU" else col for col in power_columns]
@@ -278,7 +278,7 @@ class LayoutManager:
            str(f"{pflops:.2f}"),
            str(f"{gflop_per_watt:.1f}"),
            total_loss_str + " (" + percent_loss_str+ ")",
            f"{pue:.2f}",
            f"{cooling_outputs['pue']:.2f}",
            style="white"  # Apply white style to all elements in the row
        )