"""This file is used to read the data center configuration from user inputs provided inside dc_config.json. It also performs some auxiliary steps to calculate the server power specifications based on the given parameters."""importosimportmathimportjsonfromconcurrent.futuresimportThreadPoolExecutor,as_completed
[docs]classDC_Config:def__init__(self,dc_config_file='dc_config.json',total_cores=0,total_gpus=0,total_mem_GB=0,datacenter_capacity_mw=0):""" Initializes a new instance of the DC_Config class, loading configuration data from the specified JSON configuration file. Args: dc_config_file (str): The name of the data center configuration JSON file (which should live in ../configs). datacenter_capacity_mw (float): The maximum compute power capacity of the datacenter in MW. """self.config_path=os.path.abspath(dc_config_file)# Keep the capacity parameterself.datacenter_capacity_mw=datacenter_capacity_mwself.total_cores=total_coresself.total_gpus=total_gpusself.total_mem_GB=total_mem_GBself.CORES_PER_SERVER=64self.MAX_W_PER_CORE=6# Watts per coreself.GPUS_PER_SERVER=4self.MAX_SERVERS_PER_RACK=25# Load the JSON data from the configuration fileself.config_data=self._load_config()# Set up configuration parametersself._setup_config()def_load_config(self):""" Loads the data center configuration from the specified JSON file. Returns: dict: A dictionary containing the loaded configuration data. """withopen(self.config_path,'r')asfile:returnjson.load(file)def_setup_config(self):dc=self.config_data['data_center_configuration']servers=self.config_data['server_characteristics']hvac=self.config_data['hvac_configuration']hru=self.config_data['heat_recovery_configuration']# === Compute total number of servers needed ===self.total_servers_cpu=math.ceil(self.total_cores/self.CORES_PER_SERVER)self.total_servers_gpu=math.ceil(self.total_gpus/self.GPUS_PER_SERVER)self.total_servers=max(self.total_servers_cpu,self.total_servers_gpu)# === Racks based on max 25 servers per rack ===self.NUM_RACKS=math.ceil(self.total_servers/self.MAX_SERVERS_PER_RACK)self.CPUS_PER_RACK=math.ceil(self.total_cores/self.NUM_RACKS)self.GPUS_PER_RACK=math.ceil(self.total_gpus/self.NUM_RACKS)# print(f"[INFO] Using {self.NUM_RACKS} racks with max {self.MAX_SERVERS_PER_RACK} servers per rack")# print(f"[INFO] CPUs per rack: {self.CPUS_PER_RACK}, GPUs per rack: {self.GPUS_PER_RACK}")# === Use average rack-level values ===avg_supply_temp=sum(dc['RACK_SUPPLY_APPROACH_TEMP_LIST'])/len(dc['RACK_SUPPLY_APPROACH_TEMP_LIST'])avg_return_temp=sum(dc['RACK_RETURN_APPROACH_TEMP_LIST'])/len(dc['RACK_RETURN_APPROACH_TEMP_LIST'])self.RACK_SUPPLY_APPROACH_TEMP_LIST=[avg_supply_temp]*self.NUM_RACKSself.RACK_RETURN_APPROACH_TEMP_LIST=[avg_return_temp]*self.NUM_RACKS# avg_cpu_power = self._avg_pair_list(self.config_data['server_characteristics']['DEFAULT_SERVER_POWER_CHARACTERISTICS'])# The average CPU power is calculated based on the 20 Watts per core and the number of cores per serveravg_cpu_power=[self.MAX_W_PER_CORE*self.CORES_PER_SERVER,20]# [full_load_pwr, idle_pwr]avg_gpu_power=self._avg_pair_list(self.config_data['server_characteristics']['DEFAULT_GPU_POWER_CHARACTERISTICS'])self.DEFAULT_SERVER_POWER_CHARACTERISTICS=[avg_cpu_power]*self.NUM_RACKSself.DEFAULT_GPU_POWER_CHARACTERISTICS=[avg_gpu_power]*self.NUM_RACKS# === Build power config per rack ===defmake_cpu_cfg(spec):num_servers=math.ceil(self.CPUS_PER_RACK/self.CORES_PER_SERVER)return[{'full_load_pwr':spec[0],'idle_pwr':spec[1]}for_inrange(num_servers)]# return [{'full_load_pwr': spec[0], 'idle_pwr': spec[1]} for _ in range(self.CPUS_PER_RACK)]defmake_gpu_cfg(spec):return[{'full_load_pwr':spec[0],'idle_pwr':spec[1]}for_inrange(self.GPUS_PER_RACK)]withThreadPoolExecutor()asexecutor:cpu_futures=[executor.submit(make_cpu_cfg,spec)forspecinself.DEFAULT_SERVER_POWER_CHARACTERISTICS]gpu_futures=[executor.submit(make_gpu_cfg,spec)forspecinself.DEFAULT_GPU_POWER_CHARACTERISTICS]self.RACK_CPU_CONFIG=[f.result()forfinas_completed(cpu_futures)]self.RACK_GPU_CONFIG=[f.result()forfinas_completed(gpu_futures)]# Compute actual MAX_W_PER_RACK based on final rack contentsself.MAX_W_PER_RACK=max(sum(cpu['full_load_pwr']forcpuinrack_cpu)+sum(gpu['full_load_pwr']forgpuinrack_gpu)forrack_cpu,rack_gpuinzip(self.RACK_CPU_CONFIG,self.RACK_GPU_CONFIG))# print("\n[INFO] --- Rack Device Summary ---")fori,(rack_cpu,rack_gpu)inenumerate(zip(self.RACK_CPU_CONFIG,self.RACK_GPU_CONFIG)):num_servers=len(rack_cpu)num_gpus=len(rack_gpu)total_cores=num_servers*self.CORES_PER_SERVERcpu_power=sum(cpu['full_load_pwr']forcpuinrack_cpu)gpu_power=sum(gpu['full_load_pwr']forgpuinrack_gpu)# print(f"Rack {i+1:02d}: {num_servers} CPU servers × {self.CORES_PER_SERVER} cores → {total_cores} cores, "# f"{num_gpus} GPUs → Total theory Power ≈ {cpu_power + gpu_power:.1f} W")# A default value of HP_PROLIANT server for standalone testingself.HP_PROLIANT=servers['HP_PROLIANT']# A default value of HP_PROLIANT server for standalone testingself.NVIDIA_V100=servers['NVIDIA_V100']# Serve/cpu parameters; Obtained from [3]self.CPU_POWER_RATIO_LB=servers['CPU_POWER_RATIO_LB']self.CPU_POWER_RATIO_UB=servers['CPU_POWER_RATIO_UB']self.IT_FAN_AIRFLOW_RATIO_LB=servers['IT_FAN_AIRFLOW_RATIO_LB']self.IT_FAN_AIRFLOW_RATIO_UB=servers['IT_FAN_AIRFLOW_RATIO_UB']self.IT_FAN_FULL_LOAD_V=servers['IT_FAN_FULL_LOAD_V']self.ITFAN_REF_V_RATIO=servers['ITFAN_REF_V_RATIO']self.ITFAN_REF_P=servers['ITFAN_REF_P']self.INLET_TEMP_RANGE=servers['INLET_TEMP_RANGE']###################################################################################### HVAC CONFIGURATION ############################################################################################# Air parametersself.C_AIR=hvac['C_AIR']# J/kg.Kself.RHO_AIR=hvac['RHO_AIR']# kg/m3# CRAC Unit paramtersself.CRAC_SUPPLY_AIR_FLOW_RATE_pu=hvac['CRAC_SUPPLY_AIR_FLOW_RATE_pu']self.CRAC_REFRENCE_AIR_FLOW_RATE_pu=hvac['CRAC_REFRENCE_AIR_FLOW_RATE_pu']self.CRAC_FAN_REF_P=hvac['CRAC_FAN_REF_P']# Chiller Statsself.CHILLER_COP=hvac['CHILLER_COP_BASE']self.CW_PRESSURE_DROP=hvac['CW_PRESSURE_DROP']#Pa self.CW_WATER_FLOW_RATE=hvac['CW_WATER_FLOW_RATE']#m3/sself.CW_PUMP_EFFICIENCY=hvac['CW_PUMP_EFFICIENCY']#%self.CHILLER_COP_K=hvac['CHILLER_COP_K']self.CHILLER_COP_T_NOMINAL=hvac['CHILLER_COP_T_NOMINAL']# Cooling Tower parametersself.CT_FAN_REF_P=hvac['CT_FAN_REF_P']self.CT_REFRENCE_AIR_FLOW_RATE=hvac['CT_REFRENCE_AIR_FLOW_RATE']self.CT_PRESSURE_DROP=hvac['CT_PRESSURE_DROP']#Pa self.CT_WATER_FLOW_RATE=hvac['CT_WATER_FLOW_RATE']#m3/sself.CT_PUMP_EFFICIENCY=hvac['CT_PUMP_EFFICIENCY']#%# Heat Recovery paremetersself.AVE_HLP=hru['AVE_HLP']# W/(K*m^2) self.OFFICE_GUIDE_TEMP=hru['OFFICE_GUIDE_TEMP']#Deg C self.DC_AREA_PU=hru['DC_AREA_PU']#m^2 per W self.OFFICE_BUILDING_AREA=hru['OFFICE_BUILDING_AREA']#mdef_avg_pair_list(self,pair_list):avg_first=sum(p[0]forpinpair_list)/len(pair_list)avg_second=sum(p[1]forpinpair_list)/len(pair_list)return[avg_first,avg_second]
#References:#[1]: Postema, Björn Frits. "Energy-efficient data centres: model-based analysis of power-performance trade-offs." (2018).#[2]: Raghunathan, S., & Vk, M. (2014). Power management using dynamic power state transitions and dynamic voltage frequency scaling controls in virtualized server clusters. Turkish Journal of Electrical Engineering and Computer Sciences, 24(4). doi: 10.3906/elk-1403-264#[3]: Sun, Kaiyu, et al. "Prototype energy models for data centers." Energy and Buildings 231 (2021): 110603.#[4]: Breen, Thomas J., et al. "From chip to cooling tower data center modeling: Part I influence of server inlet temperature and temperature rise across cabinet." 2010 12th IEEE Intersociety Conference on Thermal and Thermomechanical Phenomena in Electronic Systems. IEEE, 2010.#[5]: https://h2ocooling.com/blog/look-cooling-tower-fan-efficiences/#:~:text=The%20tower%20has%20been%20designed,of%200.42%20inches%20of%20water.