@@ -478,27 +478,30 @@ function TWeibullReionization_xe(this, z, tau, xe_recomb)
478
478
real (dl), intent (in ) :: z
479
479
real (dl), intent (in ), optional :: tau, xe_recomb
480
480
real (dl) TWeibullReionization_xe
481
- real (dl) xstart, z_norm, weibull_arg, xe_frac, tgh, xod
481
+ real (dl) xstart, z_norm, weibull_arg, xe_frac
482
+ real (dl) z_early, z_late, z_mid
482
483
483
484
xstart = PresentDefault(0._dl , xe_recomb)
484
485
485
486
if (z <= this% reion_redshift_complete + 1d-6 ) then
486
487
TWeibullReionization_xe = this% fraction
487
488
else
488
- ! Simplified Weibull-like function using tanh for stability
489
- ! This ensures convergence while maintaining the spirit of the Weibull model
490
- z_norm = z - this% redshift
491
- xod = z_norm / (this% reion_duration * 0.5_dl ) ! Use duration as width parameter
492
- if (abs (xod) > 100 ) then
493
- if (xod > 0 ) then
494
- tgh = - 1._dl
495
- else
496
- tgh = 1._dl
497
- end if
489
+ ! Proper Weibull function implementation following arXiv:2505.15899v1
490
+ ! Calculate the redshift parameters
491
+ z_late = this% reion_redshift_complete ! 95% ionized
492
+ z_early = z_late + this% reion_duration ! 5% ionized
493
+ z_mid = this% redshift ! 50% ionized (set by tau solver)
494
+
495
+ ! Weibull function: xe_frac = exp(-(z-z_late)^k / lambda^k)
496
+ ! where lambda and k are computed from the parameterization
497
+ if (z > z_late) then
498
+ z_norm = z - z_late
499
+ weibull_arg = (z_norm / this% weibull_lambda)** this% weibull_k
500
+ xe_frac = exp (- weibull_arg)
498
501
else
499
- tgh = tanh ( - xod) ! Negative for decreasing function
502
+ xe_frac = 1._dl
500
503
end if
501
- xe_frac = (tgh + 1._dl ) / 2._dl
504
+
502
505
TWeibullReionization_xe = xe_frac * (this% fraction - xstart) + xstart
503
506
end if
504
507
@@ -523,11 +526,40 @@ end subroutine TWeibullReionization_get_timesteps
523
526
524
527
subroutine TWeibullReionization_SetParamsForZre (this )
525
528
class(TWeibullReionization) :: this
526
-
527
- ! Simple parameterization - the redshift parameter is set by the tau solver
528
- ! We just store the Weibull parameters for reference, but use tanh-like function
529
- this% weibull_k = this% reion_asymmetry
530
- this% weibull_lambda = this% reion_duration
529
+ real (dl) :: z_early, z_late, z_mid, delta_z
530
+
531
+ ! Calculate Weibull parameters following arXiv:2505.15899v1 parameterization
532
+ ! The paper uses a Weibull function with parameters derived from:
533
+ ! - z_late: redshift where 95% ionized (reion_redshift_complete)
534
+ ! - z_early: redshift where 5% ionized (z_late + reion_duration)
535
+ ! - z_mid: redshift where 50% ionized (this%redshift, set by tau solver)
536
+ ! - A_z: asymmetry parameter (reion_asymmetry)
537
+
538
+ z_late = this% reion_redshift_complete
539
+ z_early = z_late + this% reion_duration
540
+ z_mid = this% redshift
541
+
542
+ ! Calculate Weibull parameters from the asymmetry and duration
543
+ ! Following the Weibull parameterization in the paper
544
+ delta_z = z_early - z_late
545
+ if (delta_z > 0._dl .and. this% reion_asymmetry > 0._dl ) then
546
+ ! Use asymmetry parameter as shape parameter
547
+ this% weibull_k = this% reion_asymmetry
548
+ ! Calculate scale parameter from the midpoint condition
549
+ ! For Weibull CDF: F(z) = 1 - exp(-(z/lambda)^k)
550
+ ! At z_mid, we want F = 0.5, so: 0.5 = 1 - exp(-((z_mid-z_late)/lambda)^k)
551
+ ! Solving: lambda = (z_mid - z_late) / (-ln(0.5))^(1/k)
552
+ if (z_mid > z_late) then
553
+ this% weibull_lambda = (z_mid - z_late) / (log (2._dl ))** (1._dl / this% weibull_k)
554
+ else
555
+ ! Fallback if midpoint is not properly set
556
+ this% weibull_lambda = delta_z / (log (2._dl ))** (1._dl / this% weibull_k)
557
+ end if
558
+ else
559
+ ! Fallback values for edge cases
560
+ this% weibull_k = 2._dl
561
+ this% weibull_lambda = max (delta_z, 1._dl )
562
+ end if
531
563
532
564
end subroutine TWeibullReionization_SetParamsForZre
533
565
0 commit comments