def mainEnginePowerCalculation(processed, CONSTANTS): print("Started calculating main engine power...", end="", flush=True) # This function calculates the Power of the engine starting from the efficiency of the engine, # which is calcualted starting from other available data for system in CONSTANTS["General"]["NAMES"]["MainEngines"]: # Calculate fuel flow-based engine load fuel_based_load = processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] / CONSTANTS["MainEngines"]["MFR_FUEL_DES_ISO"] # Calculate ISO bsfc (break specific fuel consumption) bsfc_iso = fuel_based_load.apply( polyvalHelperFunction, args=(CONSTANTS["MainEngines"]["POLY_FUEL_LOAD_2_BSFC_ISO"], )) # Corrects the bsfc from ISO conditions to "real" conditions (bsfc, LHV) = ppo.bsfcISOCorrection( bsfc_iso, processed[d2df(system, "CAC_LT", "Air_out", "T")], processed[d2df(system, "CAC_LT", "LTWater_in", "T")], processed[d2df(system, "Cyl", "FuelPh_in", "T")], CONSTANTS) # Calculates the real fuel flow using the ISO conversion processed[d2df(system, "Cyl", "FuelPh_in", "mdot")] = processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] * bsfc / bsfc_iso # Calculates the power of the engine as mfr/bsfc, with unit conversion to get the output in kW # Shaft energy out processed[d2df(system, "Cyl", "Power_out", "Edot")] = processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] / bsfc * 1000 * 3600 # Chemical energy in the fuel processed[d2df(system, "Cyl", "FuelCh_in", "Edot")] = processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] * LHV print("...done!") return processed
def mainEngineFuelFlowCalculation(raw, processed, CONSTANTS, hd): print("Started calculating main engine fuel flows...", end="", flush=True) # This function calculates the engine for system in CONSTANTS["General"]["NAMES"]["MainEngines"]: # This function calculates the fuel flow of the main engines # In the case of the main engines, the fuel flow of an engine is calculated given its fuel # rack position and its rotating speed. fuel_rack_position = CONSTANTS["MainEngines"]["FRP_2_MFR"]["FRP_MIN"][ system] + (CONSTANTS["MainEngines"]["FRP_2_MFR"]["FRP_MAX"][system] - CONSTANTS["MainEngines"]["FRP_2_MFR"]["FRP_MIN"] [system]) * raw[hd[system + "__FRP_"]] / 100 # Temporarily, only the ISO fuel flow is calculated processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] = CONSTANTS["MainEngines"]["MFR_FUEL_DES_ISO"] * ( (CONSTANTS["MainEngines"]["FRP_2_MFR"]["POLY"][system][0] + CONSTANTS["MainEngines"]["FRP_2_MFR"]["POLY"][system][1] * fuel_rack_position) / (CONSTANTS["MainEngines"]["FRP_2_MFR"]["POLY"][system][0] + CONSTANTS["MainEngines"]["FRP_2_MFR"]["POLY"][system][1] * CONSTANTS["MainEngines"]["FRP_DES"][system])) * ( processed[d2df(system, "Cyl", "Power_out", "omega")] / CONSTANTS["MainEngines"]["RPM_DES"]) print("...done!") return processed
def mainEngineAirFlowPostCalculation(processed, dict_structure, CONSTANTS): # This function does the post-analysis after the various properties have been calculated print("Started calculating main engine air and exhaust flows...", end="", flush=True) for system in CONSTANTS["General"]["NAMES"]["MainEngines"]: # Calculating the turbine's power output to the compressor processed[d2df(system, "Turbine", "Power_out", "Edot")] = processed[d2df(system,"BPmerge","Mix_out","mdot")] * ( processed[d2df(system, "Turbine", "Mix_in", "h")] - processed[d2df(system,"Turbine","Mix_out","h")]) # Calculating the compressor's power input. processed[d2df(system, "Comp", "Power_in", "Edot")] = processed[d2df(system, "BPsplit", "Air_in", "mdot")] * ( processed[d2df(system, "Comp", "Air_out", "h")] - processed[d2df(system, "Comp", "Air_in", "h")]) # Losses at the TC shaft level are calculated processed[d2df(system, "TCshaft", "Losses_out", "Edot")] = processed[d2df(system, "Turbine", "Power_out", "Edot")] - processed[d2df(system, "Comp", "Power_in", "Edot")] return processed
def massBalance(processed, dict_structure, CONSTANTS): # This function checks that the mass balance is respected. # Errors are shown: # - On an occurrence basis: every time that the balance is not respected counts as 1 # - On an "average error" basis text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") text_file.write("\n *** CHECKING THE MASS BALANCE *** \n") print("Started checking mass balances...", end="", flush=True) for system in dict_structure["systems"]: for unit in dict_structure["systems"][system]["units"]: if (system == "Steam" and unit == "SteamDistribution"): aaa = 0 balance = pd.Series(index=processed.index) balance[:] = 0 max_value = 0 counter = 0 for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: if dict_structure["systems"][system]["units"][unit]["flows"][ flow]["type"] in {"CPF", "IPF", "SF"}: counter = counter + 1 balance = balance + processed[d2df( system, unit, flow, "mdot")] * (2 * float("out" not in flow) - 1) max_value = max( max_value, max(processed[d2df(system, unit, flow, "mdot")])) balance_occ = np.sum( balance < 0.001 * max_value) / len(balance) * 100 balance_ave = np.sum(balance) / (len(balance) * (100 - balance_occ) / 100) / max_value * 100 if balance_occ == 100: text_file.write( "The mass balance is fine for {}_{} unit \n".format( system, unit)) elif (balance_occ >= 99) or (balance_ave <= 1): text_file.write( "The mass balance is ALMOST fine for {}_{} unit \n".format( system, unit)) elif counter == 0: text_file.write( "There is no mass balance for {}_{} unit \n".format( system, unit)) else: text_file.write( "---Mass balance for {}_{} unit is respected {}% of the times, with {}% average error \n" .format(system, unit, str(balance_occ), str(balance_ave))) print("...done!") text_file.close()
def connectionAssignment(processed, dict_structure, CONSTANTS, system, unit, call_ID): text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") # Opens the log file counter = 0 for flow in dict_structure["systems"][system]["units"][unit]["flows"]: if "Connections" in dict_structure["systems"][system]["units"][unit][ "flows"][flow]: for connected_flow in dict_structure["systems"][system]["units"][ unit]["flows"][flow]["Connections"]: for property in CONSTANTS["General"]["PROPERTY_LIST"][ dict_structure["systems"][system]["units"][unit] ["flows"][flow]["type"]]: ID = d2df( system, unit, flow, property ) # Writing the property full ID of the flow we are checking ID_c = connected_flow + ":" + property # Writing the property full ID of the flow connected to the flow we are checking if processed[ID].isnull().sum() != len( processed[ID]): # If the flow is not empty if (processed[ID_c].isnull().sum() == len( processed[ID_c])) or ( sum(processed[ID_c]) == 0): # If the connected flow IS empty processed[ID_c] = processed[ID] counter = counter + 1 elif (processed[ID] - processed[ID_c]).sum() > processed[ID].max(): text_file.write( "ERROR. FUN: ppo.connectionAssignment. Something is wrong. Flows {} and {} should be the same, they are not. \n" .format(ID, ID_c)) text_file.close() return (counter, processed)
def unitOffCheck(processed, dict_structure, CONSTANTS, system_set, call_ID): # Assigns to 0 all values related to components when they are off for system in system_set: if processed[system + ":" + "on"].isnull().sum() == 0: for unit in dict_structure["systems"][system]["units"]: for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: try: for property in dict_structure["systems"][system][ "units"][unit]["flows"][flow]["properties"]: if processed[d2df(system, unit, flow, property)].isnull().sum() == len( processed[d2df( system, unit, flow, property)]): pass # the value is still untouched, better leave it that way elif property == "T": processed.loc[~processed[system + ":" + "on"], d2df(system, unit, flow, property )] = processed.loc[ ~processed[system + ":" + "on"], "T_0"] else: processed.loc[ ~processed[system + ":" + "on"], d2df(system, unit, flow, property )] = CONSTANTS["General"][ "PROPERTY_LIST"]["REF"][property] except KeyError: print( "Something went wrong when checking the engine on/off" ) elif processed[system + ":" + "on"].isnull().sum() < len( processed[system + ":" + "on"]): print( "Something went wrong here, the system -on- field has NaNs for system {}" .format(system)) else: pass return processed
def plottingFunction(plot_info, processed, data_type): # Here we go if data_type == "processed": for figure in plot_info: if figure["plot_mode"] == "sankey": print("Plot Sankey diagram...as if this was easy") else: fig = plt.figure() for plot in figure["variables"]: x = processed[d2df(plot["system"], plot["unit"], plot["flow"], plot["property"])] if figure["plot_mode"] == "hist": num_bins = 50 # the histogram of the data n, bins, patches = plt.hist(x, num_bins, normed=1, alpha=0.5) # add a 'best fit' line plt.xlabel(plot["property"] + " of " + plot["flow"] + " of " + plot["unit"] + " in " + plot["system"]) plt.ylabel('Probability') if figure["plot_mode"] == "timeSeries": plt.plot(x) plt.ylabel("Time [YYY:MM]") plt.ylabel(plot["property"] + " of " + plot["flow"] + " of " + plot["unit"] + " in " + plot["system"]) plt.show() elif data_type == "raw": for figure in plot_info: if figure["plot_mode"] == "sankey": print("Plot Sankey diagram...as if this was easy") else: fig = plt.figure() for plot in figure["variables"]: x = processed[plot] if figure["plot_mode"] == "hist": num_bins = 50 # the histogram of the data n, bins, patches = plt.hist(x, num_bins, normed=1, alpha=0.5) # add a 'best fit' line plt.xlabel("Variable of interest") plt.ylabel('Probability') if figure["plot_mode"] == "timeSeries": x.plot() else: print("Data type is wrong. It should be either -raw- or -processed-")
def auxEnginePowerCalculation(processed, CONSTANTS): print("Started calculating auxiliary engine power...", end="", flush=True) # Calculating the power of the auxiliary engines for system in CONSTANTS["General"]["NAMES"]["AuxEngines"]: load = processed[d2df(system,"AG","Power_out","Edot")] / CONSTANTS["AuxEngines"]["MCR"] eta_AG = CONSTANTS["AuxEngines"]["AG"]["ETA_DES"] - CONSTANTS["AuxEngines"]["AG"]["A"] * np.exp( -CONSTANTS["AuxEngines"]["AG"]["k"] * (load)) processed[d2df(system,"AG","Power_in","Edot")] = processed[d2df(system,"AG","Power_out","Edot")] / eta_AG processed[d2df(system,"AG","Losses_out","Edot")] = processed[d2df(system,"AG","Power_in","Edot")] - processed[d2df(system,"AG","Power_out","Edot")] processed[d2df(system,"Cyl","Power_out","Edot")] = processed[d2df(system,"AG","Power_in","Edot")] print("...done!") return processed
def energyBalance(processed, dict_structure, CONSTANTS): # This function checks that the mass balance is respected text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") text_file.write("\n *** CHECKING THE ENERGY BALANCE *** \n") print("Started checking the energy balances...", end="", flush=True) for system in dict_structure["systems"]: for unit in dict_structure["systems"][system]["units"]: balance = pd.Series(index=processed.index) balance[:] = 0 max_value = 0 for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: balance = balance + processed[d2df( system, unit, flow, "Edot")] * (2 * float("out" not in flow) - 1) max_value = max( max_value, max(processed[d2df(system, unit, flow, "Edot")])) balance_occ = np.sum(balance < 0.001 * max_value) / max( 1, len(balance)) * 100 balance_ave = np.sum(balance) / (len(balance) * (100 - balance_occ) / 100) / max_value * 100 if balance_occ == 100: text_file.write( "The energy balance is fine for {}_{} unit \n".format( system, unit)) elif (balance_occ >= 99) or (balance_ave <= 1): text_file.write( "The energy balance is ALMOST fine for {}_{} unit \n". format(system, unit)) else: text_file.write( "---energy balance for {}_{} unit is respected {}% of the times, with {}% average error \n" .format(system, unit, str(balance_occ), str(balance_ave))) print("...done!") text_file.close()
def missingValues(processed, dict_structure, CONSTANTS): text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") text_file.write("\n *** LIST OF MISSING VALUES *** \n") print("Started looking for missing values...", end="", flush=True) for system in dict_structure["systems"]: for unit in dict_structure["systems"][system]["units"]: for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: for property in dict_structure["systems"][system]["units"][ unit]["flows"][flow]["properties"]: if processed[d2df(system, unit, flow, property)].isnull().sum() == len( processed[system + ":" + "on"]): text_file.write( "The field {}:{}:{}:{} is still empty \n".format( system, unit, flow, property)) text_file.close() print("...done!")
def auxEngineFuelFlowCalculation(raw, processed, CONSTANTS): print("Started calculating auxiliary engine fuel flows...", end="", flush=True) # Proceeding with the auxiliary engines for system in CONSTANTS["General"]["NAMES"]["AuxEngines"]: # First we calculate the ISO break specific fuel consumption (BSFC) bsfc_iso = processed[system+":"+"load"].apply(ppo.polyvalHelperFunction, args=(CONSTANTS["AuxEngines"][ "POLY_LOAD_2_ISO_BSFC"],)) (bsfc, LHV) = ppo.bsfcISOCorrection(bsfc_iso, processed[d2df(system,"Cyl","Air_in","T")], processed[d2df(system,"CAC_LT", "LTWater_in","T")], processed[d2df(system,"Cyl","FuelPh_in","T")], CONSTANTS) processed[d2df(system,"Cyl","FuelPh_in","mdot")] = bsfc * processed[d2df(system,"Cyl","Power_out","Edot")] / 3600 / 1000 processed[d2df(system,"Cyl","FuelCh_in","Edot")] = processed[d2df(system,"Cyl","FuelPh_in","mdot")] * LHV print("...done!") return processed
def SteamCheck(processed, CONSTANTS, dict_structure): # This function checks that all relative values are consistent tot = len(processed.index) text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") print("Started consistency check for the steam systems...", end="", flush=True) text_file.write("\n *** CONSISTENTCY CHECK FOR THE STEAM SYSTEMS *** \n") for unit in dict_structure["systems"]["Steam"]["units"]: if unit in { "TankHeating", "OtherTanks", "HFOtankHeating", "MachinerySpaceHeaters", "HFOheater", "Galley" }: temp = sum(processed[d2df("Steam", unit, "Steam_in", "mdot")] >= 0 ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write(warn + unit + "Steam mass flows are consistent for " + str(temp) + " % of the datapoints \n") text_file.close() print("...done!")
def auxEngineAirFlowCalculation(raw, processed, CONSTANTS): print("Started calculating auxiliary engine air and exhaust flows...", end="", flush=True) # This function calculates the different air and exhaust gas flows in the main engines, taking into account the # presence of air bypass and exhaust wastegate valves for system in CONSTANTS["General"]["NAMES"]["AuxEngines"]: # Calculating the compressor's compression ratio beta_comp = processed[d2df(system,"Comp","Air_out","p")] / processed[d2df(system,"Comp","Air_in","p")] # Calculating the compressor isentropic efficiency comp_isentropic_efficiency = beta_comp.apply(ppo.polyvalHelperFunction, args=(CONSTANTS["AuxEngines"]["POLY_PIN_2_ETA_IS"],)) # Calculating the temperature after the compressor, based on ideal gas assumption T_Comp_out_iso = processed[d2df(system, "Comp", "Air_in", "T")] * beta_comp ** ((CONSTANTS["General"]["K_AIR"] - 1) / CONSTANTS["General"]["K_AIR"]) T_Comp_out = processed[d2df(system, "Comp", "Air_in", "T")] + (T_Comp_out_iso - processed[d2df(system, "Comp", "Air_in", "T")]) / comp_isentropic_efficiency #### NOTE: HERE WE MAKE THE ASSUMPTION THAT THE COMPRESSOR OUTLET TEMPERATURE CANNOT BE LOWER THAN THE CYLINDER INLET TEMPERATURE T_Comp_out[T_Comp_out < processed[d2df(system, "Cyl", "Air_in", "T")]] = processed.loc[T_Comp_out < processed[d2df(system, "Cyl", "Air_in", "T")], d2df(system, "Cyl", "Air_in", "T")] processed[d2df(system, "Comp", "Air_out", "T")] = T_Comp_out # Calculating the air inflow aspired by the cylinder: calculated as inlet air density times the maximum volume, # times the engine speed processed[d2df(system,"Cyl","Air_in","mdot")] = CONSTANTS["AuxEngines"]["V_MAX"] * ( processed[d2df(system,"Comp","Air_out","p")]) / ( CONSTANTS["General"]["R_AIR"] * processed[d2df(system,"Cyl","Air_in","T")]) * ( processed[d2df(system,"Cyl","Power_out","omega")] / 60 / 2 * CONSTANTS["General"]["ETA_VOL"]) * ( CONSTANTS["AuxEngines"]["N_CYL"]) # Exhaust gas flow after the cylinders processed[d2df(system,"Cyl","EG_out","mdot")] = processed[d2df(system,"Cyl","Air_in","mdot")] + processed[d2df(system,"Cyl","FuelPh_in","mdot")] # Here we calculate the bypass mass flow. THIS NEEDS TO BE CHECKED FOR CONSISTENCY (i.e. the bypass mass flow # should always be kind of low, and anyway only be seen at low to medium load). # The equation is the result of a mass and energy balance over the whole engine # dT_comp = processed[d2df(system,"Comp","Air_out","T")] - processed[d2df(system,"Comp","Air_in","T")] # dT_turb = processed[d2df(system,"Turbine","Mix_in","T")] - processed[d2df(system,"Turbine","Mix_out","T")] # processed[d2df(system, "BPsplit", "BP_out", "mdot")] = (processed[d2df(system, "Cyl", "Air_in", "mdot")] * CONSTANTS["General"]["CP_AIR"] * dT_comp - # processed[d2df(system,"Cyl","EG_out","mdot")] * CONSTANTS["General"]["CP_EG"] * dT_turb * CONSTANTS["MainEngines"]["ETA_MECH_TC"]) / ( # CONSTANTS["General"]["CP_AIR"] * (CONSTANTS["MainEngines"]["ETA_MECH_TC"] * dT_turb - dT_comp)) processed.loc[:, d2df(system, "BPmerge", "BP_in", "mdot")] = 0 # The air mass flow going through the compressor is equal to the sum of the air flow through the bypass valve and # to the cylinders processed[d2df(system,"BPsplit","Air_in","mdot")] = processed[d2df(system, "BPmerge", "BP_in", "mdot")] + processed[d2df(system,"Cyl","Air_in","mdot")] # The flow through the turbine is equal to the sum of the bypass flow and the exhaust coming from the cylinders processed[d2df(system,"BPmerge","Mix_out","mdot")] = processed[d2df(system,"BPmerge","BP_in","mdot")] + processed[d2df(system,"Cyl","EG_out","mdot")] # Calculating the temperature of the mixture after the merge between bypass and exhaust gas from the cylinders processed[d2df(system,"Cyl","EG_out","T")] = ((processed[d2df(system,"Cyl","EG_out","mdot")] * CONSTANTS["General"]["CP_EG"] + processed[d2df(system,"BPmerge","BP_in","mdot")] * CONSTANTS["General"]["CP_AIR"]) * processed[d2df(system,"Turbine","Mix_in","T")] - processed[d2df(system,"BPmerge","BP_in","mdot")] * CONSTANTS["General"]["CP_AIR"] * processed[d2df(system, "Comp", "Air_out", "T")]) / ( processed[d2df(system,"Cyl","EG_out","mdot")] * CONSTANTS["General"]["CP_EG"]) # Assiging the mass flow values for the HRSGs otherwise it makes a mess processed[d2df(system, "HRSG", "Mix_in", "mdot")] = processed[d2df(system, "BPmerge", "Mix_out", "mdot")] processed[d2df(system, "HRSG", "Mix_out", "mdot")] = processed[d2df(system, "BPmerge", "Mix_out", "mdot")] print("...done!") return processed
def predefinedPlots(processed, dataset_raw, CONSTANTS, dict_structure, filenames): for filename in filenames: fig, ax = plt.subplots() ### TIME SERIES ### if filename == "TimeSeries:Heat_vs_time": # Contribution from the HRSGs temp = (processed["ME2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["ME3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE1:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE4:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]) hrsg = temp.resample("D").sum() * 60 * 15 # Contribution from the HTHR temp = processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS[ "General"]["CP_WATER"] * ( processed["HTHR:HTHR13:HRWater_out:T"] - processed["HTHR:HTHR24:HRWater_in:T"]) hthr = temp.resample("D").sum() * 60 * 15 # Maximum theoretical contribution from the HT systems engine_set = { "ME1", "ME2", "ME3", "ME4", "AE1", "AE2", "AE3", "AE4" } temp = (sum((processed[d2df(idx, "CAC_HT", "HTWater_out", "T")] - processed[d2df(idx, "JWC", "HTWater_in", "T")]) * processed[d2df(idx, "CAC_HT", "HTWater_out", "mdot")] * CONSTANTS["General"]["CP_WATER"] for idx in engine_set)) hthr_max = temp.resample("D").sum() * 60 * 15 # Contribution from the auxiliary boilers boilers_measured = ( dataset_raw["Boiler_Port"].resample("D").mean() + dataset_raw["Boiler_starbord"].resample("D").mean() ) * CONSTANTS["General"]["HFO"]["LHV"] boilers_calculated = processed[ "Steam:Boiler1:FuelPh_in:mdot"].resample( "D").sum() * 60 * 15 * CONSTANTS["General"]["HFO"]["LHV"] # Total demand total = processed["Demands:Heat:Total:Edot"].resample( "D").sum() * 60 * 15 # Actual plotting ax.plot(hrsg, 'k-', label="HRSG") ax.plot(hthr, 'b-', label="HTHR") # plt.plot(hthr_max, 'b:', label="HTHR max") ax.plot(boilers_measured, 'r-', label="Boilers (M)") ax.plot(boilers_calculated, 'r:', label="Boilers (C)") ax.plot(total, 'g-', label='Total heating demand') plt.legend() if filename == "TimeSeries:TypicalWinterDay": ax.plot(processed["Demands:Mechanical:Total:Edot"]["2014-01-31"], "g-", label="Propulsion power") ax.plot(processed["Demands:Electricity:Total:Edot"]["2014-01-31"], "b--", label="Electric power") ax.plot(processed["Demands:Heat:Total:Edot"]["2014-01-31"], "r:", label="Heat") fig.autofmt_xdate() plt.xlabel("Time [MM-DD HH]") plt.ylabel("Power [kW]") plt.legend() if filename == "TimeSeries:TypicalSummerDay": ax.plot(processed["Demands:Mechanical:Total:Edot"]["2014-07-31"], "g-", label="Propulsion power") ax.plot(processed["Demands:Electricity:Total:Edot"]["2014-07-31"], "b--", label="Electric power") ax.plot(processed["Demands:Heat:Total:Edot"]["2014-07-31"], "r:", label="Heat") fig.autofmt_xdate() plt.xlabel("Time, [MM-DD HH]") plt.ylabel("Power [kW]") plt.legend() if filename == "TimeSeries:El+Tair_vs_time": # Plotting with two different y axis ax.plot(processed["Demands:Electricity:Total:Edot"] ["2014-04-01":"2014-11-01"].resample('D').mean(), "b--", label="Electric power") ax.set_xlabel('Time [YYYY:MM]') ax.set_ylabel('Power [kW]') plt.legend() # Adding the second axis ax2 = ax.twinx() ax2.plot(processed["T_air"]["2014-04-01":"2014-11-01"].resample( 'D').mean(), 'r--', label="Ambient air temperature") ax2.set_ylabel('Temperature [K]') plt.legend() if filename == "TimeSeries:HeatBalance": # Contribution from the HRSGs Qdot_hrsg = (processed["ME2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["ME3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE1:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE4:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]) # Contribution from the HTHR Qdot_hthr = processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS[ "General"]["CP_WATER"] * ( processed["HTHR:HTHR13:HRWater_out:T"] - processed["HTHR:HTHR24:HRWater_in:T"]) Qdot_ab = processed["Steam:Boiler1:FuelPh_in:mdot"] * CONSTANTS[ "General"]["HFO"]["LHV"] * CONSTANTS["OtherUnits"]["BOILER"][ "ETA_DES"] Qdot_dumped = processed["Steam:HotWell:LTWater_in:mdot"] * ( processed["Steam:HotWell:LTWater_out:T"] - processed["Steam:HotWell:LTWater_in:T"] ) * CONSTANTS["General"]["CP_WATER"] Qdot_balance = Qdot_hrsg + Qdot_hthr + Qdot_ab - processed[ "Demands:Heat:Total:Edot"] - Qdot_dumped Qdot_balance.plot() ax.plot(Qdot_balance.cumsum()) plt.title("Heat balance") plt.xlabel("Time") plt.ylabel("Heat balance [kW]") if filename == "TimeSeries:HeatGenerationStacked": Qdot_hrsg = (processed["ME2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["ME3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE1:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE4:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).resample('D').mean() Qdot_hthr = ( processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS["General"]["CP_WATER"] * (processed["HTHR:HTHR13:HRWater_out:T"] - processed["HTHR:HTHR24:HRWater_in:T"])).resample('D').mean() Qdot_ab = (processed["Steam:Boiler1:Steam_HotWell_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).resample('D').mean() x = Qdot_ab.index ax.stackplot( x, Qdot_hrsg, Qdot_hthr, Qdot_ab, colors=("0.66", "0.33", "0")) # label = ["HRSG", "HTHR", "Aux boiler"] p1 = Rectangle((0, 0), 1, 1, fc="0.66") p2 = Rectangle((0, 0), 1, 1, fc="0.33") p3 = Rectangle((0, 0), 1, 1, fc="0") plt.legend([p1, p2, p3], ["HRSG", "HTHR", "Aux boiler"]) plt.xlabel("Time [YYYY-MM]") plt.ylabel("Power [kW]") ### PIE CHARTS ### if filename == "Pie:TotalEnergySimple": quantities = [ processed["Demands:Mechanical:Total:Edot"].sum(), processed["Demands:Electricity:Total:Edot"].sum(), processed["Demands:Heat:Total:Edot"].sum() ] labels = ["Mechanical Power", "Electric Power", "Thermal Power"] explode = (0.05, 0.05, 0.05) ax.pie( quantities, labels=labels, explode=explode, autopct='%1.1f%%', shadow=True, ) if filename == "Pie:DemandFull": quantities = [ processed["Demands:Mechanical:Propeller1:Edot"].sum(), processed["Demands:Mechanical:Propeller2:Edot"].sum(), processed["Demands:Electricity:HVAC:Edot"].sum(), processed["Demands:Electricity:Thrusters:Edot"].sum(), processed["Demands:Electricity:Other:Edot"].sum(), processed["Demands:Heat:HVACpreheater:Edot"].sum(), processed["Demands:Heat:HVACreheater:Edot"].sum(), processed["Demands:Heat:HotWaterHeater:Edot"].sum(), processed["Demands:Heat:MachinerySpaceHeaters:Edot"].sum(), processed["Demands:Heat:OtherTanks:Edot"].sum(), processed["Demands:Heat:TankHeating:Edot"].sum(), processed["Demands:Heat:HFOheater:Edot"].sum(), processed["Demands:Heat:HFOtankHeating:Edot"].sum(), processed["Demands:Heat:Galley:Edot"].sum() ] labels = [ "Propeller-1", "Propeller-2", "HVAC", "Thrusters", "Other users", "HVAC Preheater", "HVAC Reheater", "Hot water heater", "Machinery space heaters", "Other tanks heating", "Fuel tanks heating", "HFO tanks heating", "HFO pre-injection heating", "Galley" ] #explode = [0, 0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] explode = [] for idx in range(len(labels)): explode.append( (1 - (quantities[idx] / sum(quantities))) * 0.05) colors = [ "green", "green", "blue", "blue", "blue", "sandybrown", "sandybrown", "sandybrown", "red", "red", "red", "red", "red", "red" ] patches, texts, autotexts = ax.pie(quantities, labels=labels, explode=explode, autopct='%1.1f%%', colors=colors, pctdistance=0.9) [_.set_fontsize(14) for _ in texts] [_.set_fontsize(14) for _ in autotexts] if filename == "Pie:GenerationFull": quantities = [ processed["ME1:Cyl:FuelPh_in:mdot"].sum(), processed["ME2:Cyl:FuelPh_in:mdot"].sum(), processed["ME3:Cyl:FuelPh_in:mdot"].sum(), processed["ME4:Cyl:FuelPh_in:mdot"].sum(), processed["AE1:Cyl:FuelPh_in:mdot"].sum(), processed["AE2:Cyl:FuelPh_in:mdot"].sum(), processed["AE3:Cyl:FuelPh_in:mdot"].sum(), processed["AE4:Cyl:FuelPh_in:mdot"].sum(), processed["Steam:Boiler1:FuelPh_in:mdot"].sum() ] labels = [ "ME1", "ME2", "ME3", "ME4", "AE1", "AE2", "AE3", "AE4", "AB" ] colors = [ "0.33", "0.33", "0.33", "0.33", "0.66", "0.66", "0.66", "0.66", "black" ] ax.pie(quantities, labels=labels, explode=(0.05, ) * len(labels), autopct='%1.1f%%', colors=colors) if filename == "Pie:HeatDemand": quantities = [] labels = [] explode = [] for demand in dict_structure["systems"]["Demands"]["units"][ "Heat"]["flows"]: quantities.append(processed[d2df("Demands", "Heat", demand, "Edot")].sum()) labels.append(demand) explode.append(0.05) ax.pie(quantities, labels=labels, explode=tuple(explode), autopct='%1.1f%%', shadow=True) if filename == "Pie:HeatGeneration": quantities = [] quantities.append((processed["ME2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["ME3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["AE1:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["AE2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["AE3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["AE4:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) quantities.append((processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS["General"]["CP_WATER"] * (processed["HTHR:HTHR13:HRWater_out:T"] - processed["HTHR:HTHR13:HRWater_in:T"])).sum()) quantities.append((processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS["General"]["CP_WATER"] * (processed["HTHR:HTHR24:HRWater_out:T"] - processed["HTHR:HTHR24:HRWater_in:T"])).sum()) quantities.append( (processed["Steam:Boiler1:Steam_HotWell_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum()) labels = [ "HRSG - ME2", "HRSG - ME3", "HRSG - AE1", "HRSG - AE2", "HRSG - AE3", "HRSG - AE4", "HTHR - ER13", "HTHR - ER24", "Aux Boiler" ] explode = (0.05, ) * len(labels) colors = ("0.33", "0.33", "0.33", "0.33", "0.33", "0.33", "0.66", "0.66", "1.0") ax.pie(quantities, labels=labels, explode=tuple(explode), autopct='%1.1f%%', shadow=True, colors=colors) if filename == "Pie:OperationalMode": quantities = [] labels = [] colors = [] temp = pd.Series(processed["operationalMode"].values, dtype="category") for category in temp.cat.categories: quantities.append(sum(temp == category)) labels.append(category) colors.append("gray") patches = ax.pie(quantities, labels=labels, explode=(0.05, 0.05, 0.05, 0.05), autopct='%1.1f%%', shadow=True, colors=colors)[0] patches[0].set_hatch('/') patches[1].set_hatch('\\') patches[2].set_hatch('x') ### HISTOGRAMS ### if filename == "Hist:WHR": temp = processed["HTHR:HTHR13:HRWater_in:mdot"] * CONSTANTS[ "General"]["CP_WATER"] * ( processed["HTHR:HTHR13:HRWater_out:T"] - processed["HTHR:HTHR24:HRWater_in:T"]) temp2 = (processed["ME2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["ME3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE1:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE2:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE3:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"] + processed["AE4:HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]) ax.hist(temp, 50, normed=1, alpha=0.5, label="HTHR") ax.hist(temp2, 50, normed=1, alpha=0.5, label="HRSG") plt.legend() if filename == "Hist:AuxEngines": temp1 = [] for engine in {"AE1", "AE2", "AE3", "AE4"}: temp1.append( processed[engine + ":Cyl:Power_out:Edot"][processed[engine + ":on"]] / CONSTANTS["AuxEngines"]["MCR"]) ax.hist(tuple(temp1), normed=False, alpha=0.8, label=["AE1", "AE2", "AE3", "AE4"]) plt.legend() plt.xlabel("Engine load") plt.ylabel("Number of observations") if filename == "Hist:MainEngines": temp1 = [] for engine in {"ME1", "ME2", "ME3", "ME4"}: temp1.append( processed[engine + ":Cyl:Power_out:Edot"][processed[engine + ":on"]] / CONSTANTS["MainEngines"]["MCR"]) ax.hist(tuple(temp1), normed=False, alpha=0.8, label=["ME1", "ME2", "ME3", "ME4"]) plt.legend() plt.xlabel("Engine load") plt.ylabel("Number of observations") ### SCATTER PLOTS ### if filename == "Scatter:Pmech_vs_Vship": enginesOn = processed["ME1:on"].astype(int) + processed[ "ME2:on"].astype(int) + processed["ME3:on"].astype( int) + processed["ME4:on"].astype(int) for idx in range(5): ax.scatter(dataset_raw["SHIPS SPEED:79025:knot:Average:900"][ enginesOn == idx], processed["Demands:Mechanical:Total:Edot"][enginesOn == idx], label=(str(idx) + "Engines on")) plt.legend() ### BAR CHARTS ### if filename == "Bar:PercentageWHR": # Exhaust gas Qdot_hrsg = 0 Qdot_eg = 0 Qdot_eg160 = 0 Bdot_hrsg = 0 Bdot_eg = 0 Bdot_eg160diff = 0 Qdot_hthr = (processed["HTHR:HTHR13:HRWater_out:Edot"] - processed["HTHR:HTHR24:HRWater_in:Edot"]).sum() Qdot_ht = 0 Qdot_lt = 0 Bdot_hthr = (processed["HTHR:HTHR13:HRWater_out:Bdot"] - processed["HTHR:HTHR24:HRWater_in:Bdot"]).sum() Bdot_ht = 0 Bdot_lt = 0 for system in { "AE1", "AE2", "AE3", "AE4", "ME1", "ME2", "ME3", "ME4" }: # Exhaust gas, Energy if system in {"AE1", "AE2", "AE3", "AE4", "ME2", "ME3"}: Qdot_hrsg = Qdot_hrsg + ( processed[system + ":HRSG:Steam_in:mdot"] * CONSTANTS["Steam"]["DH_STEAM"]).sum() Bdot_hrsg = Bdot_hrsg + ( processed[system + ":HRSG:Steam_out:Bdot"] - processed[system + ":HRSG:Steam_in:Bdot"]).sum() Qdot_eg = Qdot_eg + processed[system + ":Turbine:Mix_out:Edot"].sum() Qdot_eg160 = Qdot_eg160 + ( processed[system + ":Turbine:Mix_out:mdot"] * CONSTANTS["General"]["CP_EG"] * (processed[system + ":Turbine:Mix_out:T"] - 160 - 273.15)).sum() # Exhaust gas, Exergy Bdot_eg = Bdot_eg + processed[system + ":Turbine:Mix_out:Bdot"].sum() Bdot_eg160diff = Bdot_eg160diff + ( processed[system + ":Turbine:Mix_out:mdot"] * CONSTANTS["General"]["CP_EG"] * np.log( (160 + 237.15) / (processed["T_0"])) * ((160 + 237.15 - processed["T_0"]) / np.log( (160 + 237.15) / (processed["T_0"])) - processed["T_0"])).sum() # Heating systems, Energy Qdot_ht = Qdot_ht + ( processed[system + ":CAC_HT:HTWater_out:Edot"] - processed[system + ":JWC:HTWater_in:Edot"]).sum() Qdot_lt = Qdot_lt + ( processed[system + ":LOC:LTWater_out:Edot"] - processed[system + ":CAC_LT:LTWater_in:Edot"]).sum() # Heating systems, Exergy Bdot_ht = Bdot_ht + ( processed[system + ":CAC_HT:HTWater_out:Bdot"] - processed[system + ":JWC:HTWater_in:Bdot"]).sum() Bdot_lt = Bdot_lt + ( processed[system + ":LOC:LTWater_out:Bdot"] - processed[system + ":CAC_LT:LTWater_in:Bdot"]).sum() Bdot_eg160 = Bdot_eg - Bdot_eg160diff Qdot_cool = Qdot_ht + Qdot_lt Bdot_cool = Bdot_ht + Bdot_lt # Exhast gas, efficiencies eta_hrsg = Qdot_hrsg / Qdot_eg eta_hrsg160 = Qdot_hrsg / Qdot_eg160 eps_hrsg = Bdot_hrsg / Bdot_eg eps_hrsg160 = Bdot_hrsg / Bdot_eg160 # Cooling systems, efficiencies eta_hthr_ht = Qdot_hthr / Qdot_ht eta_hthr_lt = Qdot_hthr / Qdot_cool eps_hthr_ht = Bdot_hthr / Bdot_ht eps_hthr_lt = Bdot_hthr / Bdot_cool # Now we plot for real n_groups = 4 bar_width = 0.4 opacity = 0.4 index = np.arange(n_groups) labels = ("HT water", "All cooling water", "Exhaust Gas, to 160 degC", "Exhaust gas, to environment") group1 = ax.bar(index, [eta_hthr_ht, eta_hthr_lt, eta_hrsg160, eta_hrsg], bar_width, alpha=opacity, color='b', label="Energy-based efficiency") group2 = ax.bar(index + bar_width, [eps_hthr_ht, eps_hthr_lt, eps_hrsg160, eps_hrsg], bar_width, alpha=opacity, color='r', label="Exergy-based efficiency") plt.ylabel('Proportion of available heat recovered') plt.xticks(index + bar_width / 2, labels, rotation=10) plt.legend() plt.show()
def readMainEnginesExistingValues(raw, processed, CONSTANTS, hd): print("Started reading main engines raw values...", end="", flush=True) # This function only reads existing series. It does not do any pre-processing action. for system in CONSTANTS["General"]["NAMES"]["MainEngines"]: # Reading main engines exhaust gas temperature, TC inlet and outlet processed[d2df(system, "Cyl", "EG_out", "T")] = raw[hd[ system + "-TC_EG_T_IN"]] + 273.15 # Measured before mixer with flow form bypass processed[d2df(system, "Turbine", "Mix_out", "T")] = raw[hd[ system + "-TC_EG_T_OUT"]] + 273.15 # Measured after mixer with waste gate # Reading main engines exhaust gas temperature, after HRSG. Only two of the four main engines have the HRSG if system == "ME2" or system == "ME3": processed[d2df(system, "HRSG", "Mix_out", "T")] = raw[hd[system + "-EGB_EG_T_OUT"]] + 273.15 processed[d2df(system, "HRSG", "Mix_in", "T")] = raw[hd[system + "-TC_EG_T_OUT"]] + 273.15 # Temperature in the engine room, i.e. inlet to the compressor of the TC processed[d2df(system, "Comp", "Air_in", "T")] = raw[hd["ER-FWD_AIR_T_"]] + 273.15 # Reading the HT temperature before and after the main engine processed[d2df(system, "JWC", "HTWater_in", "T")] = raw[hd[system + "-HT_FW_T_IN"]] + 273.15 #processed[d2df(system, "CAC_HT", "HTWater_out", "T")] = raw[hd[system + "-HT_FW_T_OUT"]] + 273.15 # Reading the LT temperature before the main engine processed[d2df(system, "CAC_LT", "LTWater_in", "T")] = raw[hd[system + "-LT_FW_T_IN"]] + 273.15 # Reading the Lubricating oil temperature before and after the Lubricating Oil Cooler (hence, In is higher) processed[d2df(system, "LOC", "LubOil_out", "T")] = raw[hd[system + "-LOC_OIL_T_OUT"]] + 273.15 # Reading fuel oil temperature before injection processed[d2df(system, "Cyl", "FuelPh_in", "T")] = raw[hd[system + "-CYL_FUEL_T_IN"]] + 273.15 # Reading charge air temperature, after the charge air cooler (or at cylinder inlet) processed[d2df(system, "CAC_LT", "Air_out", "T")] = raw[hd[system + "-CAC_AIR_T_OUT"]] + 273.15 # Reading Engine rpm processed[d2df(system, "Cyl", "Power_out", "omega")] = raw[hd[system + "__RPM_"]] # Pressure of the charge air, at the compressor outlet (and, hence, at the cylinder inlet) processed[d2df( system, "Comp", "Air_out", "p")] = (raw[hd[system + "-CAC_AIR_P_OUT"]] + 1.01325) * 100000 # Reading the pressure of the lubricating oil # processed[d2df(system, "LOC", "LubOil_out", "p")] = (raw[hd[system + "-LOC_OIL_P_IN"]] + 1.01325) * 100000 # Reading the pressure in the cooling flows processed[d2df( system, "CAC_LT", "LTWater_in", "p")] = (raw[hd[system + "-LT-CAC_FW_P_IN"]] + 1.01325) * 100000 processed[d2df( system, "JWC", "HTWater_in", "p")] = (raw[hd[system + "-HT-JWC_FW_P_IN"]] + 1.01325) * 100000 # Reading turbocharger speed processed[d2df(system, "TCshaft", "Power_in", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "TCshaft", "Power_out", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "Turbine", "Power_out", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "Compressor", "Power_in", "omega")] = raw[hd[system + "-TC__RPM_"]] print("...done!") return processed
def assumptions(raw, processed, CONSTANTS, hd): # This function includes generic assumed values in the main structure # ALL ENGINES for system in {"ME1", "ME2", "ME3", "ME4", "AE1", "AE2", "AE3", "AE4"}: # The pressure at the turbocharger air inlet and exhaust outlet is equal to the atmospheric pressure processed.loc[:,d2df(system,"Comp","Air_in","p")] = CONSTANTS["General"]["P_ATM"] processed.loc[:,d2df(system, "Turbine", "Mix_out", "p")] = CONSTANTS["General"]["P_ATM"] # Temperature in the engine room, i.e. inlet to the compressor of the TC processed[d2df(system, "Comp", "Air_in", "T")] = raw[hd["ER_AIR_T_"]] + 273.15 # Assuming that the pressure in the exhaust gas is 90% of the pressure in the inlet manifold. Somewhat reasonable processed[d2df(system, "Cyl", "EG_out", "p")] = (0.98 * raw[hd[system + "-CAC_AIR_P_OUT"]] + 1.01325) * 100000 # Assuming the pressure of the fuel to be around 9 barg, based on measurements from ME4 processed.loc[:,d2df(system, "Cyl", "FuelPh_in", "p")] = (9 + 1.01325) * 10e5 # Assuming the temperature of the cylinder wall to be 150 degC processed.loc[:,d2df(system, "Cyl", "QdotJW_out", "T")] = 150 + 273.15 processed.loc[:,d2df(system, "JWC", "QdotJW_in", "T")] = 150 + 273.15 # Assuming a temperature of 100 degC for heat losses from the TC shaft processed.loc[:,d2df(system, "TCshaft", "Losses_out", "T")] = 100 + 273.15 # We assume the mixgin temperature at the LT inlet of the HT mixer to be constant processed.loc[:,d2df(system, "HTmerge", "LTWater_in", "T")] = CONSTANTS["MainEngines"]["T_COOLING_MIX"] if system in {"ME1", "ME2", "ME3", "ME4"}: processed.loc[:,d2df(system, "Cyl", "QdotRad_out", "Edot")] = 0.01 * CONSTANTS["MainEngines"]["MCR"] # Assuming the steam pressure and temperature in the HRSG to be constant... hrsg_pressure_assumption = (6 + 1.01325) * 100000 # Adding radiative losses processed.loc[:, d2df(system, "Cyl", "QdotRad_out", "T")] = 100 + 273.15 if system in {"AE1", "AE2", "AE3", "AE4"}: processed.loc[:,d2df(system, "AG", "Losses_out", "T")] = 100 + 273.15 processed.loc[:,d2df(system, "Cyl", "Power_out", "omega")] = 750 processed.loc[:, d2df(system, "Cyl", "QdotRad_out", "Edot")] = 0.01 * CONSTANTS["AuxEngines"]["MCR"] # Others processed.loc[:,"T_0"] = raw[hd["water_T_forsmark_smhi-opendata"]] + 273.15 processed.loc[:,"T_air"] = raw[hd["air_T_sv_hogarna_smhi-opendata"]] + 273.15 processed.loc[:,"ShipSpeed"] = raw[hd["SHIP_SPEED_KNOT_"]] processed[d2df("CoolingSystems","SWC13","SeaWater_out","T")] = raw[hd["SWC13_SW_T_OUT"]] + 273.15 # CHECK IF IT IS IN OR OUT processed[d2df("CoolingSystems","SWC24","SeaWater_out","T")] = raw[hd["SWC24_SW_T_OUT"]] + 273.15 # CHECK IF IT IS IN OR OUT # Boilers processed.loc[:, "Steam:Boiler1:EG_out:p"] = 101325 + 10000 processed.loc[:, "Steam:Boiler1:Air_in:T"] = raw[hd["ER_AIR_T_"]] + 273.15 processed.loc[:, "Steam:Boiler1:Air_in:p"] = 101325 # HTHR system processed.loc[:,"HTHR:SteamHeater:HRWater_out:T"] = 90 + 273.15 # From the heat balance, the temperature needs to rise at 90 degrees # processed.loc[:,"HTHR:SteamHeater:HRWater_out:mdot"] = 298 / 3600 * CONSTANTS["General"]["RHO_W"] # the original value is in m3/h processed.loc[:,"HTHR:HTHR24:HRWater_in:T"] = CONSTANTS["OtherUnits"]["HEAT_DEMAND"]["HTHR_INLET_TEMPERATURE"] # Assumption on the Temperature at the HTHR-24 inlet (HT side) processed.loc[:, "HTHR:HVACpreheater:Qdot_out:T"] = (50 - 23) / np.log((50+273.15)/(23+273.15)) processed.loc[:, "HTHR:HVACreheater:Qdot_out:T"] = (80 - 60) / np.log((80 + 273.15) / (60 + 273.15)) processed.loc[:, "HTHR:HotWaterHeater:Qdot_out:T"] = 70 + 273.15 processed.loc[:, "Steam:TankHeating:Qdot_out:T"] = 60 + 273.15 processed.loc[:, "Steam:MachinerySpaceHeaters:Qdot_out:T"] = processed["HTHR:HVACpreheater:Qdot_out:T"] processed.loc[:, "Steam:Galley:Qdot_out:T"] = 90 + 273.15 processed.loc[:, "Steam:OtherTanks:Qdot_out:T"] = 60 + 273.15 processed.loc[:, "Steam:HFOtankHeating:Qdot_out:T"] = 75 + 273.15 # some sort of average value... processed.loc[:, "Steam:HFOheater:Qdot_out:T"] = (110 - 75) / np.log((110 + 273.15) / (75 + 273.15)) return processed
def engineCoolingSystemsCalculation(processed, CONSTANTS, engine_type): print("Started calculating analysis for {} cooling systems...".format(engine_type), end="", flush=True) # This function calculates the different flows related to the cooling systems of the main engines. for system in CONSTANTS["General"]["NAMES"][engine_type]: # Calculating the total energy flow going to the cooling systems, based on the energy balance on the engine energy_2_cooling = (processed[d2df(system,"Cyl","FuelCh_in","Edot")] + CONSTANTS["General"]["HFO"]["CP"] * processed[d2df(system,"Cyl","FuelPh_in","mdot")] * (processed[d2df(system,"Cyl","FuelPh_in","T")] - processed["T_0"]) - processed[d2df(system, "Cyl", "Power_out", "Edot")] - processed[d2df(system,"Turbine","Mix_out","Edot")] + processed[d2df(system,"Comp","Air_in","Edot")] - processed[d2df(system, "Cyl", "QdotRad_out", "Edot")]) # Calculating the energy going to the charge air cooler, based on the estimated temperatures on the air line energy_2_cac = CONSTANTS["General"]["CP_AIR"] * processed[d2df(system,"Cyl","Air_in","mdot")] * (processed[d2df(system,"Comp","Air_out","T")] - processed[d2df(system,"Cyl","Air_in","T")]) # Calculating the energy going to the HT cooling systems, based on interpolation from the project guide energy_2_ht_theoric = processed[system+":"+"load"].apply(polyvalHelperFunction,args=(CONSTANTS[engine_type]["POLY_LOAD_2_QDOT_HT"],)) * CONSTANTS[engine_type]["QDOT_HT_DES"] energy_2_lt_theoric = processed[system+":"+"load"].apply(polyvalHelperFunction,args=(CONSTANTS[engine_type]["POLY_LOAD_2_QDOT_LT"],)) * CONSTANTS[engine_type]["QDOT_LT_DES"] # The values calculated based on the project guide are reconciled based on the energy balance energy_2_ht = energy_2_cooling * energy_2_ht_theoric / (energy_2_ht_theoric + energy_2_lt_theoric) energy_2_ht[energy_2_ht.isnull()] = 0 energy_2_lt = energy_2_cooling - energy_2_ht # The energy going to the CAC, HT stage is calculated assuming a 85% effectiveness of the heat exchanger energy_2_cac_ht = CONSTANTS[engine_type]["EPS_CAC_HTSTAGE"] * processed[d2df(system,"Comp","Air_in","mdot")] * CONSTANTS["General"]["CP_AIR"] * ( processed[d2df(system,"Comp","Air_out","T")] - processed[d2df(system,"JWC","HTWater_in","T")]) energy_2_cac_ht[energy_2_cac_ht<0] = 0 # The energy going to the CAC, LT stage results as a consequence by thermal balance over the CAC energy_2_cac_lt = energy_2_cac - energy_2_cac_ht # The energy to the JWC results as a balance over the HT cooling systems # energy_2_jwc = energy_2_ht - energy_2_cac_ht energy_2_jwc = (energy_2_cooling - energy_2_cac) / 2 processed[d2df(system,"JWC","QdotJW_in","Edot")] = energy_2_jwc processed[d2df(system, "Cyl", "QdotJW_out", "Edot")] = energy_2_jwc # The energy to the LOC results as a balance over the LT cooling systems # energy_2_loc = energy_2_lt - energy_2_cac_lt energy_2_loc = (energy_2_cooling - energy_2_cac) / 2 # Finally, the temperatures in the flows are calculated based on the calculated energy and mass flow values # For LT, first we have the CAC, then the LOC processed[d2df(system,"CAC_LT","LTWater_out","T")] = processed[d2df(system,"CAC_LT","LTWater_in","T")] + energy_2_cac_lt / processed[d2df(system,"CAC_LT","LTWater_out","mdot")] / CONSTANTS["General"]["CP_WATER"] processed[d2df(system,"LOC","LTWater_out","T")] = processed[d2df(system,"CAC_LT","LTWater_out","T")] + energy_2_loc / processed[d2df(system,"LOC","LTWater_out","mdot")] / CONSTANTS["General"]["CP_WATER"] # For HT, first we have the JWC, then the CAC, HT processed[d2df(system,"JWC","HTWater_out","T")] = processed[d2df(system,"JWC","HTWater_in","T")] + energy_2_jwc / processed[d2df(system,"JWC","HTWater_out","mdot")] / CONSTANTS["General"]["CP_WATER"] processed[d2df(system,"CAC_HT","HTWater_out","T")] = processed[d2df(system,"JWC","HTWater_out","T")] + energy_2_cac_ht / processed[d2df(system,"CAC_HT","HTWater_out","mdot")] / CONSTANTS["General"]["CP_WATER"] # For the LOC, we know the outlet (lower) temperature, we calculate the inlet temperature processed[d2df(system,"LOC","LubOil_in","T")] = processed[d2df(system,"LOC","LubOil_out","T")] + energy_2_loc / processed[d2df(system,"LOC","LubOil_out","mdot")] / CONSTANTS["General"]["CP_LO"] # Now calculating the temperature of the air in the charge air cooler processed[d2df(system, "CAC_HT", "Air_out", "T")] = processed[d2df(system, "Comp", "Air_out", "T")] - energy_2_cac_ht / processed[d2df(system,"Cyl","Air_in","mdot")] / CONSTANTS["General"]["CP_AIR"] processed[d2df(system, "CAC_LT", "Air_out", "T")] = processed[d2df(system, "CAC_HT", "Air_out", "T")] - energy_2_cac_lt / processed[d2df(system, "Cyl", "Air_in", "mdot")] / CONSTANTS["General"]["CP_AIR"] # Finally, we have the HRSG (for some cases) if system == "ME1": aaa = 0 if engine_type == "AuxEngines" or system in {"ME2", "ME3"}: processed[d2df(system,"HRSG","Steam_in","mdot")] = ((processed[d2df(system,"HRSG","Mix_in","h")] - processed[d2df(system,"HRSG","Mix_out","h")]) * processed[d2df(system, "HRSG", "Mix_in", "mdot")] / (CONSTANTS["Steam"]["H_STEAM_VS"] - CONSTANTS["Steam"]["H_STEAM_LS"])) processed.loc[processed[d2df(system, "HRSG", "Steam_in", "mdot")]<0, d2df(system, "HRSG", "Steam_in", "mdot")] = 0 # Calculation of the mass recirculating from the LT outlet to the HT inlet (not exactly...) processed[d2df(system, "HTmerge", "LTWater_in", "mdot")] = processed[d2df(system,"JWC","HTWater_out","mdot")] * ( processed[d2df(system, "CAC_HT", "HTWater_out", "T")] - processed[d2df(system,"JWC","HTWater_in","T")]) / ( processed[d2df(system, "CAC_HT", "HTWater_out", "T")] - CONSTANTS[engine_type]["T_COOLING_MIX"]) print("...done!") return processed
def propertyCalculator(processed, dict_structure, CONSTANTS, system_list): print("Started calculating flow properties...", end="", flush=True) df_index = processed.index for system in system_list: for unit in dict_structure["systems"][system]["units"]: for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: if system + ":" + unit + ":" + flow == "Steam:Boiler1:Air_in": aaa = 0 # The calculation of the properties is done if and only if the exergy flow is completely empty if processed[d2df(system, unit, flow, "Bdot")].isnull().sum() == len( processed[d2df(system, unit, flow, "Bdot")]): if dict_structure["systems"][system]["units"][unit][ "flows"][flow]["type"] == "CPF": # Only doing the calculations if the values for p and T are not NaN if processed[d2df(system, unit, flow, "T")].isnull().sum() != len( processed[d2df( system, unit, flow, "T")]): temp = processed[d2df(system, unit, flow, "T")] # .values() press = processed[d2df(system, unit, flow, "p")] # .values() # If the specific enthalpy is available already, it needs to be calculated if ("Air" in flow) or ("BP" in flow): # print("Calculating properties for " + system + "_" + unit + "_" + flow) # dh = pd.Series(cp.PropsSI('H','T',np.array(temp),'P',np.array(press), 'Air.mix'), index=df_index) - pd.Series(cp.PropsSI('H', 'T', np.array(processed["T_0"]), 'P', CONSTANTS["General"]["P_ATM"], 'Air.mix'), index=df_index) # ds = pd.Series(cp.PropsSI('S', 'T', np.array(temp), 'P', np.array(press), 'Air.mix'), index=df_index) - pd.Series(cp.PropsSI('S', 'T', np.array(processed["T_0"]), 'P', CONSTANTS["General"]["P_ATM"], 'Air.mix'), index=df_index) R = CONSTANTS["General"]["R_0"] / 29 dh = ( pd.Series(enthalpyCalculator( np.array(temp), CONSTANTS), index=df_index) - pd.Series(enthalpyCalculator( np.array(processed["T_0"]), CONSTANTS), index=df_index)) ds = ( pd.Series(entropyCalculator( np.array(temp), CONSTANTS), index=df_index) - pd.Series(entropyCalculator( np.array(processed["T_0"]), CONSTANTS), index=df_index) - R * np.log( np.array(press) / CONSTANTS["General"]["P_ATM"])) elif ("Mix" in flow) or ("EG" in flow): if system in CONSTANTS["General"]["NAMES"][ "MainEngines"].union( CONSTANTS["General"]["NAMES"] ["AuxEngines"]): mixture = ppo.mixtureCompositionNew( processed[d2df(system, unit, flow, "mdot")], processed[d2df(system, "Cyl", "FuelPh_in", "mdot")], processed[d2df(system, "Cyl", "FuelPh_in", "T")], CONSTANTS) elif system == "Steam": mixture = ppo.mixtureCompositionNew( processed[d2df(system, unit, flow, "mdot")], processed[d2df(system, "Boiler1", "FuelPh_in", "mdot")], processed[d2df(system, "Boiler1", "FuelPh_in", "T")], CONSTANTS) R = CONSTANTS["General"]["R_0"] * sum( mixture[idx] / CONSTANTS["General"]["MOLAR_MASSES"][idx] for idx in {"N2", "O2", "CO2", "H2O"}) dh = pd.Series(enthalpyCalculator( np.array(temp), CONSTANTS, mixture), index=df_index) - pd.Series( enthalpyCalculator( np.array( processed["T_0"]), CONSTANTS, mixture), index=df_index) ds = pd.Series( entropyCalculator(np.array(temp), CONSTANTS, mixture), index=df_index) - pd.Series( entropyCalculator( np.array(processed["T_0"]), CONSTANTS, mixture), index=df_index) - (R * np.log( np.array(press) / CONSTANTS["General"]["P_ATM"])) #elif "Steam" in flow: # if "in" in flow: # dh = CONSTANTS["Steam"]["DH_STEAM"] + CONSTANTS["General"]["CP_WATER"] * (processed[d2df(system, unit, flow, "T")] - processed["T_0"]) # ds = CONSTANTS["Steam"]["DS_STEAM"] + CONSTANTS["General"]["CP_WATER"] * np.log((processed[d2df(system, unit, flow, "T")] / processed["T_0"])) #elif "out" in flow: # dh = CONSTANTS["General"]["CP_WATER"] * (processed[d2df(system, unit, flow, "T")] - processed["T_0"]) # ds = CONSTANTS["General"]["CP_WATER"] * np.log((processed[d2df(system, unit, flow, "T")] / processed["T_0"])) if system + ":" + unit + ":on" in processed.keys(): dh.loc[~processed[system + ":" + unit + ":on"]] = 0 ds.loc[~processed[system + ":" + unit + ":on"]] = 0 processed[d2df(system, unit, flow, "h")] = dh processed[d2df(system, unit, flow, "b")] = dh - processed["T_0"] * ds processed[d2df(system, unit, flow, "Edot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "h")] processed[d2df(system, unit, flow, "Bdot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "b")] else: pass # print("Couldn't calculate the properties for the {} flow, didn't have all what I needed, {}% of the values are NaN".format(system+":"+unit+":"+flow, processed[d2df(system,unit,flow,"T")].isnull().sum()/len(processed[d2df(system,unit,flow,"T")])*100)) elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["type"] == "IPF": if processed[d2df(system, unit, flow, "T")].isnull().sum() != len( processed[d2df( system, unit, flow, "T")]): if "Water" in flow: if flow == "SeaWater_in": dh = pd.Series(index=df_index) ds = pd.Series(index=df_index) dh[:] = 0 ds[:] = 0 dh = CONSTANTS["General"]["CP_WATER"] * ( processed[d2df(system, unit, flow, "T")] - processed["T_0"]) ds = CONSTANTS["General"]["CP_WATER"] * np.log( (processed[d2df(system, unit, flow, "T")] / processed["T_0"])) if "LubOil" in flow: dh = CONSTANTS["General"]["CP_LO"] * ( processed[d2df(system, unit, flow, "T")] - processed["T_0"]) ds = CONSTANTS["General"]["CP_LO"] * np.log( (processed[d2df(system, unit, flow, "T")] / processed["T_0"])) if "Fuel" in flow: dh = CONSTANTS["General"]["HFO"]["CP"] * ( processed[d2df(system, unit, flow, "T")] - processed["T_0"]) ds = CONSTANTS["General"]["HFO"]["CP"] * np.log( (processed[d2df(system, unit, flow, "T")] / processed["T_0"])) if system + ":" + unit + ":on" in processed.keys(): dh.loc[~processed[system + ":" + unit + ":on"]] = 0 ds.loc[~processed[system + ":" + unit + ":on"]] = 0 processed[d2df(system, unit, flow, "h")] = dh processed[d2df(system, unit, flow, "b")] = dh - processed["T_0"] * ds processed[d2df(system, unit, flow, "Edot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "h")] processed[d2df(system, unit, flow, "Bdot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "b")] else: pass #print("Couldn't calculate the properties for the {} flow, didn't have all what I needed, {}% of the values are NaN".format(system + ":" + unit + ":" + flow, processed[d2df(system,unit,flow,"T")].isnull().sum()/len(processed[d2df(system,unit,flow,"T")])*100)) elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["type"] == "SF": if dict_structure["systems"][system]["units"][unit][ "flows"][flow]["state"] == "SL": dh = CONSTANTS["Steam"]["H_STEAM_LS"] - CONSTANTS[ "General"]["CP_WATER"] * (processed["T_0"] - 273.15) ds = CONSTANTS["Steam"]["S_STEAM_LS"] - CONSTANTS[ "General"]["CP_WATER"] * np.log( processed["T_0"] / 273.15) elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["state"] == "SV": dh = CONSTANTS["Steam"]["H_STEAM_VS"] - CONSTANTS[ "General"]["CP_WATER"] * (processed["T_0"] - 273.15) ds = CONSTANTS["Steam"]["S_STEAM_VS"] - CONSTANTS[ "General"]["CP_WATER"] * np.log( processed["T_0"] / 273.15) else: print( "Steam can be either saturated liquid or saturated vapor, nothing in between" ) processed[d2df(system, unit, flow, "h")] = dh processed[d2df(system, unit, flow, "b")] = dh - processed["T_0"] * ds processed[d2df( system, unit, flow, "Edot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "h")] processed[d2df( system, unit, flow, "Bdot")] = processed[d2df( system, unit, flow, "mdot")] * processed[d2df( system, unit, flow, "b")] elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["type"] == "Qdot": processed[d2df( system, unit, flow, "Bdot")] = processed[d2df( system, unit, flow, "Edot")] * ( 1 - processed["T_0"] / processed[d2df(system, unit, flow, "T")]) elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["type"] in {"Wdot", "CEF"}: processed[d2df(system, unit, flow, "Bdot")] = processed[d2df( system, unit, flow, "Edot")] print("...done!") return processed
def mainEngineAirFlowCalculation(raw, processed, dict_structure, CONSTANTS): print("Started calculating main engine air and exhaust flows...", end="", flush=True) # This function calculates the different air and exhaust gas flows in the main engines, taking into account the # presence of air bypass and exhaust wastegate valves for system in CONSTANTS["General"]["NAMES"]["MainEngines"]: # Calculating the compressor's compression ratio beta_comp = processed[d2df(system, "Comp", "Air_out", "p")] / processed[d2df( system, "Comp", "Air_in", "p")] # Calculating the turbocharger's mechancial efficiency based on the regression eta_tc = ( processed[d2df(system, "TCshaft", "Power_in", "omega")] / CONSTANTS["MainEngines"]["RPM_TC_DES"]).apply( polyvalHelperFunction, args=(CONSTANTS["MainEngines"]["POLY_TC_RPM_2_ETA_MECH"], )) # Calculating the compressor isentropic efficiency comp_isentropic_efficiency = beta_comp.apply( polyvalHelperFunction, args=(CONSTANTS["MainEngines"]["POLY_PIN_2_ETA_IS"], )) # Calculating the temperature after the compressor, based on ideal gas assumption T_Comp_out_iso = processed[d2df( system, "Comp", "Air_in", "T")] * beta_comp**( (CONSTANTS["General"]["K_AIR"] - 1) / CONSTANTS["General"]["K_AIR"]) T_Comp_out = processed[d2df( system, "Comp", "Air_in", "T")] + (T_Comp_out_iso - processed[d2df( system, "Comp", "Air_in", "T")]) / comp_isentropic_efficiency #### NOTE: HERE WE MAKE THE ASSUMPTION THAT THE COMPRESSOR OUTLET TEMPERATURE CANNOT BE LOWER THAN THE CYLINDER INLET TEMPERATURE T_Comp_out[T_Comp_out < processed[d2df( system, "Cyl", "Air_in", "T")]] = processed.loc[ T_Comp_out < processed[d2df(system, "Cyl", "Air_in", "T")], d2df(system, "Cyl", "Air_in", "T")] processed[d2df(system, "Comp", "Air_out", "T")] = T_Comp_out # Calculating the air inflow aspired by the cylinder: calculated as inlet air density times the maximum volume, # times the engine speed processed[d2df( system, "Cyl", "Air_in", "mdot")] = CONSTANTS["MainEngines"]["AIR_FLOW_MULT"] * CONSTANTS[ "MainEngines"]["V_MAX"] * (processed[d2df( system, "Comp", "Air_out", "p")]) / ( CONSTANTS["General"]["R_AIR"] * processed[d2df(system, "Cyl", "Air_in", "T")] ) * (processed[d2df(system, "Cyl", "Power_out", "omega")] / 60 / 2 * CONSTANTS["General"]["ETA_VOL"]) * ( CONSTANTS["MainEngines"]["N_CYL"]) processed[d2df(system, "Cyl", "EG_out", "mdot")] = processed[d2df( system, "Cyl", "Air_in", "mdot")] + processed[d2df( system, "Cyl", "FuelPh_in", "mdot")] # Calculating the bypass flow #processed[d2df(system,"BPsplit","BP_out","mdot")] = ( # CONSTANTS["General"]["CP_AIR"] * processed[d2df(system,"Cyl","Air_in","mdot")] * (processed[d2df(system,"Comp","Air_out","T")] - processed[d2df(system,"Comp","Air_in","T")]) + # CONSTANTS["General"]["CP_EG"] * CONSTANTS["MainEngines"]["ETA_MECH_TC"] * (processed[d2df(system,"Cyl","Air_in","mdot")] + processed[d2df(system,"Cyl","FuelPh_in","mdot")]) * # (processed[d2df(system,"Turbine","Mix_out","T")] - processed[d2df(system,"Cyl","EG_out","T")])) / ( # CONSTANTS["General"]["CP_AIR"] * ( # processed[d2df(system,"Comp","Air_in","T")] - CONSTANTS["MainEngines"]["ETA_MECH_TC"] * processed[d2df(system,"Turbine","Mix_out","T")] - # (CONSTANTS["MainEngines"]["ETA_MECH_TC"] - 1) * processed[d2df(system,"Comp","Air_out","T")])) num1 = eta_tc * processed[d2df( system, "Cyl", "EG_out", "mdot")] * CONSTANTS["General"]["CP_EG"] * ( processed[d2df(system, "Cyl", "EG_out", "T")] - processed[d2df(system, "Turbine", "Mix_out", "T")]) num2 = processed[d2df( system, "Cyl", "Air_in", "mdot")] * CONSTANTS["General"]["CP_AIR"] * ( processed[d2df(system, "Comp", "Air_out", "T")] - processed[d2df(system, "Comp", "Air_in", "T")]) den1 = CONSTANTS["General"]["CP_AIR"] * ( processed[d2df(system, "Comp", "Air_out", "T")] - processed[d2df(system, "Comp", "Air_in", "T")]) den2 = eta_tc * CONSTANTS["General"]["CP_AIR"] * ( processed[d2df(system, "Turbine", "Mix_out", "T")] - processed[d2df(system, "Comp", "Air_out", "T")]) processed[d2df(system, "BPsplit", "BP_out", "mdot")] = (num1 - num2) / (den1 + den2) # Calculating the temperature of the mixture after the merge between bypass and exhaust gas from the cylinders processed[d2df( system, "Turbine", "Mix_in", "T")] = (processed[d2df(system, "BPsplit", "BP_out", "mdot")] * CONSTANTS["General"]["CP_AIR"] * processed[d2df(system, "Comp", "Air_out", "T")] + processed[d2df(system, "Cyl", "EG_out", "mdot")] * CONSTANTS["General"]["CP_EG"] * processed[d2df(system, "Cyl", "EG_out", "T")]) / ( processed[d2df(system, "Cyl", "EG_out", "mdot")] * CONSTANTS["General"]["CP_EG"] + processed[d2df(system, "BPsplit", "BP_out", "mdot")] * CONSTANTS["General"]["CP_AIR"]) # The air mass flow going through the compressor is equal to the sum of the air flow through the bypass valve and to the cylinders processed[d2df(system, "BPsplit", "Air_in", "mdot")] = processed[d2df( system, "BPsplit", "BP_out", "mdot")] + processed[d2df( system, "Cyl", "Air_in", "mdot")] # The flow through the turbine is equal to the sum of the bypass flow and the exhaust coming from the cylinders processed[d2df(system, "BPmerge", "Mix_out", "mdot")] = processed[d2df( system, "BPsplit", "BP_out", "mdot")] + processed[d2df( system, "Cyl", "EG_out", "mdot")] # Assiging the mass flow values for the HRSGs otherwise it makes a mess if system in {"ME2", "ME3"}: processed[d2df(system, "HRSG", "Mix_in", "mdot")] = processed[d2df(system, "BPmerge", "Mix_out", "mdot")] processed[d2df(system, "HRSG", "Mix_out", "mdot")] = processed[d2df(system, "BPmerge", "Mix_out", "mdot")] print("...done!") return processed
def seaWaterCoolers(processed, CONSTANTS, dict_structure): # Calculations for the seaWaterCoolers processed[d2df("CoolingSystems", "SWC13", "SeaWater_in", "T")] = processed.loc[:, "T_0"] # Inlet temperature equal to the sea water temperature processed[d2df("CoolingSystems", "SWC24", "SeaWater_in", "T")] = processed.loc[:, "T_0"] # Inlet temperature equal to the sea water temperature dT_13 = processed[d2df("CoolingSystems", "SWC13", "SeaWater_out", "T")] - processed[d2df("CoolingSystems", "SWC13", "SeaWater_in", "T")] dT_13[dT_13 < 5] = 5 dT_24 = processed[d2df("CoolingSystems", "SWC24", "SeaWater_out", "T")] - processed[d2df("CoolingSystems", "SWC24", "SeaWater_in", "T")] dT_24[dT_24 < 5] = 5 processed[d2df("CoolingSystems", "SWC13", "SeaWater_in", "mdot")] = ( processed[d2df("CoolingSystems", "SWC13", "LTWater_out", "mdot")] * (processed[d2df("CoolingSystems", "SWC13", "LTWater_in", "T")] - processed[d2df("CoolingSystems", "SWC13", "LTWater_out", "T")]) / (dT_13)) processed[d2df("CoolingSystems", "SWC13", "SeaWater_out", "mdot")] = processed[d2df("CoolingSystems", "SWC13", "SeaWater_in", "mdot")] processed[d2df("CoolingSystems", "SWC24", "SeaWater_in", "mdot")] = ( processed[d2df("CoolingSystems", "SWC24", "LTWater_out", "mdot")] * (processed[d2df("CoolingSystems", "SWC24", "LTWater_in", "T")] - processed[d2df("CoolingSystems", "SWC24", "LTWater_out", "T")]) / (dT_24)) processed[d2df("CoolingSystems", "SWC24", "SeaWater_out", "mdot")] = processed[d2df("CoolingSystems", "SWC24", "SeaWater_in", "mdot")] # Extra calls to the mass balance calculation function to make sure all values are calculated (counter, processed) = ff.massFill(processed, dict_structure, CONSTANTS, "CoolingSystems", "SWC13", dict_structure["systems"]["CoolingSystems"]["units"]["SWC13"]["streams"], "extra-1") processed[d2df("CoolingSystems", "LTcollector13", "LTWater_out", "mdot")] = processed[d2df("CoolingSystems", "SWC13", "LTWater_in", "mdot")] (counter, processed) = ff.massFill(processed, dict_structure, CONSTANTS, "CoolingSystems", "LTcollector13", dict_structure["systems"]["CoolingSystems"]["units"]["LTcollector13"]["streams"],"extra-1") processed[d2df("CoolingSystems", "LTHTmerge13", "LTWater_in", "mdot")] = processed[d2df("CoolingSystems", "LTcollector13", "HTWater_out", "mdot")] return processed
def predefinedTables(processed, name, CONSTANTS, dict_structure, system, load_vector): file = open(CONSTANTS["filenames"]["latex_table"], "w") if name == "MainEnginesModel": for unit in dict_structure["systems"]["ME1"]["units"]: for flow in dict_structure["systems"]["ME1"]["units"][unit][ "flows"]: if dict_structure["systems"]["ME1"]["units"][unit]["flows"][ flow]["type"] in {"IPF", "CPF"}: for property in {"T", "mdot"}: value = [] for load in [0.3, 0.5, 0.7, 0.9]: if property == "T": rounding = 1 else: rounding = 2 value.append( round( processed[d2df("ME1", unit, flow, property)] [(processed["ME1:load"] < load + 0.005) & (processed["ME1:load"] > load - 0.005)].mean(), rounding)) print(property + "_" + unit + "_" + flow + " = " + str(value[0]) + " & " + str(value[1]) + " & " + str(value[2]) + " & " + str(value[3]) + " \\\\ ") if name == "MainEnginesEnergyFlows": df = pd.DataFrame(index=processed.index) df["Wdot_mech"] = processed[d2df(system, "Cyl", "Power_out", "Edot")] df["Qdot_eg"] = processed[d2df(system, "Turbine", "Mix_out", "Edot")] df["Qdot_jwc"] = processed[d2df(system, "Cyl", "QdotJW_out", "Edot")] df["Qdot_loc"] = processed[d2df( system, "LOC", "LTWater_out", "Edot")] - processed[d2df( system, "LOC", "LTWater_in", "Edot")] df["Qdot_caclt"] = processed[d2df( system, "CAC_LT", "LTWater_out", "Edot")] - processed[d2df( system, "CAC_LT", "LTWater_in", "Edot")] df["Qdot_cacht"] = processed[d2df( system, "CAC_HT", "HTWater_out", "Edot")] - processed[d2df( system, "CAC_HT", "HTWater_in", "Edot")] df["Qdot_ht"] = df["Qdot_cacht"] + df["Qdot_jwc"] df["Qdot_lt"] = df["Qdot_caclt"] + df["Qdot_loc"] output = {} load_vector = [0.3, 0.5, 0.7, 0.9] for flow in df.keys(): output[flow] = [] string = flow + " = " for load in load_vector: value = round( df[flow][(processed[system + ":load"] < load + 0.005) & ( processed[system + ":load"] > load - 0.005)].mean(), 0) output[flow].append(value) string = string + " & " + str(value) print(string) plt.figure() for flow in output: plt.plot(load_vector, output[flow], label=flow) plt.xlabel("Engine load") plt.ylabel("Energy flow [kW]") plt.legend() plt.grid()
["TimeSeries:HeatGenerationStacked"]) # processed = ea.efficiencyCalculator(processed, dict_structure, CONSTANTS) ## PLAYGROUND ## #%% import matplotlib matplotlib.style.use('ggplot') #%% k_1_3 = 927.27 k_2_4 = 903.65 ME1_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] ME2_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] ME3_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] ME4_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] AE1_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] AE2_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] AE3_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] AE4_FO = processed[d2df('ME1', 'Cyl', 'FuelPh_in', 'mdot')] FO1_flow = dataset_raw[ 'FO BOOST 1 CONSUMPT:6165:m3/h:Average:900'] / 3.600 * k_1_3 FO2_flow = dataset_raw[ 'FO BOOST 2 CONSUMPT:6166:m3/h:Average:900'] / 3.600 * k_2_4 tot_ME13 = (ME1_FO + ME3_FO + AE1_FO) * 1000 tot_ME24 = (ME2_FO + ME4_FO + AE2_FO + AE4_FO) * 1000
def engineLoadCalculation(type, raw, processed, CONSTANTS, hd): for system in CONSTANTS["General"]["NAMES"][type]: processed[system + ":" + "load"] = processed[d2df( system, "Cyl", "Power_out", "Edot")] / CONSTANTS[type]["MCR"] return processed
def enginesCheck(processed, CONSTANTS): # This function checks that all relative values are consistent text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") print("Started consistency check for the engines...", end="", flush=True) text_file.write("\n *** CONSISTENTCY CHECK FOR ENGINES *** \n") for type in ["MainEngines", "AuxEngines"]: for name in CONSTANTS["General"]["NAMES"][type]: on = processed[name + ":" + "on"] tot = sum(on) # Compressor outlet temperature must be higher than compressor inlet temperature temp = sum( processed[d2df(name, "Comp", "Air_out", "T")][on] >= processed[ d2df(name, "Comp", "Air_in", "T")][on]) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write(warn + name + " Compressor temperatures are consistent for " + str(temp) + " % of the datapoints \n") # Exhaust temperature should be higher closer to the engine exhaust valve temp = sum( processed[d2df(name, "Cyl", "EG_out", "T")][on] >= processed[ d2df(name, "Turbine", "Mix_in", "T")][on]) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " Exhaust temperatures (Cyl->TC are consistent for " + str(temp) + " % of the datapoints \n") temp = sum(processed[d2df(name, "Turbine", "Mix_in", "T")][on] >= processed[d2df(name, "Turbine", "Mix_out", "T")][on] ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write(warn + name + " Turbine temperatures are consistent for " + str(temp) + " % of the datapoints \n") # Checking the consistency of the LOC temperatures temp = sum(processed[d2df(name, "LOC", "LubOil_in", "T")][on] >= processed[d2df(name, "LOC", "LubOil_out", "T")][on] ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " LOC temperatures (oil side) are consistent for " + str(temp) + " % of the datapoints \n") temp = sum(processed[d2df(name, "LOC", "LTWater_out", "T")][on] >= processed[d2df(name, "LOC", "LTWater_in", "T")][on] ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " LOC temperatures (LT water side) are consistent for " + str(temp) + " % of the datapoints \n") # Checking the consistency of the CAC_LT temperatures temp = sum(processed[d2df(name, "CAC_LT", "Air_in", "T")][on] >= processed[d2df(name, "CAC_LT", "Air_out", "T")][on] ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " CAC_LT temperatures (air side) are consistent for " + str(temp) + " % of the datapoints \n") temp = sum(processed[d2df( name, "CAC_LT", "LTWater_out", "T")][on] >= processed[d2df( name, "CAC_LT", "LTWater_in", "T")][on]) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " CAC_LT temperatures (LT water side) are consistent for " + str(temp) + " % of the datapoints \n") # Checking the consistency of the CAC_HT temperatures temp = sum(processed[d2df(name, "CAC_HT", "Air_in", "T")][on] >= processed[d2df(name, "CAC_HT", "Air_out", "T")][on] ) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " CAC_HT temperatures (air side) are consistent for " + str(temp) + " % of the datapoints \n") temp = sum(processed[d2df( name, "CAC_HT", "HTWater_out", "T")][on] >= processed[d2df( name, "CAC_HT", "HTWater_in", "T")][on]) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " CAC_HT temperatures (HT water side) are consistent for " + str(temp) + " % of the datapoints \n") # Checking the overall engine balance energyOutput = ( processed[d2df(name, "Cyl", "Power_out", "Edot")] + processed[d2df(name, "Turbine", "Mix_out", "Edot")] + (processed[d2df(name, "LOC", "LTWater_out", "Edot")] - processed[d2df(name, "CAC_LT", "LTWater_in", "Edot")]) + (processed[d2df(name, "CAC_HT", "HTWater_out", "Edot")] - processed[d2df(name, "JWC", "HTWater_in", "Edot")]) + processed[d2df(name, "Cyl", "QdotRad_out", "Edot")]) energyInput = (processed[d2df(name, "Cyl", "FuelCh_in", "Edot")] + processed[d2df(name, "Cyl", "FuelPh_in", "Edot")] + processed[d2df(name, "Comp", "Air_in", "Edot")]) energyBalance = abs(((energyInput - energyOutput) / energyInput)) temp = sum( energyBalance[processed[name + ":on"]] <= 0.01) / tot * 100 warn = "WARNING " if temp < 95 else "" text_file.write( warn + name + " The overall energy balance of the engine is consistent for " + str(temp) + " % of the datapoints \n") text_file.close() print("...done!")
def auxEngineAirFlowPostCalculation(processed, CONSTANTS): print("Started calculating auxiliary engine air and exhaust flows...", end="", flush=True) # This function calculates the different air and exhaust gas flows in the main engines, taking into account the # presence of air bypass and exhaust wastegate valves for system in CONSTANTS["General"]["NAMES"]["AuxEngines"]: # Calculating the turbine's power outpput to the compressor processed[d2df(system, "Turbine", "Power_out", "Edot")] = processed[d2df(system, "BPmerge", "Mix_out", "mdot")] * ( processed[d2df(system, "Turbine", "Mix_in", "h")] - processed[d2df(system, "Turbine", "Mix_out", "h")]) # Calculating the compressor's power input. processed[d2df(system, "Comp", "Power_in", "Edot")] = processed[d2df(system, "BPsplit", "Air_in", "mdot")] * ( processed[d2df(system, "Comp", "Air_out", "h")] - processed[d2df(system, "Comp", "Air_in", "h")]) # Losses at the TC shaft level are calculated etaTcMech = (processed[d2df(system, "TCshaft", "Power_in", "omega")]/CONSTANTS["AuxEngines"]["RPM_TC_DES"]).apply(polyvalHelperFunction,args=(CONSTANTS["MainEngines"]["POLY_TC_RPM_2_ETA_MECH"],)) processed[d2df(system, "TCshaft", "Losses_out", "Edot")] = processed[d2df(system, "Turbine", "Power_out", "Edot")] * (1 - etaTcMech) return processed
def readAuxEnginesExistingValues(raw, processed,CONSTANTS,hd): print("Started reading raw values for auxiliary engines...", end="", flush=True) for system in CONSTANTS["General"]["NAMES"]["AuxEngines"]: # Reading main engines exhaust gas temperature, TC inlet and outlet processed[d2df(system,"Turbine","Mix_in","T")] = raw[hd[system + "-TC_EG_T_IN1"]] + 273.15 processed[d2df(system,"Turbine","Mix_out","T")] = raw[hd[system + "-TC_EG_T_OUT"]] + 273.15 # Reading main engines exhaust gas temperature, after HRSG processed[d2df(system,"HRSG","Mix_out","T")] = raw[hd[system + "-EGB_EG_T_OUT"]] + 273.15 # Reading the HT temperature before and after the main engine processed[d2df(system,"JWC","HTWater_in","T")] = raw[hd[system + "-HT_FW_T_IN"]] + 273.15 #processed[d2df(system, "CAC_HT", "HTWater_out", "T")] = raw[hd[system + "-HT_FW_T_OUT2"]] + 273.15 # Reading the LT temperature before the main engine processed[d2df(system,"CAC_LT","LTWater_in","T")] = raw[hd[system + "-LT-CAC_FW_T_IN"]] + 273.15 # Reading the Lubricating oil temperature before and after the Lubricating oil cooler processed[d2df(system,"LOC","LubOil_out","T")] = raw[hd[system + "-LOC_OIL_T_OUT"]] + 273.15 # Reading fuel oil temperature before injection processed[d2df(system,"Cyl","FuelPh_in","T")] = raw[hd[system + "-CYL_FUEL_T_IN"]] + 273.15 # Reading charge air temperature. processed[d2df(system,"CAC_LT","Air_out","T")] = raw[hd[system + "-CAC_AIR_T_OUT"]] + 273.15 # Reading power output processed[d2df(system,"AG","Power_out","Edot")] = raw[hd[system + "_POWER_Wdot_OUT"]] # Reading Engine rpm # processed[d2df(system, "Cyl", "Power_out", "omega")] = raw[hd[system + "__RPM_"]] # Reading the pressure in the cooling flows processed[d2df(system, "CAC_LT", "LTWater_in", "p")] = (raw[hd[system + "-LT-CAC_FW_P_IN"]] + 1.01325) * 100000 processed[d2df(system, "JWC", "HTWater_in", "p")] = raw[hd[system + "-HT-JWC_FW_P_IN"]] + 273.15 processed[d2df(system, "Comp", "Air_out", "p")] = (raw[hd[system + "-CAC_AIR_P_OUT"]] + 1.01325) * 100000 # Reading the pressure of the lubricating oil processed[d2df(system, "LOC", "LubOil_out", "p")] = (raw[hd[system + "-LOC_OIL_P_IN"]] + 1.01325) * 100000 # Reading the pressure in the cooling flows processed[d2df(system, "CAC_LT", "LTWater_in", "p")] = (raw[hd[system + "-LT-CAC_FW_P_IN"]] + 1.01325) * 100000 processed[d2df(system, "JWC", "HTWater_in", "p")] = (raw[hd[system + "-HT-JWC_FW_P_IN"]] + 1.01325) * 100000 # Reading turbocharger speed processed[d2df(system, "TCshaft", "Power_in", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "TCshaft", "Power_out", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "Turbine", "Power_out", "omega")] = raw[hd[system + "-TC__RPM_"]] processed[d2df(system, "Compressor", "Power_in", "omega")] = raw[hd[system + "-TC__RPM_"]] # TEMPORARY: Filter on fuel temperature if system == "AE3": processed.loc[ processed[d2df(system, "Cyl", "FuelPh_in", "T")] < 300, d2df(system, "Cyl", "FuelPh_in", "T")] = 300 else: processed.loc[ processed[d2df(system, "Cyl", "FuelPh_in", "T")] < 350, d2df(system, "Cyl", "FuelPh_in", "T")] = 350 print("...done!") return processed
def coolingFlows(processed, CONSTANTS, engine_type): print("Started calculating cooling flows for the {}...".format(engine_type), end="", flush=True) # This function calculates the different flows related to the cooling systems of the main engines. for system in CONSTANTS["General"]["NAMES"][engine_type]: processed.loc[processed[d2df(system, "JWC", "HTWater_in", "p")] < 150000,d2df(system, "JWC", "HTWater_in", "p")] = 190000 processed.loc[processed[d2df(system, "CAC_LT", "LTWater_in", "p")] < 150000, d2df(system, "CAC_LT", "LTWater_in", "p")] = 190000 head_HT = processed[d2df(system, "JWC", "HTWater_in", "p")][~processed[system+":on"]].mean() heat_LT = processed[d2df(system, "CAC_LT", "LTWater_in", "p")][~processed[system+":on"]].mean() # Mass flow in the LT water cooling systems processed[d2df(system, "CAC_LT", "LTWater_in", "mdot")] = pumpFlow(processed[d2df(system, "Cyl", "Power_out", "omega")], processed[d2df(system, "CAC_LT", "LTWater_in", "p")], heat_LT, CONSTANTS, engine_type) processed.loc[:,d2df(system, "CAC_LT", "LTWater_in", "mdot")] = processed[d2df(system, "CAC_LT", "LTWater_in", "mdot")] / max(processed[d2df(system, "CAC_LT", "LTWater_in", "mdot")]) * CONSTANTS[engine_type]["MFR_LT"] processed.loc[processed[d2df(system, "CAC_LT", "LTWater_in", "mdot")] < 0,d2df(system, "CAC_LT", "LTWater_in", "mdot")] = 0 processed.loc[processed[d2df(system, "CAC_LT", "LTWater_in", "mdot")] > CONSTANTS[engine_type]["MFR_LT"], d2df(system, "CAC_LT", "LTWater_in","mdot")] = CONSTANTS[engine_type]["MFR_LT"] # Mass flow in the HT water cooling systems processed[d2df(system, "JWC", "HTWater_in", "mdot")] = pumpFlow(processed[d2df(system, "Cyl", "Power_out", "omega")], processed[d2df(system, "JWC", "HTWater_in", "p")], head_HT, CONSTANTS, engine_type) processed.loc[:, d2df(system, "JWC", "HTWater_in", "mdot")] = processed[d2df(system, "JWC", "HTWater_in","mdot")] / max(processed[d2df(system, "JWC", "HTWater_in", "mdot")]) * CONSTANTS[engine_type]["MFR_HT"] * 2 processed.loc[processed[d2df(system, "JWC", "HTWater_in", "mdot")] < 0, d2df(system, "JWC", "HTWater_in","mdot")] = 0 processed.loc[processed[d2df(system, "JWC", "HTWater_in", "mdot")] > CONSTANTS[engine_type]["MFR_HT"], d2df(system,"JWC","HTWater_in","mdot")] = CONSTANTS[engine_type]["MFR_HT"] # Mass flow in the lubricating oil cooler processed.loc[:, d2df(system, "LOC", "LubOil_out", "mdot")] = CONSTANTS[engine_type]["MFR_LO"] print("done!") return processed
def centralCoolingSystems(processed, CONSTANTS): # Doing the calculations for the 1-3 engine room ER13set = {"AE1", "AE3", "ME1", "ME3", "AB1"} # Calculating the temperature at the LT collector outlet mdot_temp = sum(processed[d2df("CoolingSystems", "LTcollector13", "LTWater_" + idx + "_in", "mdot")] for idx in ER13set) processed[d2df("CoolingSystems", "LTcollector13", "LTWater_out", "T")] = ( (sum(processed[d2df("CoolingSystems", "LTcollector13", "LTWater_"+idx+"_in", "T")] * processed[d2df("CoolingSystems", "LTcollector13", "LTWater_"+idx+"_in", "mdot")] for idx in ER13set)) / ( mdot_temp)) processed.loc[mdot_temp == 0, d2df("CoolingSystems", "LTcollector13", "LTWater_out", "T")] = processed['T_0'] # The temperature at the other output of the collector is the same processed["CoolingSystems:LTcollector13:HTWater_out:T"] = processed["CoolingSystems:LTcollector13:LTWater_out:T"] # Note that the temperature at the LT distribution inlet is calculated based on the average temperature at the LT collector outlets. # The idea is that we have different temperatures at different instants, and we need to average them mdot_temp = sum(processed[d2df("CoolingSystems", "LTdistribution13", "LTWater_" + idx + "_out", "mdot")] for idx in ER13set) processed[d2df("CoolingSystems", "LTdistribution13", "LTWater_in", "T")] = ( sum(processed[d2df("CoolingSystems", "LTdistribution13", "LTWater_" + idx + "_out", "T")] * processed[d2df("CoolingSystems", "LTdistribution13", "LTWater_" + idx + "_out", "mdot")] for idx in ER13set) / ( mdot_temp)) processed.loc[mdot_temp==0, d2df("CoolingSystems", "LTdistribution13", "LTWater_in", "T")] = processed['T_0'] # The temperature at the Sea water cooler outlet is then equal to the inlet to the distribution systems #processed[d2df("CoolingSystems", "SWC13", "LTWater_out", "T")] = processed[d2df("CoolingSystems", "LTdistribution13", "LTWater_in", "T")] # Doing the calculations for the "2-4 engine room ER24set = {"AE2", "AE4", "ME2", "ME4"} # Calculating the temperature at the LT collector outlet mdot_temp = sum(processed[d2df("CoolingSystems", "LTcollector24", "LTWater_" + idx + "_in", "mdot")] for idx in ER24set) processed[d2df("CoolingSystems", "LTcollector24", "LTWater_out", "T")] = ( (sum(processed[d2df("CoolingSystems", "LTcollector24", "LTWater_" + idx + "_in", "T")] * processed[d2df("CoolingSystems", "LTcollector24", "LTWater_" + idx + "_in", "mdot")] for idx in ER24set)) / ( mdot_temp)) processed.loc[mdot_temp==0, d2df("CoolingSystems", "LTcollector24", "LTWater_out", "T")] = processed['T_0'] processed["CoolingSystems:LTcollector24:HTWater_out:T"] = processed["CoolingSystems:LTcollector24:LTWater_out:T"] # Note that the temperature at the LT distribution inlet is calculated based on the average temperature at the LT collector outlets mdot_temp = sum(processed[d2df("CoolingSystems", "LTdistribution24", "LTWater_" + idx + "_out", "mdot")] for idx in ER24set) processed[d2df("CoolingSystems", "LTdistribution24", "LTWater_in", "T")] = ( sum(processed[d2df("CoolingSystems", "LTdistribution24", "LTWater_" + idx + "_out", "T")] * processed[d2df("CoolingSystems", "LTdistribution24", "LTWater_" + idx + "_out", "mdot")] for idx in ER24set) / ( mdot_temp)) processed.loc[mdot_temp == 0, d2df("CoolingSystems", "LTdistribution24", "LTWater_in", "T")] = processed['T_0'] # We can now calculate the flows into the LTHT merge for the ER 13 mdot_HTHR13_tot = processed["CoolingSystems:LTHTmerge13:HTWater_ME1_out:mdot"] + processed["CoolingSystems:LTHTmerge13:HTWater_ME3_out:mdot"] + processed["CoolingSystems:LTHTmerge13:HTWater_AE1_out:mdot"] + processed["CoolingSystems:LTHTmerge13:HTWater_AE3_out:mdot"] #processed["CoolingSystems:LTHTmerge13:HTWater_in:mdot"] = mdot_HTHR13_tot * ( # CONSTANTS["MainEngines"]["T_COOLING_MIX"] - processed["CoolingSystems:LTcollector13:HTWater_out:T"]) / ( # processed["CoolingSystems:LTHTmerge13:HTWater_in:T"] - processed["CoolingSystems:LTcollector13:HTWater_out:T"]) # If the previously calculated mass flow is NaN, we set it equal to 0 processed.loc[np.isnan(processed["CoolingSystems:LTHTmerge13:HTWater_in:mdot"]), "CoolingSystems:LTHTmerge13:HTWater_in:mdot"] = 0 processed["CoolingSystems:LTHTmerge13:LTWater_in:mdot"] = mdot_HTHR13_tot - processed["CoolingSystems:LTHTmerge13:HTWater_in:mdot"] # We can now calculate the flows into the LTHT merge for the ER 24 mdot_HTHR24_tot = processed["CoolingSystems:LTHTmerge24:HTWater_ME2_out:mdot"] + processed["CoolingSystems:LTHTmerge24:HTWater_ME4_out:mdot"] + processed["CoolingSystems:LTHTmerge24:HTWater_AE2_out:mdot"] + processed["CoolingSystems:LTHTmerge24:HTWater_AE4_out:mdot"] #processed["CoolingSystems:LTHTmerge24:HTWater_in:mdot"] = mdot_HTHR24_tot * ( # CONSTANTS["MainEngines"]["T_COOLING_MIX"] - processed["CoolingSystems:LTcollector24:HTWater_out:T"]) / ( # processed["CoolingSystems:LTHTmerge24:HTWater_in:T"] - processed["CoolingSystems:LTcollector24:HTWater_out:T"]) # If the previously calculated mass flow is NaN, we set it equal to 0 processed.loc[np.isnan(processed["CoolingSystems:LTHTmerge24:HTWater_in:mdot"]), "CoolingSystems:LTHTmerge24:HTWater_in:mdot"] = 0 processed["CoolingSystems:LTHTmerge24:LTWater_in:mdot"] = mdot_HTHR24_tot - processed["CoolingSystems:LTHTmerge24:HTWater_in:mdot"] return processed
def efficiencyCalculator(processed, dict_structure, CONSTANTS): text_file = open(CONSTANTS["filenames"]["consistency_check_report"], "a") text_file.write("\n *** CALCULATING EFFICIENCIES *** \n") df_index = processed.index for system in dict_structure["systems"]: for unit in dict_structure["systems"][system]["units"]: if system + ":" + unit == "CoolingSystems:LTdistribution13": aaa = 0 # Here I create eight (8) series: 4 Edot and 4 Bdot. 2 "Full" and 2 "useful". temp_flow_list = { "Edot_in", "Edot_in_useful", "Edot_out", "Edot_out_useful", "Bdot_in", "Bdot_in_useful", "Bdot_out", "Bdot_out_useful" } temp_df = pd.DataFrame(0, columns=temp_flow_list, index=df_index) for flow in dict_structure["systems"][system]["units"][unit][ "flows"]: dict_structure["systems"][system]["units"][unit][ "flows"][flow]["E"] = processed[d2df( system, unit, flow, "Edot")].sum() * 60 * 15 * 1e-6 dict_structure["systems"][system]["units"][unit][ "flows"][flow]["B"] = processed[d2df( system, unit, flow, "Bdot")].sum() * 60 * 15 * 1e-6 if flow[-2:] == "in": temp_df['Edot_in'] = temp_df['Edot_in'] + processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_in'] = temp_df['Bdot_in'] + processed[d2df( system, unit, flow, "Bdot")] elif flow[-3:] == "out": temp_df['Edot_out'] = temp_df['Edot_out'] + processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_out'] = temp_df['Bdot_out'] + processed[d2df( system, unit, flow, "Bdot")] else: text_file.write( "Flow {}:{}:{} is not recognised as either input or output \n" .format(system, unit, flow)) # The "Edot_useful" and "Bdot_useful" inputs and outputs are only assigned when defined if "IO" in dict_structure["systems"][system]["units"][unit][ "flows"][flow]: if dict_structure["systems"][system]["units"][unit][ "flows"][flow]["IO"] == "input": if flow[-2:] == "in": temp_df['Edot_in_useful'] = temp_df[ 'Edot_in_useful'] + processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_in_useful'] = temp_df[ 'Bdot_in_useful'] + processed[d2df( system, unit, flow, "Bdot")] elif flow[-3:] == "out": temp_df['Edot_in_useful'] = temp_df[ 'Edot_in_useful'] - processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_in_useful'] = temp_df[ 'Bdot_in_useful'] - processed[d2df( system, unit, flow, "Bdot")] else: text_file.write( "Flow {}:{}:{} is not recognised as either input or output \n" .format(system, unit, flow)) elif dict_structure["systems"][system]["units"][unit][ "flows"][flow]["IO"] == "output": if flow[-2:] == "in": temp_df['Edot_out_useful'] = temp_df[ 'Edot_out_useful'] - processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_out_useful'] = temp_df[ 'Bdot_out_useful'] - processed[d2df( system, unit, flow, "Bdot")] elif flow[-3:] == "out": temp_df['Edot_out_useful'] = temp_df[ 'Edot_out_useful'] + processed[d2df( system, unit, flow, "Edot")] temp_df['Bdot_out_useful'] = temp_df[ 'Bdot_out_useful'] + processed[d2df( system, unit, flow, "Bdot")] else: text_file.write( "Flow {}:{}:{} is not recognised as either input or output \n" .format(system, unit, flow)) else: text_file.write( "Flow {}:{}:{} is not recognised as either USEFEUL input or output \n" .format(system, unit, flow)) # Saving the total energy flows dict_structure["systems"][system]["units"][unit][ "E_in"] = temp_df["Edot_in"].sum() * 60 * 15 * 1e-6 dict_structure["systems"][system]["units"][unit][ "E_out"] = temp_df["Edot_out"].sum() * 60 * 15 * 1e-6 dict_structure["systems"][system][ "units"][unit]["E_in_useful"] = temp_df["Edot_in_useful"].sum( ) * 60 * 15 * 1e-6 dict_structure["systems"][system]["units"][unit][ "E_out_useful"] = temp_df["Edot_out_useful"].sum( ) * 60 * 15 * 1e-6 # Saving total exergy flows dict_structure["systems"][system]["units"][unit][ "B_in"] = temp_df["Bdot_in"].sum() * 60 * 15 * 1e-6 dict_structure["systems"][system]["units"][unit][ "B_out"] = temp_df["Bdot_out"].sum() * 60 * 15 * 1e-6 dict_structure["systems"][system][ "units"][unit]["B_in_useful"] = temp_df["Bdot_in_useful"].sum( ) * 60 * 15 * 1e-6 dict_structure["systems"][system]["units"][unit][ "B_out_useful"] = temp_df["Bdot_out_useful"].sum( ) * 60 * 15 * 1e-6 # We first calculate the energy efficiency (if possible) if system + ":" + unit + ":" + "eta" in processed.columns: processed[system + ":" + unit + ":" + "eta"] = temp_df[ 'Edot_out_useful'] / temp_df['Edot_in_useful'] processed.loc[temp_df['Edot_in_useful'] == 0, system + ":" + unit + ":" + "eta"] = 0 # Calculating the average value if dict_structure["systems"][system]["units"][unit][ "E_in_useful"] == 0: dict_structure["systems"][system]["units"][unit]["eta"] = 0 else: dict_structure["systems"][system]["units"][unit][ "eta"] = dict_structure["systems"][system]["units"][ unit]["E_out_useful"] / dict_structure["systems"][ system]["units"][unit]["E_in_useful"] # Then exergy efficiency (again, if possible) if system + ":" + unit + ":" + "eps" in processed.columns: processed[system + ":" + unit + ":" + "eps"] = temp_df[ 'Bdot_out_useful'] / temp_df['Bdot_in_useful'] processed.loc[temp_df['Bdot_in_useful'] == 0, system + ":" + unit + ":" + "eps"] = 0 # Calculating the average value if dict_structure["systems"][system]["units"][unit][ "B_in_useful"] == 0: dict_structure["systems"][system]["units"][unit]["eps"] = 0 else: dict_structure["systems"][system]["units"][unit][ "eps"] = dict_structure["systems"][system]["units"][ unit]["B_out_useful"] / dict_structure["systems"][ system]["units"][unit]["B_in_useful"] # We calculate also the irreversibility ratio. Might come in handy processed[system + ":" + unit + ":" + "Idot"] = temp_df['Bdot_in'] - temp_df['Bdot_out'] dict_structure["systems"][system]["units"][unit][ "Idot"] = processed[system + ":" + unit + ":" + "Idot"].sum() * 60 * 15 * 1e-6 # Finally, we calculate the lambda processed[system + ":" + unit + ":" + "lambda"] = (temp_df['Bdot_in'] - temp_df['Bdot_out']) / temp_df['Bdot_in'] processed.loc[temp_df['Bdot_in'] == 0, system + ":" + unit + ":" + "lambda"] = 0 # Calculate the average value if dict_structure["systems"][system]["units"][unit]["B_in"] == 0: dict_structure["systems"][system]["units"][unit]["lambda"] = 0 else: dict_structure["systems"][system]["units"][unit][ "lambda"] = 1 - dict_structure["systems"][system]["units"][ unit]["B_out"] / dict_structure["systems"][system][ "units"][unit]["B_in"] #### ADD THE CALCULATION OF THE DELTA ##### temp_total_idot = sum( processed[system + ":" + unit + ":" + "Idot"] for system in dict_structure["systems"] for unit in dict_structure["systems"][system]["units"]) for system in dict_structure["systems"]: temp_system_idot = sum( processed[system + ":" + unit + ":" + "Idot"] for unit in dict_structure["systems"][system]["units"]) processed[system + ":delta"] = temp_system_idot / temp_total_idot dict_structure["systems"][system]["delta"] = temp_system_idot.sum( ) / temp_total_idot.sum() for unit in dict_structure["systems"][system]["units"]: processed[system + ":" + unit + ":" + "delta"] = processed[system + ":" + unit + ":" + "Idot"] / temp_system_idot processed.loc[temp_system_idot == 0, system + ":" + unit + ":" + "Idot"] = 0 if temp_system_idot.sum() == 0: dict_structure["systems"][system]["units"][unit]["delta"] = 0 else: dict_structure["systems"][system]["units"][unit][ "delta"] = dict_structure["systems"][system]["units"][ unit]["Idot"] / temp_system_idot.sum() / 60 / 15 / 1e-6 text_file.close() return processed