2626from openmc .stats import Univariate , Discrete , Mixture , Tabular
2727from openmc .data .data import _get_element_symbol , BARN_PER_CM_SQ , JOULE_PER_EV
2828from openmc .data .function import Combination , Tabulated1D , Sum
29- from openmc .data import mu_en_coefficients
29+ from openmc .data import mu_en_coefficients , dose_coefficients
3030from openmc .data .photon_attenuation import linear_attenuation_xs
3131
3232
@@ -478,11 +478,11 @@ def get_photon_mass_attenuation(self) -> Sum | None:
478478 return Sum (terms ) if terms else None
479479
480480
481- def get_photon_contact_dose_rate (self , by_nuclide : bool = False ) -> float | dict [str , float ]:
481+ def get_photon_contact_dose_rate (self , dose_quantity : str = "absorbed-air" , build_up : float = 2.0 , by_nuclide : bool = False ) -> float | dict [str , float ]:
482482 """Compute the photon contact dose rate (CDR) produced by radioactive decay
483483 of the material.
484484
485- A slab-geometry approximation and a fixed photon build-up factor are used.
485+ A slab-geometry approximation and a photon build-up factor are used.
486486
487487 The method implemented here follows the approach described in FISPACT-II
488488 manual (UKAEA-CCFE-RE(21)02 - May 2021). Appendix C.7.1.
@@ -508,17 +508,27 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
508508
509509 Parameters
510510 ----------
511+ dose_quantity : {'absorbed-air', 'effective'}, optional
512+ Specifies the dose quantity to be calculated.
513+ The only supported options are 'aborbed-air' which implements a the methodology
514+ from FISPACT-II, and 'effective' which uses ICRP-116 effective dose coefficients.
515+ build_up : float, optional. The default value is 2.0 as suggested in the FISPACT-II
516+ manual.
511517 by_nuclide : bool, optional
512518 Specifies if the cdr should be returned for the material as a
513519 whole or per nuclide. Default is False.
514520
515521 Returns
516522 -------
517523 cdr : float or dict[str, float]
518- Photon Contact Dose Rate due to material decay in [Sv/hr].
524+ Photon Contact Dose Rate due to material decay
525+ If the dose quantity is [Sv/hr].
519526 """
520527
521528 cv .check_type ("by_nuclide" , by_nuclide , bool )
529+ cv .check_type ("dose_quantity" , dose_quantity , str )
530+ cv .check_value ("dose_quantity" , dose_quantity , ['absorbed-air' , 'effective' ])
531+ cv .check_type ("build_up" , build_up , float )
522532
523533 # Mass density of the material [g/cm^3]
524534 rho = self .get_mass_density () # g/cm^3
@@ -529,11 +539,6 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
529539 "cannot compute mass attenuation coefficient."
530540 )
531541
532- # mu_en/ rho for air distribution, [eV, cm2/g]
533- mu_en_x , mu_en_y = mu_en_coefficients ("air" , data_source = "nist126" )
534- mu_en_air = Tabulated1D (mu_en_x , mu_en_y , breakpoints = [len (mu_en_x )], interpolation = [5 ])
535-
536-
537542 # photon mass attenuation distribution as a function of energy
538543 # distribution values in [cm2/g]
539544 mass_attenuation_dist = self .get_photon_mass_attenuation ()
@@ -546,24 +551,45 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
546551 # CDR computation
547552 cdr = {}
548553
549- # build up factor - as reported from fispact reference
550- B = 2.0
551554 geometry_factor_slab = 0.5
552555
553556 # ancillary conversion factors for clarity
554557 seconds_per_hour = 3600.0
555558 grams_per_kg = 1000.0
559+ sv_per_psv = 1e-12
560+
561+ if dose_quantity == 'absorbed-air' :
562+
563+ # mu_en/ rho for air distribution, [eV, cm2/g]
564+ response_f_x , response_f_y = mu_en_coefficients ("air" , data_source = "nist126" )
565+
566+ # converts [eV barns-1 cm-1 s-1] to [Gy hr-1]
567+ multiplier = (
568+ build_up
569+ * geometry_factor_slab
570+ * seconds_per_hour
571+ * grams_per_kg
572+ * (1 / rho )
573+ * BARN_PER_CM_SQ
574+ * JOULE_PER_EV
575+ )
556576
557- # converts [eV barns-1 cm-1 s-1] to [Sv hr-1]
558- multiplier = (
559- B
560- * geometry_factor_slab
561- * seconds_per_hour
562- * grams_per_kg
563- * (1 / rho )
564- * BARN_PER_CM_SQ
565- * JOULE_PER_EV
566- )
577+ elif dose_quantity == 'effective' :
578+
579+ # effective dose as a function of photon fluence [pSv cm2]
580+ response_f_x , response_f_y = dose_coefficients ("photon" , geometry = 'AP' , data_source = 'icrp116' )
581+
582+ # converts [pSv g barns-1 cm-1 s-1] to [Sv hr-1]
583+ multiplier = (
584+ build_up
585+ * geometry_factor_slab
586+ * seconds_per_hour
587+ * sv_per_psv
588+ * (1 / rho )
589+ * BARN_PER_CM_SQ
590+ )
591+
592+ response_f = Tabulated1D (response_f_x , response_f_y , breakpoints = [len (response_f_x )], interpolation = [5 ])
567593
568594 for nuc , nuc_atoms_per_bcm in self .get_nuclide_atom_densities ().items ():
569595
@@ -580,7 +606,7 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
580606 e_vals = np .array (photon_source_per_atom .x )
581607 p_vals = np .array (photon_source_per_atom .p )
582608
583- e_lists = [e_vals , mu_en_air .x ]
609+ e_lists = [e_vals , response_f .x ]
584610 e_lists .extend (mass_attenuation_e_lists )
585611
586612 # clip distributions for values outside the tabulated values
@@ -604,18 +630,20 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
604630 raise ValueError (
605631 f"Mass attenuation coefficient <= 0 at energies: { zero_vals } "
606632 )
607- # units [eV atoms-1 s-1]
608- cdr_nuc += np .sum ((mu_en_air (e_vals ) / mu_vals ) * p_vals * e_vals )
633+ if dose_quantity == 'absorbed-air' :
634+ # units [eV atoms-1 s-1]
635+ cdr_nuc += np .sum ((response_f (e_vals ) / mu_vals ) * p_vals * e_vals )
636+ elif dose_quantity == 'effective' :
637+ # units [pSv g atoms-1 s-1]
638+ cdr_nuc += np .sum ((response_f (e_vals ) / mu_vals ) * p_vals )
639+
609640
610641 elif isinstance (photon_source_per_atom , Tabular ):
611642
612643 # generate the tabulated1D functions
613644 e_p_dist = Tabulated1D (
614645 e_vals , p_vals , breakpoints = [len (e_vals )], interpolation = [1 ]
615646 )
616- e_e_dist = Tabulated1D (
617- e_vals , e_vals , breakpoints = [len (e_vals )], interpolation = [2 ]
618- )
619647
620648
621649 # limit the computation to the tabulated mu_en_air range
@@ -632,10 +660,22 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
632660 f"Mass attenuation coefficient <= 0 at energies: { zero_vals } "
633661 )
634662
635- integrand_operator = Combination (
636- functions = [mu_en_air , e_p_dist , e_e_dist , mass_attenuation_dist ],
637- operations = [np .multiply , np .multiply , np .divide ],
638- )
663+ if dose_quantity == 'absorbed-air' :
664+ # units [eV atoms-1 s-1]
665+ e_e_dist = Tabulated1D (
666+ e_vals , e_vals , breakpoints = [len (e_vals )], interpolation = [2 ]
667+ )
668+ integrand_operator = Combination (
669+ functions = [response_f , e_p_dist , e_e_dist , mass_attenuation_dist ],
670+ operations = [np .multiply , np .multiply , np .divide ],
671+ )
672+ elif dose_quantity == 'effective' :
673+ # units [pSv g atoms-1 s-1]
674+ integrand_operator = Combination (
675+ functions = [response_f , e_p_dist , mass_attenuation_dist ],
676+ operations = [np .multiply , np .divide ],
677+ )
678+
639679
640680 y_evaluated = integrand_operator (e_union )
641681
@@ -646,10 +686,12 @@ def get_photon_contact_dose_rate(self, by_nuclide: bool = False) -> float | dic
646686 cdr_nuc += integrand_function .integral ()[- 1 ]
647687
648688
649- # units [eV barns-1 cm-1 s-1]
689+ # units effective dose [eV barns-1 cm-1 s-1]
690+ # units air-absorbed dose [pSv g barns-1 cm-1 s-1]
650691 cdr_nuc *= nuc_atoms_per_bcm
651692
652- # units [Sv hr-1] - includes build up factor
693+ # units effective dose [Sv hr-1]
694+ # units air-absorbed dose [Gy hr-1]
653695 cdr_nuc *= multiplier
654696
655697 cdr [nuc ] = cdr_nuc
0 commit comments