Skip to content

Commit 78f28e6

Browse files
committed
fixed k_eff calculations going bonkers and fixed control rod handling
1 parent d136f47 commit 78f28e6

3 files changed

Lines changed: 152 additions & 43 deletions

File tree

examples/bwr_core_simulator_opengl.f90

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ subroutine setup_bwr_geometry_realistic(sim)
714714

715715
end subroutine setup_bwr_geometry_realistic
716716

717-
!> Setup BWR simulation (from original)
717+
!> Setup BWR simulation
718718
subroutine setup_bwr_simulation(sim)
719719
type(simulation_t), intent(out) :: sim
720720

@@ -856,7 +856,6 @@ subroutine setup_bwr_simulation(sim)
856856
print *, ""
857857
end subroutine setup_bwr_simulation
858858

859-
!> Coupled physics time step (from original)
860859
subroutine coupled_time_step(sim, dt)
861860
type(simulation_t), intent(inout) :: sim
862861
real(wp), intent(in) :: dt
@@ -870,6 +869,48 @@ subroutine coupled_time_step(sim, dt)
870869
real(wp), parameter :: rho_vapor = 0.038_wp
871870
logical :: converged
872871

872+
real(wp) :: v_coolant
873+
integer :: i, j, k
874+
real(wp) :: Re, h_conv
875+
real(wp), parameter :: D_h = 0.01_wp ! hydraulic diameter
876+
real(wp), parameter :: mu = 0.0001_wp ! viscosity
877+
real(wp), parameter :: k_fluid = 0.6_wp ! thermal conductivity
878+
real(wp), parameter :: Pr = 0.9_wp ! Prandtl number for water
879+
880+
! Set coolant velocity field for heat transfer
881+
! Approximate axial flow velocity from mass flux
882+
! v_z = G / rho where G is mass flux [kg/m^2.s]
883+
884+
v_coolant = sim%mass_flux_core / rho_liquid
885+
886+
! Set velocity in heat transfer module
887+
if (allocated(sim%heat%vz)) then
888+
sim%heat%vz = v_coolant
889+
end if
890+
891+
! Also update convective boundary conditions
892+
! Higher flow = higher heat transfer coefficient
893+
894+
! Reynolds number
895+
Re = rho_liquid * v_coolant * D_h / mu
896+
897+
! Dittus-Boelter correlation for heat transfer coefficient
898+
h_conv = 0.023_wp * Re**0.8_wp * Pr**0.4_wp * k_fluid / D_h
899+
900+
! Update boundary conditions in heat transfer
901+
do k = 1, sim%nz
902+
do j = 1, sim%ny
903+
do i = 1, sim%nx
904+
! Apply convective cooling in heat source term
905+
906+
end do
907+
end do
908+
end do
909+
910+
! ========================================================================
911+
! Continue with original coupling
912+
! ========================================================================
913+
873914
! Neutronics
874915
call mg_solve_eigenvalue(sim%neutronics, sim%k_eff, converged)
875916

@@ -920,7 +961,7 @@ subroutine coupled_time_step(sim, dt)
920961

921962
end subroutine coupled_time_step
922963

923-
!> Solve for initial steady state (from original)
964+
!> Solve for initial steady state
924965
subroutine solve_steady_state(sim)
925966
type(simulation_t), intent(inout) :: sim
926967

@@ -983,7 +1024,7 @@ subroutine solve_steady_state(sim)
9831024

9841025
end subroutine solve_steady_state
9851026

986-
!> Update cross sections with feedback (from original)
1027+
!> Update cross sections with feedback
9871028
subroutine update_cross_sections_feedback(sim, T, rho)
9881029
type(simulation_t), intent(inout) :: sim
9891030
real(wp), intent(in) :: T(:, :, :)
@@ -999,23 +1040,26 @@ subroutine update_cross_sections_feedback(sim, T, rho)
9991040
T_fuel = T(i, j, k)
10001041
rho_mod = rho(i, j, k)
10011042

1043+
! Get cross-sections with feedback
10021044
call xslib_get_xsec(sim%xslib, "UO2_35", &
10031045
T_fuel, rho_mod, sim%burnup%burnup(i, j, k), xsec, &
10041046
Xe_conc=sim%burnup%Xe135(i, j, k), &
10051047
Sm_conc=sim%burnup%Sm149(i, j, k))
10061048

1049+
! ================================================================
1050+
! CRITICAL FIX: Apply control rod BEFORE setting cross-sections!
1051+
! ================================================================
10071052
block
10081053
real(wp) :: node_bottom, node_top, rod_tip, inserted_fraction
10091054
real(wp) :: H_core
10101055

1011-
! Use sim%nz and sim%dz directly from simulation_t [cite: 136, 137]
10121056
H_core = real(sim%nz, wp) * sim%dz
10131057

1014-
! Calculate physical height of this node [cite: 137]
1058+
! Calculate physical height of this node
10151059
node_bottom = real(k-1, wp) * sim%dz
10161060
node_top = real(k, wp) * sim%dz
10171061

1018-
! BWR rods come from the BOTTOM.
1062+
! BWR rods come from the BOTTOM
10191063
! Position 0.0 = fully withdrawn (bottom)
10201064
! Position 1.0 = fully inserted (top)
10211065
rod_tip = sim%rod_bank_position * H_core
@@ -1030,19 +1074,21 @@ subroutine update_cross_sections_feedback(sim, T, rho)
10301074
inserted_fraction = (rod_tip - node_bottom) / sim%dz
10311075
end if
10321076

1033-
! Access the xsec array directly within the neutronics state
1077+
! Apply control rod to LOCAL xsec variable
1078+
! BEFORE calling mg_set_cross_sections!
10341079
if (inserted_fraction > 0.0_wp) then
1035-
call xslib_apply_control_rod(sim%neutronics%xsec(i,j,k), inserted_fraction)
1080+
call xslib_apply_control_rod(xsec, inserted_fraction)
10361081
end if
10371082
end block
10381083

1084+
! Now set the modified cross-sections
10391085
call mg_set_cross_sections(sim%neutronics, xsec, i, i, j, j, k, k)
10401086
end do
10411087
end do
10421088
end do
10431089
end subroutine update_cross_sections_feedback
10441090

1045-
!> Apply reactivity insertion (from original)
1091+
!> Apply reactivity insertion
10461092
subroutine apply_reactivity_insertion(sim, rho_pcm)
10471093
type(simulation_t), intent(inout) :: sim
10481094
real(wp), intent(in) :: rho_pcm
@@ -1064,7 +1110,7 @@ subroutine apply_reactivity_insertion(sim, rho_pcm)
10641110
end do
10651111
end subroutine apply_reactivity_insertion
10661112

1067-
!> Check safety limits (from original)
1113+
!> Check safety limits
10681114
function check_safety_limits(sim) result(approaching_limits)
10691115
type(simulation_t), intent(in) :: sim
10701116
logical :: approaching_limits
@@ -1087,7 +1133,7 @@ function check_safety_limits(sim) result(approaching_limits)
10871133
end if
10881134
end function check_safety_limits
10891135

1090-
!> Print steady-state summary (from original)
1136+
!> Print steady-state summary
10911137
subroutine print_steady_state_summary(sim)
10921138
type(simulation_t), intent(in) :: sim
10931139

@@ -1104,7 +1150,7 @@ subroutine print_steady_state_summary(sim)
11041150
print *, ""
11051151
end subroutine print_steady_state_summary
11061152

1107-
!> Print transient summary (from original)
1153+
!> Print transient summary
11081154
subroutine print_transient_summary(sim, step, t)
11091155
type(simulation_t), intent(in) :: sim
11101156
integer, intent(in) :: step
@@ -1120,7 +1166,7 @@ subroutine print_transient_summary(sim, step, t)
11201166
print *, ""
11211167
end subroutine print_transient_summary
11221168

1123-
!> Cleanup (from original)
1169+
!> Cleanup
11241170
subroutine cleanup_simulation(sim)
11251171
type(simulation_t), intent(inout) :: sim
11261172

models/cross_sections.f90

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
!
2424
module cross_sections
2525
use kinds, only: wp, i32
26-
use constants, only: TOL_DEFAULT, N_AVOGADRO
26+
use constants, only: TOL_DEFAULT, N_AVOGADRO, PI
2727
use multigroup_diffusion, only: mg_xsec_t
2828
implicit none
2929
private
@@ -500,7 +500,12 @@ subroutine xslib_create_two_group_fuel(xsec, enrichment)
500500
real(wp), intent(in) :: enrichment
501501

502502
real(wp) :: f_U235, f_U238
503-
503+
real(wp) :: V_fuel, V_mod, f_fuel ! Volume fractions
504+
real(wp) :: pitch, r_fuel
505+
506+
real(wp) :: sigma_a_fuel, sigma_f_fuel, N_U
507+
real(wp) :: sigma_a_water
508+
504509
xsec%n_groups = 2
505510

506511
allocate(xsec%D(2))
@@ -518,35 +523,66 @@ subroutine xslib_create_two_group_fuel(xsec, enrichment)
518523
f_U235 = enrichment
519524
f_U238 = 1.0_wp - enrichment
520525

526+
! Compute fuel volume fraction for homogenization
527+
pitch = 0.0163_wp ! 1.63 cm BWR pin pitch
528+
r_fuel = 0.0052_wp ! 5.2 mm fuel radius
529+
530+
! Fuel volume fraction in lattice
531+
! (Requires PI to be imported or defined)
532+
V_fuel = PI * r_fuel**2
533+
V_mod = pitch**2 - V_fuel
534+
f_fuel = V_fuel / (V_fuel + V_mod)
535+
536+
print '(A,F6.4)', " Fuel volume fraction: ", f_fuel
537+
521538
! ========================================================================
522539
! GROUP 1: FAST (E > 0.625 eV)
523540
! ========================================================================
524541

525-
xsec%D(1) = 1.50_wp
542+
! Homogenized diffusion coefficient
543+
xsec%D(1) = f_fuel * 1.50_wp + (1.0_wp - f_fuel) * 1.30_wp
544+
545+
! Total cross-section
526546
xsec%sigma_t(1) = 0.28_wp
527-
xsec%sigma_a(1) = 0.001_wp
528547

529-
! Fission is also small in fast group, derived from coefficients
530-
xsec%sigma_f(1) = 0.0053_wp * f_U235
548+
! CRITICAL: Homogenized absorption
549+
xsec%sigma_a(1) = f_fuel * 0.001_wp + (1.0_wp - f_fuel) * 0.0001_wp
550+
551+
! Fast fission
552+
xsec%sigma_f(1) = f_fuel * f_U235 * 0.0053_wp
531553
xsec%nu_sigma_f(1) = 2.50_wp * xsec%sigma_f(1)
554+
555+
! All fast neutrons born in fast group
532556
xsec%chi(1) = 1.0_wp
533557
xsec%kappa(1) = 200.0_wp
534558

535559
! ========================================================================
536-
! GROUP 2: THERMAL (E < 0.625 eV)
560+
! GROUP 2: THERMAL (E < 0.625 eV)
537561
! ========================================================================
538562

539-
xsec%D(2) = 0.40_wp
563+
! Homogenized diffusion coefficient
564+
xsec%D(2) = f_fuel * 0.40_wp + (1.0_wp - f_fuel) * 0.16_wp
565+
540566
xsec%sigma_t(2) = 1.50_wp
541567

542-
! Macroscopic absorption (Capture + Fission):
543-
xsec%sigma_a(2) = f_U235 * 0.02354_wp * 681.0_wp + &
544-
f_U238 * 0.02354_wp * 2.7_wp
568+
! CRITICAL FIX: Homogenized macroscopic cross-sections
569+
! These are averaged over fuel + moderator volumes
570+
571+
! Fuel contribution (using proper number density)
572+
N_U = 0.02354_wp ! atoms/barn-cm
573+
574+
! Macroscopic XS for pure fuel [cm^-1]
575+
sigma_a_fuel = N_U * (f_U235 * 681.0_wp + f_U238 * 2.7_wp)
576+
sigma_f_fuel = N_U * f_U235 * 584.0_wp
545577

546-
! Fission cross-section:
547-
xsec%sigma_f(2) = f_U235 * 0.02354_wp * 584.0_wp
578+
! Water absorption: σ_a,water ≈ 0.0196 cm^-1
579+
sigma_a_water = 0.0196_wp
548580

549-
! Production (nu*sigma_f)
581+
! HOMOGENIZED cross-sections (volume-weighted)
582+
xsec%sigma_a(2) = f_fuel * sigma_a_fuel + (1.0_wp - f_fuel) * sigma_a_water
583+
xsec%sigma_f(2) = f_fuel * sigma_f_fuel
584+
585+
! Production
550586
xsec%nu_sigma_f(2) = 2.42_wp * xsec%sigma_f(2)
551587

552588
xsec%chi(2) = 0.0_wp
@@ -556,10 +592,17 @@ subroutine xslib_create_two_group_fuel(xsec, enrichment)
556592
! SCATTERING MATRIX [cm^-1]
557593
! ========================================================================
558594

559-
xsec%sigma_s(1, 1) = 0.260_wp
560-
xsec%sigma_s(1, 2) = 0.012_wp
595+
! Fast-to-fast (homogenized)
596+
xsec%sigma_s(1, 1) = f_fuel * 0.260_wp + (1.0_wp - f_fuel) * 1.05_wp
597+
598+
! CRITICAL: Fast-to-thermal slowing down (mostly in water!)
599+
xsec%sigma_s(1, 2) = (1.0_wp - f_fuel) * 0.048_wp + f_fuel * 0.012_wp
600+
601+
! No upscatter
561602
xsec%sigma_s(2, 1) = 0.0_wp
562-
xsec%sigma_s(2, 2) = 1.35_wp
603+
604+
! Thermal-to-thermal (mostly water)
605+
xsec%sigma_s(2, 2) = f_fuel * 1.35_wp + (1.0_wp - f_fuel) * 3.48_wp
563606

564607
! Compute removal cross-section
565608
xsec%sigma_r(1) = xsec%sigma_a(1) + xsec%sigma_s(1, 2)
@@ -570,12 +613,14 @@ subroutine xslib_create_two_group_fuel(xsec, enrichment)
570613
xsec%chi_d(1) = 1.0_wp
571614
xsec%chi_d(2) = 0.0_wp
572615

573-
! (Optional: Print updated values to verify they are now ~0.1 instead of ~1e-25)
574-
print *, "Created UO2 fuel cross-sections:"
616+
! Verification printout
617+
print *, "Created HOMOGENIZED UO2 fuel cross-sections:"
575618
print '(A,F6.4)', " Enrichment: ", enrichment * 100.0_wp, "%"
576-
print '(A,ES11.4)', " sigma_a(thermal): ", xsec%sigma_a(2), " cm^-1"
577-
print '(A,ES11.4)', " nu*sf(thermal): ", xsec%nu_sigma_f(2), " cm^-1"
578-
619+
print '(A,ES11.4)', " σ_a(thermal): ", xsec%sigma_a(2), " cm^-1"
620+
print '(A,ES11.4)', " σ_f(thermal): ", xsec%sigma_f(2), " cm^-1"
621+
print '(A,ES11.4)', " ν*σ_f(thermal): ", xsec%nu_sigma_f(2), " cm^-1"
622+
print '(A,F6.3)', " k-infinity est: ", xsec%nu_sigma_f(2) / xsec%sigma_a(2)
623+
579624
end subroutine xslib_create_two_group_fuel
580625

581626
subroutine xslib_create_two_group_moderator(xsec)

models/heat_transfer.f90

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ subroutine heat_step(state, dt)
245245
real(wp), allocatable :: dT_dx(:, :, :), dT_dy(:, :, :), dT_dz(:, :, :)
246246
integer :: i, j, k
247247
real(wp) :: alpha, rho_cp, diffusion, convection, source
248+
real(wp) :: h_conv, T_fluid, q_conv ! Convective cooling variables
249+
real(wp) :: D_equiv, A_over_V ! Geometry variables
248250

249251
allocate(laplacian(state%nx, state%ny, state%nz))
250252

@@ -259,36 +261,52 @@ subroutine heat_step(state, dt)
259261
allocate(dT_dy(state%nx, state%ny, state%nz))
260262
allocate(dT_dz(state%nx, state%ny, state%nz))
261263

262-
! Compute gradients
263264
call compute_gradient_3d(state%T, dT_dx, dT_dy, dT_dz, &
264265
state%dx, state%dy, state%dz)
265266
end if
266267

268+
! Geometry parameters for convective cooling
269+
D_equiv = 0.01_wp ! 10 mm equivalent diameter
270+
A_over_V = 4.0_wp / D_equiv ! Surface area to volume ratio [1/m]
271+
272+
! Heat transfer coefficient (typical BWR value)
273+
h_conv = 30000.0_wp ! W/m²·K
274+
275+
! Coolant temperature (approximation)
276+
T_fluid = 558.0_wp ! Saturation at 7 MPa
277+
267278
! Update temperature field
268279
do k = 1, state%nz
269280
do j = 1, state%ny
270281
do i = 1, state%nx
271282
alpha = state%material(i, j, k)%thermal_diffusivity
272283
rho_cp = state%material(i, j, k)%density * &
273-
state%material(i, j, k)%specific_heat
284+
state%material(i, j, k)%specific_heat
274285

275286
! Diffusion
276287
diffusion = alpha * laplacian(i, j, k)
277288

278-
! Convection
289+
! Convection (fluid flow)
279290
convection = 0.0_wp
280291
if (state%config%include_convection) then
281292
convection = -(state%vx(i, j, k) * dT_dx(i, j, k) + &
282-
state%vy(i, j, k) * dT_dy(i, j, k) + &
283-
state%vz(i, j, k) * dT_dz(i, j, k))
293+
state%vy(i, j, k) * dT_dy(i, j, k) + &
294+
state%vz(i, j, k) * dT_dz(i, j, k))
284295
end if
285296

286-
! Source term
287-
source = state%Q(i, j, k) / rho_cp
297+
! Convective heat removal to coolant [W/m³]
298+
q_conv = h_conv * A_over_V * (state%T(i, j, k) - T_fluid)
299+
300+
! Source term (includes heat generation minus cooling)
301+
source = state%Q(i, j, k) / rho_cp - q_conv / rho_cp
288302

289303
! Explicit Euler update
290304
state%T(i, j, k) = state%T(i, j, k) + dt * &
291305
(diffusion + convection + source)
306+
307+
! Prevent unphysical temperatures
308+
state%T(i, j, k) = max(state%T(i, j, k), 300.0_wp) ! Min 300 K
309+
state%T(i, j, k) = min(state%T(i, j, k), 3000.0_wp) ! Max 3000 K
292310
end do
293311
end do
294312
end do

0 commit comments

Comments
 (0)