class RadPydro: def __init__(self, input): # Store input parameters and check them self.input = input self.input.checkInputs() # Define geometry based on geometry input type if input.geometry == 'slab': self.geo = SlabGeometry(self) elif input.geometry == 'cylindrical': self.geo = CylindricalGeometry(self) else: self.geo = SphericalGeometry(self) # Initialize material handler now that geometry is initialized self.mat = Materials(self) # Initialize field variables self.fields = Fields(self) # Time parameters self.timeSteps = [] self.time = 0. self.timeStep_num = 0 self.Tf = input.Tf # Initialize hydro problem self.hydro = LagrangianHydro(self) # Initialize radiation problem (if used) self.radPredictor = LagrangianRadiationPredictor(self) self.radCorrector = LagrangianRadiationCorrector(self) # Init storage for energies in conservation check self.kinetic_energy = [] self.internal_energy = [] self.radiation_energy = [] self.radiation_leakage = [] self.work_energy = [] self.total_energy = [] # Compute initial energies for each kinetic = 0 internal = 0 radiation = 0 for i in range(self.geo.N + 1): kinetic += 1 / 2 * self.mat.m_half[i] * self.fields.u_IC[i]**2 if i < self.geo.N: internal += self.mat.m[i] * self.fields.e_IC[i] radiation += self.mat.m[i] * self.fields.E_IC[ i] / self.fields.rho_IC[i] total = kinetic + internal + radiation self.kinetic_energy.append(kinetic) self.internal_energy.append(internal) self.radiation_energy.append(radiation) self.radiation_leakage.append(0) self.work_energy.append(0) self.total_energy.append(total) self.total_radiation_leakage = 0 self.total_work_energy = 0 def computeTimeStep(self): dr = self.geo.dr u = self.fields.u F_c = self.input.CoFactor relEFactor = self.input.relEFactor c_s = (self.mat.gamma * self.fields.P / self.fields.rho)**(1 / 2) E_k = (self.fields.E + self.fields.E_old) / 2 dE_k = np.zeros(self.geo.N) if len(self.timeSteps) == 0: dE_k = E_k else: dE_k = abs( (self.fields.E - self.fields.E_old) / self.timeSteps[-1]) u_center = np.zeros(self.geo.N) for i in range(self.geo.N): u_center = abs((u[i] + u[i + 1]) / 2) dt_E = min(relEFactor * E_k / dE_k) dt_u = min(dr * F_c / u_center) dt_cs = min(dr * F_c / c_s) self.timeSteps.append(min(self.input.maxTimeStep, dt_E, dt_u, dt_cs)) def run(self): if self.input.running_mode == 'hydro': self.runHydro() elif self.input.running_mode == 'rad': self.runRad() elif self.input.running_mode == 'radhydro': self.runRadHydro() def runHydro(self): while self.time < self.input.T_final: # Compute time step size for this time step self.computeTimeStep() # Update time and time step number self.time += self.timeSteps[-1] self.timeStep_num += 1 print('=========================================================') print('Starting time step %i, time = %.3e' \ % (self.timeStep_num, self.time)) print( '=========================================================\n') # Add artificial viscosity for this time step self.fields.addArtificialViscosity() # Predictor step self.hydro.recomputeVelocity(True) self.geo.moveMesh(True) self.hydro.recomputeDensity(True) self.hydro.recomputeInternalEnergy(True) self.fields.recomputeTemperature(True) self.fields.recomputePressure(True) # Corrector step self.hydro.recomputeVelocity(False) self.geo.moveMesh(False) self.hydro.recomputeDensity(False) self.hydro.recomputeInternalEnergy(False) self.fields.recomputeTemperature(False) self.fields.recomputePressure(False) # Energy conservation check energy_diff = self.recomputeEnergyConservation() print('Energy conservation check: ', energy_diff, '\n') # Copy to old containers for next time step self.fields.stepFields() self.geo.stepGeometry() def runRad(self): while self.time < self.input.T_final: # Compute time step size for this time step self.computeTimeStep() # Update time and time step number self.time += self.timeSteps[-1] self.timeStep_num += 1 print('=========================================================') print('Starting time step %i, time = %.3e' \ % (self.timeStep_num, self.time)) print( '=========================================================\n') # Predictor step self.radPredictor.recomputeRadiationEnergy() self.radPredictor.recomputeInternalEnergy() self.fields.recomputeTemperature(True) self.fields.recomputePressure(True) # Corrector step self.radCorrector.recomputeRadiationEnergy() self.radCorrector.recomputeInternalEnergy() self.fields.recomputeTemperature(False) self.fields.recomputePressure(False) # Energy conservation check energy_diff = self.recomputeEnergyConservation() print('Energy conservation check: ', energy_diff, '\n') # Copy to old containers for next time step self.fields.stepFields() def runRadHydro(self): while self.time < self.input.T_final: # Compute time step size for this time step self.computeTimeStep() # Update time and time step number self.time += self.timeSteps[-1] self.timeStep_num += 1 print('=========================================================') print('Starting time step %i, time = %.3e' \ % (self.timeStep_num, self.time)) print( '=========================================================\n') # Add artificial viscosity for this time step self.fields.addArtificialViscosity() # Predictor step self.hydro.recomputeVelocity(True) self.geo.moveMesh(True) self.hydro.recomputeDensity(True) self.radPredictor.recomputeRadiationEnergy() self.radPredictor.recomputeInternalEnergy() self.fields.recomputeTemperature(True) self.fields.recomputePressure(True) # Corrector step self.hydro.recomputeVelocity(False) self.geo.moveMesh(False) self.hydro.recomputeDensity(False) self.radCorrector.recomputeRadiationEnergy() self.radCorrector.recomputeInternalEnergy() self.fields.recomputeTemperature(False) self.fields.recomputePressure(False) # Energy conservation check energy_diff = self.recomputeEnergyConservation() print('Energy conservation check: ', energy_diff, '\n') # Copy to old containers for next time step self.fields.stepFields() self.geo.stepGeometry() def recomputeEnergyConservation(self): kinetic_energy = self.kinetic_energy internal_energy = self.internal_energy radiation_energy = self.radiation_energy radiation_leakage = self.radiation_leakage work_energy = self.work_energy total_energy = self.total_energy c = self.input.c dt = self.timeSteps[-1] m = self.mat.m m_half = self.mat.m_half u = self.fields.u e = self.fields.e E = self.fields.E rho = self.fields.rho A_k = (self.geo.A + self.geo.A_old) / 2 A_pk = (self.geo.A_p + self.geo.A_old) / 2 dr_k = (self.geo.dr + self.geo.dr_old) / 2 dr_pk = (self.geo.dr_p + self.geo.dr_old) / 2 E_k = (self.fields.E + self.fields.E_old) / 2 E_pk = (self.fields.E_p + self.fields.E_old) / 2 T_k = (self.fields.T + self.fields.T_old) / 2 T_pk = (self.fields.T_p + self.fields.T_old) / 2 rho_k = (self.fields.rho + self.fields.rho_old) / 2 rho_pk = (self.fields.rho_p + self.fields.rho_old) / 2 u_k = (self.fields.u + self.fields.u_old) / 2 P_pk = (self.fields.P_p + self.fields.P_old) / 2 # Recomputing kappa_t at the cell edges and cell centers self.mat.recomputeKappa_t(T_pk) kappa_t_pk_edge = self.mat.kappa_t self.mat.recomputeKappa_a(T_pk) kappa_t_pk_center = self.mat.kappa_a + self.mat.kappa_s # Setting up boundary parameters for the radiation terms # in the momentum equation if self.input.rad_L is 'source': E_bL_k = self.fields.E_bL E_bL_pk = self.fields.E_bL else: E_bL_k = E_k[0] E_bL_pk = E_pk[0] if self.input.rad_R is 'source': E_bR_k = self.fields.E_bR E_bR_pk = self.fields.E_bR else: E_bR_k = E_k[-1] E_bR_pk = E_pk[-1] # Compute the boundary radiation energies in the momentum eqn coeff_E_L = 3 * rho_pk[0] * dr_pk[0] * kappa_t_pk_center[0] coeff_E_R = 3 * rho_pk[-1] * dr_pk[-1] * kappa_t_pk_center[-1] E_L = (coeff_E_L * E_bL_pk + 4 * E_pk[0]) / (coeff_E_L + 4) E_R = (coeff_E_R * E_bR_pk + 4 * E_pk[-1]) / (coeff_E_R + 4) # Compute radiation flux at boundaries coeff_F_L = -2 * c / (3 * rho_k[0] * dr_k[0] * kappa_t_pk_edge[0] + 4) coeff_F_R = -2 * c / (3 * rho_k[-1] * dr_k[-1] * kappa_t_pk_edge[-1] + 4) F_L = coeff_F_L * (E_k[0] - E_bL_k) F_R = coeff_F_R * (E_bR_k - E_k[-1]) # Setting up boundary parameters for the pressure boundary values if self.input.hydro_L is 'P': P_bL_pk = self.fields.P_L else: P_bL_pk = P_pk[0] + 1 / 3 * (E_pk[0] - E_L) if self.input.hydro_R is 'P': P_bR_pk = self.fields.P_R else: P_bR_pk = P_pk[-1] + 1 / 3 * (E_pk[-1] - E_R) # Compute kinetic, internal, and radiation energies for this timestep kinetic, internal, radiation = 0, 0, 0 for i in range(self.geo.N + 1): kinetic += 1 / 2 * m_half[i] * u[i]**2 if i < self.geo.N: internal += m[i] * e[i] radiation += m[i] * E[i] / rho[i] # Compute radiation leakage leakage = (A_k[-1] * F_R - A_k[0] * F_L) * dt # Compute compressive work work = (A_pk[-1] * 1 / 3 * E_R * u_k[-1] - A_pk[0] * 1 / 3 * E_L * u_k[0]) * dt work += (A_pk[-1] * P_bR_pk * u_k[-1] - A_pk[0] * P_bL_pk * u_k[0]) * dt # Compute total energy total = kinetic + internal + radiation + leakage + work # Compute energy final - initial energies dKE = kinetic - kinetic_energy[0] dIE = internal - internal_energy[0] dRE = radiation - radiation_energy[0] # Compute energy losses from pressure work, drift, and leakage total_work = self.total_work_energy + work total_leak = self.total_radiation_leakage + leakage # Update loss terms from pressure work, drift, and leakage self.total_work_energy += work self.total_radiation_leakage += leakage # Append to storage kinetic_energy.append(kinetic) internal_energy.append(internal) radiation_energy.append(radiation) radiation_leakage.append(leakage) work_energy.append(work) total_energy.append(total) return dKE + dIE + dRE + total_work + total_leak