diff --git a/process/models/blankets/hcpb.py b/process/models/blankets/hcpb.py index 4187fe05cb..2cba6913d3 100644 --- a/process/models/blankets/hcpb.py +++ b/process/models/blankets/hcpb.py @@ -586,12 +586,6 @@ def nuclear_heating_magnets(self, output: bool): "(p_tf_nuclear_heat_mw.)", self.data.fwbs.p_tf_nuclear_heat_mw, ) - po.ovarre( - self.outfile, - "p_fusion_total_mw", - "(p_fusion_total_mw.)", - self.data.physics.p_fusion_total_mw, - ) po.ovarre( self.outfile, "total mass of the TF coils (kg)", diff --git a/process/models/physics/impurity_radiation.py b/process/models/physics/impurity_radiation.py index f4b5363134..567a64c244 100644 --- a/process/models/physics/impurity_radiation.py +++ b/process/models/physics/impurity_radiation.py @@ -655,8 +655,10 @@ def integrate_radiation_loss_profiles(self): """Integrate the radiation loss profiles using the Simpson rule. Store the total values for each aspect of impurity radiation loss. """ - # 2.0e-6 converts from W/m^3 to MW/m^3 and also accounts for both sides of the - # plasma + # 1e-6 converts from W/m^3 to MW/m^3 + # The factor 2 below and and normalised radius profile_x above may be unexpected, but are correct: + # see github.com/ukaea/PROCESS/issues/3968#issuecomment-3491154712 + # and github.com/ukaea/PROCESS/issues/3968#issuecomment-4935567006 self.pden_impurity_rad_total_mw = 2.0e-6 * integrate.simpson( self.pden_impurity_rad_profile, x=self.plasma_profile.neprofile.profile_x, diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 795dc0899a..44e4415b8a 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -2282,20 +2282,7 @@ def outplas(self): self.data.physics.f_alpha_ion, "OP ", ) - po.ovarre( - self.outfile, - "Ion transport (MW)", - "(p_ion_transport_loss_mw)", - self.data.physics.p_ion_transport_loss_mw, - "OP ", - ) - po.ovarre( - self.outfile, - "Electron transport (MW)", - "(p_electron_transport_loss_mw)", - self.data.physics.p_electron_transport_loss_mw, - "OP ", - ) + # Ion and electron transpor are now output belowin power accounting po.ovarre( self.outfile, "Injection power to ions (MW)", @@ -2316,6 +2303,422 @@ def outplas(self): ): po.ocmmnt(self.outfile, " (Injected power only used for start-up phase)") + # Global power imbalance output #4233 + po.oheadr(self.outfile, "Power accounting") + po.ocmmnt( + self.outfile, + "See Figure in https://ukaea.github.io/PROCESS/physics-models/plasma_power_balance", + ) + p_loss_mw = ( + self.data.current_drive.f_p_beam_orbit_loss + + self.data.current_drive.p_beam_shine_through_mw + + self.data.physics.p_fw_alpha_mw + ) + p_plasma_out = ( + self.data.physics.p_electron_transport_loss_mw + + self.data.physics.p_ion_transport_loss_mw + + p_loss_mw + + self.data.physics.p_plasma_rad_mw + ) + + p_plasma_in = ( + self.data.physics.p_alpha_total_mw + + self.data.physics.p_non_alpha_charged_mw + + self.data.current_drive.p_hcd_injected_total_mw + + self.data.physics.p_plasma_ohmic_mw + ) + p_plasma_imbalance_mw = p_plasma_in - p_plasma_out + po.oshead(self.outfile, "Plasma power balance across separatrix") + po.ocmmnt(self.outfile, "IN") + po.ovarre( + self.outfile, + "Net power transported by electrons (MW)", + "(p_electron_transport_loss_mw)", + self.data.physics.p_electron_transport_loss_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Net power transported by ions (MW)", + "(p_ion_transport_loss_mw)", + self.data.physics.p_ion_transport_loss_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Power lost by beam ions and unthermalised alphas (MW)", + "(p_loss_mw)", + p_loss_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Total radiation loss, including net loss by synchrotron radiation (MW)", + "(p_plasma_rad_mw)", + self.data.physics.p_plasma_rad_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_plasma_out)", + p_plasma_out, + "OP ", + ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "OUT") + po.ovarre( + self.outfile, + "Alpha power (MW)", + "(p_alpha_total_mw)", + self.data.physics.p_alpha_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Power from p, 3He, T products of DD and/or D-He3 fusion (MW)", + "(p_non_alpha_charged_mw)", + self.data.physics.p_non_alpha_charged_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Injected power (MW)", + "(p_hcd_injected_total_mw)", + self.data.current_drive.p_hcd_injected_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Ohmic heating (MW)", + "(p_plasma_ohmic_mw)", + self.data.physics.p_plasma_ohmic_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_plasma_in)", + p_plasma_in, + "OP ", + ) + po.ovarre( + self.outfile, + "Plasma power imbalance (MW)", + "(p_plasma_imbalance_mw)", + p_plasma_imbalance_mw, + "OP ", + ) + if abs(p_plasma_imbalance_mw) > 0.1: + logger.error("Plasma power imbalance > 0.1 MW") + + po.oshead(self.outfile, "Power balance for reactor") + p_reactor_in = ( + self.data.physics.p_fusion_total_mw + + self.data.fwbs.p_blkt_multiplication_mw + + self.data.current_drive.p_hcd_injected_total_mw + + self.data.physics.p_plasma_ohmic_mw + + self.data.primary_pumping.p_fw_blkt_coolant_pump_mw + + self.data.heat_transport.p_div_coolant_pump_mw + ) + p_reactor_out = ( + self.data.heat_transport.p_plant_primary_heat_mw + + self.data.heat_transport.p_div_secondary_heat_mw + + self.data.heat_transport.p_shld_secondary_heat_mw + + self.data.fwbs.p_tf_nuclear_heat_mw + + self.data.fwbs.p_fw_hcd_nuclear_heat_mw + + self.data.fwbs.p_fw_hcd_rad_total_mw + ) + p_reactor_imbalance_mw = p_reactor_in - p_reactor_out + po.ocmmnt(self.outfile, "IN") + po.ovarre( + self.outfile, + "Fusion power (MW)", + "(p_fusion_total_mw)", + self.data.physics.p_fusion_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Energy multiplication in blanket and shield (MW)", + "(p_blkt_multiplication_mw)", + self.data.fwbs.p_blkt_multiplication_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Injected power (MW)", + "(p_hcd_injected_total_mw)", + self.data.current_drive.p_hcd_injected_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Ohmic heating (MW)", + "(p_plasma_ohmic_mw)", + self.data.physics.p_plasma_ohmic_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Power deposited by pump in coolant for FW and blanket circuit (MW)", + "(p_fw_blkt_coolant_pump_mw)", + self.data.primary_pumping.p_fw_blkt_coolant_pump_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Power deposited by pump in coolant for divertor circuit (MW)", + "(p_div_coolant_pump_mw)", + self.data.heat_transport.p_div_coolant_pump_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_reactor_in)", + p_reactor_in, + "OP ", + ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "OUT") + po.ovarre( + self.outfile, + "Total primary thermal power used for electricity production (MW)", + "(p_plant_primary_heat_mw)", + self.data.heat_transport.p_plant_primary_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Divertor thermal power not used for electricity production (MW)", + "(p_div_secondary_heat_mw)", + self.data.heat_transport.p_div_secondary_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Shield thermal power not used for electricity production (MW)", + "(p_shld_secondary_heat_mw)", + self.data.heat_transport.p_shld_secondary_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Nuclear heating in TF coils (MW)", + "(p_tf_nuclear_heat_mw)", + self.data.fwbs.p_tf_nuclear_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Nuclear heating in H&CD systems and diagnostics (MW)", + "(p_fw_hcd_nuclear_heat_mw)", + self.data.fwbs.p_fw_hcd_nuclear_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Radiation heat deposited in H&CD systems and diagnostics (MW)", + "(p_fw_hcd_rad_total_mw)", + self.data.fwbs.p_fw_hcd_rad_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_reactor_out)", + p_reactor_out, + "OP ", + ) + po.ovarre( + self.outfile, + "Reactor power imbalance (MW)", + "(p_reactor_imbalance_mw)", + p_reactor_imbalance_mw, + "OP ", + ) + if abs(p_reactor_imbalance_mw) > 0.1: + logger.error("Reactor power imbalance > 0.1 MW") + + po.oshead(self.outfile, "Electrical power balance") + p_electric_demand = ( + self.data.heat_transport.p_plant_electric_net_mw + + self.data.heat_transport.p_tf_electric_supplies_mw + + self.data.pf_coil.p_pf_electric_supplies_mw + + self.data.heat_transport.p_hcd_electric_total_mw + + self.data.heat_transport.p_coolant_pump_elec_total_mw + + self.data.heat_transport.vachtmw + + self.data.heat_transport.p_cryo_plant_electric_mw + + self.data.heat_transport.p_tritium_plant_electric_mw + + self.data.heat_transport.fachtmw + ) + p_electric_imbalance = ( + self.data.heat_transport.p_plant_electric_gross_mw - p_electric_demand + ) + po.ocmmnt(self.outfile, "GENERATION") + po.ovarre( + self.outfile, + "Gross electric output (MW)", + "(p_plant_electric_gross_mw)", + self.data.heat_transport.p_plant_electric_gross_mw, + "OP ", + ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "PURPOSE") + po.ovarre( + self.outfile, + "Net electric exported (MW)", + "(p_plant_electric_net_mw)", + self.data.heat_transport.p_plant_electric_net_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TF coils electric power (MW)", + "(p_tf_electric_supplies_mw)", + self.data.heat_transport.p_tf_electric_supplies_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "PF coils electric power (MW)", + "(p_pf_electric_supplies_mw)", + self.data.pf_coil.p_pf_electric_supplies_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Heating and current drive electric power (MW)", + "(p_hcd_electric_total_mw)", + self.data.heat_transport.p_hcd_electric_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Primary coolant pump electric power (MW)", + "(p_coolant_pump_elec_total_mw)", + self.data.heat_transport.p_coolant_pump_elec_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Vacuum pumps electric power (MW)", + "(vachtmw)", + self.data.heat_transport.vachtmw, + "OP ", + ) + po.ovarre( + self.outfile, + "Cryoplant electric power (MW)", + "(p_cryo_plant_electric_mw)", + self.data.heat_transport.p_cryo_plant_electric_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Tritium plant electric power (MW)", + "(p_tritium_plant_elec_mw)", + self.data.heat_transport.p_tritium_plant_electric_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "All other internal electric power requirements (MW)", + "(fachtmw)", + self.data.heat_transport.fachtmw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_electric_demand)", + p_electric_demand, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Electric power imbalance (MW)", + "(p_electric_imbalance)", + p_electric_imbalance, + "OP ", + ) + if abs(p_electric_imbalance) > 0.1: + logger.error("Electric power imbalance > 0.1 MW") + + po.oshead(self.outfile, "Power balance for power plant") + po.ocmmnt(self.outfile, "IN") + p_plant_in_mw = ( + self.data.physics.p_fusion_total_mw + self.data.fwbs.p_blkt_multiplication_mw + ) + p_plant_out_mw = ( + self.data.heat_transport.p_plant_electric_net_mw + + self.data.power.p_turbine_loss_mw + + self.data.heat_transport.p_plant_secondary_heat_mw + ) + p_plant_imbalance_mw = p_plant_in_mw - p_plant_out_mw + po.ovarre( + self.outfile, + "Fusion power (MW)", + "(p_fusion_total_mw)", + self.data.physics.p_fusion_total_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Energy multiplication in blanket and shield (MW)", + "(p_blkt_multiplication_mw)", + self.data.fwbs.p_blkt_multiplication_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_nuclear_total_mw)", + p_plant_in_mw, + "OP ", + ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "OUT") + po.ovarre( + self.outfile, + "Net electric (MW)", + "(p_plant_electric_net_mw)", + self.data.heat_transport.p_plant_electric_net_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Heat rejected by main power conversion circuit (MW)", + "(p_turbine_loss_mw)", + self.data.power.p_turbine_loss_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Heat rejected by other circuits (secondary heat) (MW)", + "(p_plant_secondary_heat_mw)", + self.data.heat_transport.p_plant_secondary_heat_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "TOTAL (MW)", + "(p_plant_out_mw)", + p_plant_out_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Power plant overall imbalance (MW)", + "(p_plant_imbalance_mw)", + p_plant_imbalance_mw, + "OP ", + ) + if abs(p_plant_imbalance_mw) > 0.1: + logger.error("Power plant overall imbalance > 0.1 MW") + self.exhaust.output() if self.data.stellarator.istell == 0: diff --git a/process/models/power.py b/process/models/power.py index f118788469..478cd4ed2e 100644 --- a/process/models/power.py +++ b/process/models/power.py @@ -1410,13 +1410,6 @@ def output_plant_electric_powers(self): po.ocmmnt(self.outfile, "Turbine conversion : ") po.oblnkl(self.outfile) - po.ovarre( - self.outfile, - "Total high grade thermal power used for electricity production [MWth]", - "(p_plant_primary_heat_mw)", - self.data.heat_transport.p_plant_primary_heat_mw, - ) - po.ovarrf( self.outfile, "Thermal to electric conversion efficiency of the turbine",