From afa690de153e1f9ea8dc68e0198a8e4566c009dc Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Fri, 31 Mar 2023 17:38:32 +0100 Subject: [PATCH 001/133] Adding DBRC --- .../neutronCEimp_class.f90 | 71 ++++++-- .../neutronCEstd_class.f90 | 76 +++++++-- CollisionOperator/scatteringKernels_func.f90 | 97 ++++++++++- .../aceDatabase/aceNeutronDatabase_class.f90 | 151 +++++++++++++++++- .../aceDatabase/aceNeutronNuclide_class.f90 | 98 ++++++++++-- .../ceNeutronData/ceNeutronNuclide_inter.f90 | 2 +- 6 files changed, 451 insertions(+), 44 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index d836bc340..ac9b8ef34 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -17,8 +17,12 @@ module neutronCEimp_class use nuclearDataReg_mod, only : ndReg_getNeutronCE => getNeutronCE use nuclearDatabase_inter, only : nuclearDatabase use ceNeutronDatabase_inter, only : ceNeutronDatabase + use aceNeutronDatabase_class, only : aceNeutronDatabase + use aceNeutronDatabase_class, only : aceNeutronDatabase_CptrCast use ceNeutronMaterial_class, only : ceNeutronMaterial, ceNeutronMaterial_CptrCast use ceNeutronNuclide_inter, only : ceNeutronNuclide, ceNeutronNuclide_CptrCast + use aceNeutronNuclide_class, only : aceNeutronNuclide_CptrCast + use aceNeutronNuclide_class, only : aceNeutronNuclide ! Nuclear reactions use reactionHandle_inter, only : reactionHandle @@ -31,7 +35,7 @@ module neutronCEimp_class ! Scattering procedures use scatteringKernels_func, only : asymptoticScatter, targetVelocity_constXS, & - asymptoticInelasticScatter + asymptoticInelasticScatter, targetVelocity_DBRCXS implicit none private @@ -58,6 +62,8 @@ module neutronCEimp_class !! kT is target material temperature in [MeV]. (default = 400.0) !! thresh_A -> Mass threshold for explicit tratment of target nuclide movement [Mn]. !! Target movment is sampled if target mass A < thresh_A. (default = 1.0) + !! DBRCeMin -> Minimum energy to which DBRC is applied + !! DBRCeMax -> Maximum energy to which DBRC is applied !! !! Sample dictionary input: !! collProcName { @@ -81,6 +87,8 @@ module neutronCEimp_class class(ceNeutronDatabase), pointer, public :: xsData => null() class(ceNeutronMaterial), pointer, public :: mat => null() class(ceNeutronNuclide), pointer, public :: nuc => null() + class(aceNeutronNuclide), pointer, public :: aceNuc => null() + class(aceNeutronDatabase), pointer, public:: aceData=> null() !! Settings - private real(defReal) :: minE @@ -90,6 +98,9 @@ module neutronCEimp_class real(defReal) :: avWgt real(defReal) :: thresh_E real(defReal) :: thresh_A + real(defReal) :: DBRCeMin + real(defReal) :: DBRCeMax + ! Variance reduction options logical(defBool) :: splitting logical(defBool) :: roulette @@ -157,6 +168,10 @@ subroutine init(self, dict) if( self % thresh_E < 0) call fatalError(Here,' -ve energyThreshold') if( self % thresh_A < 0) call fatalError(Here,' -ve massThreshold') + ! DBRC energy limits + call dict % getOrDefault(self % DBRCeMin,'DBRCeMin', (1.0E-8_defReal)) + call dict % getOrDefault(self % DBRCeMax,'DBRCeMax', (200E-6_defReal)) + if (self % splitting) then if (self % maxWgt < 2 * self % minWgt) call fatalError(Here,& 'Upper weight bound must be at least twice the lower weight bound') @@ -389,7 +404,7 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle class(uncorrelatedReactionCE), pointer :: reac - logical(defBool) :: isFixed + logical(defBool) :: isFixed, hasDBRC character(100),parameter :: Here = 'elastic (neutronCEimp_class.f90)' ! Get reaction @@ -400,7 +415,14 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) collDat % A = self % nuc % getMass() collDat % kT = self % nuc % getkT() - isFixed = (p % E > collDat % kT * self % thresh_E) .and. (collDat % A > self % thresh_A) + ! Check is DBRC is on + ! Cast pointer to aceNeutronNuclide + self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) + if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retive ACE Neutron Nuclide') + hasDBRC = self % aceNuc % hasDBRC + + isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & + & .and. (collDat % A > self % thresh_A) ! Apply criterion for Free-Gas vs Fixed Target scattering if (.not. reac % inCMFrame()) then @@ -573,7 +595,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) class(particle), intent(inout) :: p type(collisionData),intent(inout) :: collDat class(uncorrelatedReactionCE), intent(in) :: reac - integer(shortInt) :: MT, nucIdx + integer(shortInt) :: nucIdx real(defReal) :: A, kT, mu real(defReal),dimension(3) :: V_n ! Neutron velocity (vector) real(defReal) :: U_n ! Neutron speed (scalar) @@ -581,19 +603,49 @@ subroutine scatterFromMoving(self, p, collDat, reac) real(defReal),dimension(3) :: dir_post ! Post-collicion direction real(defReal),dimension(3) :: V_t, V_cm ! Target and CM velocity real(defReal) :: phi, dummy + real(defReal) :: maj + logical(defBool) :: eRange, hasDBRC + character(100), parameter :: Here = 'ScatterFromMoving (neutronCEimp_class.f90)' - ! Read data - MT = collDat % MT - nucIdx = collDat % nucIdx + ! Read collision data A = collDat % A kT = collDat % kT + nucIdx = collDat % nucIdx ! Get neutron direction and velocity dir_pre = p % dirGlobal() V_n = dir_pre * sqrt(p % E) - ! Sample velocity of target - V_t = targetVelocity_constXS(p % E, dir_pre, A, kT, p % pRNG) + ! Sample target velocity with constant XS or with DBRC + ! Check energy range + eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) + ! Check if DBRC is on for this target nuclide + hasDBRC = (self % aceNuc % hasDBRC) + + if (eRange .and. hasDBRC) then + + ! Cast pointer to aceNeutronDatabase + self % aceData => aceNeutronDatabase_CptrCast(self % xsData) + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + + ! Retrive 0K nuclide index from DBRC nuclide map + nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) + + ! Reassign pointer for the 0K nuclide + self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + + ! Get elastic scattering 0K majorant + maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) + + ! Use DBRC to sample target velocity + V_t = targetVelocity_DBRCXS(self % aceNuc, p % E, dir_pre, A, kT, p % pRNG, maj) + + else + ! Constant cross section approximation + V_t = targetVelocity_constXS(p % E, dir_pre, A, kT, p % pRNG) + + end if ! Calculate Centre-of-Mass velocity V_cm = (V_n + V_t *A)/(A+1) @@ -620,6 +672,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) p % E = U_n * U_n call p % point(dir_post) collDat % muL = dot_product(dir_pre, dir_post) + end subroutine scatterFromMoving diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index b70b48e1d..178e827a9 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -17,8 +17,12 @@ module neutronCEstd_class use nuclearDataReg_mod, only : ndReg_getNeutronCE => getNeutronCE use nuclearDatabase_inter, only : nuclearDatabase use ceNeutronDatabase_inter, only : ceNeutronDatabase + use aceNeutronDatabase_class, only : aceNeutronDatabase + use aceNeutronDatabase_class, only : aceNeutronDatabase_CptrCast use ceNeutronMaterial_class, only : ceNeutronMaterial, ceNeutronMaterial_CptrCast use ceNeutronNuclide_inter, only : ceNeutronNuclide, ceNeutronNuclide_CptrCast + use aceNeutronNuclide_class, only : aceNeutronNuclide_CptrCast + use aceNeutronNuclide_class, only : aceNeutronNuclide ! Nuclear reactions use reactionHandle_inter, only : reactionHandle @@ -31,7 +35,7 @@ module neutronCEstd_class ! Scattering procedures use scatteringKernels_func, only : asymptoticScatter, targetVelocity_constXS, & - asymptoticInelasticScatter + asymptoticInelasticScatter, targetVelocity_DBRCXS implicit none private @@ -51,6 +55,8 @@ module neutronCEstd_class !! kT is target material temperature in [MeV]. (default = 400.0) !! thresh_A -> Mass threshold for explicit tratment of target nuclide movement [Mn]. !! Target movment is sampled if target mass A < thresh_A. (default = 1.0) + !! DBRCeMin -> Minimum energy to which DBRC is applied + !! DBRCeMax -> Maximum energy to which DBRC is applied !! !! Sample dictionary input: !! collProcName { @@ -67,12 +73,16 @@ module neutronCEstd_class class(ceNeutronDatabase), pointer, public :: xsData => null() class(ceNeutronMaterial), pointer, public :: mat => null() class(ceNeutronNuclide), pointer, public :: nuc => null() + class(aceNeutronNuclide), pointer, public :: aceNuc => null() + class(aceNeutronDatabase), pointer, public:: aceData=> null() !! Settings - private real(defReal) :: minE real(defReal) :: maxE real(defReal) :: thresh_E real(defReal) :: thresh_A + real(defReal) :: DBRCeMin + real(defReal) :: DBRCeMax contains ! Initialisation procedure @@ -122,6 +132,10 @@ subroutine init(self, dict) if( self % thresh_E < 0) call fatalError(Here,' -ve energyThreshold') if( self % thresh_A < 0) call fatalError(Here,' -ve massThreshold') + ! DBRC energy limits + call dict % getOrDefault(self % DBRCeMin,'DBRCeMin', (1.0E-8_defReal)) + call dict % getOrDefault(self % DBRCeMax,'DBRCeMax', (200E-6_defReal)) + end subroutine init !! @@ -263,13 +277,13 @@ end subroutine fission !! All CE elastic scattering happens in the CM frame !! subroutine elastic(self, p, collDat, thisCycle, nextCycle) - class(neutronCEstd), intent(inout) :: self - class(particle), intent(inout) :: p - type(collisionData), intent(inout) :: collDat - class(particleDungeon),intent(inout) :: thisCycle - class(particleDungeon),intent(inout) :: nextCycle + class(neutronCEstd), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle class(uncorrelatedReactionCE), pointer :: reac - logical(defBool) :: isFixed + logical(defBool) :: isFixed, hasDBRC character(100),parameter :: Here = 'elastic (neutronCEstd_class.f90)' ! Get reaction @@ -280,7 +294,14 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) collDat % A = self % nuc % getMass() collDat % kT = self % nuc % getkT() - isFixed = (p % E > collDat % kT * self % thresh_E) .and. (collDat % A > self % thresh_A) + ! Check is DBRC is on + ! Cast pointer to aceNeutronNuclide + self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) + if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retive ACE Neutron Nuclide') + hasDBRC = self % aceNuc % hasDBRC + + isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & + & .and. (collDat % A > self % thresh_A) ! Apply criterion for Free-Gas vs Fixed Target scattering if (.not. reac % inCMFrame()) then @@ -404,6 +425,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) class(particle), intent(inout) :: p type(collisionData),intent(inout) :: collDat class(uncorrelatedReactionCE), intent(in) :: reac + integer(shortInt) :: nucIdx real(defReal) :: A, kT, mu real(defReal),dimension(3) :: V_n ! Neutron velocity (vector) real(defReal) :: U_n ! Neutron speed (scalar) @@ -411,17 +433,49 @@ subroutine scatterFromMoving(self, p, collDat, reac) real(defReal),dimension(3) :: dir_post ! Post-collicion direction real(defReal),dimension(3) :: V_t, V_cm ! Target and CM velocity real(defReal) :: phi, dummy + real(defReal) :: maj + logical(defBool) :: eRange, hasDBRC + character(100), parameter :: Here = 'ScatterFromMoving (neutronCEstd_class.f90)' - ! Read data + ! Read collision data A = collDat % A kT = collDat % kT + nucIdx = collDat % nucIdx ! Get neutron direction and velocity dir_pre = p % dirGlobal() V_n = dir_pre * sqrt(p % E) - ! Sample velocity of target - V_t = targetVelocity_constXS(p % E, dir_pre, A, kT, p % pRNG) + ! Sample target velocity with constant XS or with DBRC + ! Check energy range + eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) + ! Check if DBRC is on for this target nuclide + hasDBRC = (self % aceNuc % hasDBRC) + + if (eRange .and. hasDBRC) then + + ! Cast pointer to aceNeutronDatabase + self % aceData => aceNeutronDatabase_CptrCast(self % xsData) + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + + ! Retrive 0K nuclide index from DBRC nuclide map + nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) + + ! Reassign pointer for the 0K nuclide + self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + + ! Get elastic scattering 0K majorant + maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) + + ! Use DBRC to sample target velocity + V_t = targetVelocity_DBRCXS(self % aceNuc, p % E, dir_pre, A, kT, p % pRNG, maj) + + else + ! Constant cross section approximation + V_t = targetVelocity_constXS(p % E, dir_pre, A, kT, p % pRNG) + + end if ! Calculate Centre-of-Mass velocity V_cm = (V_n + V_t *A)/(A+1) diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 60d9df361..5747cbf28 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -5,11 +5,15 @@ module scatteringKernels_func use RNG_class, only : RNG use particle_class, only : particle + ! Nuclear Data + use aceNeutronNuclide_class, only : aceNeutronNuclide + implicit none private public :: asymptoticScatter public :: targetVelocity_constXS + public :: targetVelocity_DBRCXS public :: asymptoticInelasticScatter private :: sample_x2expx2 @@ -91,7 +95,6 @@ end subroutine asymptoticInelasticScatter !! so that V_t*V_t=E_t with E_t beeing kinetic energy of a NEUTRON traveling with TARGET VELOCITY !! (note that it is not a kinetic energy of the target). !! - !! function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) real(defReal), intent(in) :: E real(defReal), dimension(3), intent(in) :: dir @@ -107,7 +110,7 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). Y = sqrt(A*E/kT) - ! Calculate treshhold factor alpha + ! Calculate threshold factor alpha alpha = 2.0/(Y*sqrt(PI)+2.0) @@ -130,7 +133,7 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) ! Sample polar angle of target velocity wrt. neutron direction mu = 2.0 * r2 - 1.0; - ! Calculate Acceptance Propability + ! Calculate acceptance probability P_acc = sqrt(Y*Y + X*X - 2.0*X*Y*mu) / (Y+X) ! Accept or reject mu @@ -138,7 +141,7 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) end do rejectionLoop - ! Calculate azimithal angle for traget and obtain target direction + ! Calculate azimithal angle for target and obtain target direction r4 = rand % get() phi = 2.0 *PI * r4 @@ -149,6 +152,91 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) end function targetVelocity_constXS + !! + !! Function that returns a sample of target velocity with DBRC + !! V_t is a vector. The velocity is scaled by a factor sqrt(Mn/2) where Mn is mass of a neutron + !! so that V_t*V_t=E_t with E_t being kinetic energy of a NEUTRON traveling with TARGET VELOCITY + !! (note that it is not a kinetic energy of the target). + !! + !! + function targetVelocity_DBRCXS(aceNuc, E, dir, A, kT, rand, tempMaj) result (V_t) + class(aceNeutronNuclide), intent(in) :: aceNuc + real(defReal), intent(in) :: E + real(defReal), dimension(3), intent(in) :: dir + real(defReal), intent(in) :: A + real(defReal), intent(in) :: kT + real(defReal), intent(in) :: tempMaj + class(RNG), intent(inout) :: rand + integer(shortInt) :: idx + real(defReal),dimension(3) :: V_t + real(defReal) :: alpha, mu, phi, P_acc, DBRC_acc + real(defReal) :: X, Y + real(defReal) :: r1, r2, r3, r4, r5 + real(defreal) :: rel_v, rel_E, xs_rel_v, f + + ! Calculate neutron Y = beta *V_n + ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). + Y = sqrt(A * E / kT) + + ! Calculate threshold factor alpha + ! In MCNP, alpha is p1 + alpha = 2.0 / (Y * sqrt(PI) + 2.0) + + rejectionLoop: do + + ! Obtain random numbers + r1 = rand % get() + r2 = rand % get() + r3 = rand % get() + + ! Sample X = beta * V_t + ! Uses helper functions below + if ( r1 > alpha ) then + X = sample_x2expx2(rand) + else + X = sample_x3expx2(rand) + end if + + ! Sample polar angle of target velocity wrt. neutron direction + mu = 2.0 * r2 - 1.0; + + ! Calculate relative velocity between neutron and target + rel_v = sqrt(Y * Y + X * X - 2.0 * X * Y * mu) + + ! Calculate Acceptance Propability + P_acc = rel_v / (Y + X) + + ! Accept or reject mu and target velocity + if (P_acc < r3) cycle rejectionLoop + + ! Relative energy = relative velocity **2 due to sqrt(Mn/2) scaling factor + rel_E = (rel_v**2 * kT / A) + + ! Find 0K scattering xs of target at relative energy + call aceNuc % search(idx, f, rel_E) + xs_rel_v = aceNuc % scatterXS(idx, f) + + ! Introduce DBRC acceptance condition + DBRC_acc = (xs_rel_v / tempMaj) + r4 = rand % get() + + ! Accept or reject with DBRC + if (DBRC_acc > r4) then + exit rejectionLoop + end if + + end do rejectionLoop + + ! Calculate azimithal angle for target and obtain target direction + r5 = rand % get() + phi = 2.0 * PI * r5 + + V_t = rotateVector(dir, mu, phi) + + ! Scale target direction by magnitude of velocity + V_t = V_t * (X * sqrt(kT / A)) + + end function targetVelocity_DBRCXS !! @@ -189,7 +277,6 @@ function sample_x2expx2(rand) result(sample) end function sample_x2expx2 - !! !! Helper function to sample x^3 * exp( - x^2) probability distribution !! Uses random numbers from provided RNG diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 26ac0498d..66821a3f4 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -54,15 +54,17 @@ module aceNeutronDatabase_class !! Sample input: !! nuclearData { !! handles { - !! ce {type aceNeutronDatabase; ures <1 or 0>; aceLibrary ;} } + !! ce {type aceNeutronDatabase; DBRC (92238 94242); ures <1 or 0>; aceLibrary ;} } !! !! Public Members: - !! nuclides -> array of aceNeutronNuclides with data - !! materials -> array of ceNeutronMaterials with data - !! Ebounds -> array with bottom (1) and top (2) energy bound - !! activeMat -> array of materials present in the geometry - !! nucToZaid -> map to link nuclide index to zaid index - !! hasUrr -> ures probability tables flag, it's false by default + !! nuclides -> array of aceNeutronNuclides with data + !! materials -> array of ceNeutronMaterials with data + !! Ebounds -> array with bottom (1) and top (2) energy bound + !! activeMat -> array of materials present in the geometry + !! nucToZaid -> map to link nuclide index to zaid index + !! hasUrr -> ures probability tables flag, it's false by default + !! hasDBRC -> DBRC flag, it's false by default + !! mapDBRCnuc -> map to link indexes of DBRC nuclides with their corresponding 0K !! !! Interface: !! nuclearData Interface @@ -77,6 +79,8 @@ module aceNeutronDatabase_class ! Probability tables data integer(shortInt),dimension(:),allocatable :: nucToZaid logical(defBool) :: hasUrr = .false. + logical(defBool) :: hasDBRC = .false. + type(intMap) :: mapDBRCnuc contains ! nuclearData Procedures @@ -85,8 +89,10 @@ module aceNeutronDatabase_class procedure :: getMaterial procedure :: getNuclide procedure :: getReaction + procedure :: getScattMicroMajXS procedure :: init procedure :: init_urr + procedure :: init_DBRC procedure :: activate ! ceNeutronDatabase Procedures @@ -228,6 +234,47 @@ function getReaction(self, MT, idx) result(reac) end function getReaction + !! + !! Subroutine to get the elastic scattering majorant cross section in a nuclide + !! over a certain energy range, defined as a function of a given temperature + !! + !! NOTE: This function is called by the collision operator to apply DBRC; nucIdx + !! should correspond to a nuclide with temperature 0K, while kT is the + !! temperature of the target nuclide the neutron is colliding with + !! + !! Args: + !! A [in] -> Nuclide atomic weight ratio + !! kT [in] -> Thermal energy of nuclide + !! E [in] -> Energy of neutron incident to target for which majorant needs to be found + !! maj [out] -> Temperature majorant cross section + !! + function getScattMicroMajXS(self, E, kT, A, nucIdx) result(maj) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal), intent(in) :: kT + real(defReal), intent(in) :: A + integer(shortInt), intent(in) :: nucIdx + real(defReal) :: maj + real(defReal) :: E_upper, E_lower, E_min, E_max + real(defReal) :: alpha + + ! Find energy limits to define majorant calculation range + alpha = 4 / (sqrt( E * A / kT )) + E_upper = E * (1 + alpha) * (1 + alpha) + E_lower = E * (1 - alpha) * (1 - alpha) + + ! Find system minimum and maximum energies + call self % energyBounds(E_min, E_max) + + ! Avoid energy limits being outside system range + if (E_lower < E_min) E_lower = E_min + if (E_upper > E_max) E_upper = E_max + + ! Find largest elastic scattering xs in energy range given by E_lower and E_upper + maj = self % nuclides(nucIdx) % elScattMaj(E_lower, E_upper) + + end function getScattMicroMajXS + !! !! Return energy bounds for data in the database !! @@ -453,7 +500,8 @@ subroutine init(self, dict, ptr, silent ) integer(shortInt) :: i, j, envFlag, nucIdx, idx integer(shortInt) :: maxNuc logical(defBool) :: isFissileMat - integer(shortInt),dimension(:),allocatable :: nucIdxs + integer(shortInt),dimension(:),allocatable :: nucIdxs, DBRCidxs + character(nameLen),dimension(:),allocatable :: DBRC_nucs integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 character(100), parameter :: Here = 'init (aceNeutronDatabase_class.f90)' @@ -521,6 +569,25 @@ subroutine init(self, dict, ptr, silent ) ! Load library call aceLib_load(aceLibPath) + ! Check if DBRC is listed in the input file + if (dict % isPresent('DBRC')) then + + ! Set flag to true if DBRC nucs are in input file + self % hasDBRC = .true. + + ! Call through list of DBRC nuclides + call dict % get(DBRCidxs, 'DBRC') + allocate(DBRC_nucs(size(DBRCidxs))) + + ! Add all DBRC nuclides to nucSet for initialisation + do i = 1, size(DBRCidxs) + DBRC_nucs(i) = numToChar(DBRCidxs(i)) + DBRC_nucs(i) = trim(DBRC_nucs(i))//'.00' + call nucSet % add(DBRC_nucs(i), IN_SET) + end do + + end if + ! Build nuclide definitions allocate(self % nuclides(nucSet % length())) i = nucSet % begin() @@ -597,10 +664,16 @@ subroutine init(self, dict, ptr, silent ) self % Ebounds(2) = min(self % Ebounds(2), self % nuclides(i) % eGrid(j)) end do + ! If on, initialise probability tables for ures if (self % hasUrr) then call self % init_urr() end if + ! If on, initialise DBRC + if (self % hasDBRC) then + call self % init_DBRC(DBRC_nucs, nucSet, self % mapDBRCnuc) + end if + !! Clean up call aceLib_kill() @@ -645,6 +718,68 @@ subroutine init_urr(self) end subroutine init_urr + !! + !! Checks through all nuclides, creates map with nuclides present and corresponding 0K nuclide + !! + !! NOTE: compares the first 5 letters of the ZAID.TT. It would be wrong with isotopes + !! with Z > 99 + !! + subroutine init_DBRC(self, DBRC_nucs, nucSet, map) + class(aceNeutronDatabase), intent(inout) :: self + character(nameLen), dimension(:), intent(in) :: DBRC_nucs + type(charMap), intent(in) :: nucSet + type(intMap), intent(out) :: map + integer(shortInt) :: i, j, k, idx + character(nameLen) :: nuc0K, nucDBRC + character(5) :: nuc0Ktemp, nucDBRCtemp + + idx = 1 + + ! Loop through DBRC nuclides + do i = 1, size(DBRC_nucs) + ! Get ZAIDs with and without 0K temperature codes + nuc0K = DBRC_nucs(i) + nuc0Ktemp = nuc0K(1:5) + + ! Loop through nucSet to find the nucIdxs of the 0K DBRC nuclides + k = nucSet % begin() + do while (k /= nucSet % end()) + + ! Exit loop if a match is found + if (nucSet % atKey(k) == nuc0K) then + idx = nucSet % atVal(k) + exit + end if + + ! Increment index + k = nucSet % next(k) + + end do + + ! Loop through nucSec again to find the nucIdxs of the DBRC nuclides with + ! temperature different from 0K + j = nucSet % begin() + do while (j /= nucSet % end()) + ! Get ZAIDs with and without temperature code + nucDBRC = nucSet % atKey(j) + nucDBRCtemp = nucDBRC(1:5) + + ! If the ZAID of the DBRC nuclide matches one in nucSet, save them in the map + if (nucDBRCtemp == nuc0Ktemp) then + call map % add(nucSet % atVal(j), idx) + ! Set nuclide DBRC flag on + self % nuclides(nucSet % atVal(j)) % hasDBRC = .true. + end if + + ! Increment index + j = nucSet % next(j) + + end do + + end do + + end subroutine init_DBRC + !! !! Activate this nuclearDatabase !! diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index c3db38cd2..64e4d79d9 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -92,19 +92,22 @@ module aceNeutronNuclide_class !! thData -> S(a,b) thermal data class to store XSs and outgoing distributions !! SabEl -> energy boundaries of elastic S(a,b) data !! SabInel -> energy boundaries of inelastic S(a,b) data + !! hasDBRC -> Doppler Broadening Rejection Correction flag !! !! Interface: !! ceNeutronNuclide Interface - !! search -> search energy grid and return index and interpolation factor - !! totalXS -> return totalXS given index and interpolation factor - !! microXSs -> return interpolated ceNeutronMicroXSs package given index and inter. factor - !! getUrrXSs -> return ceNeutronMicroXSs accounting for ures probability tables - !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment - !! init -> build nuclide from aceCard - !! init_urr -> build list and mapping of nuclides to maintain temperature correlation - !! when reading ures probability tables - !! init_Sab -> builds S(a,b) propertied from aceCard - !! display -> print information about the nuclide to the console + !! search -> search energy grid and return index and interpolation factor + !! totalXS -> return totalXS given index and interpolation factor + !! scatterXS -> return elastic scattering XS given index and interpolation factor + !! microXSs -> return interpolated ceNeutronMicroXSs package given index and inter. factor + !! getUrrXSs -> return ceNeutronMicroXSs accounting for ures probability tables + !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment + !! elScattMaj -> returns the elastic scattering majorant within an energy range given as input + !! init -> build nuclide from aceCard + !! init_urr -> build list and mapping of nuclides to maintain temperature correlation + !! when reading ures probability tables + !! init_Sab -> builds S(a,b) propertied from aceCard + !! display -> print information about the nuclide to the console !! type, public, extends(ceNeutronNuclide) :: aceNeutronNuclide character(nameLen) :: ZAID = '' @@ -129,6 +132,9 @@ module aceNeutronNuclide_class real(defReal), dimension(2) :: SabEl = ZERO real(defReal), dimension(2) :: SabInel = ZERO + ! DBRC nuclide flag + logical(defBool) :: hasDBRC = .false. + contains ! Superclass Interface procedure :: invertInelastic @@ -138,9 +144,11 @@ module aceNeutronNuclide_class ! Local interface procedure :: search procedure :: totalXS + procedure :: scatterXS procedure :: microXSs procedure :: getUrrXSs procedure :: getThXSs + procedure :: elScattMaj procedure :: init procedure :: init_urr procedure :: init_Sab @@ -359,6 +367,32 @@ elemental function totalXS(self, idx, f) result(xs) end function totalXS + !! + !! Return value of the elastic scattering XS given interpolation factor and index + !! + !! Does not perform any check for valid input! + !! + !! Args: + !! idx [in] -> index of the bottom bin in nuclide Energy-Grid + !! f [in] -> interpolation factor in [0;1] + !! + !! Result: + !! xs = sigma(idx+1) * f + (1-f) * sigma(idx) + !! + !! Errors: + !! Invalid idx beyond array bounds -> undefined behaviour + !! Invalid f (outside [0;1]) -> incorrect value of XS + !! + elemental function scatterXS(self, idx, f) result(xs) + class(aceNeutronNuclide), intent(in) :: self + integer(shortInt), intent(in) :: idx + real(defReal), intent(in) :: f + real(defReal) :: xs + + xs = self % mainData(ESCATTER_XS, idx+1) * f + (ONE-f) * self % mainData(ESCATTER_XS, idx) + + end function scatterXS + !! !! Return interpolated neutronMicroXSs package for the given interpolation factor and index !! @@ -534,6 +568,50 @@ subroutine getUrrXSs(self, xss, idx, f, E, xi) end subroutine getUrrXSs + !! Function to calculate the maximum elastic scattering cross section within + !! an energy range given by an upper and lower energy bound. + !! + !! Args: + !! upperE [in] -> Upper bound of energy range + !! upperE [in] -> Upper bound of energy range + !! maj [out] -> Maximum scattering cross section within energy range + !! + function elScattMaj(self, lowerE, upperE) result (maj) + class(aceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: lowerE + real(defReal), intent(in) :: upperE + real(defReal) :: maj + integer(shortInt) :: idx + real(defReal) :: f, E, xs + + ! Search for idx, f, and xs for the lower energy limit + call self % search(idx, f, lowerE) + + ! Conservative: choose the xs at the energy point before the lower energy limit + f = 0 + maj = scatterXS(self, idx, f) + + majorantLoop: do + + ! Increase index + idx = idx + 1 + + ! Find XS and energy at index + xs = self % mainData(ESCATTER_XS, idx) + E = self % eGrid(idx) + + ! Compare cross sections and possibly update majorant + if (xs > maj) then + maj = xs + end if + + ! Exit loop after getting to the upper energy limit + if (E > upperE) exit majorantLoop + + end do majorantLoop + + end function elScattMaj + !! !! Initialise from an ACE Card !! diff --git a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 index 24339234e..f7542f537 100644 --- a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 @@ -218,7 +218,7 @@ subroutine set(self, nucIdx, database, fissile, mass, kT) end if if(present(kT)) then - if(kT <= ZERO) call fatalError(Here, "Temperature of nuclide cannot be -ve: "//numToChar(kT)) + if(kT < ZERO) call fatalError(Here, "Temperature of nuclide cannot be -ve: "//numToChar(kT)) self % kT = kT end if From c224e4428033ef7aa73a4a73244d67ef2e6f369a Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Tue, 20 Jun 2023 12:45:34 +0100 Subject: [PATCH 002/133] Adding collision number map --- .../collisionProcessor_inter.f90 | 3 + ParticleObjects/particle_class.f90 | 7 +- Tallies/TallyMaps/CMakeLists.txt | 1 + Tallies/TallyMaps/collNumMap_class.f90 | 223 ++++++++++++++++++ Tallies/TallyMaps/tallyMap1DFactory_func.f90 | 8 +- 5 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 Tallies/TallyMaps/collNumMap_class.f90 diff --git a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 index b19a106b7..2b36d0ef2 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 @@ -154,6 +154,9 @@ subroutine collide(self, p, tally ,thisCycle, nextCycle) ! Apply post collision implicit treatments call self % cutoffs(p, collDat, thisCycle, nextCycle) + ! Update particle collision counter + p % collisionN = p % collisionN + 1 + ! Report out-of-collision call tally % reportOutColl(p, collDat % MT, collDat % muL) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index a331d2105..331347670 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -36,6 +36,7 @@ module particle_class !! matIdx -> material Index in which particle is present !! cellIdx -> Cell Index at the lowest level in which particle is present !! uniqueID -> Unique ID of the cell at the lowest level in which particle is present + !! collisionN -> Number of collisions the particle went through !! !! Interface: !! assignemnt(=) -> Build particleState from particle @@ -54,6 +55,7 @@ module particle_class integer(shortInt) :: matIdx = -1 ! Material index where particle is integer(shortInt) :: cellIdx = -1 ! Cell idx at the lowest coord level integer(shortInt) :: uniqueID = -1 ! Unique id at the lowest coord level + integer(shortInt) :: collisionN = 0 ! Number of collisions contains generic :: assignment(=) => fromParticle generic :: operator(.eq.) => equal_particleState @@ -108,11 +110,12 @@ module particle_class real(defReal) :: timeMax = ZERO ! Maximum neutron time before cut-off integer(shortInt) :: fate = 0 ! Neutron's fate after being subjected to an operator integer(shortInt) :: type ! Particle type + integer(shortInt) :: collisionN = 0 ! Index of the number of collisions the particle went through ! Particle processing information class(RNG), pointer :: pRNG => null() ! Pointer to RNG associated with the particle real(defReal) :: k_eff ! Value of default keff for implicit source generation - integer(shortInt) :: geomIdx ! Index of the geometry used by the particle + integer(shortInt) :: geomIdx ! Index of the geometry used by the particle ! Archived snapshots of previous states type(particleState) :: preHistory @@ -611,6 +614,7 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % matIdx = RHS % coords % matIdx LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() + LHS % collisionN = RHS % collisionN end subroutine particleState_fromParticle @@ -693,6 +697,7 @@ elemental subroutine kill_particleState(self) self % matIdx = -1 self % cellIdx = -1 self % uniqueID = -1 + self % collisionN = 0 end subroutine kill_particleState diff --git a/Tallies/TallyMaps/CMakeLists.txt b/Tallies/TallyMaps/CMakeLists.txt index 60db155a5..52b3179ce 100644 --- a/Tallies/TallyMaps/CMakeLists.txt +++ b/Tallies/TallyMaps/CMakeLists.txt @@ -14,6 +14,7 @@ add_sources(./tallyMap_inter.f90 ./sphericalMap_class.f90 ./cellMap_class.f90 ./cylindricalMap_class.f90 + ./collNumMap_class.f90 # ./matXsMap_class.f90 ) diff --git a/Tallies/TallyMaps/collNumMap_class.f90 b/Tallies/TallyMaps/collNumMap_class.f90 new file mode 100644 index 000000000..f34e09a46 --- /dev/null +++ b/Tallies/TallyMaps/collNumMap_class.f90 @@ -0,0 +1,223 @@ +module collNumMap_class + + use numPrecision + use genericProcedures, only : fatalError, numToChar + use dictionary_class, only : dictionary + use intMap_class, only : intMap + use particle_class, only : particleState + use outputFile_class, only : outputFile + use tallyMap1D_inter, only : tallyMap1D, kill_super => kill + + implicit none + private + + !! + !! Constructor + !! + interface collNumMap + module procedure collNumMap_fromDict + end interface + + !! + !! Map that divides based on the number of collisions a particle underwent + !! + !! Private Members: + !! binMap -> intMap that maps collNumber to binIdx + !! default -> binIdx for numbers not in binMap + !! Nbins -> Number of bins in the map + !! collisionNumbers -> List of collision numbers required, stored in the map + !! + !! Interface: + !! tallyMap Interface + !! build -> builds instance without dictionary + !! + !! Sample Dictionary Input: + !! myMap { + !! type collNumMap; + !! collNumbers ( 0 1 2 3 5 10 ); + !! } + !! + type, public,extends(tallyMap1D) :: collNumMap + private + type(intMap) :: binMap + integer(shortInt) :: default = 0 + integer(shortInt) :: Nbins = 0 + integer(shortInt), dimension(:), allocatable :: collisionNumbers + + contains + ! Superclass interface implementaction + procedure :: init + procedure :: bins + procedure :: map + procedure :: getAxisName + procedure :: print + procedure :: kill + + ! Class specific procedures + procedure :: build + + end type collNumMap + +contains + + !! + !! Build collision number map from dictionary + !! + !! Args: + !! collNumbers [in] -> Array of collision numbers to be included in the map + !! + !! Erorrs: + !! None from here. + !! + subroutine build(self, collNumbers) + class(collNumMap), intent(inout) :: self + integer(shortInt), dimension(:), intent(in) :: collNumbers + integer(shortInt) :: i, N + character(100), parameter :: Here = 'build (collNumMap_class.f90)' + + ! Find number of collision numbers to bin + N = size(collNumbers) + if (N == 0) call fatalError(Here, 'No collision number was specified') + + ! Allocate array with number of collisions + allocate(self % collisionNumbers(N)) + self % collisionNumbers = collNumbers + + ! Allocate space in map + call self % binMap % init(N) + + ! Load collision numbers and bins + do i = 1, N + call self % binMap % add(collNumbers(i), i) + end do + + ! Save number of bins + self % Nbins = N + + end subroutine build + + !! + !! Initialise cell map from dictionary + !! + !! See tallyMap for specification + !! + subroutine init(self, dict) + class(collNumMap), intent(inout) :: self + class(dictionary), intent(in) :: dict + integer(shortInt), dimension(:), allocatable :: collNum + + ! Get cell names list + call dict % get(collNum, 'collNumbers') + + ! Initialise Map + call self % build(collNum) + + end subroutine init + + !! + !! Return total number of bins in this division + !! + !! See tallyMap for specification + !! + elemental function bins(self, D) result(N) + class(collNumMap), intent(in) :: self + integer(shortInt), intent(in) :: D + integer(shortInt) :: N + + if (D == 1 .or. D == 0) then + N = self % Nbins + else + N = 0 + end if + + end function bins + + !! + !! Map particle to a single bin. Return 0 for particle out of division + !! + !! See tallyMap for specification + !! + elemental function map(self,state) result(idx) + class(collNumMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + + idx = self % binMap % getOrDefault( state % collisionN, self % default) + + end function map + + !! + !! Return string that describes variable used to divide event space + !! + !! See tallyMap for specification + !! + function getAxisName(self) result(name) + class(collNumMap), intent(in) :: self + character(nameLen) :: name + + name = 'CollisionNumber' + + end function getAxisName + + !! + !! Add information about division axis to the output file + !! + !! See tallyMap for specification + !! + subroutine print(self,out) + class(collNumMap), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen) :: name + integer(shortInt) :: i + + ! Name the array + name = trim(self % getAxisName()) // 'Bins' + + call out % startArray(name, [1, self % Nbins]) + + ! Print cell indexes + do i = 1, self % Nbins + call out % addValue(numToChar(self % collisionNumbers(i))) + end do + + call out % endArray() + + end subroutine print + + !! + !! Build new cell Map from dictionary + !! + !! Args: + !! dict[in] -> input dictionary for the map + !! + !! Result: + !! Initialised cellMap instance + !! + !! Errors: + !! See init procedure. + !! + function collNumMap_fromDict(dict) result(new) + class(dictionary), intent(in) :: dict + type(collNumMap) :: new + + call new % init(dict) + + end function collNumMap_fromDict + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(collNumMap), intent(inout) :: self + + call kill_super(self) + + call self % binMap % kill() + self % Nbins = 0 + + if (allocated(self % collisionNumbers)) deallocate(self % collisionNumbers) + + end subroutine kill + + +end module collNumMap_class diff --git a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 index 1bcf4f6b9..a9dda8cdf 100644 --- a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 @@ -32,6 +32,7 @@ module tallyMap1DFactory_func use weightMap_class, only : weightMap use cellMap_class, only : cellMap use testMap_class, only : testMap + use collNumMap_class, only : collNumMap ! use matXsMap_class, only : matXsMap implicit none @@ -52,7 +53,8 @@ module tallyMap1DFactory_func 'homogMatMap',& 'weightMap ',& 'cellMap ',& - 'testMap '] + 'testMap ',& + 'collNumMap '] contains @@ -111,6 +113,10 @@ subroutine new_tallyMap1D(new, dict) allocate(testMap :: new) call new % init(dict) + case('collNumMap') + allocate(collNumMap :: new) + call new % init(dict) + !*** NEW TALLY MAP TEMPLATE ***! !case('') ! allocate( :: new) From b81c2b2deb5246cf977929a67467818f5a72e8f6 Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Tue, 20 Jun 2023 14:13:56 +0100 Subject: [PATCH 003/133] Restart collision counter for fission source particles --- CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 | 2 ++ CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 | 1 + CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 | 1 + ParticleObjects/particle_class.f90 | 1 + 4 files changed, 5 insertions(+) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 072e367bb..8ba23b8e1 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -307,6 +307,7 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) pTemp % dir = dir pTemp % E = E_out pTemp % wgt = wgt + pTemp % collisionN = 0 call nextCycle % detain(pTemp) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) @@ -411,6 +412,7 @@ subroutine fission(self, p, collDat, thisCycle, nextCycle) pTemp % dir = dir pTemp % E = E_out pTemp % wgt = wgt + pTemp % collisionN = 0 call nextCycle % detain(pTemp) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index b70b48e1d..a0595c6c7 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -222,6 +222,7 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) pTemp % dir = dir pTemp % E = E_out pTemp % wgt = wgt + pTemp % collisionN = 0 call nextCycle % detain(pTemp) end do diff --git a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 index b357319cb..0665c7891 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 @@ -175,6 +175,7 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) pTemp % dir = dir pTemp % G = G_out pTemp % wgt = wgt + pTemp % collisionN = 0 call nextCycle % detain(pTemp) end do diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 331347670..90f5289b1 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -272,6 +272,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % isMG = RHS % isMG LHS % type = RHS % type LHS % time = RHS % time + LHS % collisionN = RHS % collisionN end subroutine particle_fromParticleState From 0e1c38435244dc38f3bc76591cd3b2172346afa2 Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Wed, 21 Jun 2023 12:57:11 +0100 Subject: [PATCH 004/133] Adding test for collision number tally map --- Tallies/TallyMaps/CMakeLists.txt | 3 +- Tallies/TallyMaps/Tests/collNumMap_test.f90 | 112 +++++++++++++++++++ Tallies/TallyMaps/Tests/materialMap_test.f90 | 2 +- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 Tallies/TallyMaps/Tests/collNumMap_test.f90 diff --git a/Tallies/TallyMaps/CMakeLists.txt b/Tallies/TallyMaps/CMakeLists.txt index 52b3179ce..35383328a 100644 --- a/Tallies/TallyMaps/CMakeLists.txt +++ b/Tallies/TallyMaps/CMakeLists.txt @@ -27,4 +27,5 @@ add_unit_tests(./Tests/materialMap_test.f90 ./Tests/homogMatMap_test.f90 ./Tests/sphericalMap_test.f90 ./Tests/cellMap_test.f90 - ./Tests/cylindricalMap_test.f90) + ./Tests/cylindricalMap_test.f90 + ./Tests/collNumMap_test.f90) diff --git a/Tallies/TallyMaps/Tests/collNumMap_test.f90 b/Tallies/TallyMaps/Tests/collNumMap_test.f90 new file mode 100644 index 000000000..ca9b72e89 --- /dev/null +++ b/Tallies/TallyMaps/Tests/collNumMap_test.f90 @@ -0,0 +1,112 @@ +module collNumMap_test + use numPrecision + use pFUnit_mod + use particle_class, only : particleState + use dictionary_class, only : dictionary + use dictParser_func, only : charToDict + use outputFile_class, only : outputFile + + use collNumMap_class, only : collNumMap + + implicit none + + +@testCase + type, extends(TestCase) :: test_collNumMap + private + type(collNumMap) :: map + contains + procedure :: setUp + procedure :: tearDown + end type test_collNumMap + + !! + !! Test parameters + !! + integer(shortInt), dimension(*), parameter :: COLL_NUMS = [0, 1, 2, 5, 10, 50, 81] + + +contains + + !! + !! Sets up test_collNumMap object we can use in a number of tests + !! + subroutine setUp(this) + class(test_collNumMap), intent(inout) :: this + type(dictionary) :: dict + + ! Initialise dictionary and build map + call dict % init(1) + + ! Build material map definition + call dict % store('collNumbers', COLL_NUMS) + call this % map % init(dict) + + end subroutine setUp + + !! + !! Kills test_collNumMap object + !! + subroutine tearDown(this) + class(test_collNumMap), intent(inout) :: this + + call this % map % kill() + + end subroutine tearDown + +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +!! PROPER TESTS BEGIN HERE +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> + + !! + !! Mapping test + !! +@Test + subroutine testMapping(this) + class(test_collNumMap), intent(inout) :: this + type(particleState) :: state + integer(shortInt) :: i + integer(shortInt),dimension(5) :: bins + integer(shortInt),dimension(5),parameter :: EXPECTED_BINS = [2, 3, 0, 0, 4] + + do i = 1,5 + state % collisionN = i + bins(i) = this % map % map(state) + end do + + @assertEqual(EXPECTED_BINS,bins) + + end subroutine testMapping + + !! + !! Test number of bins inquiry + !! +@Test + subroutine testNumberOfBinsInquiry(this) + class(test_collNumMap), intent(inout) :: this + + @assertEqual(7, this % map % bins(0), 'Total number of bins') + @assertEqual(7, this % map % bins(1), 'Number of bins in dimension 1') + @assertEqual(0, this % map % bins(2), 'Number of bins in higher dimension') + + end subroutine testNumberOfBinsInquiry + + !! + !! Test correctness of print subroutine + !! Does not checks that values are correct, but that calls sequence is without errors + !! +@Test + subroutine testPrint(this) + class(test_collNumMap), intent(inout) :: this + type(outputFile) :: out + + call out % init('dummyPrinter', fatalErrors = .false.) + + call this % map % print(out) + @assertTrue(out % isValid(),'For number of collisions map ') + call out % reset() + + end subroutine testPrint + + +end module collNumMap_test diff --git a/Tallies/TallyMaps/Tests/materialMap_test.f90 b/Tallies/TallyMaps/Tests/materialMap_test.f90 index 41219247a..9217652a9 100644 --- a/Tallies/TallyMaps/Tests/materialMap_test.f90 +++ b/Tallies/TallyMaps/Tests/materialMap_test.f90 @@ -162,7 +162,7 @@ end subroutine testNumberOfBinsInquiry !! !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequance is without errors + !! Does not checks that values are correct, but that calls sequence is without errors !! @Test subroutine testPrint(this) From e331758aaa8d24896e665bbd2fd34dd6241af9c1 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 27 Jul 2023 14:48:08 +0100 Subject: [PATCH 005/133] Fix doc typos in collNumMap_class.f90 --- Tallies/TallyMaps/collNumMap_class.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tallies/TallyMaps/collNumMap_class.f90 b/Tallies/TallyMaps/collNumMap_class.f90 index f34e09a46..d4ad46563 100644 --- a/Tallies/TallyMaps/collNumMap_class.f90 +++ b/Tallies/TallyMaps/collNumMap_class.f90 @@ -45,7 +45,7 @@ module collNumMap_class integer(shortInt), dimension(:), allocatable :: collisionNumbers contains - ! Superclass interface implementaction + ! Superclass interface implementation procedure :: init procedure :: bins procedure :: map @@ -97,7 +97,7 @@ subroutine build(self, collNumbers) end subroutine build !! - !! Initialise cell map from dictionary + !! Initialise collision number map from dictionary !! !! See tallyMap for specification !! @@ -185,13 +185,13 @@ subroutine print(self,out) end subroutine print !! - !! Build new cell Map from dictionary + !! Build new collision number Map from dictionary !! !! Args: !! dict[in] -> input dictionary for the map !! !! Result: - !! Initialised cellMap instance + !! Initialised collNumMap instance !! !! Errors: !! See init procedure. From 7919d0622c2d0b81ec4b270dc801945bd75e6e3d Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:35:56 +0100 Subject: [PATCH 006/133] Change function call in aceNeutronNuclide_class.f90 --- .../ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 64e4d79d9..542c12f74 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -589,7 +589,7 @@ function elScattMaj(self, lowerE, upperE) result (maj) ! Conservative: choose the xs at the energy point before the lower energy limit f = 0 - maj = scatterXS(self, idx, f) + maj = self % scatterXS(idx, f) majorantLoop: do From 27b3a44a2aeee58f9a7802b1bc47462387cf633f Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:38:34 +0100 Subject: [PATCH 007/133] Fix typos in neutronCEimp_class.f90 --- .../CollisionProcessors/neutronCEimp_class.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index ac9b8ef34..87346b1bb 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -215,7 +215,7 @@ subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) collDat % nucIdx = self % mat % sampleNuclide(p % E, p % pRNG) self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retive CE Neutron Nuclide') + if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Select Main reaction channel call self % nuc % getMicroXSs(microXss, p % E, p % pRNG) @@ -418,7 +418,7 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) ! Check is DBRC is on ! Cast pointer to aceNeutronNuclide self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retive ACE Neutron Nuclide') + if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retrieve ACE Neutron Nuclide') hasDBRC = self % aceNuc % hasDBRC isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & @@ -626,14 +626,14 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Cast pointer to aceNeutronDatabase self % aceData => aceNeutronDatabase_CptrCast(self % xsData) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') - ! Retrive 0K nuclide index from DBRC nuclide map + ! Retrieve 0K nuclide index from DBRC nuclide map nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) ! Reassign pointer for the 0K nuclide self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') ! Get elastic scattering 0K majorant maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) From bcc0c132fb92d85a4756639402a1ccbd92fbe46c Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:39:26 +0100 Subject: [PATCH 008/133] Fix typos in neutronCEstd_class.f90 --- .../CollisionProcessors/neutronCEstd_class.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index 178e827a9..2878a8609 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -168,7 +168,7 @@ subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) collDat % nucIdx = self % mat % sampleNuclide(p % E, p % pRNG) self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retive CE Neutron Nuclide') + if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Select Main reaction channel call self % nuc % getMicroXSs(microXss, p % E, p % pRNG) @@ -297,7 +297,7 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) ! Check is DBRC is on ! Cast pointer to aceNeutronNuclide self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retive ACE Neutron Nuclide') + if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retrieve ACE Neutron Nuclide') hasDBRC = self % aceNuc % hasDBRC isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & @@ -456,14 +456,14 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Cast pointer to aceNeutronDatabase self % aceData => aceNeutronDatabase_CptrCast(self % xsData) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') - ! Retrive 0K nuclide index from DBRC nuclide map + ! Retrieve 0K nuclide index from DBRC nuclide map nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) ! Reassign pointer for the 0K nuclide self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retive ACE Neutron Database') + if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') ! Get elastic scattering 0K majorant maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) From 9353397343558d543c7a0dcf0f98adc1b63bf665 Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Tue, 8 Aug 2023 17:04:05 +0100 Subject: [PATCH 009/133] Modify collProc to use ceNeutronDB interface rather than aceDB --- .../neutronCEimp_class.f90 | 29 ++----- .../neutronCEstd_class.f90 | 27 ++----- CollisionOperator/scatteringKernels_func.f90 | 12 ++- .../aceDatabase/aceNeutronDatabase_class.f90 | 21 ++--- .../aceDatabase/aceNeutronNuclide_class.f90 | 54 ++++++++----- .../ceNeutronData/ceNeutronDatabase_inter.f90 | 59 ++++++++++---- .../ceNeutronData/ceNeutronNuclide_inter.f90 | 78 ++++++++++++++++++- 7 files changed, 180 insertions(+), 100 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index f349be82b..a54a15cce 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -18,12 +18,8 @@ module neutronCEimp_class use nuclearDataReg_mod, only : ndReg_getNeutronCE => getNeutronCE use nuclearDatabase_inter, only : nuclearDatabase use ceNeutronDatabase_inter, only : ceNeutronDatabase - use aceNeutronDatabase_class, only : aceNeutronDatabase - use aceNeutronDatabase_class, only : aceNeutronDatabase_CptrCast use ceNeutronMaterial_class, only : ceNeutronMaterial, ceNeutronMaterial_CptrCast use ceNeutronNuclide_inter, only : ceNeutronNuclide, ceNeutronNuclide_CptrCast - use aceNeutronNuclide_class, only : aceNeutronNuclide_CptrCast - use aceNeutronNuclide_class, only : aceNeutronNuclide ! Nuclear reactions use reactionHandle_inter, only : reactionHandle @@ -96,9 +92,7 @@ module neutronCEimp_class !! Nuclear Data block pointer -> public so it can be used by subclasses (protected member) class(ceNeutronDatabase), pointer, public :: xsData => null() class(ceNeutronMaterial), pointer, public :: mat => null() - class(ceNeutronNuclide), pointer, public :: nuc => null() - class(aceNeutronNuclide), pointer, public :: aceNuc => null() - class(aceNeutronDatabase), pointer, public:: aceData => null() + class(ceNeutronNuclide), pointer, public :: nuc => null() class(uniFissSitesField), pointer :: ufsField => null() !! Settings - private @@ -461,10 +455,7 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) collDat % kT = self % nuc % getkT() ! Check is DBRC is on - ! Cast pointer to aceNeutronNuclide - self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retrieve ACE Neutron Nuclide') - hasDBRC = self % aceNuc % hasDBRC + hasDBRC = self % nuc % hasDBRC() isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & & .and. (collDat % A > self % thresh_A) @@ -691,26 +682,22 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Check energy range eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) ! Check if DBRC is on for this target nuclide - hasDBRC = (self % aceNuc % hasDBRC) + hasDBRC = self % nuc % hasDBRC() if (eRange .and. hasDBRC) then - ! Cast pointer to aceNeutronDatabase - self % aceData => aceNeutronDatabase_CptrCast(self % xsData) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') - ! Retrieve 0K nuclide index from DBRC nuclide map - nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) + nucIdx = self % xsData % mapDBRCnuc % get(nucIdx) ! Reassign pointer for the 0K nuclide - self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') + self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(self % nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Database') ! Get elastic scattering 0K majorant - maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) + maj = self % xsData % getScattMicroMajXS(p % E, kT, A, nucIdx) ! Use DBRC to sample target velocity - V_t = targetVelocity_DBRCXS(self % aceNuc, p % E, dir_pre, A, kT, p % pRNG, maj) + V_t = targetVelocity_DBRCXS(self % nuc, p % E, dir_pre, A, kT, p % pRNG, maj) else ! Constant cross section approximation diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index 2878a8609..e146567fc 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -17,12 +17,8 @@ module neutronCEstd_class use nuclearDataReg_mod, only : ndReg_getNeutronCE => getNeutronCE use nuclearDatabase_inter, only : nuclearDatabase use ceNeutronDatabase_inter, only : ceNeutronDatabase - use aceNeutronDatabase_class, only : aceNeutronDatabase - use aceNeutronDatabase_class, only : aceNeutronDatabase_CptrCast use ceNeutronMaterial_class, only : ceNeutronMaterial, ceNeutronMaterial_CptrCast use ceNeutronNuclide_inter, only : ceNeutronNuclide, ceNeutronNuclide_CptrCast - use aceNeutronNuclide_class, only : aceNeutronNuclide_CptrCast - use aceNeutronNuclide_class, only : aceNeutronNuclide ! Nuclear reactions use reactionHandle_inter, only : reactionHandle @@ -73,8 +69,6 @@ module neutronCEstd_class class(ceNeutronDatabase), pointer, public :: xsData => null() class(ceNeutronMaterial), pointer, public :: mat => null() class(ceNeutronNuclide), pointer, public :: nuc => null() - class(aceNeutronNuclide), pointer, public :: aceNuc => null() - class(aceNeutronDatabase), pointer, public:: aceData=> null() !! Settings - private real(defReal) :: minE @@ -295,10 +289,7 @@ subroutine elastic(self, p, collDat, thisCycle, nextCycle) collDat % kT = self % nuc % getkT() ! Check is DBRC is on - ! Cast pointer to aceNeutronNuclide - self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % aceNuc)) call fatalError(Here, 'Failed to retrieve ACE Neutron Nuclide') - hasDBRC = self % aceNuc % hasDBRC + hasDBRC = self % nuc % hasDBRC() isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & & .and. (collDat % A > self % thresh_A) @@ -450,26 +441,22 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Check energy range eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) ! Check if DBRC is on for this target nuclide - hasDBRC = (self % aceNuc % hasDBRC) + hasDBRC = self % nuc % hasDBRC() if (eRange .and. hasDBRC) then - ! Cast pointer to aceNeutronDatabase - self % aceData => aceNeutronDatabase_CptrCast(self % xsData) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') - ! Retrieve 0K nuclide index from DBRC nuclide map - nucIdx = self % aceData % mapDBRCnuc % get(nucIdx) + nucIdx = self % xsData % mapDBRCnuc % get(nucIdx) ! Reassign pointer for the 0K nuclide - self % aceNuc => aceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % aceData)) call fatalError(Here, 'Failed to retrieve ACE Neutron Database') + self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(self % nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Database') ! Get elastic scattering 0K majorant - maj = self % aceData % getScattMicroMajXS(p % E, kT, A, nucIdx) + maj = self % xsData % getScattMicroMajXS(p % E, kT, A, nucIdx) ! Use DBRC to sample target velocity - V_t = targetVelocity_DBRCXS(self % aceNuc, p % E, dir_pre, A, kT, p % pRNG, maj) + V_t = targetVelocity_DBRCXS(self % nuc, p % E, dir_pre, A, kT, p % pRNG, maj) else ! Constant cross section approximation diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 5747cbf28..87b7130c8 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -6,7 +6,7 @@ module scatteringKernels_func use particle_class, only : particle ! Nuclear Data - use aceNeutronNuclide_class, only : aceNeutronNuclide + use ceNeutronNuclide_inter, only : ceNeutronNuclide implicit none private @@ -159,20 +159,19 @@ end function targetVelocity_constXS !! (note that it is not a kinetic energy of the target). !! !! - function targetVelocity_DBRCXS(aceNuc, E, dir, A, kT, rand, tempMaj) result (V_t) - class(aceNeutronNuclide), intent(in) :: aceNuc + function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) + class(ceNeutronNuclide), intent(in) :: nuc real(defReal), intent(in) :: E real(defReal), dimension(3), intent(in) :: dir real(defReal), intent(in) :: A real(defReal), intent(in) :: kT real(defReal), intent(in) :: tempMaj class(RNG), intent(inout) :: rand - integer(shortInt) :: idx real(defReal),dimension(3) :: V_t real(defReal) :: alpha, mu, phi, P_acc, DBRC_acc real(defReal) :: X, Y real(defReal) :: r1, r2, r3, r4, r5 - real(defreal) :: rel_v, rel_E, xs_rel_v, f + real(defreal) :: rel_v, rel_E, xs_rel_v ! Calculate neutron Y = beta *V_n ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). @@ -213,8 +212,7 @@ function targetVelocity_DBRCXS(aceNuc, E, dir, A, kT, rand, tempMaj) result (V_t rel_E = (rel_v**2 * kT / A) ! Find 0K scattering xs of target at relative energy - call aceNuc % search(idx, f, rel_E) - xs_rel_v = aceNuc % scatterXS(idx, f) + xs_rel_v = nuc % elScatteringXS(rel_E) ! Introduce DBRC acceptance condition DBRC_acc = (xs_rel_v / tempMaj) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 66821a3f4..e6bddc1ab 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -64,7 +64,6 @@ module aceNeutronDatabase_class !! nucToZaid -> map to link nuclide index to zaid index !! hasUrr -> ures probability tables flag, it's false by default !! hasDBRC -> DBRC flag, it's false by default - !! mapDBRCnuc -> map to link indexes of DBRC nuclides with their corresponding 0K !! !! Interface: !! nuclearData Interface @@ -80,7 +79,6 @@ module aceNeutronDatabase_class integer(shortInt),dimension(:),allocatable :: nucToZaid logical(defBool) :: hasUrr = .false. logical(defBool) :: hasDBRC = .false. - type(intMap) :: mapDBRCnuc contains ! nuclearData Procedures @@ -89,7 +87,6 @@ module aceNeutronDatabase_class procedure :: getMaterial procedure :: getNuclide procedure :: getReaction - procedure :: getScattMicroMajXS procedure :: init procedure :: init_urr procedure :: init_DBRC @@ -102,6 +99,7 @@ module aceNeutronDatabase_class procedure :: updateMacroXSs procedure :: updateTotalNucXS procedure :: updateMicroXSs + procedure :: getScattMicroMajXS end type aceNeutronDatabase @@ -235,18 +233,9 @@ function getReaction(self, MT, idx) result(reac) end function getReaction !! - !! Subroutine to get the elastic scattering majorant cross section in a nuclide - !! over a certain energy range, defined as a function of a given temperature - !! - !! NOTE: This function is called by the collision operator to apply DBRC; nucIdx - !! should correspond to a nuclide with temperature 0K, while kT is the - !! temperature of the target nuclide the neutron is colliding with + !! Returns the elastic scattering majorant cross section for a nuclide !! - !! Args: - !! A [in] -> Nuclide atomic weight ratio - !! kT [in] -> Thermal energy of nuclide - !! E [in] -> Energy of neutron incident to target for which majorant needs to be found - !! maj [out] -> Temperature majorant cross section + !! See ceNeutronDatabase for more details !! function getScattMicroMajXS(self, E, kT, A, nucIdx) result(maj) class(aceNeutronDatabase), intent(in) :: self @@ -271,7 +260,7 @@ function getScattMicroMajXS(self, E, kT, A, nucIdx) result(maj) if (E_upper > E_max) E_upper = E_max ! Find largest elastic scattering xs in energy range given by E_lower and E_upper - maj = self % nuclides(nucIdx) % elScattMaj(E_lower, E_upper) + maj = self % nuclides(nucIdx) % elScatteringMaj(E_lower, E_upper) end function getScattMicroMajXS @@ -768,7 +757,7 @@ subroutine init_DBRC(self, DBRC_nucs, nucSet, map) if (nucDBRCtemp == nuc0Ktemp) then call map % add(nucSet % atVal(j), idx) ! Set nuclide DBRC flag on - self % nuclides(nucSet % atVal(j)) % hasDBRC = .true. + call self % nuclides(nucSet % atVal(j)) % setDBRC() end if ! Increment index diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 542c12f74..27481891b 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -92,22 +92,21 @@ module aceNeutronNuclide_class !! thData -> S(a,b) thermal data class to store XSs and outgoing distributions !! SabEl -> energy boundaries of elastic S(a,b) data !! SabInel -> energy boundaries of inelastic S(a,b) data - !! hasDBRC -> Doppler Broadening Rejection Correction flag !! !! Interface: !! ceNeutronNuclide Interface - !! search -> search energy grid and return index and interpolation factor - !! totalXS -> return totalXS given index and interpolation factor - !! scatterXS -> return elastic scattering XS given index and interpolation factor - !! microXSs -> return interpolated ceNeutronMicroXSs package given index and inter. factor - !! getUrrXSs -> return ceNeutronMicroXSs accounting for ures probability tables - !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment - !! elScattMaj -> returns the elastic scattering majorant within an energy range given as input - !! init -> build nuclide from aceCard - !! init_urr -> build list and mapping of nuclides to maintain temperature correlation - !! when reading ures probability tables - !! init_Sab -> builds S(a,b) propertied from aceCard - !! display -> print information about the nuclide to the console + !! search -> search energy grid and return index and interpolation factor + !! totalXS -> return totalXS given index and interpolation factor + !! scatterXS -> return elastic scattering XS given index and interpolation factor + !! microXSs -> return interpolated ceNeutronMicroXSs package given index and inter. factor + !! getUrrXSs -> return ceNeutronMicroXSs accounting for ures probability tables + !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment + !! elScatteringMaj -> returns the elastic scattering majorant within an energy range given as input + !! init -> build nuclide from aceCard + !! init_urr -> build list and mapping of nuclides to maintain temperature correlation + !! when reading ures probability tables + !! init_Sab -> builds S(a,b) propertied from aceCard + !! display -> print information about the nuclide to the console !! type, public, extends(ceNeutronNuclide) :: aceNeutronNuclide character(nameLen) :: ZAID = '' @@ -132,13 +131,11 @@ module aceNeutronNuclide_class real(defReal), dimension(2) :: SabEl = ZERO real(defReal), dimension(2) :: SabInel = ZERO - ! DBRC nuclide flag - logical(defBool) :: hasDBRC = .false. - contains ! Superclass Interface procedure :: invertInelastic procedure :: xsOf + procedure :: elScatteringXS procedure :: kill ! Local interface @@ -148,7 +145,7 @@ module aceNeutronNuclide_class procedure :: microXSs procedure :: getUrrXSs procedure :: getThXSs - procedure :: elScattMaj + procedure :: elScatteringMaj procedure :: init procedure :: init_urr procedure :: init_Sab @@ -277,6 +274,25 @@ function xsOf(self, MT, E) result(xs) end function xsOf + !! + !! Return value of the elastic scattering XS given neutron energy + !! + !! See ceNeutronNuclide documentation + !! + function elScatteringXS(self, E) result(xs) + class(aceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal) :: xs + integer(shortInt) :: idx + real(defReal) :: f + + ! Find energy index + call self % search(idx, f, E) + ! Retrieve cross section + xs = self % scatterXS(idx, f) + + end function elScatteringXS + !! !! Return to uninitialised state !! @@ -576,7 +592,7 @@ end subroutine getUrrXSs !! upperE [in] -> Upper bound of energy range !! maj [out] -> Maximum scattering cross section within energy range !! - function elScattMaj(self, lowerE, upperE) result (maj) + function elScatteringMaj(self, lowerE, upperE) result (maj) class(aceNeutronNuclide), intent(in) :: self real(defReal), intent(in) :: lowerE real(defReal), intent(in) :: upperE @@ -610,7 +626,7 @@ function elScattMaj(self, lowerE, upperE) result (maj) end do majorantLoop - end function elScattMaj + end function elScatteringMaj !! !! Initialise from an ACE Card diff --git a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 index 988b35594..d0c8fd1d2 100644 --- a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 @@ -5,6 +5,7 @@ module ceNeutronDatabase_inter use RNG_class, only : RNG use particle_class, only : particle, P_NEUTRON, printType use charMap_class, only : charMap + use intMap_class, only : intMap ! Nuclear Data Handles use nuclideHandle_inter, only : nuclideHandle @@ -32,16 +33,21 @@ module ceNeutronDatabase_inter !! It is also used by material and nuclide handles for CE Neutron data to order an !! update of XSs on the cache !! + !! Public Members: + !! mapDBRCnuc -> map to link indexes of DBRC nuclides with their corresponding 0K + !! !! Interface: !! nuclearDatabase Interface - !! energyBounds -> return maximum and minimum energy - !! updateTotalMatXS -> update Total Material XS on CE Neutron Cache - !! updateMajorantXS -> update Majorant XS on CE Neutron Cache - !! updateMacroXSs -> update Macroscopic XSs for a selected material - !! updateTotalXS -> update Total XS for a selected nuclide - !! updateMicroXSs -> update Microscopic XSs for a selected nuclide + !! energyBounds -> return maximum and minimum energy + !! updateTotalMatXS -> update Total Material XS on CE Neutron Cache + !! updateMajorantXS -> update Majorant XS on CE Neutron Cache + !! updateMacroXSs -> update Macroscopic XSs for a selected material + !! updateTotalXS -> update Total XS for a selected nuclide + !! updateMicroXSs -> update Microscopic XSs for a selected nuclide + !! getScattMicroMajXS -> returns elastic scattering microscopic xs majorant !! type, public, abstract, extends(nuclearDatabase) :: ceNeutronDatabase + type(intMap) :: mapDBRCnuc contains ! nuclearDatabase Interface Implementation @@ -50,12 +56,13 @@ module ceNeutronDatabase_inter procedure :: getMajorantXS ! Procedures implemented by a specific CE Neutron Database - procedure(updateTotalMatXS),deferred :: updateTotalMatXS - procedure(updateMajorantXS),deferred :: updateMajorantXS - procedure(updateMacroXSs),deferred :: updateMacroXSs - procedure(updateTotalXS),deferred :: updateTotalNucXS - procedure(updateMicroXSs),deferred :: updateMicroXSs - procedure(energyBounds),deferred :: energyBounds + procedure(updateTotalMatXS),deferred :: updateTotalMatXS + procedure(updateMajorantXS),deferred :: updateMajorantXS + procedure(updateMacroXSs),deferred :: updateMacroXSs + procedure(updateTotalXS),deferred :: updateTotalNucXS + procedure(updateMicroXSs),deferred :: updateMicroXSs + procedure(energyBounds),deferred :: energyBounds + procedure(getScattMicroMajXS),deferred :: getScattMicroMajXS end type ceNeutronDatabase abstract interface @@ -186,8 +193,32 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) integer(shortInt), intent(in) :: nucIdx class(RNG), intent(inout) :: rand end subroutine updateMicroXSs - end interface + !! + !! Subroutine to get the elastic scattering majorant cross section in a nuclide + !! over a certain energy range, defined as a function of a given temperature + !! + !! NOTE: This function is called by the collision operator to apply DBRC; nucIdx + !! should correspond to a nuclide with temperature 0K, while kT is the + !! temperature of the target nuclide the neutron is colliding with + !! + !! Args: + !! A [in] -> Nuclide atomic weight ratio + !! kT [in] -> Thermal energy of nuclide + !! E [in] -> Energy of neutron incident to target for which majorant needs to be found + !! maj [out] -> Majorant cross section + !! + function getScattMicroMajXS(self, E, kT, A, nucIdx) result(maj) + import :: ceNeutronDatabase, defReal, shortInt + class(ceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal), intent(in) :: kT + real(defReal), intent(in) :: A + integer(shortInt), intent(in) :: nucIdx + real(defReal) :: maj + end function getScattMicroMajXS + + end interface contains !! @@ -287,5 +318,5 @@ pure function ceNeutronDatabase_CptrCast(source) result(ptr) end function ceNeutronDatabase_CptrCast - + end module ceNeutronDatabase_inter diff --git a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 index f7542f537..fd52007b6 100644 --- a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 @@ -35,9 +35,10 @@ module ceNeutronNuclide_inter !! mantain and optimise. !! !! Private Members - !! nucIdx -> nucIdx for this nuclide - !! data -> pointer to a database to request update of XSs - !! fissile -> flag that specifies if the nuclide is fissile + !! nucIdx -> nucIdx for this nuclide + !! data -> pointer to a database to request update of XSs + !! fissile -> flag that specifies if the nuclide is fissile + !! DBRC -> Doppler Broadening Rejection Correction flag !! !! Interface: !! nuclideHandle Interface @@ -48,6 +49,9 @@ module ceNeutronNuclide_inter !! isFissile -> Return .true. if nuclide can fission !! invertInelastic -> Selects type of inelastic neutron scattering !! xsOf -> Returns microscopic XS given MT number + !! elScatteringXS -> Returns elastic scattering XS for the nuclide + !! setDBRC -> Turns the hasDBRC flag to true + !! hasDBRC -> Returns the value of the hasDBRC flag !! type, public, abstract, extends(nuclideHandle) :: ceNeutronNuclide private @@ -56,6 +60,10 @@ module ceNeutronNuclide_inter logical(defBool) :: fissile = .false. real(defReal) :: mass = ZERO real(defReal) :: kT = ZERO + + ! DBRC nuclide flag + logical(defBool) :: DBRC = .false. + contains procedure, non_overridable :: getTotalXS @@ -63,6 +71,8 @@ module ceNeutronNuclide_inter procedure, non_overridable :: set procedure, non_overridable :: getNucIdx procedure, non_overridable :: isFissile + procedure, non_overridable :: setDBRC + procedure, non_overridable :: hasDBRC procedure :: getMass procedure :: getkT procedure :: kill @@ -70,6 +80,7 @@ module ceNeutronNuclide_inter ! Procedures for specific implementations procedure(invertInelastic),deferred :: invertInelastic procedure(xsOf), deferred :: xsOf + procedure(elScatteringXS), deferred :: elScatteringXS end type ceNeutronNuclide @@ -122,6 +133,28 @@ function xsOf(self, MT, E) result(xs) end function xsOf + !! + !! Return elastic scattering XS for the nuclide + !! + !! Args: + !! E [in] -> required energy [MeV] + !! + !! Result: + !! Elastic scattering nuclide microscopic cross-section [barn] + !! + !! Errors: + !! fatalError if E is out-of-bounds of the present data + !! Invalid idx beyond array bounds -> undefined behaviour + !! Invalid f (outside [0;1]) -> incorrect value of XS + !! + function elScatteringXS(self, E) result(xs) + import :: ceNeutronNuclide, defReal + class(ceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal) :: xs + + end function elScatteringXS + end interface contains @@ -262,6 +295,45 @@ pure function isFissile(self) result(isIt) end function isFissile + !! + !! Set the hasDBRC flag to .true. if called + !! + !! Args: + !! None + !! + !! Result: + !! None + !! + !! Errors: + !! None + !! + subroutine setDBRC(self) + class(ceNeutronNuclide), intent(inout) :: self + + self % DBRC = .true. + + end subroutine setDBRC + + !! + !! Return .true. if the nuclide needs to use DBRC + !! + !! Args: + !! None + !! + !! Result: + !! .TRUE. if DBRC is on, .FALSE. otherwise + !! + !! Errors: + !! None + !! + pure function hasDBRC(self) result(hasIt) + class(ceNeutronNuclide), intent(in) :: self + logical(defBool) :: hasIt + + hasIt = self % DBRC + + end function hasDBRC + !! !! Return a mass of the nuclide !! From 5eb06a0f31236abcfafcaf83492825454a2b8441 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:17:19 +0100 Subject: [PATCH 010/133] Adding DBRC to User Manual.rst --- docs/User Manual.rst | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 49d62ffb3..0fc72a087 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -206,11 +206,13 @@ neutronCEstd, to perform analog collision processing energyThreshold where kT is target material temperature in [MeV]. [-] * massThreshold (*optional*, default = 1): mass threshold for explicit treatment of target nuclide movement. Target movement is sampled if target mass A < massThreshold. [Mn] +* DBRCeMin (*optional*, default = 1.0e-08): minimum DBRC energy. [MeV] +* DBRCeMax (*optional*, default = 2.0e-04): maximum DBRC energy. [MeV] Example: :: collisionOperator { neutronCE { type neutronCEstd; minEnergy 1.0e-12; maxEnergy 30.0; - energyThreshold 200; massThreshold 2; } } + energyThreshold 200; massThreshold 2; DBRCeMin 1.0e-06; DBRCeMax 0.001; } } neutronCEimp ############ @@ -239,6 +241,8 @@ neutronCEimp, to perform implicit collision processing weight windows * UFS (*optional*, default = 0): 1 for true; 0 for false; enables the use of uniform fission sites +* DBRCeMin (*optional*, default = 1.0e-08): minimum DBRC energy. [MeV] +* DBRCeMax (*optional*, default = 2.0e-04): maximum DBRC energy. [MeV] Example: :: @@ -650,10 +654,17 @@ from ACE files. the ACE files * ures (*optional*, default = 0): 1 for true; 0 for false; activates the unresolved resonance probability tables treatment +* DBRC (*optional*, default = no DBRC): list of ZAIDs of nuclides for which DBRC has + to be applied. Example: :: - ceData { type aceNuclearDatabase; aceLibrary ./myFolder/ACElib/JEF311.aceXS; ures 1; } + ceData { type aceNuclearDatabase; aceLibrary ./myFolder/ACElib/JEF311.aceXS; + ures 1; DBRC (92238 94242)} + +.. note:: + If DBRC is applied, the 0K cross section ace files of the relevant nuclides must + be included in the aceLibrary file. baseMgNeutronDatabase ##################### @@ -983,8 +994,8 @@ Example: :: .. note:: To calculate the average weight, one should divide weight moment 1 (weight1) - by weight moment 0 (weight0). To calculate the variance of the weights, the - tally results have to be post-processed as: var = weight2/weight0 - (weight1/weight0)^2 + by weight moment 0 (weight0). To calculate the variance of the weights, the + tally results have to be post-processed as: var = weight2/weight0 - (weight1/weight0)^2 Tally Maps ########## From 9fadec57172fb4b550054ac1d79282471d94058e Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Mon, 14 Aug 2023 14:16:21 +0100 Subject: [PATCH 011/133] Update mgXsClerk_class.f90 Fix problem where inelastic S(a,b) was not scoring to mgXS tallies. --- Tallies/TallyClerks/mgXsClerk_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 1c8e6c5a8..8ef3ad7b3 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -308,7 +308,7 @@ subroutine reportOutColl(self, p, MT, muL, xsData, mem) ! Score in case of scattering events select case(MT) - case ( N_N_ELASTIC, N_N_INELASTIC, N_Nl(1):N_Nl(40), N_Ncont, & + case ( N_N_ELASTIC, N_N_INELASTIC, N_N_ThermINEL, N_Nl(1):N_Nl(40), N_Ncont, & N_2N, N_2Na, N_2Nd, N_2Nf, N_2Np, N_2N2a, N_2Nl(1):N_2Nl(16), & N_3N, N_3Na, N_3Nf, N_3Np, N_4N, N_Na, N_Np, N_Nd, N_Nt) From 8ac16766d797a8694f6ab8e4a431549ab3c6ff44 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Fri, 25 Aug 2023 13:06:28 +0200 Subject: [PATCH 012/133] Add section title for composition defs in manual --- docs/User Manual.rst | 586 ++++++++++++++++++++++--------------------- 1 file changed, 298 insertions(+), 288 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 96008fbbe..f5926b516 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -22,14 +22,14 @@ eigenPhysicsPackage, used for criticality (or eigenvalue) calculations * active: number of active cycles * inactive: number of inactive cycles * dataType: determines type of nuclear data used; can be ``ce`` or ``mg`` -* XSdata: keyword to the name of the nuclearDataHandle used -* seed (*optional*): initial seed for the pseudo random number generator +* XSdata: keyword to the name of the nuclearDataHandle used +* seed (*optional*): initial seed for the pseudo random number generator * outputFile (*optional*, default = 'output'): name of the output file -* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. - Choices are ``asciiMATLAB`` and ``asciiJSON`` - +* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. + Choices are ``asciiMATLAB`` and ``asciiJSON`` + Example: :: - + type eigenPhysicsPackage; pop 100000; active 100; @@ -39,20 +39,20 @@ Example: :: seed -244654; outputFile PWR_1; outputFormat asciiJSON; - + transportOperator { } collisionOperator { } inactiveTally { } activeTally { } geometry { } nuclearData { } - + *Optional entries* :: uniformFissionSites { } varianceReduction { } source { } - + .. note:: Although a ``source`` definition is not required, it can be included to replace the default uniform fission source guess used in the first cycle @@ -65,12 +65,12 @@ fixedSourcePhysicsPackage, used for fixed source calculations * pop: number of particles used per batch * cycles: number of batches * dataType: determines type of nuclear data used. Can be ``ce`` or ``mg`` -* XSdata: keyword to the name of the nuclearDataHandle used -* seed (*optional*): initial seed for the pseudo random number generator +* XSdata: keyword to the name of the nuclearDataHandle used +* seed (*optional*): initial seed for the pseudo random number generator * outputFile (*optional*, default = 'output'): name of the output file -* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. - Choices are ``asciiMATLAB`` and ``asciiJSON`` - +* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. + Choices are ``asciiMATLAB`` and ``asciiJSON`` + Example: :: type fixedSourcePhysicsPackage; @@ -80,7 +80,7 @@ Example: :: XSdata ceData; seed 2829741; outputFile shield_type11; - + transportOperator { } collisionOperator { } tally { } @@ -101,15 +101,15 @@ rayVolPhysicsPackage, used to perform ray-tracing based volume calculation * cycles: number of cycles * mfp: mean length of ray segments * abs_prob: ray absorption probability after each segment -* robust: 1 for true; 0 for false; enable robust mode: in this case at each collision, - each particle verifies that the material it currently thinks it is in and the one - obtained by *placing* a particle in the geometry with the same spatial position and +* robust: 1 for true; 0 for false; enable robust mode: in this case at each collision, + each particle verifies that the material it currently thinks it is in and the one + obtained by *placing* a particle in the geometry with the same spatial position and direction are in agreement * cache: 1 for true; 0 for false; enable distance caching -* seed (*optional*): initial seed for the pseudo random number generator - +* seed (*optional*): initial seed for the pseudo random number generator + Example: :: - + type rayVolPhysicsPackage; pop 1000000; cycles 100; @@ -117,61 +117,61 @@ Example: :: abs_prob 0.1; robust 1; cache 1; - + geometry { } nuclearData { } vizPhysicsPackage ################# -vizPhysicsPackage, used for visualising geometry +vizPhysicsPackage, used for visualising geometry Example: :: - + type vizPhysicsPackage; geometry { } viz { } - + Source ------ - -For the moment, the only possible external **source** type in SCONE in a point source. + +For the moment, the only possible external **source** type in SCONE in a point source. The properties of a point source are: * r: (x y z) vector with the origin position. [cm] -* particle: ``neutron`` or ``photon``, according to the type of particles emitted by the +* particle: ``neutron`` or ``photon``, according to the type of particles emitted by the source * E or G: emission energy - E: energy of the particles emitted, for continuous energy calculations. [MeV] - G: energy group of the particles emitted, for multi-group calculations - -* dir (*optional*, default = isotropic): (u v w) vector with the direction of the source + +* dir (*optional*, default = isotropic): (u v w) vector with the direction of the source particles Hence, an input would look like: :: source { type pointSource; r (0.0 1.0 5.2); particle neutron; E 14.1; dir (0.0 1.0 0.0); } - + Transport Operator ------------------ The **transport operator** takes care of moving the particles from one collision location to another. In the input file, one must include: :: - + transportOperator { type ; *keywords* } - -The possible types are: + +The possible types are: * transportOperatorST, performs surface tracking (ST) or ray tracing * transportOperatorDT, performs Woodcock delta tracking (DT) * transportOperatorHT, performs a hybrid between ST and DT - - cutoff (*optional*, default = 0.9): cutoff between ST and DT. If, at the particle - energy, the ratio between the local material cross section and the majorant cross + - cutoff (*optional*, default = 0.9): cutoff between ST and DT. If, at the particle + energy, the ratio between the local material cross section and the majorant cross section is larger than the cutoff, DT is used; otherwise ST is used. - + Example: :: transportOperator { type transportOperatorHT; cutoff 0.85; } @@ -179,8 +179,8 @@ Example: :: Collision Operator ------------------ -The **collision operator** process all collision types. It samples the colliding nuclide -and the reaction, and calculates all relevant by-products. In the input file, one must +The **collision operator** process all collision types. It samples the colliding nuclide +and the reaction, and calculates all relevant by-products. In the input file, one must include: :: collisionOperator { neutronCE { type ; *keywords* } } @@ -189,8 +189,8 @@ if continuos energy nuclear data are used, or :: collisionOperator { neutronMG { type ; } } -if multi-group nuclear data are used. In a hybrid simulation, both ``neutronCE`` and -``neutronMG`` can be included. +if multi-group nuclear data are used. In a hybrid simulation, both ``neutronCE`` and +``neutronMG`` can be included. The possible types to be used with **continuous energy** data are: @@ -201,15 +201,15 @@ neutronCEstd, to perform analog collision processing * minEnergy (*optional*, default = 1.0e-11): minimum energy cut-off. [MeV] * maxEnergy (*optional*, default = 20.0): maximum energy cut-off. [MeV] -* energyThreshold (*optional*, default = 400): energy threshold for explicit treatment - of target nuclide movement. Target movement is sampled if neutron energy E < kT ∗ +* energyThreshold (*optional*, default = 400): energy threshold for explicit treatment + of target nuclide movement. Target movement is sampled if neutron energy E < kT ∗ energyThreshold where kT is target material temperature in [MeV]. [-] -* massThreshold (*optional*, default = 1): mass threshold for explicit treatment of - target nuclide movement. Target movement is sampled if target mass A < massThreshold. [Mn] - +* massThreshold (*optional*, default = 1): mass threshold for explicit treatment of + target nuclide movement. Target movement is sampled if target mass A < massThreshold. [Mn] + Example: :: - - collisionOperator { neutronCE { type neutronCEstd; minEnergy 1.0e-12; maxEnergy 30.0; + + collisionOperator { neutronCE { type neutronCEstd; minEnergy 1.0e-12; maxEnergy 30.0; energyThreshold 200; massThreshold 2; } } neutronCEimp @@ -219,37 +219,37 @@ neutronCEimp, to perform implicit collision processing * minEnergy (*optional*, default = 1.0e-11): minimum energy cut-off. [MeV] * maxEnergy (*optional*, default = 20.0): maximum energy cut-off. [MeV] -* energyThreshold (*optional*, default = 400): energy threshold for explicit treatment - of target nuclide movement. Target movement is sampled if neutron energy E < kT ∗ +* energyThreshold (*optional*, default = 400): energy threshold for explicit treatment + of target nuclide movement. Target movement is sampled if neutron energy E < kT ∗ energyThreshold where kT is target material temperature in [MeV]. [-] -* massThreshold (*optional*, default = 1): mass threshold for explicit treatment - of target nuclide movement. Target movement is sampled if target mass A < - massThreshold. [Mn] -* splitting (*optional*, default = 0): 1 for true; 0 for false; enables splitting +* massThreshold (*optional*, default = 1): mass threshold for explicit treatment + of target nuclide movement. Target movement is sampled if target mass A < + massThreshold. [Mn] +* splitting (*optional*, default = 0): 1 for true; 0 for false; enables splitting for particles above a certain weight -* roulette (*optional*, default = 0): 1 for true; 0 for false; enables rouletting +* roulette (*optional*, default = 0): 1 for true; 0 for false; enables rouletting of particles below a certain weight * minWgt (*optional*, default = 0.25): minimum particle weight for rouletting * maxWgt (*optional*, default = 1.25): maximum particle weight for splitting * avgWgt (*optional*, default = 0.5): weight of a particle on surviving rouletting * impAbs (*optional*, default = 0): 1 for true; 0 for false; enables implicit capture -* impGen (*optional*, default = 1): 1 for true; 0 for false; enables implicit fission +* impGen (*optional*, default = 1): 1 for true; 0 for false; enables implicit fission sites generation -* weightWindows (*optional*, default = 0): 1 for true; 0 for false; enables the use of - weight windows -* UFS (*optional*, default = 0): 1 for true; 0 for false; enables the use of uniform - fission sites - +* weightWindows (*optional*, default = 0): 1 for true; 0 for false; enables the use of + weight windows +* UFS (*optional*, default = 0): 1 for true; 0 for false; enables the use of uniform + fission sites + Example: :: - - collisionOperator { neutronCE { type neutronCEimp; minEnergy 1.0e-12; maxEnergy 30.0; + + collisionOperator { neutronCE { type neutronCEimp; minEnergy 1.0e-12; maxEnergy 30.0; impAbs 1; roulette 1; splitting 1; impGen 1; maxWgt 2.0; minWgt 0.1; UFS 1; } } - + The possible types to be used with **multi-group** data are: neutronMGstd ############ - + neutronMGstd, to perform analog collision processing Example: :: @@ -259,7 +259,7 @@ Example: :: Weight Windows -------------- -Weight windows can be used if, inside the collision operator ``CEneutronimp``, the +Weight windows can be used if, inside the collision operator ``CEneutronimp``, the keyword ``weightWindows`` is set to 1. Then, in the input file, one needs to add: :: varianceReduction { type weightWindowsField; file ; } @@ -276,49 +276,49 @@ The file that contains **weight windows** has to include: Example: :: - map { type multiMap; maps (mapx mapy); - mapx { type spaceMap; axis x; grid unstruct; bins (0.0 1.0 2.0); } - mapy { type spaceMap; axis y; grid unstruct; bins (0.0 5.0 10.0 15.0); } } - constSurvival 2.0; - wLower (0.5 0.1 0.2 0.1 0.5 0.5); - wUpper (2.0 1.2 1.5 1.1 2.0 4.0); - + map { type multiMap; maps (mapx mapy); + mapx { type spaceMap; axis x; grid unstruct; bins (0.0 1.0 2.0); } + mapy { type spaceMap; axis y; grid unstruct; bins (0.0 5.0 10.0 15.0); } } + constSurvival 2.0; + wLower (0.5 0.1 0.2 0.1 0.5 0.5); + wUpper (2.0 1.2 1.5 1.1 2.0 4.0); + Uniform Fission Sites --------------------- -Weight windows can be used if, inside the collision operator ``CEneutronimp``, the +Weight windows can be used if, inside the collision operator ``CEneutronimp``, the keyword ``UFS`` is set to 1. Then, in the input file, one needs to add: :: uniformFissionSites { type uniFissSitesField; map { } *keywords* } - -In the input above, ``map`` is the geometrical map used for UFS. The map has to contain + +In the input above, ``map`` is the geometrical map used for UFS. The map has to contain fissile material for the method to make sense. Other keywords are: -* uniformVolMap (*optional*, default = 1): 1 for true; 0 for false; flag that states +* uniformVolMap (*optional*, default = 1): 1 for true; 0 for false; flag that states whether the bins of the map contain equal volumes of fissile material or not * popVolumes (*optional*, default = 1.0e7): if ``uniformVolMap`` is false, a Monte Carlo calculation is run to estimate the fissile material volumes in each map bin. This entry - correspond to the number of points sampled in the geometry for the volume calculation. + correspond to the number of points sampled in the geometry for the volume calculation. Note that this volume calculation is done only once during initialisation Example: :: - uniformFissionSites { type uniFissSitesField; uniformVolMap 0; popVolumes 1.0e8; - map { } + uniformFissionSites { type uniFissSitesField; uniformVolMap 0; popVolumes 1.0e8; + map { } } Geometry -------- -A detailed description about the geometry modelling adopted in SCONE can be found at +A detailed description about the geometry modelling adopted in SCONE can be found at :ref:`Geometry `. In an input file, one has to include: :: - geometry { type ; boundary (a b c d e f); graph { type ; } + geometry { type ; boundary (a b c d e f); graph { type ; } surfaces { } cells { } - universes { } + universes { } } - + At the moment, the only **geometry** type available is ``geometryStd``. As for the boundary six integers have to be inputted. These correspond to the boundary conditions at boundaries (-x +x -y +y -z +z). The possibilities are: @@ -327,11 +327,11 @@ six integers have to be inputted. These correspond to the boundary conditions at * reflective: input 1 * periodic: input 2 -.. note:: +.. note:: Strictly speaking it is up to a particular boundary surface to interpret how the values in the boundary condition sequence are interpreted. For all cube-like surfaces the rule above holds, but for more exotic boundaries (e.g., hexagons) it is worth double checking - the documentation comment of the particular surface in the source code. + the documentation comment of the particular surface in the source code. .. note:: Curved surfaces only allow for vacuum boundaries. @@ -343,10 +343,10 @@ The **graph** definition allows two options: Hence, an example of a geometry input could look like: :: - geometry { type geometryStd; boundary (1 1 1 1 0 0); graph { type shrunk; } + geometry { type geometryStd; boundary (1 1 1 1 0 0); graph { type shrunk; } surfaces { } cells { } - universes { } + universes { } } For more details about the graph-like structure of the nested geometry see the relevant @@ -357,18 +357,18 @@ Surfaces To define one or multiple **surfaces**, the necessary entries are: :: - surfaces { - { id ; type ; *keywords* } - { id ; type ; *keywords* } + surfaces { + { id ; type ; *keywords* } + { id ; type ; *keywords* } ... - { id ; type ; *keywords* } + { id ; type ; *keywords* } } Here, the ``name`` can be anything at the discretion of the user, as long as it doesn't contain spaces. The ``idNumber`` can be any integer; attention must be paid that all -``idNumbers`` are unique. +``idNumbers`` are unique. -Several ``surfaceTypes`` are possible: +Several ``surfaceTypes`` are possible: * box: axis aligned box @@ -390,7 +390,7 @@ input type has to be ``xSquareCylinder``, ``ySquareCylinder`` or ``zSquareCylind Example: :: surf2 { id 25; type ySquareCylinder; origin (3.0 0.0 9.0); halfwidth (4.4 0.0 0.1); } - + * truncCylinder: finite length cylinder aligned with x, y or z axis. The input type has to be ``xTruncCylinder``, ``yTruncCylinder`` or ``zTruncCylinder`` @@ -402,7 +402,7 @@ Example: :: surf3 { id 3; type zTruncCylinder; origin (3.0 2.1 5.0); halfwidth 20.0; radius 1.6; } - + * aPlane: plane with normal along x, y or z. The input type has to be ``xPlane``, ``yPlane`` or ``zPlane`` @@ -412,7 +412,7 @@ Example: :: Example: :: surf4 { id 8; type xPlane; x0 4.0; } - + * plane: generic plane (F(r) = c1 * x + c2 * y + c3 * z - c4) - coeffs: (c1 c2 c3 c4) vector with coefficients @@ -420,8 +420,8 @@ Example: :: Example: :: surf5 { id 55; type plane; coeffs (8.6 3.0 66.0 1.5); } - -* cylinder: infinitely long cylinder aligned with x, y or z axis. The input type + +* cylinder: infinitely long cylinder aligned with x, y or z axis. The input type has to be ``xCylinder``, ``yCylinder`` or ``zCylinder`` - origin: (x y z) vector with the origin position; the entry corresponding to @@ -431,7 +431,7 @@ Example: :: Example: :: billy { id 92; type xCylinder; origin (0.0 0.0 9.0); radius 4.8; } - + * sphere - origin: (x y z) vector with the origin position. [cm] @@ -446,24 +446,24 @@ Cells Similarly to the surfaces, the **cells** in the geometry can be defined as: :: - cells { - { id ; type ; surfaces (); filltype ; *keywords* } - { id ; type ; surfaces (); filltype ; *keywords* } + cells { + { id ; type ; surfaces (); filltype ; *keywords* } + { id ; type ; surfaces (); filltype ; *keywords* } ... - { id ; type ; surfaces (); filltype ; *keywords* } + { id ; type ; surfaces (); filltype ; *keywords* } } - -At the moment, in SCONE, the only ``cellType`` available is ``simpleCell``. + +At the moment, in SCONE, the only ``cellType`` available is ``simpleCell``. In the surface definition, one should include the indexes of the corresponding surfaces with no sign to indicate a positive half-space, or minus sign to indicate -a negative half-space. The space in between cells corresponds to an intersection. +a negative half-space. The space in between cells corresponds to an intersection. The possible ``fillTypes`` are: * mat: if the cells is filled with a homogeneous material - - - material: takes as an input the material name - + + - material: takes as an input the material name + Example: :: cell1 { id 1; type simpleCell; surfaces (1 -6 90); filltype mat; material fuel; } @@ -471,7 +471,7 @@ Example: :: * uni: if the cell is filled with a universe - universe: takes as an input the universe ``id`` - + Example: :: cellX { id 5; type simpleCell; surfaces (2 -3); filltype uni; universe 6; } @@ -481,50 +481,50 @@ Example: :: Example: :: cellixx { id 55; type simpleCell; surfaces (-10); filltype outside; } - + Universes ######### - + Similarly to the surfaces and cells, the **universes** in the geometry can be defined as: :: - universes { - { id ; type ; *keywords* } - { id ; type ; *keywords* } + universes { + { id ; type ; *keywords* } + { id ; type ; *keywords* } ... - { id ; type ; *keywords* } + { id ; type ; *keywords* } } - + Several ``universeTypes`` are possible: -* cellUniverse, composed of the union of different cells. Note that overlaps are +* cellUniverse, composed of the union of different cells. Note that overlaps are forbidden, but there is no check to find overlaps - cells: array containing the ``cellIds`` as used in the cell definition - - origin (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the origin + - origin (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the origin of the universe. [cm] - - rotation (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the + - rotation (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the rotation angles in degrees applied to the universe. [°] -.. note:: +.. note:: When creating a ``cellUniverse`` a user needs to take care to avoid leaving - any 'unspecified' regions (sets in space which do not belong to any cell). - If these are reachable by a particle (e.g., are not covered by any higher - level universe) they will cause a calculation to crash. - + any 'unspecified' regions (sets in space which do not belong to any cell). + If these are reachable by a particle (e.g., are not covered by any higher + level universe) they will cause a calculation to crash. + Example: :: uni3 { id 3; type cellUniverse; cells (1 2 55); origin (1.0 0.0 0.0); rotation (0.0 90.0 180.0); } * pinUniverse, composed of infinite co-centred cylinders - - radii: array containing the radii of the co-centred cylinders. There - must be an entry equal to 0.0, which corresponds to the outermost + - radii: array containing the radii of the co-centred cylinders. There + must be an entry equal to 0.0, which corresponds to the outermost layer, which is infinite. [cm] - fills: array containing the names or ids of what is inside each cylindrical shell. The order of the fills must correspond to the order of the corresponding radii. An entry can be a material name, the keyword ``void``, or a ``u``, where ``id`` is the id of a defined universe - - origin (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the + - origin (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the origin of the universe. [cm] - rotation (*optional*, default = (0.0 0.0 0.0)): (x y z) array with the rotation angles in degrees applied to the universe. [°] @@ -535,11 +535,11 @@ Example: :: * latUniverse, cartesian lattice of constant pitch - - shape: (x y z) array of integers, stating the numbers of x, y and z + - shape: (x y z) array of integers, stating the numbers of x, y and z elements of the lattice. For a 2D lattice, one of the entries has to be 0 - pitch: (x y z) array with the x, y and z lattice pitches. In a 2D lattice, the value entered in the third dimension is not used. [cm] - - padmat: material name or universe index (u) that fills the possible + - padmat: material name or universe index (u) that fills the possible extra space between the lattice and its bounding surface. Also the keyword ``void`` is allowed - map: map that includes the universe ids of the elements of the lattice. @@ -557,7 +557,7 @@ Example: :: 7 8 9 // x: 1-3, y: 2, z: 1 10 11 12 ) } // x: 1-3, y: 1, z: 1 -.. note:: +.. note:: The order of the elements in the lattice is different from other MC codes, e.g., Serpent. The lattice is written in the style *WYSIWYG*: What You See Is What You Get. @@ -567,7 +567,7 @@ Example: :: - fill: inside filling, as a material name or a universe (u) Example: :: - + root { id 1000; type rootUniverse; border 10; fill u<1>; } Visualiser @@ -579,7 +579,7 @@ To **plot** a geometry, the keyword ``viz`` must be present in the input file: : { type ; *keywords* } { type ; *keywords* } } - + The possible types of files that the geometry is plotted in are: vtk @@ -588,7 +588,7 @@ vtk * corner: (x y z) array with the corner of the geometry [cm] * width: (x y z) array with the width of the mesh in each direction [cm] * vox: (x y z) array with the number of voxels requested in each direction -* what (*optional*, default = material): defines what is highlighted in the +* what (*optional*, default = material): defines what is highlighted in the plot; options are ``material`` and ``cellID`` Example: :: @@ -600,26 +600,26 @@ bmp * centre: (x y z) array with the coordinates of the center of the plot [cm] * axis: ``x``, ``y`` or ``z``, it's the axis normal to the 2D plot -* width (*optional*, default = whole geometry): (y z), (x z) or (x y) array +* width (*optional*, default = whole geometry): (y z), (x z) or (x y) array with the width of the geometry plotted in each direction [cm] * res: (y z), (x z) or (x y) array with the resolution of the mesh in each direction * output: name of the output file, with extension ``.bmp`` -* what (*optional*, default = material): defines what is highlighted in the +* what (*optional*, default = material): defines what is highlighted in the plot; options are ``material`` and ``cellID`` Example: :: plotBMP { type bmp; axis z; width (50 10); res (1000 200); output geomZ; what material; } - -.. note:: - SCONE can be run to visualise geometry without actually doing transport, by - including ``--plot`` when running the application. In this case the visualiser + +.. note:: + SCONE can be run to visualise geometry without actually doing transport, by + including ``--plot`` when running the application. In this case the visualiser has to be included in the file. Nuclear Data ------------ -SCONE can be used with both continuous energy data and multi-group data. The type +SCONE can be used with both continuous energy data and multi-group data. The type of data used must be specified in the ``physicsPackage`` options, as well as in the ``collisionOperator`` options. As for **nuclear data**, the input files has to look like: :: @@ -627,7 +627,7 @@ of data used must be specified in the ``physicsPackage`` options, as well as in handles { } materials { } } - + The **handles** definition is structured as the following: :: handles { @@ -636,63 +636,73 @@ The **handles** definition is structured as the following: :: } The name of a handle has to be the same as defined in a ``physicsPackage`` under the -keyword ``XSdata``. +keyword ``XSdata``. -Otherwise, the possible **nuclear database** types allowed are: +Otherwise, the possible **nuclear database** types allowed are: aceNeutronDatabase ################## -aceNeutronDatabase, used for continuous energy data. In this case, the data is read -from ACE files. +aceNeutronDatabase, used for continuous energy data. In this case, the data is read +from ACE files. -* aceLibrary: includes the path to the *.aceXS* file, which includes the paths to +* aceLibrary: includes the path to the *.aceXS* file, which includes the paths to the ACE files * ures (*optional*, default = 0): 1 for true; 0 for false; activates the unresolved resonance probability tables treatment - + Example: :: ceData { type aceNuclearDatabase; aceLibrary ./myFolder/ACElib/JEF311.aceXS; ures 1; } - + baseMgNeutronDatabase ##################### -baseMgNeutronDatabase, used for multi-group data. In this case, the data is read -from files provided by the user. +baseMgNeutronDatabase, used for multi-group data. In this case, the data is read +from files provided by the user. * PN: includes a flag for anisotropy treatment. Could be ``P0`` or ``P1`` - + Example: :: mgData { type baseMgNeutronDatabase; PN P1; } - + +Materials definition +#################### + The *materials* definition is structured as: :: materials { - { temp ; - composition { } + { temp ; + composition { } *keywords* } - { temp ; - composition { } + { temp ; + composition { } *keywords* } } - + In this case, ``materialName`` can be any name chosen by the user; ``temp`` is the -material temperature in [K]. +material temperature in [K]. + +.. note:: + At the moment ``temp`` is not used in any way since SCONE has no way to treat + the temperature dependence of cross-sections. It is included for future use. + To change the temperature, a user needs to set appropriate suffix to each + individual nuclide in the composition definition. + -The ``composition`` dictionary must always be included, but it can be empty in -multi-group simulations. In continuous energy simulations, it should include a +The ``composition`` dictionary must always be included, but it can be empty in +multi-group simulations. In continuous energy simulations, it should include a list of the ZAIDs of all the nuclides that compose that material, and the respective atomic densities in [atoms/cm/barn]. The ZAIDs are normally in the form ``ZZAAA.TT``, or ``ZAAA.TT`` for nuclides with Z<10. The code ``TT`` indicates the temperature used -in the nuclear data evaluation, and the options are 03, 06, 09, 12 and 15, +in the nuclear data evaluation, and the options are 03, 06, 09, 12 and 15, corresponding to temperatures of 300K, 600K, 900K, 1200K and 1500K. Other options are: * moder: dictionary that includes information on thermal scattering data. It has to - include a list of ZAIDs for which S(a,b) has to be used, and the name of the file + include a list of ZAIDs for which S(a,b) has to be used, and the name of the file that contains the data. The file has to be included in the list of files in the *.aceXS* input file. Note that this input is ignored if the nuclide or nuclides listed are not included in the material. Only needed for continuous energy simulations. @@ -703,16 +713,16 @@ Other options are: Example 1: :: materials { - fuel { temp 273; - composition { - 92238.03 0.021; + fuel { temp 273; + composition { + 92238.03 0.021; 92235.03 0.004; - 8016.03 0.018535464; } + 8016.03 0.018535464; } } - water { temp 273; - composition { + water { temp 273; + composition { 1001.03 0.0222222; - 8016.03 0.00535; } + 8016.03 0.00535; } moder { 1001.03 h-h2o.42; } } } @@ -720,8 +730,8 @@ Example 1: :: Example 2: :: materials { - fuel { temp 573; - composition { } + fuel { temp 573; + composition { } xsFile ./xss/fuel.txt } } @@ -729,62 +739,62 @@ Example 2: :: Multi-group cross sections -------------------------- -In the case of a multi-group calculation, **multi-group cross sections** must be -provided by the user. These are in separate files compared to the input file. The +In the case of a multi-group calculation, **multi-group cross sections** must be +provided by the user. These are in separate files compared to the input file. The structure of such cross section files is the following: they must include * numberOfGroups: number of energy groups used (=N) * capture: vector of size N with the material-wise macroscopic capture cross section. - The order of the elements corresponds to groups from fast (group 1) to thermal + The order of the elements corresponds to groups from fast (group 1) to thermal (group N) * fission (*optional*): vector of size N with the material-wise macroscopic fission cross section. The order of the elements corresponds to groups from fast (group 1) to thermal (group N). Must be included only if the materials is fissile -* nu (*optional*): vector of size N with the material-wise macroscopic neutron - production nu-bar. The order of the elements corresponds to groups from +* nu (*optional*): vector of size N with the material-wise macroscopic neutron + production nu-bar. The order of the elements corresponds to groups from fast (group 1) to thermal (group N). Must be included only if the materials is fissile * chi (*optional*): vector of size N with the material-wise fission spectrum. The order - of the elements corresponds to groups from fast (group 1) to thermal (group N). + of the elements corresponds to groups from fast (group 1) to thermal (group N). Must be included only if the materials is fissile -* P0: P0 scattering matrix, of size NxN. In the case of a 3x3 matrix, the elements are +* P0: P0 scattering matrix, of size NxN. In the case of a 3x3 matrix, the elements are ordered as: :: 1 -> 1 1 -> 2 1 -> 3 2 -> 1 2 -> 2 2 -> 3 3 -> 1 3 -> 2 3 -> 3 -* scatteringMultiplicity: P0 scattering multiplicity matrix, of size NxN. Contains +* scatteringMultiplicity: P0 scattering multiplicity matrix, of size NxN. Contains multiplicative elements that will be multiplied to the P0 matrix elements for scattering production cross section, hence all elements must be >= 1.0 -* P1 (*optional*): necessary only if ``P1`` is defined in the ``baseMgNeutronDatabase`` +* P1 (*optional*): necessary only if ``P1`` is defined in the ``baseMgNeutronDatabase`` entry ``PN``. It contains the P1 scattering matrix, of size NxN An example file is: :: - numberOfGroups 2; + numberOfGroups 2; capture (0.0010046 0.025788); fission (0.0010484 0.050632); - nu (2.5 2.5); - chi (1.0 0.0); - scatteringMultiplicity ( - 1.0 1.0 - 1.0 1.0 ); - P0 ( - 0.62568 0.029227 + nu (2.5 2.5); + chi (1.0 0.0); + scatteringMultiplicity ( + 1.0 1.0 + 1.0 1.0 ); + P0 ( + 0.62568 0.029227 0.0 2.443830 - ); + ); P1 ( 0.27459 0.0075737 0.0 0.83318 - ); + ); Tallies ------- -As mentioned previously, one might have to include the keywords ``inactiveTally`` and -``activeTally`` in the input file (in the case of ``eigenPhysicsPackage``), or just -``tally`` (in the case of ``fixedSourcePhysicsPackage``). Either way, the **tally** +As mentioned previously, one might have to include the keywords ``inactiveTally`` and +``activeTally`` in the input file (in the case of ``eigenPhysicsPackage``), or just +``tally`` (in the case of ``fixedSourcePhysicsPackage``). Either way, the **tally** definition is the same for all cases: :: tally { @@ -794,9 +804,9 @@ definition is the same for all cases: :: ... { type ; } } - -In this case, ``resName`` can be any name chosen by the user, and it is what will be -reported in the output file. + +In this case, ``resName`` can be any name chosen by the user, and it is what will be +reported in the output file. Tally Clerks ############ @@ -807,30 +817,30 @@ The **tally clerks** determine which kind of estimator will be used. The options - response: defines which response function has to be used for this tally. Note that more than one response can be defined per each tally - - map (*optional*): contains a dictionary with the ``tallyMap`` definition, + - map (*optional*): contains a dictionary with the ``tallyMap`` definition, that defines the domains of integration of each tally - - filter (*optional*): can filter out particles with certain properties, + - filter (*optional*): can filter out particles with certain properties, preventing them from scoring results * trackClerk - - response: defines which response function has to be used for this tally. + - response: defines which response function has to be used for this tally. Note that more than one response can be defined per each tally - - map (*optional*): contains a dictionary with the ``tallyMap`` definition, + - map (*optional*): contains a dictionary with the ``tallyMap`` definition, that defines the domains of integration of each tally - - filter (*optional*): can filter out particles with certain properties, + - filter (*optional*): can filter out particles with certain properties, preventing them from scoring results - + Example: :: tally { - collision_estimator { type collisionClerk; response (); { type ; *keywords* } - map { } + collision_estimator { type collisionClerk; response (); { type ; *keywords* } + map { } filter { } } - track_estimator { type trackClerk; response ( ); - { type ; *keywords* } - { type ; *keywords* } + track_estimator { type trackClerk; response ( ); + { type ; *keywords* } + { type ; *keywords* } } } @@ -856,7 +866,7 @@ Example: :: * collisionProbabilityClerk, tallies a collision probability matrix - - map: contains a dictionary with the ``tallyMap`` definition, that defines + - map: contains a dictionary with the ``tallyMap`` definition, that defines the bins of the matrix Example: :: @@ -866,41 +876,41 @@ Example: :: } * dancoffBellClerk, calculates a single-term rational approximation for a lattice - + - fuelMat: list of fuel material names - modMat: list of moderator material names - Elow (*optional*, default = 0.0): bottom energy boundary; [MeV] - Etop (*optional*, default = 20.0): top energy boundary; [MeV] - + Example: :: tally { dancoff_bell_factors { type dancoffBellClerk; fuelMat (fuel1 fuel2 fuel_Gd); modMat (water); Elow 0.06; Etop 10.0; } } -* mgXsClerk, calculates multi-group cross sections via a collision estimator +* mgXsClerk, calculates multi-group cross sections via a collision estimator of reaction rates and analog tallies of fission spectrum and scattering events ingoing and outgoing energies and multiplicity - - energyMap (*optional*, default = 1 group): definition of the energy group + - energyMap (*optional*, default = 1 group): definition of the energy group structure to be used - spaceMap (*optional*, default = whole geometry): definition of a spatial tally map - PN (*optional*, default = 0): 1 for true; 0 for false; flag that indicates - whether to calculate scattering matrices only up to P1 (``PN 0``) or P7 (``PN 1``) - + whether to calculate scattering matrices only up to P1 (``PN 0``) or P7 (``PN 1``) + Example: :: tally { MGxss { type mgXsClerk; - energyMap { } - spaceMap { } + energyMap { } + spaceMap { } PN 1; } } * shannonEntropyClerk, implicit Shannon entropy estimator - - - map: contains a dictionary with the ``tallyMap`` definition, that defines + + - map: contains a dictionary with the ``tallyMap`` definition, that defines the (spatial) discretisation used to score the entropy - cycles: number of cycles to tally the entropy for @@ -908,7 +918,7 @@ Example: :: tally { shannon_entropy { type shannonEntropyClerk; - map { } + map { } cycles 200; } } @@ -926,7 +936,7 @@ Example: :: Tally Responses ############### -Certain tally clerks, like the ``collisionClerk`` and ``trackClerk``, require +Certain tally clerks, like the ``collisionClerk`` and ``trackClerk``, require a **response function**. The different types of responses could be: * fluxResponse: used to calculate the flux, i.e., the response function is 1.0 @@ -939,31 +949,31 @@ Example: :: * macroResponse: used to score macroscopic reaction rates - - MT: MT number of the desired reaction. The options are: -1 total, -2 capture, + - MT: MT number of the desired reaction. The options are: -1 total, -2 capture, -6 fission, -7 nu*fission, -21 absorption Example: :: tally { - collision_estimator { type collisionClerk; response (total fission); - total { type macroResponse; MT -1; } + collision_estimator { type collisionClerk; response (total fission); + total { type macroResponse; MT -1; } fission { type macroResponse; MT -6; } } } - + * microResponse: used to score microscopic reaction rates - - MT: MT number of the desired reaction. The options are: 1 total, 2 elastic + - MT: MT number of the desired reaction. The options are: 1 total, 2 elastic scattering, 18 fission, 27 absorption, 102 capture - - material: material name where to score the reaction. The material must be + - material: material name where to score the reaction. The material must be defined to include only one nuclide; its density could be anything, it doesn't affect the result Example: :: tally { - collision_estimator { type collisionClerk; response (elScatter capture); - elScatter { type microResponse; MT 2; material water; } - capture { type microResponse; MT 102; material fuel; } + collision_estimator { type collisionClerk; response (elScatter capture); + elScatter { type microResponse; MT 2; material water; } + capture { type microResponse; MT 102; material fuel; } } } @@ -974,62 +984,62 @@ Example: :: Example: :: tally { - collision_estimator { type collisionClerk; response (weight0 weight1 weight2); - weight0 { type weightResponse; moment 0; } - weight1 { type weightResponse; moment 1; } - weight2 { type weightResponse; moment 2; } + collision_estimator { type collisionClerk; response (weight0 weight1 weight2); + weight0 { type weightResponse; moment 0; } + weight1 { type weightResponse; moment 1; } + weight2 { type weightResponse; moment 2; } } } -.. note:: - To calculate the average weight, one should divide weight moment 1 (weight1) - by weight moment 0 (weight0). To calculate the variance of the weights, the - tally results have to be post-processed as: var = weight2/weight0 - (weight1/weight0)^2 +.. note:: + To calculate the average weight, one should divide weight moment 1 (weight1) + by weight moment 0 (weight0). To calculate the variance of the weights, the + tally results have to be post-processed as: var = weight2/weight0 - (weight1/weight0)^2 Tally Maps ########## -The different types of **tally maps** are: +The different types of **tally maps** are: * cellMap (1D map), cell-wise map - cells: list of ids of the cells to be used an map bins - undefBin (*optional*, default = false): 'yes','y','true','TRUE','T' for true; - 'no', 'n', 'false', 'FALSE', 'F' for false; flag that indicates whether all + 'no', 'n', 'false', 'FALSE', 'F' for false; flag that indicates whether all the cells not listed in ``cells`` should constitute a map bin or not - + Example: :: map { type cellMap; cells (1 5 3 2 4 100); undefBin T; } - + * energyMap (1D map), defines an energy group structure - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins - + + min: bottom energy [MeV] + max: top energy [MeV] + N: number of bins - + - grid: ``unstruct`` for unstructured grids, to be manually defined - + + bins: array with the explicit definition of the energy bin boundaries to be used - + - grid: ``predef`` - - + name: name of the predefined group structure. Options are: ``wims69``, + + + name: name of the predefined group structure. Options are: ``wims69``, ``wims172``, ``casmo40``, ``casmo23``, ``casmo12``, ``casmo7``, ``vitaminj`` Examples: :: map1 { type energyMap; grid log; min 1.0e-11; max 20.0; N 300; } map2 { type energyMap; grid lin; min 1.0; max 20.0; N 100; } - map3 { type energyMap; bins (1.0E-9 1.0E-8 0.6E-6 0.3 20.0); } - map4 { type energyMap; name casmo12; } + map3 { type energyMap; bins (1.0E-9 1.0E-8 0.6E-6 0.3 20.0); } + map4 { type energyMap; name casmo12; } -* homogMatMap (1D map), divides based on the material a particle is in with the +* homogMatMap (1D map), divides based on the material a particle is in with the possibility of grouping some materials together - - bins: list of names of the material bins, that can contain one or more + - bins: list of names of the material bins, that can contain one or more materials; this is followed by all the bin names as key, and the material names included in the bin as an entry - undefBin (*optional*, default = false): 'yes','y','true','TRUE','T' for true; @@ -1042,16 +1052,16 @@ Example: :: bin1 (mat1 mat2 mat3); bin2 (fuel1 fuel3 uo2); bin3 (water); - undefBin T; + undefBin T; } * materialMap (1D map), material-wise map - - materials: list of material names to be used as map bins + - materials: list of material names to be used as map bins - undefBin (*optional*, default = false): 'yes','y','true','TRUE','T' for true; - 'no', 'n', 'false', 'FALSE', 'F' for false; flag that indicates whether all + 'no', 'n', 'false', 'FALSE', 'F' for false; flag that indicates whether all the materials not included should constitute a map bin or not - + Example: :: map { type materialMap; materials (fuel water cladding reflector fuelGd); undefBin T; } @@ -1060,10 +1070,10 @@ Example: :: - maps: list of the names of the maps that will compose the ``multiMap``. This is followed by dictionaries that define the requested maps - + Example: :: - map { type multiMap; maps (map1 map2 map10); + map { type multiMap; maps (map1 map2 map10); map1 { <1D map definition> } map2 { <1D map definition> } map10 { <1D map definition> } @@ -1074,13 +1084,13 @@ Example: :: - axis: ``x``, ``y`` or ``z`` - grid: ``lin`` for linearly spaced bins - + + min: bottom coordinate [cm] + max: top coordinate [cm] + N: number of bins - grid: ``unstruct`` for unstructured grids, to be manually defined - + + bins: array with the explicit definition of the bin boundaries to be used Examples: :: @@ -1090,18 +1100,18 @@ Examples: :: * sphericalMap, geometric spherical map - - origin (*optional*, default = (0.0 0.0 .0.)): (x y z) vector with the origin + - origin (*optional*, default = (0.0 0.0 .0.)): (x y z) vector with the origin of the spherical map - - grid: ``lin`` for linearly spaced bins or ``equivolume`` for spherical shells - + - grid: ``lin`` for linearly spaced bins or ``equivolume`` for spherical shells + + Rmin (*optional*, default = 0.0): minimum radius [cm] + Rmax: maximum radius [cm] + N: number of radial bins - grid: ``unstruct`` for unstructured grids, to be manually defined - - + bins: array with the explicit definition of the spherical bin boundaries + + + bins: array with the explicit definition of the spherical bin boundaries to be used Examples: :: @@ -1114,27 +1124,27 @@ Examples: :: one could add axial and azimuthal discretisation - orientation (*optional*, default = ``z``): ``x``, ``y`` or ``z``, axial direction - - origin (*optional*, default = (0.0 0.0)): (y z), (x z) or (x y) vector with + - origin (*optional*, default = (0.0 0.0)): (y z), (x z) or (x y) vector with the origin of the cylindrical map - - rGrid: ``lin`` for linearly spaced bins or ``equivolume`` for cylindrical shells - + - rGrid: ``lin`` for linearly spaced bins or ``equivolume`` for cylindrical shells + + Rmin (*optional*, default = 0.0): minimum radius [cm] + Rmax: maximum radius [cm] + rN: number of radial bins - rGrid: ``unstruct`` for unstructured grids, to be manually defined - - + bins: array with the explicit definition of the cylindrical radial bin + + + bins: array with the explicit definition of the cylindrical radial bin boundaries to be used - + - axGrid (*optional*, default = 1 bin): ``lin`` for linearly spaced axial bins + axMin: minimum axial coordinate [cm] + axMax: maximum axial coordinate [cm] + axN: number of axial bins - - - azimuthalN (*optional*, default = 1 bin): number of angular azimuthal bins - + + - azimuthalN (*optional*, default = 1 bin): number of angular azimuthal bins + Example: :: map1 { type cylindricalMap; orientation y; origin (7.0 0.0); rGrid lin; Rmax 5.0; rN 10; } @@ -1143,36 +1153,36 @@ Example: :: * weightMap (1D map), divides weight into number of discrete bins - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins - + + min: bottom weight + max: top weight + N: number of bins - grid: ``unstruct`` for unstructured grids, to be manually defined - + + bins: array with the explicit definition of the weight bin boundaries to be used Examples: :: map1 { type weightMap; grid log; min 1.0e-3; max 100.0; N 100; } map2 { type weightMap; grid lin; min 0.1; max 2.0; N 20; } - map3 { type weightMap; bins (0.0 0.2 0.4 0.6 0.8 1.0 2.0 5.0 10.0); } - + map3 { type weightMap; bins (0.0 0.2 0.4 0.6 0.8 1.0 2.0 5.0 10.0); } + Tally Filters ############# - -Another option that can be included in the tallies is **tally filters**. These -allow to filter out certain types of particles when scoring results. For now, + +Another option that can be included in the tallies is **tally filters**. These +allow to filter out certain types of particles when scoring results. For now, the only type of filter existing is: * energyFilter, to stop particles within a certain energy range from contributing to a certain tally - + - Emin (for continuous energy particles): minimum energy [MeV] - Emax (for continuous energy particles): maximum energy [MeV] - Gtop (for multi-group particles): top energy group - Glow (for multi-group particles): bottom energy group - + Example: :: CEfilter { type energyFilter; Emin 10.0; Emax 20.0; } @@ -1184,19 +1194,19 @@ Other options Other keywords, such as for results **normalisation**, that could be included are: * norm: its entry is the name of the tally, ``resName``, to be used as a normalisation - criterion. If the tally has multiple bins, (e.g. has a map), the bin with index 1 + criterion. If the tally has multiple bins, (e.g. has a map), the bin with index 1 will be used for normalisation * normVal: value to normalise the tally ``resName`` to * display: its entry is the name of the tally, ``resName``, which will be displayed - each cycle. Only the tally clerks ``keffAnalogClerk`` and ``keffImplicitClerk`` + each cycle. Only the tally clerks ``keffAnalogClerk`` and ``keffImplicitClerk`` support display at the moment * batchSize (*optional*, default = 1): the number of cycles that constitute a single - batch for the purpose of statistical estimation. For example, a value of 5 means + batch for the purpose of statistical estimation. For example, a value of 5 means that a single estimate is obtained from a score accumulated over 5 cycles Example: :: - tally { + tally { display (k-eff); norm fissRate; normVal 100.0; From 8d3ce065e81f42cbf3a8e6e5977013999c6db432 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Fri, 25 Aug 2023 15:17:26 +0200 Subject: [PATCH 013/133] Fix a bug in dictParser Behaviour in case of a comment without a space after marker was incorrect. --- DataStructures/dictParser_func.f90 | 2 ++ IntegrationTestFiles/testDictionary | 2 ++ 2 files changed, 4 insertions(+) diff --git a/DataStructures/dictParser_func.f90 b/DataStructures/dictParser_func.f90 index 8aaa091c7..c27afa897 100644 --- a/DataStructures/dictParser_func.f90 +++ b/DataStructures/dictParser_func.f90 @@ -95,11 +95,13 @@ subroutine readFileContents(file, filePath) ! if (buffer == '!') then read(unit=unit, fmt='(A)', iostat=stat, advance='yes') buffer + buffer = ' ' else if (lastChar == '/' .and. buffer == '/') then ! We need to remove the last character call file % cut(1) read(unit=unit, fmt='(A)', iostat=stat, advance='yes') buffer + buffer = ' ' end if diff --git a/IntegrationTestFiles/testDictionary b/IntegrationTestFiles/testDictionary index 4cee6a085..96d786876 100644 --- a/IntegrationTestFiles/testDictionary +++ b/IntegrationTestFiles/testDictionary @@ -5,6 +5,8 @@ intArray (1 2 4 5); realArray ( 1 2.2 3.5 ) ; // a bit of weird formatting charArray (One element ); +!Another comment subDict{ myInt 3; myReal 3.2; } ! Note lack of space +//Line comment without space after marker. This case caused a bug at some point subDict2 { myInt 4; myReal 17.0;} From 0a14fbab3269a768d4f16769b00e7727e1b68950 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 29 Aug 2023 12:23:04 +0200 Subject: [PATCH 014/133] Make the base universe class setup common Avoid code repeat when setting up the basic data common to all universes (id, origin and rotation). --- Geometry/Universes/cellUniverse_class.f90 | 31 ++----------- Geometry/Universes/latUniverse_class.f90 | 32 +++----------- Geometry/Universes/pinUniverse_class.f90 | 32 +++----------- Geometry/Universes/rootUniverse_class.f90 | 9 ++-- Geometry/Universes/universe_inter.f90 | 53 +++++++++++++++++++++++ 5 files changed, 71 insertions(+), 86 deletions(-) diff --git a/Geometry/Universes/cellUniverse_class.f90 b/Geometry/Universes/cellUniverse_class.f90 index 017982a0b..5db4f6b28 100644 --- a/Geometry/Universes/cellUniverse_class.f90 +++ b/Geometry/Universes/cellUniverse_class.f90 @@ -78,35 +78,12 @@ subroutine init(self, fill, dict, cells, surfs, mats) type(surfaceShelf), intent(inout) :: surfs type(charMap), intent(in) :: mats integer(shortInt), dimension(:), allocatable :: cellTemp - real(defReal), dimension(:), allocatable :: temp - integer(shortInt) :: id, N, i + integer(shortInt) :: N, i character(100), parameter :: Here = 'init (cellUniverse_class.f90)' - ! Load basic data - call dict % get(id, 'id') - if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: '//numToChar(id)) - call self % setId(id) - - ! Load origin - if (dict % isPresent('origin')) then - call dict % get(temp, 'origin') - - if (size(temp) /= 3) then - call fatalError(Here, 'Origin must have size 3. Has: '//numToChar(size(temp))) - end if - call self % setTransform(origin=temp) - - end if - - ! Load rotation - if (dict % isPresent('rotation')) then - call dict % get(temp, 'rotation') - - if (size(temp) /= 3) then - call fatalError(Here, '3 rotation angles must be given. Has only: '//numToChar(size(temp))) - end if - call self % setTransform(rotation=temp) - end if + ! Setup the base class + ! With: id, origin rotations... + call self % setupBase(dict) ! Load Cells by ID call dict % get(cellTemp, 'cells') diff --git a/Geometry/Universes/latUniverse_class.f90 b/Geometry/Universes/latUniverse_class.f90 index 798ebd9d8..7f12b1a3f 100644 --- a/Geometry/Universes/latUniverse_class.f90 +++ b/Geometry/Universes/latUniverse_class.f90 @@ -111,37 +111,15 @@ subroutine init(self, fill, dict, cells, surfs, mats) type(charMap), intent(in) :: mats real(defReal), dimension(:), allocatable :: temp integer(shortInt), dimension(:), allocatable :: tempI - integer(shortInt) :: id, N, i, j, outFill + integer(shortInt) :: N, i, j, outFill type(dictionary) :: tempDict integer(shortInt), dimension(:,:), allocatable :: tempMap character(nameLen) :: name character(100), parameter :: Here = 'init (latUniverse_class.f90)' - ! Load basic data - call dict % get(id, 'id') - if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: '//numToChar(id)) - call self % setId(id) - - ! Load origin - if (dict % isPresent('origin')) then - call dict % get(temp, 'origin') - - if (size(temp) /= 3) then - call fatalError(Here, 'Origin must have size 3. Has: '//numToChar(size(temp))) - end if - call self % setTransform(origin=temp) - - end if - - ! Load rotation - if (dict % isPresent('rotation')) then - call dict % get(temp, 'rotation') - - if (size(temp) /= 3) then - call fatalError(Here, '3 rotation angles must be given. Has only: '//numToChar(size(temp))) - end if - call self % setTransform(rotation=temp) - end if + ! Setup the base class + ! With: id, origin rotations... + call self % setupBase(dict) ! Load pitch call dict % get(temp, 'pitch') @@ -308,7 +286,7 @@ subroutine distance(self, d, surfIdx, coords) ! Provide default axis to ensure no out of bounds array access if ! all distances happen to be infinite d = INF - ax = 1 + ax = 1 do i = 1, 3 ! Nominator and denominator will have the same sign (by ealier bounds selection) test_d = (bounds(i) - r_bar(i)) / u(i) diff --git a/Geometry/Universes/pinUniverse_class.f90 b/Geometry/Universes/pinUniverse_class.f90 index 2ca15091e..80f7006c0 100644 --- a/Geometry/Universes/pinUniverse_class.f90 +++ b/Geometry/Universes/pinUniverse_class.f90 @@ -77,36 +77,14 @@ subroutine init(self, fill, dict, cells, surfs, mats) type(cellShelf), intent(inout) :: cells type(surfaceShelf), intent(inout) :: surfs type(charMap), intent(in) :: mats - integer(shortInt) :: id, idx, N, i - real(defReal), dimension(:), allocatable :: radii, temp + integer(shortInt) :: idx, N, i + real(defReal), dimension(:), allocatable :: radii character(nameLen), dimension(:), allocatable :: fillNames character(100), parameter :: Here = 'init (pinUniverse_class.f90)' - ! Load basic data - call dict % get(id, 'id') - if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: '//numToChar(id)) - call self % setId(id) - - ! Load origin - if (dict % isPresent('origin')) then - call dict % get(temp, 'origin') - - if (size(temp) /= 3) then - call fatalError(Here, 'Origin must have size 3. Has: '//numToChar(size(temp))) - end if - call self % setTransform(origin=temp) - - end if - - ! Load rotation - if (dict % isPresent('rotation')) then - call dict % get(temp, 'rotation') - - if (size(temp) /= 3) then - call fatalError(Here, '3 rotation angles must be given. Has only: '//numToChar(size(temp))) - end if - call self % setTransform(rotation=temp) - end if + ! Setup the base class + ! With: id, origin rotations... + call self % setupBase(dict) ! Load radii and fill data call dict % get(radii, 'radii') diff --git a/Geometry/Universes/rootUniverse_class.f90 b/Geometry/Universes/rootUniverse_class.f90 index 550bd859e..3a4be7ea5 100644 --- a/Geometry/Universes/rootUniverse_class.f90 +++ b/Geometry/Universes/rootUniverse_class.f90 @@ -84,12 +84,11 @@ subroutine init(self, fill, dict, cells, surfs, mats) character(nameLen) :: name character(100), parameter :: Here = 'init (rootUniverse_class.f90)' - ! Set ID - call dict % get(id, 'id') - if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: '//numToChar(id)) - call self % setId(id) + ! Setup the base class + ! With: id, origin rotations... + call self % setupBase(dict) - ! Make shure root does not contain neither origin nor rotation + ! Make sure root does not contain neither origin nor rotation if (dict % isPresent('origin')) then call fatalError(Here, 'Origin is not allowed. Centre of the root universe is & &always (0.0 0.0 0.0).') diff --git a/Geometry/Universes/universe_inter.f90 b/Geometry/Universes/universe_inter.f90 index 9b434c8b6..172819aeb 100644 --- a/Geometry/Universes/universe_inter.f90 +++ b/Geometry/Universes/universe_inter.f90 @@ -29,6 +29,14 @@ module universe_inter !! !! Rotation is applied before translation to the origin. !! + !! Sample Dictionary Input: + !! uni { + !! id 7; + !! #origin (1.0 0.0 0.1);# + !! #rotation (30.0 0.0 0.0);# + !! + !! } + !! !! Private Members: !! uniId -> Id of the universe !! uniIdx -> Index of the universe @@ -64,6 +72,7 @@ module universe_inter procedure, non_overridable :: setIdx procedure, non_overridable :: setTransform procedure(init), deferred :: init + procedure :: setupBase procedure :: kill ! Runtime procedures @@ -265,6 +274,50 @@ subroutine setIdx(self, idx) end subroutine setIdx + !! + !! Read the data common to all universes from the dictionary + !! + !! Sets-up the base universe class with translations, ids and rotations (if any). + !! Is used to avoid the code repeat in each subclass of the universe. + !! + !! Args: + !! dict [in] -> Dictionary with the universe definition + !! + subroutine setupBase(self, dict) + class(universe), intent(inout) :: self + type(dictionary), intent(in) :: dict + integer(shortInt) :: id + real(defReal), dimension(:), allocatable :: temp + character(100), parameter :: Here = 'setupBase (universe_inter.f90)' + + ! Load basic data + call dict % get(id, 'id') + if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: ' // numToChar(id)) + call self % setId(id) + + ! Load origin + if (dict % isPresent('origin')) then + call dict % get(temp, 'origin') + + if (size(temp) /= 3) then + call fatalError(Here, 'Origin must have size 3. Has: ' // numToChar(size(temp))) + end if + call self % setTransform(origin=temp) + + end if + + ! Load rotation + if (dict % isPresent('rotation')) then + call dict % get(temp, 'rotation') + + if (size(temp) /= 3) then + call fatalError(Here, '3 rotation angles must be given. Has only: ' // numToChar(size(temp))) + end if + call self % setTransform(rotation=temp) + end if + + end subroutine setupBase + !! !! Set universe origin & rotation !! From c81612bdc91a8ff26341fee3a13a89fddb278b66 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 29 Aug 2023 12:41:56 +0200 Subject: [PATCH 015/133] Fix spelling --- .../Universes/Tests/cellUniverse_test.f90 | 6 +++--- Geometry/Universes/Tests/latUniverse_test.f90 | 4 ++-- Geometry/Universes/Tests/pinUniverse_test.f90 | 2 +- .../Universes/Tests/rootUniverse_test.f90 | 4 ++-- Geometry/Universes/Tests/uniFills_test.f90 | 2 +- Geometry/Universes/Tests/universe_test.f90 | 4 ++-- Geometry/Universes/cellUniverse_class.f90 | 6 +++--- Geometry/Universes/latUniverse_class.f90 | 6 +++--- Geometry/Universes/pinUniverse_class.f90 | 6 +++--- Geometry/Universes/rootUniverse_class.f90 | 2 +- Geometry/Universes/uniFills_class.f90 | 14 ++++++------- Geometry/Universes/universeFactory_func.f90 | 8 ++++---- Geometry/Universes/universeShelf_class.f90 | 8 ++++---- Geometry/Universes/universe_inter.f90 | 20 +++++++++---------- 14 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Geometry/Universes/Tests/cellUniverse_test.f90 b/Geometry/Universes/Tests/cellUniverse_test.f90 index 6755aed8d..4b37eb5e3 100644 --- a/Geometry/Universes/Tests/cellUniverse_test.f90 +++ b/Geometry/Universes/Tests/cellUniverse_test.f90 @@ -42,7 +42,7 @@ module cellUniverse_test contains !! - !! Setup enviroment + !! Setup environment !! @Before subroutine setUp() @@ -73,7 +73,7 @@ subroutine setUp() end subroutine setUp !! - !! Clean enviroment + !! Clean environment !! @After subroutine clean() @@ -201,7 +201,7 @@ subroutine test_distance() @assertEqual(ref, d, TOL * ref) @assertEqual(surfs % getIdx(2), surfIdx ) - ! ** In local cell 2 distance to infintity + ! ** In local cell 2 distance to infinity ! surfIdx must be set to 0 pos % dir = [ONE, ZERO, ZERO] call uni % distance(d, surfIdx, pos) diff --git a/Geometry/Universes/Tests/latUniverse_test.f90 b/Geometry/Universes/Tests/latUniverse_test.f90 index b17ec215e..194195671 100644 --- a/Geometry/Universes/Tests/latUniverse_test.f90 +++ b/Geometry/Universes/Tests/latUniverse_test.f90 @@ -38,7 +38,7 @@ module latUniverse_test contains !! - !! Setup enviroment + !! Setup environment !! @Before subroutine setUp() @@ -73,7 +73,7 @@ subroutine setUp() end subroutine setUp !! - !! Clean enviroment + !! Clean environment !! @After subroutine clean() diff --git a/Geometry/Universes/Tests/pinUniverse_test.f90 b/Geometry/Universes/Tests/pinUniverse_test.f90 index 53a0ca3d7..27b911f4e 100644 --- a/Geometry/Universes/Tests/pinUniverse_test.f90 +++ b/Geometry/Universes/Tests/pinUniverse_test.f90 @@ -27,7 +27,7 @@ module pinUniverse_test contains !! - !! Set-up test enviroment + !! Set-up test environment !! @Before subroutine setup() diff --git a/Geometry/Universes/Tests/rootUniverse_test.f90 b/Geometry/Universes/Tests/rootUniverse_test.f90 index 4781eac62..662f1dfe8 100644 --- a/Geometry/Universes/Tests/rootUniverse_test.f90 +++ b/Geometry/Universes/Tests/rootUniverse_test.f90 @@ -30,7 +30,7 @@ module rootUniverse_test contains !! - !! Setup enviroment + !! Setup environment !! @Before subroutine setUp() @@ -57,7 +57,7 @@ subroutine setUp() end subroutine setUp !! - !! Clean enviroment + !! Clean environment !! @After subroutine clean() diff --git a/Geometry/Universes/Tests/uniFills_test.f90 b/Geometry/Universes/Tests/uniFills_test.f90 index 7b090e856..2843951d1 100644 --- a/Geometry/Universes/Tests/uniFills_test.f90 +++ b/Geometry/Universes/Tests/uniFills_test.f90 @@ -110,7 +110,7 @@ subroutine test_cycles() @assertTrue(graph % hasCycles()) - ! Move recursion to 3rd diffrent universe (loop from 3rd to 2nd) + ! Move recursion to 3rd different universe (loop from 3rd to 2nd) ! graph % uni(2) % fill(1) = 3 graph % uni(3) % fill(1) = -2 diff --git a/Geometry/Universes/Tests/universe_test.f90 b/Geometry/Universes/Tests/universe_test.f90 index c92fd6d6c..8d383a003 100644 --- a/Geometry/Universes/Tests/universe_test.f90 +++ b/Geometry/Universes/Tests/universe_test.f90 @@ -7,7 +7,7 @@ module universe_test !! - !! Note that universe is abstract thus it canot be tested by itself + !! Note that universe is abstract thus it cannot be tested by itself !! !! Tests for universe non-overridable procedures are in cellUniverse_test !! @@ -36,7 +36,7 @@ subroutine test_charToFill() name = 'mat47' call mats % add(name, 47) - ! Test material converstion + ! Test material conversion name = 'mat13' @assertEqual(13, charToFill(name, mats, Here)) diff --git a/Geometry/Universes/cellUniverse_class.f90 b/Geometry/Universes/cellUniverse_class.f90 index 5db4f6b28..ce528ab0f 100644 --- a/Geometry/Universes/cellUniverse_class.f90 +++ b/Geometry/Universes/cellUniverse_class.f90 @@ -28,7 +28,7 @@ module cellUniverse_class !! !! Representation of a universe via cells !! - !! Each local cell in the universe corespondes to a cell given by an ID. + !! Each local cell in the universe corresponds to a cell given by an ID. !! An extra local cell is always defined inside the cellUniverse with UNDEF_MAT !! (undefined material) filling. If position is not in any user-defined cell, it is in this !! extra cell. Extra cell exists to enable plotting of geometry without fatalErrors. @@ -168,8 +168,8 @@ end subroutine distance !! !! See universe_inter for details. !! - !! Note: Introduces extra movment to the particle to push it over boundary - !! for more efficent search. Distance is NUGDE. + !! Note: Introduces extra movement to the particle to push it over boundary + !! for more efficient search. Distance is NUGDE. !! subroutine cross(self, coords, surfIdx) class(cellUniverse), intent(inout) :: self diff --git a/Geometry/Universes/latUniverse_class.f90 b/Geometry/Universes/latUniverse_class.f90 index 7f12b1a3f..ca950e9cd 100644 --- a/Geometry/Universes/latUniverse_class.f90 +++ b/Geometry/Universes/latUniverse_class.f90 @@ -31,7 +31,7 @@ module latUniverse_class !! Cells inside the lattice can only be filled with a universe (given as integer ID). !! Background cell can have any filling given by keyword (material or universe) !! - !! Every lattice cell has an offset to its centere (so the centre of the nested universe + !! Every lattice cell has an offset to its centre (so the centre of the nested universe !! is in the center of the lattice cell). !! !! Minimum lattice pitch is set to 10 * SURF_TOL @@ -66,7 +66,7 @@ module latUniverse_class !! Private Members: !! pitch -> Values of lattice pitch in x, y & z directions !! sizeN -> Number of lattice cells in x, y & z directions - !! corner -> Location of the minumum corner + !! corner -> Location of the minimum corner !! a_bar -> Halfwidth of lattice cell reduced by surface tolerance !! outline -> Box type surface that is a boundary between lattice & background !! outLocalID -> LocalID of the background cell @@ -288,7 +288,7 @@ subroutine distance(self, d, surfIdx, coords) d = INF ax = 1 do i = 1, 3 - ! Nominator and denominator will have the same sign (by ealier bounds selection) + ! Nominator and denominator will have the same sign (by earlier bounds selection) test_d = (bounds(i) - r_bar(i)) / u(i) if (test_d < d) then diff --git a/Geometry/Universes/pinUniverse_class.f90 b/Geometry/Universes/pinUniverse_class.f90 index 80f7006c0..e22fae1cc 100644 --- a/Geometry/Universes/pinUniverse_class.f90 +++ b/Geometry/Universes/pinUniverse_class.f90 @@ -34,14 +34,14 @@ module pinUniverse_class !! fills (u<3> void clad u<4>); !! } !! - !! There must be 0.0 entry, which indicates outermost annulus (infinate radius). + !! There must be 0.0 entry, which indicates outermost annulus (infinite radius). !! `fills` and `radii` are given as pairs by position in the input arrays. Thus, fills !! are sorted together with the `radii`. As a result, in the example, local cell 1 is !! filled with u<4>, cell 2 with u<3> etc. !! !! Public Members: !! r_sqr -> Array of radius^2 for each annulus - !! annuli -> Array of cylinder surfaces that represent diffrent annuli + !! annuli -> Array of cylinder surfaces that represent different annuli !! !! Interface: !! universe interface @@ -104,7 +104,7 @@ subroutine init(self, fill, dict, cells, surfs, mats) ! Change 0.0 to infinity N = size(radii) idx = minloc(radii, 1) - if (radii(idx) /= ZERO) call fatalError(Here, 'Did not found outermst element with radius 0.0.') + if (radii(idx) /= ZERO) call fatalError(Here, 'Did not found outermost element with radius 0.0.') call swap( radii(idx), radii(N)) call swap( fillNames(idx), fillNames(N)) radii(N) = INF * 1.1_defReal diff --git a/Geometry/Universes/rootUniverse_class.f90 b/Geometry/Universes/rootUniverse_class.f90 index 3a4be7ea5..3cfb112be 100644 --- a/Geometry/Universes/rootUniverse_class.f90 +++ b/Geometry/Universes/rootUniverse_class.f90 @@ -22,7 +22,7 @@ module rootUniverse_class !! !! A top level (root) universe of geometry !! - !! Is composed of two regions. Inside and outside seperated by a single surface. + !! Is composed of two regions. Inside and outside separated by a single surface. !! Inside is the -ve halfspace of the boundary surface !! +ve halfspace is OUTSIDE !! Filling can be universe given by ID (`u<67` syntax) or a material given by name (e.g. 'fuel') diff --git a/Geometry/Universes/uniFills_class.f90 b/Geometry/Universes/uniFills_class.f90 index d41a34a90..2d07cf2b4 100644 --- a/Geometry/Universes/uniFills_class.f90 +++ b/Geometry/Universes/uniFills_class.f90 @@ -30,12 +30,12 @@ module uniFills_class !! A Temporary structure to store universe fillings & check correctness !! !! Is used to transfer information about universe nesting structure decoupled from - !! the spatial subdivision. Will be used to constrct geomGraph. + !! the spatial subdivision. Will be used to construct geomGraph. !! !! TODO: The recursive procedures that do checks may not be the best from the point of !! view of efficiency. Investigate if it is a problem. !! - !! Public Mambers: + !! Public Members: !! root -> Index of the root universe !! uni -> Array of `fillInfo` with data for each universe. Universe indices are the !! same on the uni array on on the universe Shelf. @@ -304,7 +304,7 @@ function nestedOutside(self) result(hasIt) call fatalError(Here, 'Root universe has not been set.') end if - ! Serach nested universes + ! Search nested universes hasIt = .false. do i = 1, size(self % uni(self % root) % fill) fill = self % uni(self % root) % fill(i) @@ -360,7 +360,7 @@ function unusedUniverses(self) result(list) end function unusedUniverses !! - !! Get count of instances of diffrent universes in the geometry + !! Get count of instances of different universes in the geometry !! !! Args: !! map [out] -> Map of uniIdx to number of instances. If uniIdx is not present in the @@ -483,7 +483,7 @@ end function countDepth !! idx [in] -> Index of the current universe !! !! Result: - !! True if universe under idx contains outside or outisde is present below it + !! True if universe under idx contains outside or outside is present below it !! !! Errors: !! fatalError if idx is invalid @@ -554,7 +554,7 @@ recursive subroutine collectUsed(self, set, idx) end subroutine collectUsed !! - !! Count instances of diffrent univeres in the current universe or below it + !! Count instances of different universes in the current universe or below it !! !! Args: !! map [inout] -> Map of uniIdx to number of instances. Instances in the current universe @@ -578,7 +578,7 @@ recursive subroutine countInstancesBelow(self, map, idx) count = map % getOrDefault(idx, 0) + 1 call map % add(idx, count) - ! Loop over local cells and add nexted universes + ! Loop over local cells and add nested universes do i = 1, size(self % uni(idx) % fill) fill = self % uni(idx) % fill(i) diff --git a/Geometry/Universes/universeFactory_func.f90 b/Geometry/Universes/universeFactory_func.f90 index f1d75920b..810d20f03 100644 --- a/Geometry/Universes/universeFactory_func.f90 +++ b/Geometry/Universes/universeFactory_func.f90 @@ -37,7 +37,7 @@ module universeFactory_func !! !! Args: !! ptr [out] -> Pointer to the new universe - !! fill [out] -> Allocatable integer array with filling of diffrent uniqueID + !! fill [out] -> Allocatable integer array with filling of different uniqueID !! dict [in] -> Dictionary with universe definition !! cells [inout] -> Shelf with defined cells !! surfs [inout] -> Shelf with defined surfaces @@ -59,7 +59,7 @@ subroutine new_universe_ptr(ptr, fill, dict, cells, surfs, mats) ! Obtain type of the universe call dict % get(type, 'type') - ! Allocate approperiate universe + ! Allocate appropriate universe ! ** FOR NEW UNIVERSE ADD CASE STATEMENT HERE ** ! select case (type) case ('rootUniverse') @@ -87,11 +87,11 @@ subroutine new_universe_ptr(ptr, fill, dict, cells, surfs, mats) end subroutine new_universe_ptr !! - !! Allocte an allocatable universe + !! Allocate an allocatable universe !! !! Args: !! new [out] -> Universe to be allocated - !! fill [out] -> Allocatable integer array with filling of diffrent uniqueID + !! fill [out] -> Allocatable integer array with filling of different uniqueID !! dict [in] -> Dictionary with universe definition !! cells [inout] -> Shelf with defined cells !! surfs [inout] -> Shelf with defined surfaces diff --git a/Geometry/Universes/universeShelf_class.f90 b/Geometry/Universes/universeShelf_class.f90 index 1a34757c3..18744efa4 100644 --- a/Geometry/Universes/universeShelf_class.f90 +++ b/Geometry/Universes/universeShelf_class.f90 @@ -46,13 +46,13 @@ module universeShelf_class !! init -> Initialise and build uniFills !! getPtr -> Get pointer to a universe given by its index !! getPtr_fast -> Get pointer to a universe without bounds checking. Should be used in - !! speed-critical parts. + !! speed-critical parts. !! getIdx -> Get uniIdx of a universe given by uniId !! getId -> Get uniId of a universe given by uniIdx !! getSize -> Return the number of universes (max uniIdx) !! kill -> Return to uninitialised state !! - !! NOTE: Becoue universes are stored as pointers, calling `kill` is crucial + !! NOTE: Because universes are stored as pointers, calling `kill` is crucial !! to prevent memory leaks. TODO: Add `final` procedure here? !! type, public :: universeShelf @@ -132,7 +132,7 @@ subroutine init(self, fills, dict, cells, surfs, mats) ! Store content info in fills call fills % addUniverse(i, id, fillInfo) - ! Load index infor into the universe + ! Load index info into the universe call self % unis(i) % ptr % setIdx(i) end do @@ -153,7 +153,7 @@ end subroutine init !! !! Errors: !! Pointer will have undefined status if the idx is not valid (will point to some place - !! it is unlikley it will be null so associated procedure may return true!) + !! it is unlikely it will be null so associated procedure may return true!) !! function getPtr_fast(self, idx) result(ptr) class(universeShelf), intent(in) :: self diff --git a/Geometry/Universes/universe_inter.f90 b/Geometry/Universes/universe_inter.f90 index 172819aeb..c903a50bd 100644 --- a/Geometry/Universes/universe_inter.f90 +++ b/Geometry/Universes/universe_inter.f90 @@ -12,7 +12,7 @@ module universe_inter private - ! Extandable methods + ! Extendable methods public :: kill ! Universe utility functions @@ -40,7 +40,7 @@ module universe_inter !! Private Members: !! uniId -> Id of the universe !! uniIdx -> Index of the universe - !! origin -> Location of the origin of the univere co-ordinates in the frame of higher universe + !! origin -> Location of the origin of the universe co-ordinates in the frame of higher universe !! rotMat -> Rotation matrix for rotation with respect to the higher universe !! rot -> rotation flag. True is universe is rotated !! @@ -50,7 +50,7 @@ module universe_inter !! setIdx -> Set index of the universe !! setTransfrom -> Set origin and/or rotation of the universe. Rotation angles are in [deg] !! init -> Initialise universe and return fillArray with content of local cells. - !! Requires surface/cell shelfs and map of material names to matIdxs + !! Requires surface/cell shelves and map of material names to matIdxs !! kill -> Return to uninitialised state !! enter -> Generate new coord after entering a universe from higher level coord. !! findCell -> Return local cell ID and cellIdx in cellShelf for a given position. @@ -88,7 +88,7 @@ module universe_inter !! !! Initialise Universe !! - !! Must ruturn a fill array, that contains content in each local cell of the universe. + !! Must return a fill array, that contains content in each local cell of the universe. !! Array is indexed by local cell ID. Universe content is -uniID and material content !! is +ve matIdx. !! @@ -123,7 +123,7 @@ end subroutine init !! cellIdx [out] -> cellIdx in cellShelf, if the cell point is in is defined there. !! If the cell exists only in the universe return 0. !! r [in] -> Position of a point - !! u [in] -> Normalised direaction (norm2(u) = 1.0) + !! u [in] -> Normalised direction (norm2(u) = 1.0) !! !! Note: Self is intent(inout), but if a state of the universe is to be changed !! it is necessary to consider issues related to parallel calculations with shared @@ -152,7 +152,7 @@ end subroutine findCell !! Args: !! d [out] -> Distance to the next surface !! surfIdx [out] -> Index of the surface that will be crossed. If +ve than surface - !! is defined on surfaceSHelf. If -ve surface is local to this univerese. + !! is defined on surfaceSHelf. If -ve surface is local to this universe. !! coords [in] -> Coordinates of the point inside the universe (after transformations !! and with localID already set) !! @@ -172,12 +172,12 @@ end subroutine distance !! Cross between local cells !! !! Procedure assumes that the point is ON THE SURFACE between cells within under/overshoot as - !! a result of finate FP precision. + !! a result of finite FP precision. !! !! Args: !! coords [inout] -> Coordinates placed in the universe (after transformations and with !! local ID set). On exit localID will be changed - !! surfIdx [in] -> surfIdx from distance procedure, which hints which surface is beeing + !! surfIdx [in] -> surfIdx from distance procedure, which hints which surface is being !! crossed. !! !! Note: Self is intent(inout), but if a state of the universe is to be changed @@ -352,7 +352,7 @@ end subroutine setTransform !! Sets: !! - New position (r) !! - New direction (dir) - !! - Rotation infor (isRotated + rotMat) + !! - Rotation info (isRotated + rotMat) !! - Local cell (localID) !! - Cell info (cellIdx) !! @@ -362,7 +362,7 @@ end subroutine setTransform !! !! Args: !! new [out] -> New coordinates for the level. - !! r [in] -> Position affter cellOffset in upper univere is applied + !! r [in] -> Position after cellOffset in upper universe is applied !! u [in] -> Normalised direction (norm2(u) = 1.0) !! !! Note: Self is intent(inout), but if a state of the universe is to be changed From 54a0d80edba2b6e04bdd6f5311f9326447fa4807 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sun, 10 Sep 2023 16:34:21 +0200 Subject: [PATCH 016/133] Fix broken no-rotation check in rootUniverse Due to a copy-paste error keyword 'origin' was used to check if 'rotation' is provided in the input dictionary. --- Geometry/Universes/rootUniverse_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Geometry/Universes/rootUniverse_class.f90 b/Geometry/Universes/rootUniverse_class.f90 index 3cfb112be..54f6d76be 100644 --- a/Geometry/Universes/rootUniverse_class.f90 +++ b/Geometry/Universes/rootUniverse_class.f90 @@ -92,7 +92,7 @@ subroutine init(self, fill, dict, cells, surfs, mats) if (dict % isPresent('origin')) then call fatalError(Here, 'Origin is not allowed. Centre of the root universe is & &always (0.0 0.0 0.0).') - else if (dict % isPresent('origin')) then + else if (dict % isPresent('rotation')) then call fatalError(Here, 'Rotation is not allowed. Root universe cannot be rotated.') end if From 5d71ce20b64610ab2a7aae07265d3889acaf286a Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Mon, 11 Sep 2023 13:18:41 +0100 Subject: [PATCH 017/133] Address comments on DBRC implementation --- .../neutronCEimp_class.f90 | 15 ++- .../neutronCEstd_class.f90 | 15 ++- CollisionOperator/scatteringKernels_func.f90 | 122 ++++++++++-------- .../aceDatabase/aceNeutronDatabase_class.f90 | 70 +++++----- .../ceNeutronData/ceNeutronNuclide_inter.f90 | 25 +--- 5 files changed, 117 insertions(+), 130 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index a54a15cce..a1102774c 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -657,6 +657,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) class(particle), intent(inout) :: p type(collisionData),intent(inout) :: collDat class(uncorrelatedReactionCE), intent(in) :: reac + class(ceNeutronNuclide), pointer :: ceNuc0K integer(shortInt) :: nucIdx real(defReal) :: A, kT, mu real(defReal),dimension(3) :: V_n ! Neutron velocity (vector) @@ -666,7 +667,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) real(defReal),dimension(3) :: V_t, V_cm ! Target and CM velocity real(defReal) :: phi, dummy real(defReal) :: maj - logical(defBool) :: eRange, hasDBRC + logical(defBool) :: inEnergyRange, hasDBRC character(100), parameter :: Here = 'ScatterFromMoving (neutronCEimp_class.f90)' ! Read collision data @@ -680,24 +681,24 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Sample target velocity with constant XS or with DBRC ! Check energy range - eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) + inEnergyRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) ! Check if DBRC is on for this target nuclide hasDBRC = self % nuc % hasDBRC() - if (eRange .and. hasDBRC) then + if (inEnergyRange .and. hasDBRC) then ! Retrieve 0K nuclide index from DBRC nuclide map nucIdx = self % xsData % mapDBRCnuc % get(nucIdx) - ! Reassign pointer for the 0K nuclide - self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Database') + ! Assign pointer for the 0K nuclide + ceNuc0K => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(ceNuc0K)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Get elastic scattering 0K majorant maj = self % xsData % getScattMicroMajXS(p % E, kT, A, nucIdx) ! Use DBRC to sample target velocity - V_t = targetVelocity_DBRCXS(self % nuc, p % E, dir_pre, A, kT, p % pRNG, maj) + V_t = targetVelocity_DBRCXS(ceNuc0K, p % E, dir_pre, A, kT, p % pRNG, maj) else ! Constant cross section approximation diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index e146567fc..b7b044bf2 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -416,6 +416,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) class(particle), intent(inout) :: p type(collisionData),intent(inout) :: collDat class(uncorrelatedReactionCE), intent(in) :: reac + class(ceNeutronNuclide), pointer :: ceNuc0K integer(shortInt) :: nucIdx real(defReal) :: A, kT, mu real(defReal),dimension(3) :: V_n ! Neutron velocity (vector) @@ -425,7 +426,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) real(defReal),dimension(3) :: V_t, V_cm ! Target and CM velocity real(defReal) :: phi, dummy real(defReal) :: maj - logical(defBool) :: eRange, hasDBRC + logical(defBool) :: inEnergyRange, hasDBRC character(100), parameter :: Here = 'ScatterFromMoving (neutronCEstd_class.f90)' ! Read collision data @@ -439,24 +440,24 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Sample target velocity with constant XS or with DBRC ! Check energy range - eRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) + inEnergyRange = ((p % E <= self % DBRCeMax) .and. (self % DBRCeMin <= p % E)) ! Check if DBRC is on for this target nuclide hasDBRC = self % nuc % hasDBRC() - if (eRange .and. hasDBRC) then + if (inEnergyRange .and. hasDBRC) then ! Retrieve 0K nuclide index from DBRC nuclide map nucIdx = self % xsData % mapDBRCnuc % get(nucIdx) - ! Reassign pointer for the 0K nuclide - self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(self % nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Database') + ! Assign pointer for the 0K nuclide + ceNuc0K => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) + if(.not.associated(ceNuc0K)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Get elastic scattering 0K majorant maj = self % xsData % getScattMicroMajXS(p % E, kT, A, nucIdx) ! Use DBRC to sample target velocity - V_t = targetVelocity_DBRCXS(self % nuc, p % E, dir_pre, A, kT, p % pRNG, maj) + V_t = targetVelocity_DBRCXS(ceNuc0K, p % E, dir_pre, A, kT, p % pRNG, maj) else ! Constant cross section approximation diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 87b7130c8..7b09d59a6 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -18,6 +18,7 @@ module scatteringKernels_func private :: sample_x2expx2 private :: sample_x3expx2 + private :: sample_targetVelocity contains @@ -101,10 +102,11 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) real(defReal), intent(in) :: A real(defReal), intent(in) :: kT class(RNG), intent(inout) :: rand + logical(defBool) :: accept real(defReal),dimension(3) :: V_t - real(defReal) :: alpha, mu, phi, P_acc + real(defReal) :: alpha, mu, phi real(defReal) :: X, Y - real(defReal) :: r1, r2, r3, r4 + real(defReal) :: rel_v, r1 ! Calculate neutron Y = beta *V_n ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). @@ -113,37 +115,19 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) ! Calculate threshold factor alpha alpha = 2.0/(Y*sqrt(PI)+2.0) - rejectionLoop: do - ! Obtain random numbers - r1 = rand % get() - r2 = rand % get() - r3 = rand % get() - - ! Sample X = beta * V_t - if ( r1 > alpha ) then - X = sample_x2expx2(rand) - - else - X = sample_x3expx2(rand) - - end if - - ! Sample polar angle of target velocity wrt. neutron direction - mu = 2.0 * r2 - 1.0; - - ! Calculate acceptance probability - P_acc = sqrt(Y*Y + X*X - 2.0*X*Y*mu) / (Y+X) + ! Sample velocity and calculate angle and acceptance probability + call sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) ! Accept or reject mu - if (P_acc > r3) exit rejectionLoop + if (accept) exit rejectionLoop end do rejectionLoop ! Calculate azimithal angle for target and obtain target direction - r4 = rand % get() - phi = 2.0 *PI * r4 + r1 = rand % get() + phi = 2.0 *PI * r1 V_t = rotateVector(dir, mu, phi) @@ -167,11 +151,12 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) real(defReal), intent(in) :: kT real(defReal), intent(in) :: tempMaj class(RNG), intent(inout) :: rand + logical(defBool) :: accept real(defReal),dimension(3) :: V_t - real(defReal) :: alpha, mu, phi, P_acc, DBRC_acc + real(defReal) :: alpha, mu, phi, DBRC_acc real(defReal) :: X, Y - real(defReal) :: r1, r2, r3, r4, r5 - real(defreal) :: rel_v, rel_E, xs_rel_v + real(defReal) :: r1, r2 + real(defReal) :: rel_v, rel_E, xs_rel_v ! Calculate neutron Y = beta *V_n ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). @@ -183,30 +168,11 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) rejectionLoop: do - ! Obtain random numbers - r1 = rand % get() - r2 = rand % get() - r3 = rand % get() - - ! Sample X = beta * V_t - ! Uses helper functions below - if ( r1 > alpha ) then - X = sample_x2expx2(rand) - else - X = sample_x3expx2(rand) - end if - - ! Sample polar angle of target velocity wrt. neutron direction - mu = 2.0 * r2 - 1.0; - - ! Calculate relative velocity between neutron and target - rel_v = sqrt(Y * Y + X * X - 2.0 * X * Y * mu) - - ! Calculate Acceptance Propability - P_acc = rel_v / (Y + X) + ! Sample velocity and calculate angle and acceptance probability + call sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) ! Accept or reject mu and target velocity - if (P_acc < r3) cycle rejectionLoop + if (.not. accept) cycle rejectionLoop ! Relative energy = relative velocity **2 due to sqrt(Mn/2) scaling factor rel_E = (rel_v**2 * kT / A) @@ -216,18 +182,18 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) ! Introduce DBRC acceptance condition DBRC_acc = (xs_rel_v / tempMaj) - r4 = rand % get() + r1 = rand % get() ! Accept or reject with DBRC - if (DBRC_acc > r4) then + if (DBRC_acc > r1) then exit rejectionLoop end if end do rejectionLoop ! Calculate azimithal angle for target and obtain target direction - r5 = rand % get() - phi = 2.0 * PI * r5 + r2 = rand % get() + phi = 2.0 * PI * r2 V_t = rotateVector(dir, mu, phi) @@ -298,5 +264,53 @@ function sample_x3expx2(rand) result(sample) end function sample_x3expx2 + !! + !! Subroutine to sample the target velocity using the predefined helper functions, + !! sample the scattering angle, and calculate the acceptance probability for the + !! sampling loop. + !! + !! It is called used by different methods (contant xs, DBRC) when sampling the velocity + !! + subroutine sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) + real(defReal), intent(out) :: X + logical(defBool), intent(out) :: accept + real(defReal), intent(out) :: rel_v + real(defReal), intent(out) :: mu + class(RNG), intent(inout) :: rand + real(defReal), intent(in) :: Y + real(defReal), intent(in) :: alpha + real(defReal) :: r1, r2, r3, P_acc + + ! Obtain random numbers + r1 = rand % get() + r2 = rand % get() + r3 = rand % get() + + ! Sample X = beta * V_t + ! Uses helper functions below + if ( r1 > alpha ) then + X = sample_x2expx2(rand) + else + X = sample_x3expx2(rand) + end if + + ! Sample polar angle of target velocity wrt. neutron direction + mu = 2.0 * r2 - 1.0; + + ! Calculate relative velocity between neutron and target + rel_v = sqrt(Y * Y + X * X - 2.0 * X * Y * mu) + + ! Calculate Acceptance Propability + P_acc = rel_v / (Y + X) + + ! Verigy acceptance condition + if (P_acc > r3) then + accept = .true. + else + accept = .false. + end if + + end subroutine sample_targetVelocity + end module scatteringKernels_func diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index e6bddc1ab..53cf0a141 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -484,13 +484,13 @@ subroutine init(self, dict, ptr, silent ) type(aceCard) :: ACE type(aceSabCard) :: ACE_Sab character(pathLen) :: aceLibPath - character(nameLen) :: name, name_file + character(nameLen) :: name, name_file, nucDBRC_temp character(:), allocatable :: zaid, file integer(shortInt) :: i, j, envFlag, nucIdx, idx integer(shortInt) :: maxNuc logical(defBool) :: isFissileMat - integer(shortInt),dimension(:),allocatable :: nucIdxs, DBRCidxs - character(nameLen),dimension(:),allocatable :: DBRC_nucs + integer(shortInt),dimension(:),allocatable :: nucIdxs, zaidDBRC + character(nameLen),dimension(:),allocatable :: nucDBRC integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 character(100), parameter :: Here = 'init (aceNeutronDatabase_class.f90)' @@ -565,14 +565,14 @@ subroutine init(self, dict, ptr, silent ) self % hasDBRC = .true. ! Call through list of DBRC nuclides - call dict % get(DBRCidxs, 'DBRC') - allocate(DBRC_nucs(size(DBRCidxs))) + call dict % get(zaidDBRC, 'DBRC') + allocate(nucDBRC(size(zaidDBRC))) ! Add all DBRC nuclides to nucSet for initialisation - do i = 1, size(DBRCidxs) - DBRC_nucs(i) = numToChar(DBRCidxs(i)) - DBRC_nucs(i) = trim(DBRC_nucs(i))//'.00' - call nucSet % add(DBRC_nucs(i), IN_SET) + do i = 1, size(zaidDBRC) + nucDBRC(i) = numToChar(zaidDBRC(i)) + nucDBRC_temp = trim(nucDBRC(i))//'.00' + call nucSet % add(nucDBRC_temp, IN_SET) end do end if @@ -660,7 +660,7 @@ subroutine init(self, dict, ptr, silent ) ! If on, initialise DBRC if (self % hasDBRC) then - call self % init_DBRC(DBRC_nucs, nucSet, self % mapDBRCnuc) + call self % init_DBRC(nucDBRC, nucSet, self % mapDBRCnuc) end if !! Clean up @@ -713,51 +713,41 @@ end subroutine init_urr !! NOTE: compares the first 5 letters of the ZAID.TT. It would be wrong with isotopes !! with Z > 99 !! - subroutine init_DBRC(self, DBRC_nucs, nucSet, map) + subroutine init_DBRC(self, nucDBRC, nucSet, map) class(aceNeutronDatabase), intent(inout) :: self - character(nameLen), dimension(:), intent(in) :: DBRC_nucs + character(nameLen), dimension(:), intent(in) :: nucDBRC type(charMap), intent(in) :: nucSet type(intMap), intent(out) :: map - integer(shortInt) :: i, j, k, idx - character(nameLen) :: nuc0K, nucDBRC - character(5) :: nuc0Ktemp, nucDBRCtemp + integer(shortInt) :: i, j, idx0K, last + character(nameLen) :: nuc0K, nucTemp - idx = 1 + idx0K = 1 ! Loop through DBRC nuclides - do i = 1, size(DBRC_nucs) - ! Get ZAIDs with and without 0K temperature codes - nuc0K = DBRC_nucs(i) - nuc0Ktemp = nuc0K(1:5) - - ! Loop through nucSet to find the nucIdxs of the 0K DBRC nuclides - k = nucSet % begin() - do while (k /= nucSet % end()) - - ! Exit loop if a match is found - if (nucSet % atKey(k) == nuc0K) then - idx = nucSet % atVal(k) - exit - end if + do i = 1, size(nucDBRC) - ! Increment index - k = nucSet % next(k) + ! Get ZAID with 0K temperature code + nuc0K = trim(nucDBRC(i))//'.00' - end do + ! Find the nucIdxs of the 0K DBRC nuclides + idx0K = nucSet % get(nuc0K) - ! Loop through nucSec again to find the nucIdxs of the DBRC nuclides with + ! Loop through nucSec to find the nucIdxs of the DBRC nuclides with ! temperature different from 0K j = nucSet % begin() do while (j /= nucSet % end()) - ! Get ZAIDs with and without temperature code - nucDBRC = nucSet % atKey(j) - nucDBRCtemp = nucDBRC(1:5) + + ! Get ZAIDs in the nuclide set without temperature code + nucTemp = nucSet % atKey(j) + ! Remove temperature code (.TT) + last = len_trim(nucTemp) + nucTemp = nucTemp(1:last-3) ! If the ZAID of the DBRC nuclide matches one in nucSet, save them in the map - if (nucDBRCtemp == nuc0Ktemp) then - call map % add(nucSet % atVal(j), idx) + if (nucTemp == nucDBRC(i)) then + call map % add(nucSet % atVal(j), idx0K) ! Set nuclide DBRC flag on - call self % nuclides(nucSet % atVal(j)) % setDBRC() + call self % nuclides(nucSet % atVal(j)) % set(dbrc=.true.) end if ! Increment index diff --git a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 index fd52007b6..286a04e93 100644 --- a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 @@ -50,7 +50,6 @@ module ceNeutronNuclide_inter !! invertInelastic -> Selects type of inelastic neutron scattering !! xsOf -> Returns microscopic XS given MT number !! elScatteringXS -> Returns elastic scattering XS for the nuclide - !! setDBRC -> Turns the hasDBRC flag to true !! hasDBRC -> Returns the value of the hasDBRC flag !! type, public, abstract, extends(nuclideHandle) :: ceNeutronNuclide @@ -71,7 +70,6 @@ module ceNeutronNuclide_inter procedure, non_overridable :: set procedure, non_overridable :: getNucIdx procedure, non_overridable :: isFissile - procedure, non_overridable :: setDBRC procedure, non_overridable :: hasDBRC procedure :: getMass procedure :: getkT @@ -232,18 +230,20 @@ end subroutine getMicroXSs !! fatalError if kT <= 0.0 !! fatalError if mass <= 0.0 !! - subroutine set(self, nucIdx, database, fissile, mass, kT) + subroutine set(self, nucIdx, database, fissile, mass, kT, dbrc) class(ceNeutronNuclide), intent(inout) :: self integer(shortInt), intent(in),optional :: nucIdx class(ceNeutronDatabase), pointer, optional, intent(in) :: database logical(defBool), intent(in), optional :: fissile real(defReal), intent(in), optional :: mass real(defReal), intent(in), optional :: kT + logical(defBool), intent(in), optional :: dbrc character(100), parameter :: Here = 'set (ceNuetronNuclide_inter.f90)' if(present(nucIdx)) self % nucIdx = nucIdx if(present(database)) self % data => database if(present(fissile)) self % fissile = fissile + if(present(dbrc)) self % DBRC = dbrc if(present(mass)) then if(mass <= ZERO) call fatalError(Here,"Mass of nuclide cannot be -ve: "//numToChar(mass)) @@ -295,25 +295,6 @@ pure function isFissile(self) result(isIt) end function isFissile - !! - !! Set the hasDBRC flag to .true. if called - !! - !! Args: - !! None - !! - !! Result: - !! None - !! - !! Errors: - !! None - !! - subroutine setDBRC(self) - class(ceNeutronNuclide), intent(inout) :: self - - self % DBRC = .true. - - end subroutine setDBRC - !! !! Return .true. if the nuclide needs to use DBRC !! From f28e067d0640081f669004284417bc1979c9f07e Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 11 Sep 2023 14:00:44 +0100 Subject: [PATCH 018/133] Fix typos and add entries to User Manual.rst --- docs/User Manual.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 96008fbbe..fd50cf6e6 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -27,6 +27,8 @@ eigenPhysicsPackage, used for criticality (or eigenvalue) calculations * outputFile (*optional*, default = 'output'): name of the output file * outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. Choices are ``asciiMATLAB`` and ``asciiJSON`` +* printSource (*optional*, default = 0): 1 for true; 0 for false; requests + to print the particle source to a text file Example: :: @@ -70,6 +72,8 @@ fixedSourcePhysicsPackage, used for fixed source calculations * outputFile (*optional*, default = 'output'): name of the output file * outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. Choices are ``asciiMATLAB`` and ``asciiJSON`` +* printSource (*optional*, default = 0): 1 for true; 0 for false; requests + to print the particle source to a text file Example: :: @@ -531,7 +535,7 @@ Example: :: Example: :: - uni3 { id 3; type pinlUniverse; radii (0.2 1.0 1.1 1.3 0.0); fills (u<1> fuel void clad coolant); } + uni3 { id 3; type pinUniverse; radii (0.2 1.0 1.1 1.3 0.0); fills (u<1> fuel void clad coolant); } * latUniverse, cartesian lattice of constant pitch From f439a57d6acdfc7b0b058ae62235a87c03dc9505 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 11 Sep 2023 15:41:22 +0100 Subject: [PATCH 019/133] Typos in User Manual.rst --- docs/User Manual.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index fd50cf6e6..2ae31a1b4 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -593,11 +593,12 @@ vtk * width: (x y z) array with the width of the mesh in each direction [cm] * vox: (x y z) array with the number of voxels requested in each direction * what (*optional*, default = material): defines what is highlighted in the - plot; options are ``material`` and ``cellID`` + plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` + highlights unique cell IDs Example: :: - plotVTK { type vtk; corner (10.0 6.0 2.0); width (20.0 12.0 4.0); vox (4000 120 400); what cellID; } + plotVTK { type vtk; corner (10.0 6.0 2.0); width (20.0 12.0 4.0); vox (4000 120 400); what uniqueID; } bmp ### @@ -609,11 +610,11 @@ bmp * res: (y z), (x z) or (x y) array with the resolution of the mesh in each direction * output: name of the output file, with extension ``.bmp`` * what (*optional*, default = material): defines what is highlighted in the - plot; options are ``material`` and ``cellID`` + plot; options are ``material`` and ``uniqueID`` Example: :: - plotBMP { type bmp; axis z; width (50 10); res (1000 200); output geomZ; what material; } + plotBMP { type bmp; axis z; centre (0.0 0.0 0.0); width (50 10); res (1000 200); output geomZ; what material; } .. note:: SCONE can be run to visualise geometry without actually doing transport, by From 1686b5ba7b5ae4328e2e6abcffeb063fad911545 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 11 Sep 2023 15:48:23 +0100 Subject: [PATCH 020/133] Add details about printSource in User Manual.rst --- docs/User Manual.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 2ae31a1b4..6005b88d9 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -28,7 +28,8 @@ eigenPhysicsPackage, used for criticality (or eigenvalue) calculations * outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. Choices are ``asciiMATLAB`` and ``asciiJSON`` * printSource (*optional*, default = 0): 1 for true; 0 for false; requests - to print the particle source to a text file + to print the particle source (location, direction, energy of each particle + in the particleDungeon) to a text file Example: :: @@ -73,7 +74,8 @@ fixedSourcePhysicsPackage, used for fixed source calculations * outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. Choices are ``asciiMATLAB`` and ``asciiJSON`` * printSource (*optional*, default = 0): 1 for true; 0 for false; requests - to print the particle source to a text file + to print the particle source (location, direction, energy of each particle + in the particleDungeon) to a text file Example: :: From 8650addee936c618cdf9c63e3cc234d73e76cada Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Tue, 12 Sep 2023 15:58:55 +0100 Subject: [PATCH 021/133] Added a fatalError to material map Undefined materials will throw a fatal error. This should help catch any typos before running a whole simulation. Also fixed a few typos in the file. --- Tallies/TallyMaps/materialMap_class.f90 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Tallies/TallyMaps/materialMap_class.f90 b/Tallies/TallyMaps/materialMap_class.f90 index ebca2c3cd..8fe52c283 100644 --- a/Tallies/TallyMaps/materialMap_class.f90 +++ b/Tallies/TallyMaps/materialMap_class.f90 @@ -1,6 +1,7 @@ module materialMap_class use numPrecision + use universalVariables, only : NOT_FOUND use genericProcedures, only : fatalError use dictionary_class, only : dictionary use intMap_class, only : intMap @@ -48,7 +49,7 @@ module materialMap_class integer(shortInt), dimension(:), allocatable :: matIndices contains - ! Superclass interface implementaction + ! Superclass interface implementation procedure :: init procedure :: bins procedure :: map @@ -71,15 +72,15 @@ module materialMap_class !! trackRest [in] -> Logical. For TRUE makes extra bin for all materials not !! explicitly in the map. !! - !! Erorrs: - !! None from here. NuclearDataRegistry should give fatalError if material is given but - !! not defined. + !! Errors: + !! If a material is fed in but not defined a fatal error will be thrown. !! subroutine build(self, materials, trackRest) class(materialMap), intent(inout) :: self character(nameLen), dimension(:), intent(in) :: materials logical(defBool),intent(in) :: trackRest integer(shortInt) :: N, i, matIdx + character(100), parameter :: Here = 'build (materialMap_class.f90)' ! Find number of materials to bin N = size(materials) @@ -91,6 +92,8 @@ subroutine build(self, materials, trackRest) ! Load material indices and bins do i=1,N matIdx = mm_matIdx(materials(i)) + if (matIdx == NOT_FOUND) call fatalError(Here,& + 'Material '//trim(materials(i))//' does not exist in the input materials') call self % binMap % add(matIdx, i) self % matIndices(i) = matIdx @@ -138,7 +141,7 @@ subroutine init(self, dict) call fatalError(Here, undefined//' is an unrecognised entry!') end select - ! Initialise Map + ! Initialise map call self % build(matNames, trackUndefined) end subroutine init From 69590d80be6eaa87ce565a2aac6f0fa9e3909d44 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:54:11 +0100 Subject: [PATCH 022/133] Adding visualiser to fixedSourcePhysicsPackage_class.f90 --- .../fixedSourcePhysicsPackage_class.f90 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index cd200cdb6..35e2ff2d3 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -57,6 +57,9 @@ module fixedSourcePhysicsPackage_class use transportOperatorFactory_func, only : new_transportOperator use sourceFactory_func, only : new_source + ! Visualisation + use visualiser_class, only : visualiser + implicit none private @@ -306,6 +309,7 @@ subroutine init(self, dict) character(:),allocatable :: string character(nameLen) :: nucData, energy, geomName type(outputFile) :: test_out + type(visualiser) :: viz character(100), parameter :: Here ='init (fixedSourcePhysicsPackage_class.f90)' call cpu_time(self % CPU_time_start) @@ -375,6 +379,16 @@ subroutine init(self, dict) call ndReg_activate(self % particleType, nucData, self % geom % activeMats()) self % nucData => ndReg_get(self % particleType) + ! Call visualisation + if (dict % isPresent('viz')) then + print *, "Initialising visualiser" + tempDict => dict % getDictPtr('viz') + call viz % init(self % geom, tempDict) + print *, "Constructing visualisation" + call viz % makeViz() + call viz % kill() + endif + ! Read variance reduction option as a geometry field if (dict % isPresent('varianceReduction')) then ! Build and initialise From d2ca2e41ef697541026c069ac698626b4c880b3b Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 13 Sep 2023 10:57:34 +0100 Subject: [PATCH 023/133] Added a particle source from a specific material Can sample monoenergetic source particles (CE or MG) isotropically from a specified material. Sampling efficiency can be improved (or specific instances of a material can be targeted) by providing a bounding box. --- ParticleObjects/Source/CMakeLists.txt | 1 + .../Source/materialSource_class.f90 | 234 ++++++++++++++++++ ParticleObjects/Source/sourceFactory_func.f90 | 14 +- 3 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 ParticleObjects/Source/materialSource_class.f90 diff --git a/ParticleObjects/Source/CMakeLists.txt b/ParticleObjects/Source/CMakeLists.txt index 601c905be..17a73d167 100644 --- a/ParticleObjects/Source/CMakeLists.txt +++ b/ParticleObjects/Source/CMakeLists.txt @@ -4,4 +4,5 @@ add_sources( source_inter.f90 sourceFactory_func.f90 pointSource_class.f90 fissionSource_class.f90 + materialSource_class.f90 ) diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 new file mode 100644 index 000000000..a2b404a92 --- /dev/null +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -0,0 +1,234 @@ +module materialSource_class + + use numPrecision + use universalVariables, only : OUTSIDE_MAT, VOID_MAT + use genericProcedures, only : fatalError, rotateVector + use dictionary_class, only : dictionary + use RNG_class, only : RNG + use charMap_class, only : charMap + + use particle_class, only : particleState, P_NEUTRON + use source_inter, only : source, kill_super => kill + + use geometry_inter, only : geometry + use neutronMaterial_inter, only : neutronMaterial, neutronMaterial_CptrCast + use nuclearDataReg_mod, only : ndReg_getNeutronCE => getNeutronCE, & + ndReg_getNeutronMG => getNeutronMG + use nuclearDatabase_inter, only : nuclearDatabase + use ceNeutronDatabase_inter, only : ceNeutronDatabase + use mgNeutronDatabase_inter, only : mgNeutronDatabase + + implicit none + private + + !! + !! Neutron Source from a given material + !! + !! Places neutrons uniformly in regions with given material. + !! Angular distribution is isotropic. + !! + !! Can be fed a bounding box to increase sampling efficiency + !! + !! Private members: + !! isMG -> is the source multi-group? (default = .false.) + !! bottom -> Bottom corner (x_min, y_min, z_min) + !! top -> Top corner (x_max, y_max, z_max) + !! E -> Source site energy [MeV] (default = 1.0E-6) + !! G -> Source site Group (default = 1) + !! + !! Interface: + !! source_inter Interface + !! + !! Sample Dictionary Input: + !! matsource { + !! type materialSource; + !! #data MG; # + !! #E 15.0; # + !! #G 7; # + !! #bb (-x -y -z +x +y +z); # + !! } + !! + type, public,extends(source) :: materialSource + private + logical(defBool) :: isMG = .false. + real(defReal), dimension(3) :: bottom = ZERO + real(defReal), dimension(3) :: top = ZERO + real(defReal) :: E = ZERO + integer(shortInt) :: G = 0 + integer(shortInt) :: matIdx = -1 + contains + procedure :: init + procedure :: sampleParticle + procedure :: kill + end type materialSource + +contains + + !! + !! Initialise Material Source + !! + !! See source_inter for details + !! + subroutine init(self, dict, geom) + class(materialSource), intent(inout) :: self + class(dictionary), intent(in) :: dict + class(geometry), pointer, intent(in) :: geom + character(nameLen) :: type + character(nameLen) :: matName + class(nuclearDatabase), pointer :: nucData + class(charMap), pointer :: matMap + real(defReal), dimension(6) :: bounds + real(defReal), dimension(:), allocatable :: tempArray + character(100), parameter :: Here = 'init (materialSource_class.f90)' + + ! Provide geometry info to source + self % geom => geom + + ! Select Energy Type + call dict % getOrDefault(type, 'data', 'ce') + select case(type) + case('ce') + self % isMG = .false. + + case('mg') + self % isMG = .true. + + case default + call fatalError(Here, 'Invalid source data type specified: must be ce or mg') + end select + + ! Select Required fission group/energy + call dict % getOrDefault(self % E, 'E', 1.0E-6_defReal) + call dict % getOrDefault(self % G, 'G', 1) + + ! Determine which material to sample source in + call dict % get(matName, 'mat') + if (self % isMG) then + nucData => ndReg_getNeutronMG() + else + nucData => ndReg_getNeutronCE() + end if + if(.not.associated(nucData)) call fatalError(Here, 'Failed to retrieve Nuclear Database') + matMap => nucData % matNamesMap() + self % matIdx = matMap % get(matName) + + ! Set bounding region + if (dict % isPresent('bb')) then + call dict % get(tempArray, 'bb') + if (size(tempArray) /= 6) call fatalError(Here,& + 'Bounding box must have 6 entries') + self % bottom = tempArray(1:3) + self % top = tempArray(4:6) + + else + bounds = self % geom % bounds() + self % bottom = bounds(1:3) + self % top = bounds(4:6) + end if + + end subroutine init + + !! + !! Sample particle's phase space co-ordinates + !! + !! See source_inter for details + !! + function sampleParticle(self, rand) result(p) + class(materialSource), intent(inout) :: self + class(RNG), intent(inout) :: rand + type(particleState) :: p + class(nuclearDatabase), pointer :: nucData + class(neutronMaterial), pointer :: mat + real(defReal), dimension(3) :: r, rand3 + real(defReal) :: mu, phi + integer(shortInt) :: matIdx, uniqueID, i + character(100), parameter :: Here = 'sampleParticle (materialSource_class.f90)' + + ! Get pointer to approperiate nuclear database + if (self % isMG) then + nucData => ndReg_getNeutronMG() + else + nucData => ndReg_getNeutronCE() + end if + if(.not.associated(nucData)) call fatalError(Here, 'Failed to retrieve Nuclear Database') + + i = 0 + rejection : do + ! Protect against infinite loop + i = i +1 + if ( i > 200) then + call fatalError(Here, 'Infinite loop in sampling source. Please check that'//& + ' defined volume contains source material.') + end if + + ! Sample Position + rand3(1) = rand % get() + rand3(2) = rand % get() + rand3(3) = rand % get() + r = (self % top - self % bottom) * rand3 + self % bottom + + ! Find material under position + call self % geom % whatIsAt(matIdx, uniqueID, r) + + ! Reject if there is no material + if (matIdx == OUTSIDE_MAT) cycle rejection + + mat => neutronMaterial_CptrCast(nucData % getMaterial(matIdx)) + if (.not.associated(mat)) call fatalError(Here, "Nuclear data did not return neutron material.") + + ! Resample position if material is not the specified material + if (.not. (matIdx == self % matIdx)) cycle rejection + + ! Assign basic phase-space coordinates + p % matIdx = matIdx + p % uniqueID = uniqueID + p % wgt = ONE + p % time = ZERO + p % type = P_NEUTRON + p % r = r + + mu = TWO * rand % get() - ONE + phi = TWO_PI * rand % get() + + ! Set Energy + select type (nucData) + class is (ceNeutronDatabase) + + p % E = self % E + p % isMG = .false. + p % dir = rotateVector([ONE, ZERO, ZERO], mu, phi) + + class is (mgNeutronDatabase) + + p % G = self % G + p % isMG = .true. + p % dir = rotateVector([ONE, ZERO, ZERO], mu, phi) + + class default + call fatalError(Here, "Unrecognised type of nuclearDatabase") + + end select + ! Exit the loop + exit rejection + + end do rejection + + end function sampleParticle + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(materialSource), intent(inout) :: self + + call kill_super(self) + + self % isMG = .false. + self % bottom = ZERO + self % top = ZERO + self % E = ZERO + self % G = 0 + + end subroutine kill + +end module materialSource_class diff --git a/ParticleObjects/Source/sourceFactory_func.f90 b/ParticleObjects/Source/sourceFactory_func.f90 index b4e15c429..31694f2d7 100644 --- a/ParticleObjects/Source/sourceFactory_func.f90 +++ b/ParticleObjects/Source/sourceFactory_func.f90 @@ -8,8 +8,9 @@ module sourceFactory_func use source_inter, only : source ! source implementations - use pointSource_class, only : pointSource - use fissionSource_class, only : fissionSource + use pointSource_class, only : pointSource + use fissionSource_class, only : fissionSource + use materialSource_class, only : materialSource ! geometry use geometry_inter, only : geometry @@ -24,8 +25,9 @@ module sourceFactory_func ! It is printed if type was unrecognised ! NOTE: ! For now it is necessary to adjust trailing blanks so all entries have the same length - character(nameLen),dimension(*),parameter :: AVAILABLE_sources = [ 'pointSource ',& - 'fissionSource'] + character(nameLen),dimension(*),parameter :: AVAILABLE_sources = [ 'pointSource ',& + 'fissionSource ',& + 'materialSource'] contains @@ -57,6 +59,10 @@ subroutine new_source(new, dict, geom) allocate(fissionSource :: new) call new % init(dict, geom) + case('materialSource') + allocate(materialSource :: new) + call new % init(dict, geom) + !*** NEW SOURCE TEMPLATE ***! !case('') ! allocate( :: new) From ac3a13684b34d9ece71a701e5cd5f7022ba47804 Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Wed, 13 Sep 2023 12:27:20 +0100 Subject: [PATCH 024/133] Update ParticleObjects/Source/materialSource_class.f90 Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- ParticleObjects/Source/materialSource_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 index a2b404a92..2bf6aa5fe 100644 --- a/ParticleObjects/Source/materialSource_class.f90 +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -34,7 +34,7 @@ module materialSource_class !! bottom -> Bottom corner (x_min, y_min, z_min) !! top -> Top corner (x_max, y_max, z_max) !! E -> Source site energy [MeV] (default = 1.0E-6) - !! G -> Source site Group (default = 1) + !! G -> Source site group (default = 1) !! !! Interface: !! source_inter Interface From a159fab1937538dd44eb7e27c6c63513181906b2 Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Wed, 13 Sep 2023 12:29:14 +0100 Subject: [PATCH 025/133] Update ParticleObjects/Source/materialSource_class.f90 Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- ParticleObjects/Source/materialSource_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 index 2bf6aa5fe..713643b8f 100644 --- a/ParticleObjects/Source/materialSource_class.f90 +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -84,7 +84,7 @@ subroutine init(self, dict, geom) ! Provide geometry info to source self % geom => geom - ! Select Energy Type + ! Select energy type call dict % getOrDefault(type, 'data', 'ce') select case(type) case('ce') From 0a6448dcbbaf31e913e5c1f8d85e03341ddcbbce Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Wed, 13 Sep 2023 12:29:36 +0100 Subject: [PATCH 026/133] Update ParticleObjects/Source/materialSource_class.f90 Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- ParticleObjects/Source/materialSource_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 index 713643b8f..135e5801c 100644 --- a/ParticleObjects/Source/materialSource_class.f90 +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -42,7 +42,7 @@ module materialSource_class !! Sample Dictionary Input: !! matsource { !! type materialSource; - !! #data MG; # + !! #data mg; # !! #E 15.0; # !! #G 7; # !! #bb (-x -y -z +x +y +z); # From e5cc8556abe222aefb0ed75c7ed352593a6e48ef Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 13 Sep 2023 13:12:38 +0100 Subject: [PATCH 027/133] Addressing PR with small fixes and manual update --- .../Source/materialSource_class.f90 | 37 +++++++++---------- docs/User Manual.rst | 26 ++++++++++++- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 index 135e5801c..3f508f5aa 100644 --- a/ParticleObjects/Source/materialSource_class.f90 +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -1,7 +1,7 @@ module materialSource_class use numPrecision - use universalVariables, only : OUTSIDE_MAT, VOID_MAT + use universalVariables, only : OUTSIDE_MAT, VOID_MAT, NOT_FOUND use genericProcedures, only : fatalError, rotateVector use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -17,12 +17,13 @@ module materialSource_class use nuclearDatabase_inter, only : nuclearDatabase use ceNeutronDatabase_inter, only : ceNeutronDatabase use mgNeutronDatabase_inter, only : mgNeutronDatabase + use materialMenu_mod, only : mm_matIdx => matIdx implicit none private !! - !! Neutron Source from a given material + !! Neutron source from a given material !! !! Places neutrons uniformly in regions with given material. !! Angular distribution is isotropic. @@ -35,17 +36,19 @@ module materialSource_class !! top -> Top corner (x_max, y_max, z_max) !! E -> Source site energy [MeV] (default = 1.0E-6) !! G -> Source site group (default = 1) + !! matIdx -> Index of chosen material in the nuclear database !! !! Interface: - !! source_inter Interface + !! source_inter interface !! !! Sample Dictionary Input: !! matsource { !! type materialSource; + !! mat myMaterialName; !! #data mg; # !! #E 15.0; # !! #G 7; # - !! #bb (-x -y -z +x +y +z); # + !! #boundingBox (-x -y -z +x +y +z); # !! } !! type, public,extends(source) :: materialSource @@ -75,8 +78,6 @@ subroutine init(self, dict, geom) class(geometry), pointer, intent(in) :: geom character(nameLen) :: type character(nameLen) :: matName - class(nuclearDatabase), pointer :: nucData - class(charMap), pointer :: matMap real(defReal), dimension(6) :: bounds real(defReal), dimension(:), allocatable :: tempArray character(100), parameter :: Here = 'init (materialSource_class.f90)' @@ -97,24 +98,19 @@ subroutine init(self, dict, geom) call fatalError(Here, 'Invalid source data type specified: must be ce or mg') end select - ! Select Required fission group/energy + ! Select required fission group/energy call dict % getOrDefault(self % E, 'E', 1.0E-6_defReal) call dict % getOrDefault(self % G, 'G', 1) ! Determine which material to sample source in call dict % get(matName, 'mat') - if (self % isMG) then - nucData => ndReg_getNeutronMG() - else - nucData => ndReg_getNeutronCE() - end if - if(.not.associated(nucData)) call fatalError(Here, 'Failed to retrieve Nuclear Database') - matMap => nucData % matNamesMap() - self % matIdx = matMap % get(matName) + self % matIdx = mm_matIdx(matName) + if (self % matIdx == NOT_FOUND) call fatalError(Here,& + 'Source material '//trim(matName)//' was not found in the material definitions') ! Set bounding region - if (dict % isPresent('bb')) then - call dict % get(tempArray, 'bb') + if (dict % isPresent('boundingBox')) then + call dict % get(tempArray, 'boundingBox') if (size(tempArray) /= 6) call fatalError(Here,& 'Bounding box must have 6 entries') self % bottom = tempArray(1:3) @@ -144,7 +140,7 @@ function sampleParticle(self, rand) result(p) integer(shortInt) :: matIdx, uniqueID, i character(100), parameter :: Here = 'sampleParticle (materialSource_class.f90)' - ! Get pointer to approperiate nuclear database + ! Get pointer to appropriate nuclear database if (self % isMG) then nucData => ndReg_getNeutronMG() else @@ -161,7 +157,7 @@ function sampleParticle(self, rand) result(p) ' defined volume contains source material.') end if - ! Sample Position + ! Sample position rand3(1) = rand % get() rand3(2) = rand % get() rand3(3) = rand % get() @@ -190,7 +186,7 @@ function sampleParticle(self, rand) result(p) mu = TWO * rand % get() - ONE phi = TWO_PI * rand % get() - ! Set Energy + ! Set energy select type (nucData) class is (ceNeutronDatabase) @@ -228,6 +224,7 @@ elemental subroutine kill(self) self % top = ZERO self % E = ZERO self % G = 0 + self % matIdx = -1 end subroutine kill diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 6cb50fba5..794414613 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -142,7 +142,11 @@ Example: :: Source ------ -For the moment, the only possible external **source** type in SCONE in a point source. +For the moment, the only possible external **source** types in SCONE are point source and material source. + +pointSource +############ + The properties of a point source are: * r: (x y z) vector with the origin position. [cm] @@ -151,7 +155,7 @@ The properties of a point source are: * E or G: emission energy - E: energy of the particles emitted, for continuous energy calculations. [MeV] - - G: energy group of the particles emitted, for multi-group calculations + - G: energy group of the particles emitted, for multi-group calculations. * dir (*optional*, default = isotropic): (u v w) vector with the direction of the source particles @@ -160,6 +164,24 @@ Hence, an input would look like: :: source { type pointSource; r (0.0 1.0 5.2); particle neutron; E 14.1; dir (0.0 1.0 0.0); } +materialSource +############## + +A material source is a particle source which can only be produced in a given material. +It is a type of volumetric source. For the moment it is constrained to neutrons. +The properties of a material source are: + +* matName: the name of the material from which to sample (must be defined in materials). +* data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` or ``mg``. +* E (*optional*, default = 1E-6 MeV): energy of the particles emitted, for continuous energy calculations. [MeV] +* G (*optional*, default = 1): energy group of the particles emitted, for multi-group calculations. +* boundingBox (*optional*, default is the geometry bounding box): (x_min y_min z_min x_max y_max z_max) vector + describing a bounding box to improve sampling efficiency or to localise material sampling to a particular region. + +Hence, an input would look like: :: + + source { type materialSource; data ce; E 2.0; boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } + Transport Operator ------------------ From 46b45f1e9e3eca649be831a568dd9d8d98052f42 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 13 Sep 2023 13:15:37 +0100 Subject: [PATCH 028/133] Last fix to manual --- docs/User Manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 794414613..52457f3fa 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -171,7 +171,7 @@ A material source is a particle source which can only be produced in a given mat It is a type of volumetric source. For the moment it is constrained to neutrons. The properties of a material source are: -* matName: the name of the material from which to sample (must be defined in materials). +* mat: the name of the material from which to sample (must be defined in materials). * data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` or ``mg``. * E (*optional*, default = 1E-6 MeV): energy of the particles emitted, for continuous energy calculations. [MeV] * G (*optional*, default = 1): energy group of the particles emitted, for multi-group calculations. @@ -180,7 +180,7 @@ The properties of a material source are: Hence, an input would look like: :: - source { type materialSource; data ce; E 2.0; boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } + source { type materialSource; mat myMat; data ce; E 2.0; boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } Transport Operator ------------------ From 16b052e67d3bc602a917d9f6057cacf7f3d2aecd Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Wed, 13 Sep 2023 13:19:03 +0100 Subject: [PATCH 029/133] Update docs/User Manual.rst Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- docs/User Manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 52457f3fa..c10bc7752 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -173,7 +173,7 @@ The properties of a material source are: * mat: the name of the material from which to sample (must be defined in materials). * data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` or ``mg``. -* E (*optional*, default = 1E-6 MeV): energy of the particles emitted, for continuous energy calculations. [MeV] +* E (*optional*, default = 1E-6): energy of the particles emitted, for continuous energy calculations. [MeV] * G (*optional*, default = 1): energy group of the particles emitted, for multi-group calculations. * boundingBox (*optional*, default is the geometry bounding box): (x_min y_min z_min x_max y_max z_max) vector describing a bounding box to improve sampling efficiency or to localise material sampling to a particular region. From de06cecf6dfa5bc1ccb68afbcbf572e306dd4ac1 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 13 Sep 2023 13:38:11 +0100 Subject: [PATCH 030/133] Fixes to User Manual line width. --- docs/User Manual.rst | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 52457f3fa..0224d65be 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -142,7 +142,8 @@ Example: :: Source ------ -For the moment, the only possible external **source** types in SCONE are point source and material source. +For the moment, the only possible external **source** types in SCONE are point source +and material source. pointSource ############ @@ -172,15 +173,20 @@ It is a type of volumetric source. For the moment it is constrained to neutrons. The properties of a material source are: * mat: the name of the material from which to sample (must be defined in materials). -* data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` or ``mg``. -* E (*optional*, default = 1E-6 MeV): energy of the particles emitted, for continuous energy calculations. [MeV] -* G (*optional*, default = 1): energy group of the particles emitted, for multi-group calculations. -* boundingBox (*optional*, default is the geometry bounding box): (x_min y_min z_min x_max y_max z_max) vector - describing a bounding box to improve sampling efficiency or to localise material sampling to a particular region. +* data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` + or ``mg``. +* E (*optional*, default = 1E-6 MeV): energy of the particles emitted, for continuous energy + calculations. [MeV] +* G (*optional*, default = 1): energy group of the particles emitted, for multi-group + calculations. +* boundingBox (*optional*, default is the geometry bounding box): + (x_min y_min z_min x_max y_max z_max) vector describing a bounding box to improve sampling + efficiency or to localise material sampling to a particular region. Hence, an input would look like: :: - source { type materialSource; mat myMat; data ce; E 2.0; boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } + source { type materialSource; mat myMat; data ce; E 2.0; + boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } Transport Operator ------------------ From 10cd87f5fdfa7f2b6c1d57a5a1e189499fe062e0 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:55:23 +0100 Subject: [PATCH 031/133] Fix typo in User Manual.rst --- docs/User Manual.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ac3edabe3..c5ff42ee7 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -320,7 +320,7 @@ Example: :: Uniform Fission Sites --------------------- -Weight windows can be used if, inside the collision operator ``CEneutronimp``, the +Uniform Fission Sites can be used if, inside the collision operator ``CEneutronimp``, the keyword ``UFS`` is set to 1. Then, in the input file, one needs to add: :: uniformFissionSites { type uniFissSitesField; map { } *keywords* } From 5f9093716f24d2bfaf1de3f6bb8eadff974c71e9 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:01:01 +0100 Subject: [PATCH 032/133] Fix typos in User Manual.rst --- docs/User Manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index c5ff42ee7..eae5269da 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -293,7 +293,7 @@ Example: :: Weight Windows -------------- -Weight windows can be used if, inside the collision operator ``CEneutronimp``, the +Weight windows can be used if, inside the collision operator ``neutronCEimp``, the keyword ``weightWindows`` is set to 1. Then, in the input file, one needs to add: :: varianceReduction { type weightWindowsField; file ; } @@ -320,7 +320,7 @@ Example: :: Uniform Fission Sites --------------------- -Uniform Fission Sites can be used if, inside the collision operator ``CEneutronimp``, the +Uniform Fission Sites can be used if, inside the collision operator ``neutronCEimp``, the keyword ``UFS`` is set to 1. Then, in the input file, one needs to add: :: uniformFissionSites { type uniFissSitesField; map { } *keywords* } From abfe0948e3ff164ebb0f8f6a7343a0120d41ca54 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 14 Sep 2023 12:19:10 +0100 Subject: [PATCH 033/133] Yet another entry forgotten from User Manual.rst --- docs/User Manual.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index eae5269da..92e9258fa 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -76,6 +76,15 @@ fixedSourcePhysicsPackage, used for fixed source calculations * printSource (*optional*, default = 0): 1 for true; 0 for false; requests to print the particle source (location, direction, energy of each particle in the particleDungeon) to a text file +* buffer (*optional*, default = 50): size of the particle bank used by each + OpenMP thread to store secondary particles +* commonBufferSize (*optional*): if not included, the common buffer is not + used; if included, after each particle history the particles in each + thread-private buffer (or bank, or dungeon) are moved to a buffer + common to all threads to avoid long histories +* bufferShift (*optional*, default = 10): threshold of particles to be + stored in a thread-private buffer, after which particles are shifted to + the common buffer Example: :: @@ -87,6 +96,9 @@ Example: :: seed 2829741; outputFile shield_type11; + buffer 10000; + commonBufferSize 50000; + transportOperator { } collisionOperator { } tally { } From 65a9b2f93b1d007a039339559a8005879ddc9efd Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Thu, 14 Sep 2023 18:46:31 +0100 Subject: [PATCH 034/133] Catches NaN distances in transport operator --- TransportOperator/transportOperatorDT_class.f90 | 8 +++----- TransportOperator/transportOperatorHT_class.f90 | 7 +++++++ TransportOperator/transportOperatorST_class.f90 | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 0e1064f1a..ff73c37a4 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -49,6 +49,9 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Get majornat XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) + ! Should never happen! Prevents NaN distances + if (majorant_inv /= majorant_inv) call fatalError(Here, "Majorant is 0") + DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv @@ -74,11 +77,6 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Obtain the local cross-section sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) - ! Protect Against Sillines - !if( sigmaT*majorant_inv < ZERO .or. ONE < sigmaT*majorant_inv) then - ! call fatalError(Here, "TotalXS/MajorantXS is silly: "//numToChar(sigmaT*majorant_inv)) - !end if - ! Roll RNG to determine if the collision is real or virtual ! Exit the loop if the collision is real if (p % pRNG % get() < sigmaT*majorant_inv) exit DTLoop diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index 5a586da39..b7f5c4335 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -94,6 +94,9 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Get majornat XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) + ! Should never happen! Prevents NaN distances + if (majorant_inv /= majorant_inv) call fatalError(Here, "Majorant is 0") + DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv @@ -148,6 +151,10 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) else sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) dist = -log( p % pRNG % get()) / sigmaT + + ! Should never happen! Catches NaN distances + if (dist /= dist) call fatalError(Here, "Distance is NaN") + end if ! Save state before movement diff --git a/TransportOperator/transportOperatorST_class.f90 b/TransportOperator/transportOperatorST_class.f90 index 03ebfb660..c7eb24428 100644 --- a/TransportOperator/transportOperatorST_class.f90 +++ b/TransportOperator/transportOperatorST_class.f90 @@ -65,6 +65,10 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) else sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) dist = -log( p % pRNG % get()) / sigmaT + + ! Should never happen! Catches NaN distances + if (dist /= dist) call fatalError(Here, "Distance is NaN") + end if ! Save state before movement From e00eb7fffc46daaaeb5d2637b7a11b0b92dc5f77 Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Thu, 14 Sep 2023 19:22:02 +0100 Subject: [PATCH 035/133] Polishing Factories --- .../collisionProcessorFactory_func.f90 | 13 ++------ Geometry/Cells/cellFactory_func.f90 | 2 -- Geometry/Surfaces/surfaceFactory_func.f90 | 3 +- Geometry/Universes/universeFactory_func.f90 | 2 -- ParticleObjects/Source/sourceFactory_func.f90 | 13 ++------ .../physicsPackageFactory_func.f90 | 33 ++----------------- .../TallyClerks/tallyClerkFactory_func.f90 | 20 ++--------- .../TallyFilters/tallyFilterFactory_func.f90 | 12 ++----- Tallies/TallyMaps/tallyMap1DFactory_func.f90 | 30 ++++------------- Tallies/TallyMaps/tallyMapFactory_func.f90 | 17 ++++------ .../tallyResponseFactory_func.f90 | 15 ++------- .../transportOperatorFactory_func.f90 | 15 +++------ .../fileOutput/asciiOutputFactory_func.f90 | 2 -- 13 files changed, 37 insertions(+), 140 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 b/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 index 3f190f3a4..83692f38f 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 @@ -17,7 +17,6 @@ module collisionProcessorFactory_func public :: new_collisionProcessor - ! *** ADD NAME OF A NEW COLLISION PROCESSOR HERE ***! ! List that contains all accaptable types of collisionProcessors ! It is printed if type was unrecognised ! NOTE: @@ -45,31 +44,25 @@ subroutine new_collisionProcessor(new,dict) call dict % get(type,'type') ! Allocate approperiate subclass of collisionProcessor - ! *** ADD CASE STATEMENT FOR A NEW COLLISION PROCESSOR BELOW ***! select case(type) case('neutronCEstd') allocate(neutronCEstd :: new) - call new % init(dict) case('neutronCEimp') allocate(neutronCEimp :: new) - call new % init(dict) case('neutronMGstd') allocate(neutronMGstd :: new) - call new % init(dict) - !*** NEW COLLISION PROCESSOR TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict) - ! case default print *, AVALIBLE_collisionProcessors call fatalError(Here, 'Unrecognised type of collisionProcessor: ' // trim(type)) end select + ! Initialise new processor + call new % init(dict) + end subroutine new_collisionProcessor end module collisionProcessorFactory_func diff --git a/Geometry/Cells/cellFactory_func.f90 b/Geometry/Cells/cellFactory_func.f90 index 6975fb824..ea6bcc94e 100644 --- a/Geometry/Cells/cellFactory_func.f90 +++ b/Geometry/Cells/cellFactory_func.f90 @@ -14,7 +14,6 @@ module cellFactory_func implicit none private - ! ** ADD NAME OF NEW CELL TO THE LIST **! ! List that contains acceptable types of cells ! NOTE: It is necessary to adjust trailing blanks so all entries have the same length character(nameLen), dimension(*), parameter :: AVAILABLE_CELL = ['simpleCell'] @@ -49,7 +48,6 @@ function new_cell_ptr(dict, surfs) result(new) call dict % get(type, 'type') ! Allocate approperiate cell - ! ** FOR NEW CELL ADD CASE STATEMENT HERE ** ! select case (type) case ('simpleCell') allocate(simpleCell :: new) diff --git a/Geometry/Surfaces/surfaceFactory_func.f90 b/Geometry/Surfaces/surfaceFactory_func.f90 index 82752cfcb..f1a74a2f8 100644 --- a/Geometry/Surfaces/surfaceFactory_func.f90 +++ b/Geometry/Surfaces/surfaceFactory_func.f90 @@ -19,7 +19,6 @@ module surfaceFactory_func implicit none private - ! ** ADD NAME OF NEW SURFACE TO THE LIST **! ! List that contains all accaptable types of surfaces ! NOTE: It is necessary to adjust trailing blanks so all entries have the same length character(nameLen), dimension(*), parameter :: AVAILABLE_SURFACE = ['xPlane ',& @@ -67,7 +66,6 @@ function new_surface_ptr(dict) result(new) call dict % get(type, 'type') ! Allocate approperiate subclass - ! *** FOR NEW SURFACE ADD CASE STATEMENT HERE ***! select case (type) case ('xPlane', 'yPlane', 'zPlane') allocate (aPlane :: new) @@ -94,6 +92,7 @@ function new_surface_ptr(dict) result(new) print '(A)' , ' AVAILABLE SURFACES: ' print '(A)' , AVAILABLE_SURFACE call fatalError(Here, 'Unrecognised type of a surface: '//trim(type)) + end select ! Initialise surface diff --git a/Geometry/Universes/universeFactory_func.f90 b/Geometry/Universes/universeFactory_func.f90 index 810d20f03..551cc6a23 100644 --- a/Geometry/Universes/universeFactory_func.f90 +++ b/Geometry/Universes/universeFactory_func.f90 @@ -18,7 +18,6 @@ module universeFactory_func implicit none private - ! ** ADD NAME OF NEW UNIVERSE TO THE LIST ! List contains acceptable types of universe ! NOTE: It is necessary to adjust trailing blanks so all entries have the same length character(nameLen), dimension(*), parameter :: AVAILABLE_UNI = ['rootUniverse',& @@ -60,7 +59,6 @@ subroutine new_universe_ptr(ptr, fill, dict, cells, surfs, mats) call dict % get(type, 'type') ! Allocate appropriate universe - ! ** FOR NEW UNIVERSE ADD CASE STATEMENT HERE ** ! select case (type) case ('rootUniverse') allocate(rootUniverse :: ptr) diff --git a/ParticleObjects/Source/sourceFactory_func.f90 b/ParticleObjects/Source/sourceFactory_func.f90 index 31694f2d7..474001979 100644 --- a/ParticleObjects/Source/sourceFactory_func.f90 +++ b/ParticleObjects/Source/sourceFactory_func.f90 @@ -20,7 +20,6 @@ module sourceFactory_func public :: new_source - ! *** ADD NAME OF A NEW SOURCE HERE ***! ! List that contains all accaptable types of sources ! It is printed if type was unrecognised ! NOTE: @@ -49,31 +48,25 @@ subroutine new_source(new, dict, geom) call dict % get(type,'type') ! Allocate approperiate subclass of source - ! *** ADD CASE STATEMENT FOR A NEW SOURCE BELOW ***! select case(type) case('pointSource') allocate(pointSource :: new) - call new % init(dict, geom) case('fissionSource') allocate(fissionSource :: new) - call new % init(dict, geom) case('materialSource') allocate(materialSource :: new) - call new % init(dict, geom) - !*** NEW SOURCE TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict, geom) - ! case default print *, AVAILABLE_sources call fatalError(Here, 'Unrecognised type of source: ' // trim(type)) end select + ! Initialise new source + call new % init(dict, geom) + end subroutine new_source end module sourceFactory_func diff --git a/PhysicsPackages/physicsPackageFactory_func.f90 b/PhysicsPackages/physicsPackageFactory_func.f90 index 9cda76b06..48de37e1c 100644 --- a/PhysicsPackages/physicsPackageFactory_func.f90 +++ b/PhysicsPackages/physicsPackageFactory_func.f90 @@ -20,7 +20,6 @@ module physicsPackageFactory_func implicit none private - ! *** ADD NAME OF A NEW PHYSICS PACKAGE HERE ***! ! List that contains all accaptable types of Physics Packages ! It is printed if type was unrecognised ! NOTE: @@ -51,47 +50,18 @@ function new_physicsPackage(dict) result(new) call dict % get(type,'type') ! Allocate approperiate subclass of physicsPackage - ! *** ADD CASE STATEMENT FOR A PHYSICS PACKAGE BELOW ***! - ! **** AT THE MOMENT ALLOCATE + SELECT TYPE + INIT is very unelegant implementation - ! **** Will have to be improved select case(type) case('eigenPhysicsPackage') - ! Allocate and initialise allocate( eigenPhysicsPackage :: new) - select type(new) - type is (eigenPhysicsPackage) - call new % init(dict) - end select case('fixedSourcePhysicsPackage') - ! Allocate and initialise allocate( fixedSourcePhysicsPackage :: new) - select type(new) - type is (fixedSourcePhysicsPackage) - call new % init(dict) - end select -! -! case('dynamPhysicsPackage') -! ! Allocate and initialise -! allocate( dynamPhysicsPackage :: new) -! select type(new) -! type is (dynamPhysicsPackage) -! call new % init(dict) -! end select - case('vizPhysicsPackage') - ! Allocate and initialise allocate( vizPhysicsPackage :: new) - select type(new) - type is (vizPhysicsPackage) - call new % init(dict) - end select case('rayVolPhysicsPackage') - ! Allocate and initialise allocate( rayVolPhysicsPackage :: new) - call new % init(dict) case default print *, AVAILABLE_physicsPackages @@ -99,6 +69,9 @@ function new_physicsPackage(dict) result(new) end select + ! Initialise new physics package + call new % init(dict) + end function new_physicsPackage !! diff --git a/Tallies/TallyClerks/tallyClerkFactory_func.f90 b/Tallies/TallyClerks/tallyClerkFactory_func.f90 index 7d83e1430..f1277fa47 100644 --- a/Tallies/TallyClerks/tallyClerkFactory_func.f90 +++ b/Tallies/TallyClerks/tallyClerkFactory_func.f90 @@ -24,7 +24,6 @@ module tallyClerkFactory_func public :: new_tallyClerk - ! *** ADD NAME OF A NEW TALLY FILTER HERE ***! ! List that contains all accaptable types of tallyClerks ! It is printed if type was unrecognised ! NOTE: @@ -60,59 +59,46 @@ subroutine new_tallyClerk(new, dict, name) call dict % get(type,'type') ! Allocate approperiate subclass of tallyClerk - ! *** ADD CASE STATEMENT FOR A NEW TALLY MAP BELOW ***! select case(type) case('keffAnalogClerk') allocate(keffAnalogClerk :: new) - call new % init(dict, name) case('keffImplicitClerk') allocate(keffImplicitClerk :: new) - call new % init(dict, name) case('collisionClerk') allocate(collisionClerk :: new) - call new % init(dict, name) case('collisionProbabilityClerk') allocate(collisionProbabilityClerk :: new) - call new % init(dict, name) case('trackClerk') allocate(trackClerk :: new) - call new % init(dict, name) case('simpleFMClerk') allocate(simpleFMClerk :: new) - call new % init(dict, name) case('dancoffBellClerk') allocate(dancoffBellClerk :: new) - call new % init(dict, name) case('shannonEntropyClerk') allocate(shannonEntropyClerk :: new) - call new % init(dict, name) case('centreOfMassClerk') allocate(centreOfMassClerk :: new) - call new % init(dict, name) case('mgXsClerk') allocate(mgXsClerk :: new) - call new % init(dict, name) - !*** NEW TALLY MAP TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict, name) - ! case default print *, AVALIBLE_tallyClerks call fatalError(Here, 'Unrecognised type of tallyClerk: ' // trim(type)) end select + ! Initialise new clerk + call new % init(dict, name) + end subroutine new_tallyClerk end module tallyClerkFactory_func diff --git a/Tallies/TallyFilters/tallyFilterFactory_func.f90 b/Tallies/TallyFilters/tallyFilterFactory_func.f90 index c3075cbd1..567e995be 100644 --- a/Tallies/TallyFilters/tallyFilterFactory_func.f90 +++ b/Tallies/TallyFilters/tallyFilterFactory_func.f90 @@ -17,7 +17,6 @@ module tallyFilterFactory_func public :: new_tallyFilter - ! *** ADD NAME OF A NEW TALLY FILTER HERE ***! ! List that contains all accaptable types of tallyFilters ! It is printed if type was unrecognised ! NOTE: @@ -43,27 +42,22 @@ subroutine new_tallyFilter(new,dict) call dict % get(type,'type') ! Allocate approperiate subclass of tallyFilter - ! *** ADD CASE STATEMENT FOR A NEW TALLY MAP BELOW ***! select case(type) case('energyFilter') allocate(energyFilter :: new) - call new % init(dict) case('testFilter') allocate(testFilter :: new) - call new % init(dict) - !*** NEW TALLY MAP TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict) - ! case default print *, AVALIBLE_tallyFilters call fatalError(Here, 'Unrecognised type of tallyFilter: ' // trim(type)) end select + ! Initialise new filter + call new % init(dict, name) + end subroutine new_tallyFilter end module tallyFilterFactory_func diff --git a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 index 1bcf4f6b9..a3cf50788 100644 --- a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 @@ -32,7 +32,6 @@ module tallyMap1DFactory_func use weightMap_class, only : weightMap use cellMap_class, only : cellMap use testMap_class, only : testMap -! use matXsMap_class, only : matXsMap implicit none private @@ -40,8 +39,6 @@ module tallyMap1DFactory_func public :: new_tallyMap1D public :: new_tallyMap - - ! *** ADD NAME OF A NEW TALLY MAP 1D HERE ***! ! List that contains all accaptable types of tallyMaps1D ! It is printed if type was unrecognised ! NOTE: @@ -51,8 +48,7 @@ module tallyMap1DFactory_func 'materialMap',& 'homogMatMap',& 'weightMap ',& - 'cellMap ',& - 'testMap '] + 'cellMap '] contains @@ -81,48 +77,36 @@ subroutine new_tallyMap1D(new, dict) call dict % get(type,'type') ! Allocate approperiate subclass of tallyMap - ! *** ADD CASE STATEMENT FOR A NEW TALLY MAP BELOW ***! select case(type) case('energyMap') allocate(energyMap :: new) - call new % init(dict) case('spaceMap') allocate(spaceMap :: new) - call new % init(dict) case('materialMap') allocate(materialMap :: new) - call new % init(dict) case('homogMatMap') allocate(homogMatMap :: new) - call new % init(dict) case('weightMap') allocate(weightMap :: new) - call new % init(dict) case('cellMap') allocate(cellMap :: new) - call new % init(dict) case('testMap') allocate(testMap :: new) - call new % init(dict) - !*** NEW TALLY MAP TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict) - ! + case default + print *, AVALIBLE_tallyMaps1D + call fatalError(Here,'Unrecognised type of tallyMap1D : ' // trim(type)) + end select - ! Print error if failed to allocate - if(.not.allocated(new)) then - print *, AVALIBLE_tallyMaps1D - call fatalError(Here,'Unrecognised type of tallyMap1D : ' // trim(type)) - end if + ! Initialise new map + call new % init(dict, name) end subroutine new_tallyMap1D diff --git a/Tallies/TallyMaps/tallyMapFactory_func.f90 b/Tallies/TallyMaps/tallyMapFactory_func.f90 index f433193a2..5eb67f6f2 100644 --- a/Tallies/TallyMaps/tallyMapFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMapFactory_func.f90 @@ -28,8 +28,6 @@ module tallyMapFactory_func public :: new_tallyMap - - ! *** ADD NAME OF A NEW TALLY MAP 1D HERE ***! ! List that contains all accaptable types of tallyMaps1D ! It is printed if type was unrecognised ! NOTE: @@ -73,23 +71,22 @@ subroutine new_tallyMap(new, dict) select case(type) case('multiMap') allocate( multiMap :: new) - call new % init(dict) case('sphericalMap') allocate( sphericalMap :: new) - call new % init(dict) case('cylindricalMap') allocate( cylindricalMap :: new) - call new % init(dict) + + case default + print *, AVALIBLE_tallyMaps1D, AVALIBLE_tallyMaps + call fatalError(Here,' Unrecognised tallyMap : '// trim(type)) end select - end if - ! Print error if failed to build a tallyMap - if(.not.allocated(new)) then - print *, AVALIBLE_tallyMaps1D, AVALIBLE_tallyMaps - call fatalError(Here,' Unrecognised tallyMap : '// trim(type)) + ! Initialise new map + call new % init(dict) + end if end subroutine new_tallyMap diff --git a/Tallies/TallyResponses/tallyResponseFactory_func.f90 b/Tallies/TallyResponses/tallyResponseFactory_func.f90 index 82005b560..117b4c29b 100644 --- a/Tallies/TallyResponses/tallyResponseFactory_func.f90 +++ b/Tallies/TallyResponses/tallyResponseFactory_func.f90 @@ -19,7 +19,6 @@ module tallyResponseFactory_func public :: new_tallyResponse - ! *** ADD NAME OF A NEW TALLY FILTER HERE ***! ! List that contains all accaptable types of tallyResponses ! It is printed if type was unrecognised ! NOTE: @@ -49,39 +48,31 @@ subroutine new_tallyResponse(new,dict) call dict % get(type,'type') ! Allocate approperiate subclass of tallyResponse - ! *** ADD CASE STATEMENT FOR A NEW TALLY MAP BELOW ***! select case(type) case('fluxResponse') allocate(fluxResponse :: new) - call new % init(dict) case('macroResponse') allocate(macroResponse :: new) - call new % init(dict) case('microResponse') allocate(microResponse :: new) - call new % init(dict) case('weightResponse') allocate(weightResponse :: new) - call new % init(dict) case('testResponse') allocate(testResponse :: new) - call new % init(dict) - !*** NEW TALLY MAP TEMPLATE ***! - !case('') - ! allocate( :: new) - ! call new % init(dict) - ! case default print *, AVALIBLE_tallyResponses call fatalError(Here, 'Unrecognised type of tallyResponse: ' // trim(type)) end select + ! Initialise new response + call new % init(dict) + end subroutine new_tallyResponse end module tallyResponseFactory_func diff --git a/TransportOperator/transportOperatorFactory_func.f90 b/TransportOperator/transportOperatorFactory_func.f90 index 67b821f95..a308ee01e 100644 --- a/TransportOperator/transportOperatorFactory_func.f90 +++ b/TransportOperator/transportOperatorFactory_func.f90 @@ -17,15 +17,13 @@ module transportOperatorFactory_func implicit none private - ! *** ADD NAME OF A NEW TRANSPORT OPERATOR HERE ***! ! List that contains all accaptable types of transport operators ! It is printed if type was unrecognised ! NOTE: ! For now it is necessary to adjust trailing blanks so all enteries have the same length character(nameLen),dimension(*),parameter :: AVALIBLE_transportOps = [ 'transportOperatorST', & 'transportOperatorDT', & - 'transportOperatorHT']!, & - ! 'dynamicTranspOperDT'] + 'transportOperatorHT'] public :: new_transportOperator @@ -47,23 +45,15 @@ subroutine new_transportOperator(new, dict) call dict % get(type,'type') ! Allocate approperiate subclass of transportOperator - ! *** ADD CASE STATEMENT FOR A NEW TRANSPORT OPERATOR BELOW ***! select case(type) case('transportOperatorST') allocate( transportOperatorST :: new) - call new % init(dict) case('transportOperatorDT') allocate( transportOperatorDT :: new) - call new % init(dict) case('transportOperatorHT') allocate( transportOperatorHT :: new) - call new % init(dict) - -! case('dynamicTranspOperDT') -! allocate( transportOperatorDynamicDT :: new) -! call new % init(dict, geom) case default print *, AVALIBLE_transportOps @@ -71,6 +61,9 @@ subroutine new_transportOperator(new, dict) end select + ! Initialise new transport operator + call new % init(dict) + end subroutine new_transportOperator diff --git a/UserInterface/fileOutput/asciiOutputFactory_func.f90 b/UserInterface/fileOutput/asciiOutputFactory_func.f90 index 100ab7af7..4ce8a6d4f 100644 --- a/UserInterface/fileOutput/asciiOutputFactory_func.f90 +++ b/UserInterface/fileOutput/asciiOutputFactory_func.f90 @@ -14,7 +14,6 @@ module asciiOutputFactory_func implicit none private - ! *** ADD NAME OF A NEW ASCII OUTPUT HERE ***! ! List that contains all accaptable types of ascii Output printers ! It is printed if type was unrecognised ! NOTE: @@ -36,7 +35,6 @@ function new_asciiOutput(type) result(new) character(100),parameter :: Here = 'new_asciiOutput (asciiOutputFactory_func.f90)' ! Allocate approperiate subclass of asciiOutput - ! *** ADD CASE STATEMENT FOR A NEW ASCII OUTPUT BELOW ***! select case(type) case('asciiMATLAB') allocate(asciiMATLAB :: new) From 5be392033c26025d24a6fe628295d5b121876004 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:25:55 +0100 Subject: [PATCH 036/133] Fix typo tallyFilterFactory_func.f90 --- Tallies/TallyFilters/tallyFilterFactory_func.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tallies/TallyFilters/tallyFilterFactory_func.f90 b/Tallies/TallyFilters/tallyFilterFactory_func.f90 index 567e995be..d45b3d715 100644 --- a/Tallies/TallyFilters/tallyFilterFactory_func.f90 +++ b/Tallies/TallyFilters/tallyFilterFactory_func.f90 @@ -56,7 +56,7 @@ subroutine new_tallyFilter(new,dict) end select ! Initialise new filter - call new % init(dict, name) + call new % init(dict) end subroutine new_tallyFilter From 330a705cd263c7e14a980affe5f71791b95885c0 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:27:57 +0100 Subject: [PATCH 037/133] Fix typo in tallyMap1DFactory_func.f90 --- Tallies/TallyMaps/tallyMap1DFactory_func.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 index a3cf50788..e27540b37 100644 --- a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 @@ -106,7 +106,7 @@ subroutine new_tallyMap1D(new, dict) end select ! Initialise new map - call new % init(dict, name) + call new % init(dict) end subroutine new_tallyMap1D From 4406ff7eeef1e5ffccb79c59c59ba5aa20f5c914 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:40:19 +0100 Subject: [PATCH 038/133] Update tallyMap1DFactory_func.f90 --- Tallies/TallyMaps/tallyMap1DFactory_func.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 index e27540b37..e920085c9 100644 --- a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMap1DFactory_func.f90 @@ -48,7 +48,8 @@ module tallyMap1DFactory_func 'materialMap',& 'homogMatMap',& 'weightMap ',& - 'cellMap '] + 'cellMap ',& + 'testMap '] contains From c6db31344eee9397b43297f2afde9c23a544ff81 Mon Sep 17 00:00:00 2001 From: Anuj Dubey <141957266+anuj-git-coding@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:28:20 +0100 Subject: [PATCH 039/133] Update User Manual.rst Lines 1084-1085 Added grid unstruct and grid predef to examples after discussion. --- docs/User Manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 92e9258fa..d134c64b1 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1081,8 +1081,8 @@ Examples: :: map1 { type energyMap; grid log; min 1.0e-11; max 20.0; N 300; } map2 { type energyMap; grid lin; min 1.0; max 20.0; N 100; } - map3 { type energyMap; bins (1.0E-9 1.0E-8 0.6E-6 0.3 20.0); } - map4 { type energyMap; name casmo12; } + map3 { type energyMap; grid unstruct; bins (1.0E-9 1.0E-8 0.6E-6 0.3 20.0); } + map4 { type energyMap; grid predef; name casmo12; } * homogMatMap (1D map), divides based on the material a particle is in with the possibility of grouping some materials together From f8f0ab4e6c357e9bf064e2781b413347a4e7e3ea Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 20 Sep 2023 17:25:15 +0200 Subject: [PATCH 040/133] Allow '-' '_' characters in SAB ace card name --- scripts/make_ace_lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make_ace_lib.sh b/scripts/make_ace_lib.sh index 68f1dd0d3..7deeceba5 100755 --- a/scripts/make_ace_lib.sh +++ b/scripts/make_ace_lib.sh @@ -58,7 +58,7 @@ do elif [[ $MODE =~ ^SAB$ ]]; then awk -v FILE=$FULL_PATH \ - '/^[[:space:]]*[[:alnum:]]+.[[:digit:]][[:digit:]]t/\ + '/^[[:space:]]*([[:alnum:]]|_|\-)+.[[:digit:]][[:digit:]]t/\ {print $1 "; " NR "; " FILE "; "}' $var >> $OUTNAME else From eefd4a292397b981e6d2ea7c312c031f6a4dc978 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:58:54 +0100 Subject: [PATCH 041/133] Update TransportOperator/transportOperatorDT_class.f90 Co-authored-by: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> --- TransportOperator/transportOperatorDT_class.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index ff73c37a4..7c40249fa 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -49,12 +49,13 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Get majornat XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) - ! Should never happen! Prevents NaN distances - if (majorant_inv /= majorant_inv) call fatalError(Here, "Majorant is 0") + ! Should never happen! Prevents Inf distances + if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv + ! Move partice in the geometry call self % geom % teleport(p % coords, distance) From e217b57fb2eca2dc786e775148e48b03ca87d787 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:00:34 +0100 Subject: [PATCH 042/133] Remove empty space TransportOperator/transportOperatorDT_class.f90 --- TransportOperator/transportOperatorDT_class.f90 | 1 - 1 file changed, 1 deletion(-) diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 7c40249fa..ab959a347 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -55,7 +55,6 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv - ! Move partice in the geometry call self % geom % teleport(p % coords, distance) From 59116ebd36b95b92b2e5e76def7b4d3077283abc Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:01:36 +0100 Subject: [PATCH 043/133] Update distance check in TransportOperator/transportOperatorHT_class.f90 --- TransportOperator/transportOperatorHT_class.f90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index b7f5c4335..fe7e0176c 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -94,9 +94,8 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Get majornat XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) - ! Should never happen! Prevents NaN distances - if (majorant_inv /= majorant_inv) call fatalError(Here, "Majorant is 0") - + ! Should never happen! Prevents Inf distances + if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv From a103687c4e20f933c2ef9c3ec296e40a723b4d5d Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:03:28 +0100 Subject: [PATCH 044/133] Fixing spaces in TransportOperator/transportOperatorHT_class.f90 --- TransportOperator/transportOperatorHT_class.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index fe7e0176c..1bc2390e1 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -96,6 +96,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Should never happen! Prevents Inf distances if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") + DTLoop:do distance = -log( p% pRNG % get() ) * majorant_inv From 58c1719a997f5bef9cac615cf28d375f7e3d9ddf Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Wed, 20 Sep 2023 17:21:33 +0100 Subject: [PATCH 045/133] Adding ecco33 to predef energy grids --- NamedGrids/preDefEnergyGrids.f90 | 36 +++++++++++++++++++++++++++ Tallies/TallyMaps/energyMap_class.f90 | 3 +++ docs/User Manual.rst | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/NamedGrids/preDefEnergyGrids.f90 b/NamedGrids/preDefEnergyGrids.f90 index 94eadd843..ae3167264 100644 --- a/NamedGrids/preDefEnergyGrids.f90 +++ b/NamedGrids/preDefEnergyGrids.f90 @@ -345,6 +345,42 @@ module preDefEnergyGrids 5.80000E-08_defReal,& 1.00000E-11_defReal] +real(defReal),dimension(34),parameter :: ecco33 = [ & + 1.964033E+01_defReal,& + 1.000000E+01_defReal,& + 6.065307E+00_defReal,& + 3.678794E+00_defReal,& + 2.231302E+00_defReal,& + 1.353353E+00_defReal,& + 8.208500E-01_defReal,& + 4.978707E-01_defReal,& + 3.019738E-01_defReal,& + 1.831564E-01_defReal,& + 1.110900E-01_defReal,& + 6.737947E-02_defReal,& + 4.086771E-02_defReal,& + 2.478752E-02_defReal,& + 1.503439E-02_defReal,& + 9.118820E-03_defReal,& + 5.530844E-03_defReal,& + 3.354626E-03_defReal,& + 2.034684E-03_defReal,& + 1.234098E-03_defReal,& + 7.485183E-04_defReal,& + 4.539993E-04_defReal,& + 3.043248E-04_defReal,& + 1.486254E-04_defReal,& + 9.166088E-05_defReal,& + 6.790405E-05_defReal,& + 4.016900E-05_defReal,& + 2.260329E-05_defReal,& + 1.370959E-05_defReal,& + 8.315287E-06_defReal,& + 4.000000E-06_defReal,& + 5.400000E-07_defReal,& + 1.000000E-07_defReal,& + 1.000010E-11_defReal] + real(defReal),dimension(176),parameter :: vitaminj = [ & 1.964000E+01_defReal,& 1.733300E+01_defReal,& diff --git a/Tallies/TallyMaps/energyMap_class.f90 b/Tallies/TallyMaps/energyMap_class.f90 index d13f61273..0700defd6 100644 --- a/Tallies/TallyMaps/energyMap_class.f90 +++ b/Tallies/TallyMaps/energyMap_class.f90 @@ -159,6 +159,9 @@ subroutine build_predef(self, name) case('casmo7') bins = casmo7 + case('ecco33') + bins = ecco33 + case('vitaminj') bins = vitaminj diff --git a/docs/User Manual.rst b/docs/User Manual.rst index d134c64b1..e1512e501 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1075,7 +1075,7 @@ Example: :: - grid: ``predef`` + name: name of the predefined group structure. Options are: ``wims69``, - ``wims172``, ``casmo40``, ``casmo23``, ``casmo12``, ``casmo7``, ``vitaminj`` + ``wims172``, ``casmo40``, ``casmo23``, ``casmo12``, ``casmo7``, ``ecco33``, ``vitaminj`` Examples: :: From 804727a2e2458c34e2f2a379b68940556b1ec13f Mon Sep 17 00:00:00 2001 From: Valeria Raffuzzi Date: Wed, 20 Sep 2023 16:25:49 +0100 Subject: [PATCH 046/133] Fix cache bug and minor changes --- .../aceDatabase/aceNeutronDatabase_class.f90 | 2 +- .../ceNeutronData/ceNeutronMaterial_class.f90 | 4 ++-- ParticleObjects/particle_class.f90 | 10 ++++++++-- Tallies/TallyClerks/keffImplicitClerk_class.f90 | 14 -------------- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 26ac0498d..41d006cde 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -340,7 +340,7 @@ subroutine updateMacroXSs(self, E, matIdx, rand) nucIdx = self % materials(matIdx) % nuclides(i) ! Update if needed - if(cache_nuclideCache(nucIdx) % E_tail /= E) then + if (cache_nuclideCache(nucIdx) % E_tail /= E .or. cache_nuclideCache(nucIdx) % E_tot /= E) then call self % updateMicroXSs(E, nucIdx, rand) end if diff --git a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 index 48221acaf..d80a94b84 100644 --- a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 +++ b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 @@ -187,7 +187,7 @@ subroutine getMacroXSs_byE(self, xss, E, rand) class(RNG), intent(inout) :: rand ! Check Cache and update if needed - if(materialCache(self % matIdx) % E_tail /= E) then + if (materialCache(self % matIdx) % E_tail /= E .or. materialCache(self % matIdx) % E_tot /= E) then call self % data % updateMacroXSs(E, self % matIdx, rand) end if @@ -251,7 +251,7 @@ function sampleNuclide(self, E, rand) result(nucIdx) ! Loop over all nuclides do i=1,size(self % nuclides) nucIdx = self % nuclides(i) - if(E /= nuclideCache(nucIdx) % E_tot) call self % data % updateTotalNucXS(E, nucIdx, rand) + if (E /= nuclideCache(nucIdx) % E_tot) call self % data % updateTotalNucXS(E, nucIdx, rand) xs = xs - nuclideCache(nucIdx) % xss % total * self % dens(i) if(xs < ZERO) return end do diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index a331d2105..47556f487 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -564,7 +564,7 @@ subroutine display_particle(self) state = self call state % display() - print *, self % coords % matIdx + print *, 'Material: ', self % coords % matIdx end subroutine display_particle @@ -672,7 +672,13 @@ end function equal_particleState subroutine display_particleState(self) class(particleState), intent(in) :: self - print *, self % r, self % dir, self % E, self % G, self % isMG, self % wgt, self % time + print*, 'Position: ', self % r + print*, 'Direction: ', self % dir + print*, 'Energy: ', self % E + print*, 'Group: ', self % G + print*, 'isMG: ', self % isMG + print*, 'Weight: ', self % wgt + print*, 'Time: ', self % time end subroutine display_particleState diff --git a/Tallies/TallyClerks/keffImplicitClerk_class.f90 b/Tallies/TallyClerks/keffImplicitClerk_class.f90 index 20411dd2a..d676bc799 100644 --- a/Tallies/TallyClerks/keffImplicitClerk_class.f90 +++ b/Tallies/TallyClerks/keffImplicitClerk_class.f90 @@ -160,25 +160,11 @@ subroutine reportInColl(self, p, xsData, mem) real(defReal) :: s1, s2 character(100), parameter :: Here = 'reportInColl (keffImplicitClerk_class.f90)' - ! Obatin XSs -! select type( mat => xsData % getMaterial( p % matIdx())) -! class is(ceNeutronMaterial) -! call mat % getMacroXSs(xss, p % E, p % pRNG) -! -! class is(mgNeutronMaterial) -! call mat % getMacroXSs(xss, p % G, p % pRNG) -! -! class default -! call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') -! -! end select - ! Obtain XSs mat => neutronMaterial_CptrCast(xsData % getMaterial( p % matIdx())) if(.not.associated(mat)) call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') call mat % getMacroXSs(xss, p) - totalXS = xss % total nuFissXS = xss % nuFission absXS = xss % capture + xss % fission From 0df7422fad1db3078ef691b08822444f7a0ed131 Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Fri, 29 Sep 2023 18:12:22 +0100 Subject: [PATCH 047/133] Update transportOperatorDT_class.f90 Some typos in DT --- TransportOperator/transportOperatorDT_class.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index ab959a347..341fef00a 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -44,9 +44,9 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) class(particleDungeon), intent(inout) :: thisCycle class(particleDungeon), intent(inout) :: nextCycle real(defReal) :: majorant_inv, sigmaT, distance - character(100), parameter :: Here = 'deltaTracking (transportOIperatorDT_class.f90)' + character(100), parameter :: Here = 'deltaTracking (transportOperatorDT_class.f90)' - ! Get majornat XS inverse: 1/Sigma_majorant + ! Get majorant XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) ! Should never happen! Prevents Inf distances @@ -58,7 +58,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Move partice in the geometry call self % geom % teleport(p % coords, distance) - ! If particle has leaked exit + ! If particle has leaked, exit if (p % matIdx() == OUTSIDE_FILL) then p % fate = LEAK_FATE p % isDead = .true. From cc9dcf680a7ccdfa33df9088062c8605044feaa7 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 1 Nov 2023 15:27:26 +0000 Subject: [PATCH 048/133] Fix bug in cutoffs in neutronCEimp_class.f90 --- CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 072e367bb..7f17fc523 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -500,7 +500,10 @@ subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) real(defReal), dimension(3) :: val real(defReal) :: minWgt, maxWgt, avWgt - if (p % E < self % minE) then + if (p % isDead) then + ! Do nothing + + elseif (p % E < self % minE) then p % isDead = .true. ! Weight Windows treatment From f0002251431a7ecfd8a9508712fff0cd021cac66 Mon Sep 17 00:00:00 2001 From: Martin Skretteberg Date: Sat, 18 Nov 2023 15:13:03 +0000 Subject: [PATCH 049/133] Handle virtual collisions --- .../collisionProcessor_inter.f90 | 2 +- CollisionOperator/collisionOperator_class.f90 | 2 +- .../TallyClerks/Tests/collisionClerk_test.f90 | 122 +++++++++++++++++- .../Tests/collisionProbabilityClerk_test.f90 | 12 +- .../Tests/keffImplicitClerk_test.f90 | 4 +- Tallies/TallyClerks/Tests/mgXsClerk_test.f90 | 4 +- .../TallyClerks/Tests/simpleFMClerk_test.f90 | 6 +- Tallies/TallyClerks/collisionClerk_class.f90 | 18 ++- .../collisionProbabilityClerk_class.f90 | 6 +- .../TallyClerks/keffImplicitClerk_class.f90 | 6 +- Tallies/TallyClerks/mgXsClerk_class.f90 | 6 +- Tallies/TallyClerks/simpleFMClerk_class.f90 | 6 +- Tallies/TallyClerks/tallyClerkSlot_class.f90 | 5 +- Tallies/TallyClerks/tallyClerk_inter.f90 | 12 +- Tallies/tallyAdmin_class.f90 | 10 +- .../transportOperatorDT_class.f90 | 15 ++- .../transportOperatorHT_class.f90 | 15 ++- docs/User Manual.rst | 2 + 18 files changed, 209 insertions(+), 44 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 index b19a106b7..5a77a7663 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 @@ -120,7 +120,7 @@ subroutine collide(self, p, tally ,thisCycle, nextCycle) ! Note: the ordering must not be changed between feeding the particle to the tally ! and updating the particle's preCollision state, otherwise this may cause certain ! tallies (e.g., collisionProbability) to return dubious results - call tally % reportInColl(p) + call tally % reportInColl(p, .false.) call p % savePreCollision() ! Choose collision nuclide and general type (Scatter, Capture or Fission) diff --git a/CollisionOperator/collisionOperator_class.f90 b/CollisionOperator/collisionOperator_class.f90 index 07ee57a49..22cfa1b68 100644 --- a/CollisionOperator/collisionOperator_class.f90 +++ b/CollisionOperator/collisionOperator_class.f90 @@ -114,7 +114,7 @@ subroutine collide(self, p, tally, thisCycle, nextCycle) class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle integer(shortInt) :: idx, procType - character(100), parameter :: Here = 'collide ( collisionOperator_class.f90)' + character(100), parameter :: Here = 'collide (collisionOperator_class.f90)' ! Select processing index with ternary expression if(p % isMG) then diff --git a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 index f17c1aec6..210178c8e 100644 --- a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 @@ -207,11 +207,15 @@ subroutine testScoring(this) ! Perform scoring call p % setMatIdx(1) p % w = 0.7_defReal - call clerk % reportInColl(p, nucData, mem) + call clerk % reportInColl(p, nucData, mem, .false.) call p % setMatIdx(6) p % w = 1.3_defReal - call clerk % reportInColl(p, nucData, mem) + call clerk % reportInColl(p, nucData, mem, .false.) + + ! Virtual scoring should not contribute to score in this case + p % w = 1000.3_defReal + call clerk % reportInColl(p, nucData, mem, .true.) call mem % closeCycle(ONE) @@ -240,4 +244,118 @@ subroutine testScoring(this) end subroutine testScoring +@Test(cases=[1,2,3,4,5,6,7,8]) + subroutine testScoringVirtual(this) + class(test_collisionClerk), intent(inout) :: this + logical(defBool) :: hasFilter, hasMap, has2Res + character(:),allocatable :: case + type(collisionClerk) :: clerk + type(scoreMemory) :: mem + type(particle) :: p + type(testNeutronDatabase) :: nucData + type(outputFile) :: outF + type(dictionary) :: filterDict, mapDict, res1Dict, res2Dict, clerkDict + character(nameLen) :: res1Name, res2Name, clerkName + integer(shortInt) :: i + real(defReal) :: res + real(defReal), parameter :: TOL = 1.0E-9 + + ! Copy test settings + hasFilter = this % hasFilter + hasMap = this % hasMap + has2Res = this % has2Res + + ! Build case description + case = 'Vanilla case with: ' + if(hasFilter) case = case // ' Filter ' + if(hasMap) case = case // ' Map ' + if(has2Res) case = case // ' 2nd Response ' + + ! Define filter dictionary + call filterDict % init(3) + call filterDict % store('type','testFilter') + call filterDict % store('minIdx',0) + call filterDict % store('maxIdx',5) + + ! Define Map dictionary + call mapDict % init(2) + call mapDict % store('type','testMap') + call mapDict % store('maxIdx',7) + + ! Define 1st response dictionary and name + res1Name = 'flux' + call res1Dict % init(1) + call res1Dict % store('type','fluxResponse') + + ! Define 2nd response dictionary and name + res2Name ='testResponse' + call res2Dict % init(2) + call res2Dict % store('type','testResponse') + call res2Dict % store('value', 1.3_defReal) + + ! Configure dictionary for the clerk + call clerkDict % init(6) + call clerkDict % store('type','collisionClerk') + call clerkDict % store('handleVirtual', 1) + call clerkDict % store(res1Name, res1Dict) + call clerkDict % store(res2Name, res2Dict) + + ! Store filter or map + if(hasFilter) call clerkDict % store('filter', filterDict) + if(hasMap) call clerkDict % store('map', mapDict) + + ! Store responses used + if(has2Res) then + call clerkDict % store('response', [res1Name, res2Name]) + else + call clerkDict % store('response', [res1Name]) + end if + + ! Build Clerk + clerkName ='myClerk' + call clerk % init(clerkDict, clerkName) + + ! Create score memory + call mem % init(int(clerk % getSize(), longInt) , 1) + call clerk % setMemAddress(1_longInt) + + ! Build nuclear data + call nucData % build(0.3_defReal) + + ! Perform scoring, both virtual and physical should contribute + call p % setMatIdx(1) + p % w = 0.7_defReal + call clerk % reportInColl(p, nucData, mem, .true.) + + call p % setMatIdx(6) + p % w = 1.3_defReal + call clerk % reportInColl(p, nucData, mem, .false.) + + call mem % closeCycle(ONE) + + ! Verify results of scoring + do i=1,size(this % bins) + call mem % getResult(res, this % bins(i)) + @assertEqual(this % results(i), res, TOL, case // 'BIN : ' //numToChar(i) ) + end do + + ! Verify that size of memory returned is correct + @assertEqual(size(this % bins), clerk % getSize(), case // 'Memory size test:') + + ! Verify that output calls are correct + call outF % init('dummyPrinter', fatalErrors = .false.) + call clerk % print (outF, mem) + + @assertTrue(outF % isValid(), case) + + ! Clean up + call nucData % kill() + call clerkDict % kill() + call filterDict % kill() + call mapDict % kill() + call res1Dict % kill() + call res2Dict % kill() + + end subroutine testScoringVirtual + end module collisionClerk_test diff --git a/Tallies/TallyClerks/Tests/collisionProbabilityClerk_test.f90 b/Tallies/TallyClerks/Tests/collisionProbabilityClerk_test.f90 index d9ab608ea..0a26f9194 100644 --- a/Tallies/TallyClerks/Tests/collisionProbabilityClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/collisionProbabilityClerk_test.f90 @@ -101,37 +101,37 @@ subroutine testSimpleUseCase(this) call p % setMatIdx(2) p % w = 0.7 p % preCollision % matIdx = 2 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) ! Particle starts in material 1 and collides in material 2 call p % setMatIdx(2) p % w = 1.1 p % preCollision % matIdx = 1 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) ! Particle starts in material 1 and collides in material 1 call p % setMatIdx(1) p % w = 1.0 p % preCollision % matIdx = 1 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) ! Particle starts in material 2 and collides in material 1 call p % setMatIdx(1) p % w = 1.4 p % preCollision % matIdx = 2 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) ! Particle starts in material 2 and collides in another, unknown material call p % setMatIdx(7) p % w = 1.0 p % preCollision % matIdx = 2 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) ! Particle starts in an unknown material and collides in material 1 call p % setMatIdx(1) p % w = 0.9 p % preCollision % matIdx = 88 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) call this % clerk % reportCycleEnd(pop, mem) ! Close cycle diff --git a/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 b/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 index e4ae0e789..9831fcb96 100644 --- a/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 @@ -83,7 +83,7 @@ subroutine test1CycleBatch(this) !*** Start cycle 1 ! Score implicit reaction rates p % w = 0.7_defReal - call this % clerk % reportInColl(p, this % nucData, mem) + call this % clerk % reportInColl(p, this % nucData, mem, .false.) ! Score analog production p % preCollision % wgt = 0.1_defReal @@ -102,7 +102,7 @@ subroutine test1CycleBatch(this) !*** Start cycle 2 ! Score implicit reaction rates p % w = 0.6_defReal - call this % clerk % reportInColl(p, this % nucData, mem) + call this % clerk % reportInColl(p, this % nucData, mem, .false.) ! Score analog production p % preCollision % wgt = 0.1_defReal diff --git a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 index 5b15dd59b..1dbcec26a 100644 --- a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 @@ -128,7 +128,7 @@ subroutine testScoring_clerk1(this) call pit % detain(p) ! Scoring - call this % clerk_test1 % reportInColl(p, this % nucData, mem) + call this % clerk_test1 % reportInColl(p, this % nucData, mem, .false.) call this % clerk_test1 % reportCycleEnd(pit, mem) p % preCollision % wgt = 0.2_defReal @@ -203,7 +203,7 @@ subroutine testScoring_clerk2(this) call pit % detain(p) ! Scoring - call this % clerk_test2 % reportInColl(p, this % nucData, mem) + call this % clerk_test2 % reportInColl(p, this % nucData, mem, .false.) call this % clerk_test2 % reportCycleEnd(pit, mem) p % preCollision % wgt = 0.2_defReal diff --git a/Tallies/TallyClerks/Tests/simpleFMClerk_test.f90 b/Tallies/TallyClerks/Tests/simpleFMClerk_test.f90 index 97cdce9a1..a937ed15d 100644 --- a/Tallies/TallyClerks/Tests/simpleFMClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/simpleFMClerk_test.f90 @@ -111,17 +111,17 @@ subroutine testSimpleUseCase(this) call p % setMatIdx(2) p % w = 0.7 p % preHistory % matIdx = 2 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) call p % setMatIdx(1) p % w = 1.1 p % preHistory % matIdx = 2 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) call p % setMatIdx(1) p % w = 1.0 p % preHistory % matIdx = 1 - call this % clerk % reportInColl(p, xsData, mem) + call this % clerk % reportInColl(p, xsData, mem, .false.) call this % clerk % reportCycleEnd(pop, mem) diff --git a/Tallies/TallyClerks/collisionClerk_class.f90 b/Tallies/TallyClerks/collisionClerk_class.f90 index 3d9f76bce..dd5dd66df 100644 --- a/Tallies/TallyClerks/collisionClerk_class.f90 +++ b/Tallies/TallyClerks/collisionClerk_class.f90 @@ -59,6 +59,7 @@ module collisionClerk_class ! Useful data integer(shortInt) :: width = 0 + logical(defBool) :: virtual = .false. contains ! Procedures used during build @@ -115,6 +116,9 @@ subroutine init(self, dict, name) ! Set width self % width = size(responseNames) + ! Handle virtual collisions + call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + end subroutine init !! @@ -178,17 +182,26 @@ end function getSize !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(collisionClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual type(particleState) :: state integer(shortInt) :: binIdx, i integer(longInt) :: adrr real(defReal) :: scoreVal, flx character(100), parameter :: Here =' reportInColl (collisionClerk_class.f90)' + ! Calculate flux sample based on physical or virtual collision + if (self % virtual) then + flx = ONE / xsData % getMajorantXS(p) + else + if (virtual) return + flx = ONE / xsData % getTotalMatXS(p, p % matIdx()) + end if + ! Get current particle state state = p @@ -210,9 +223,6 @@ subroutine reportInColl(self, p, xsData, mem) ! Calculate bin address adrr = self % getMemAddress() + self % width * (binIdx -1) - 1 - ! Calculate flux sample 1/totXs - flx = ONE / xsData % getTotalMatXS(p, p % matIdx()) - ! Append all bins do i=1,self % width scoreVal = self % response(i) % get(p, xsData) * p % w *flx diff --git a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 index c56ee5daf..b4b33fd73 100644 --- a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 +++ b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 @@ -168,11 +168,12 @@ end function getSize !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(collisionProbabilityClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase),intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual type(particleState) :: state integer(shortInt) :: sIdx, cIdx integer(longInt) :: addr @@ -180,6 +181,9 @@ subroutine reportInColl(self, p, xsData, mem) class(neutronMaterial), pointer :: mat character(100), parameter :: Here = 'reportInColl (collisionProbabilityClerk_class.f90)' + ! This clerk does not handle virtual scoring yet + if (virtual) return + ! Get material or return if it is not a neutron mat => neutronMaterial_CptrCast( xsData % getMaterial(p % matIdx())) diff --git a/Tallies/TallyClerks/keffImplicitClerk_class.f90 b/Tallies/TallyClerks/keffImplicitClerk_class.f90 index d676bc799..501359270 100644 --- a/Tallies/TallyClerks/keffImplicitClerk_class.f90 +++ b/Tallies/TallyClerks/keffImplicitClerk_class.f90 @@ -149,17 +149,21 @@ end function getSize !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(keffImplicitClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase),intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual type(neutronMacroXSs) :: xss class(neutronMaterial), pointer :: mat real(defReal) :: totalXS, nuFissXS, absXS, flux real(defReal) :: s1, s2 character(100), parameter :: Here = 'reportInColl (keffImplicitClerk_class.f90)' + ! This clerk does not handle virtual scoring yet + if (virtual) return + ! Obtain XSs mat => neutronMaterial_CptrCast(xsData % getMaterial( p % matIdx())) if(.not.associated(mat)) call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 8ef3ad7b3..37673bf2c 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -208,11 +208,12 @@ end function getSize !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(mgXsClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual type(particleState) :: state type(neutronMacroXSs) :: xss class(neutronMaterial), pointer :: mat @@ -221,6 +222,9 @@ subroutine reportInColl(self, p, xsData, mem) integer(longInt) :: addr character(100), parameter :: Here =' reportInColl (mgXsClerk_class.f90)' + ! This clerk does not handle virtual scoring yet + if (virtual) return + ! Get current particle state state = p diff --git a/Tallies/TallyClerks/simpleFMClerk_class.f90 b/Tallies/TallyClerks/simpleFMClerk_class.f90 index 2e037b70f..bade1c62b 100644 --- a/Tallies/TallyClerks/simpleFMClerk_class.f90 +++ b/Tallies/TallyClerks/simpleFMClerk_class.f90 @@ -182,11 +182,12 @@ end subroutine reportCycleStart !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(simpleFMClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase),intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual type(particleState) :: state integer(shortInt) :: sIdx, cIdx integer(longInt) :: addr @@ -194,6 +195,9 @@ subroutine reportInColl(self, p, xsData, mem) class(neutronMaterial), pointer :: mat character(100), parameter :: Here = 'reportInColl simpleFMClear_class.f90' + ! This clerk does not handle virtual scoring yet + if (virtual) return + ! Get material or return if it is not a neutron mat => neutronMaterial_CptrCast( xsData % getMaterial(p % matIdx())) diff --git a/Tallies/TallyClerks/tallyClerkSlot_class.f90 b/Tallies/TallyClerks/tallyClerkSlot_class.f90 index a3082917a..bceba3e1a 100644 --- a/Tallies/TallyClerks/tallyClerkSlot_class.f90 +++ b/Tallies/TallyClerks/tallyClerkSlot_class.f90 @@ -165,14 +165,15 @@ end subroutine setName !! !! See tallyClerk_inter for details !! - subroutine reportInColl(self, p, xsData, mem) + subroutine reportInColl(self, p, xsData, mem, virtual) class(tallyClerkSlot), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual ! Pass call to instance in the slot - call self % slot % reportInColl(p, xsData, mem) + call self % slot % reportInColl(p, xsData, mem, virtual) end subroutine reportInColl diff --git a/Tallies/TallyClerks/tallyClerk_inter.f90 b/Tallies/TallyClerks/tallyClerk_inter.f90 index e73904f66..602fea2cb 100644 --- a/Tallies/TallyClerks/tallyClerk_inter.f90 +++ b/Tallies/TallyClerks/tallyClerk_inter.f90 @@ -216,21 +216,23 @@ end subroutine print !! !! Process incoming collision report !! - !! See tallyAdmin_class for implicit assumptionas about the report. + !! See tallyAdmin_class for implicit assumptions about the report. !! !! Args: - !! p [in] -> Partice - !! xsData [inout]-> Nuclear Database with XSs data - !! mem [inout] -> Score Memory to put results on + !! p [in] -> Partice + !! xsData [inout] -> Nuclear Database with XSs data + !! mem [inout] -> Score Memory to put results on + !! virtual [in] -> Flag indicating virtual collision !! !! Errors: !! Depend on specific Clerk !! - subroutine reportInColl(self,p, xsData, mem) + subroutine reportInColl(self,p, xsData, mem, virtual) class(tallyClerk), intent(inout) :: self class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem + logical(defBool), intent(in) :: virtual character(100),parameter :: Here = 'reportInColl (tallyClerk_inter.f90)' call fatalError(Here,'Report was send to an instance that does not support it.') diff --git a/Tallies/tallyAdmin_class.f90 b/Tallies/tallyAdmin_class.f90 index 067a52c3d..0e35adfdf 100644 --- a/Tallies/tallyAdmin_class.f90 +++ b/Tallies/tallyAdmin_class.f90 @@ -437,21 +437,23 @@ end subroutine print !! Particle is provided just after transition. Before any implicit treatment. !! !! Args: - !! p [in] -> Particle + !! p [in] -> Particle + !! virtual [in] -> Flag indicating virtual collision !! !! Errors: !! None !! - recursive subroutine reportInColl(self, p) + recursive subroutine reportInColl(self, p, virtual) class(tallyAdmin), intent(inout) :: self class(particle), intent(in) :: p + logical(defBool), intent(in) :: virtual integer(shortInt) :: i, idx class(nuclearDatabase),pointer :: xsData character(100), parameter :: Here = "reportInColl (tallyAdmin_class.f90)" ! Call attachment if(associated(self % atch)) then - call reportInColl(self % atch, p) + call reportInColl(self % atch, p, virtual) end if ! Get Data @@ -460,7 +462,7 @@ recursive subroutine reportInColl(self, p) ! Go through all clerks that request the report do i=1,self % inCollClerks % getSize() idx = self % inCollClerks % get(i) - call self % tallyClerks(idx) % reportInColl(p, xsData, self % mem) + call self % tallyClerks(idx) % reportInColl(p, xsData, self % mem, virtual) end do diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 341fef00a..30d4b1e03 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -49,7 +49,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) ! Get majorant XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) - ! Should never happen! Prevents Inf distances + ! Should never happen! Prevents Inf distances if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") DTLoop:do @@ -66,7 +66,10 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Check for void - if( p % matIdx() == VOID_MAT) cycle DTLoop + if(p % matIdx() == VOID_MAT) then + call tally % reportInColl(p, .true.) + cycle DTLoop + end if ! Give error if the particle somehow ended in an undefined material if (p % matIdx() == UNDEF_MAT) then @@ -78,8 +81,12 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual - ! Exit the loop if the collision is real - if (p % pRNG % get() < sigmaT*majorant_inv) exit DTLoop + ! Exit the loop if the collision is real, report collision if virtual + if (p % pRNG % get() < sigmaT*majorant_inv) then + exit DTLoop + else + call tally % reportInColl(p, .true.) + end if end do DTLoop diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index 1bc2390e1..f9cdfc378 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -91,7 +91,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) real(defReal) :: majorant_inv, sigmaT, distance character(100), parameter :: Here = 'deltaTracking (transportOperatorHT_class.f90)' - ! Get majornat XS inverse: 1/Sigma_majorant + ! Get majorant XS inverse: 1/Sigma_majorant majorant_inv = ONE / self % xsData % getMajorantXS(p) ! Should never happen! Prevents Inf distances @@ -111,7 +111,10 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Check for void - if( p % matIdx() == VOID_MAT) cycle DTLoop + if(p % matIdx() == VOID_MAT) then + call tally % reportInColl(p, .true.) + cycle DTLoop + end if ! Give error if the particle somehow ended in an undefined material if (p % matIdx() == UNDEF_MAT) then @@ -123,8 +126,12 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual - ! Exit the loop if the collision is real - if (p % pRNG % get() < sigmaT*majorant_inv) exit DTLoop + ! Exit the loop if the collision is real, report collision if virtual + if (p % pRNG % get() < sigmaT*majorant_inv) then + exit DTLoop + else + call tally % reportInColl(p, .true.) + end if end do DTLoop diff --git a/docs/User Manual.rst b/docs/User Manual.rst index e1512e501..6cd7a315a 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -869,6 +869,8 @@ The **tally clerks** determine which kind of estimator will be used. The options that defines the domains of integration of each tally - filter (*optional*): can filter out particles with certain properties, preventing them from scoring results + - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions + are tallied with a collisionClerk as well as physical collisions * trackClerk From 70f3e3b767993693f7885bfa9fd45734eb15a0f6 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:36:16 +0000 Subject: [PATCH 050/133] Update NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 Co-authored-by: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 53cf0a141..4c7c5f4e9 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -732,7 +732,7 @@ subroutine init_DBRC(self, nucDBRC, nucSet, map) ! Find the nucIdxs of the 0K DBRC nuclides idx0K = nucSet % get(nuc0K) - ! Loop through nucSec to find the nucIdxs of the DBRC nuclides with + ! Loop through nucSet to find the nucIdxs of the DBRC nuclides with ! temperature different from 0K j = nucSet % begin() do while (j /= nucSet % end()) From 0ba7c0b5ecf4804192431d8f12331b65c804a6ea Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:36:33 +0000 Subject: [PATCH 051/133] Update CollisionOperator/scatteringKernels_func.f90 Co-authored-by: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> --- CollisionOperator/scatteringKernels_func.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 7b09d59a6..912aaf5ef 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -303,7 +303,7 @@ subroutine sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) ! Calculate Acceptance Propability P_acc = rel_v / (Y + X) - ! Verigy acceptance condition + ! Verify acceptance condition if (P_acc > r3) then accept = .true. else From db07526076f201b94e0b928c51fd1fa981e00316 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:37:20 +0000 Subject: [PATCH 052/133] Apply suggestions from code review Co-authored-by: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> --- CollisionOperator/scatteringKernels_func.f90 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 912aaf5ef..400424fbe 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -304,11 +304,7 @@ subroutine sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) P_acc = rel_v / (Y + X) ! Verify acceptance condition - if (P_acc > r3) then - accept = .true. - else - accept = .false. - end if + accept = P_acc > r3 end subroutine sample_targetVelocity From b2bf420d2d418b997ccaba580b46b342aba858b8 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:40:34 +0000 Subject: [PATCH 053/133] Update NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 4c7c5f4e9..cc7c4b59a 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -710,9 +710,6 @@ end subroutine init_urr !! !! Checks through all nuclides, creates map with nuclides present and corresponding 0K nuclide !! - !! NOTE: compares the first 5 letters of the ZAID.TT. It would be wrong with isotopes - !! with Z > 99 - !! subroutine init_DBRC(self, nucDBRC, nucSet, map) class(aceNeutronDatabase), intent(inout) :: self character(nameLen), dimension(:), intent(in) :: nucDBRC From 6f3ccde3cebc2f4a88869194cae2252c5b7fd319 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Mon, 20 Nov 2023 17:29:17 +0100 Subject: [PATCH 054/133] Update fissionSource Allows user to specify maximum number of resamples and spatial bounds where to place the particles. --- .../Source/fissionSource_class.f90 | 65 ++++++++++++++----- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/ParticleObjects/Source/fissionSource_class.f90 b/ParticleObjects/Source/fissionSource_class.f90 index 6901c302a..bf3176c54 100644 --- a/ParticleObjects/Source/fissionSource_class.f90 +++ b/ParticleObjects/Source/fissionSource_class.f90 @@ -3,7 +3,8 @@ module fissionSource_class use numPrecision use endfConstants use universalVariables, only : OUTSIDE_MAT, VOID_MAT - use genericProcedures, only : fatalError, rotateVector + use genericProcedures, only : rotateVector, numToChar + use errors_mod, only : fatalError use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -28,17 +29,17 @@ module fissionSource_class !! Neutron Source from distributed fission sites !! !! Places fission sites uniformly in regions with fissile material. - !! Spectrum of the fission neutron is such as if it fission was caused by incdent - !! neutron with CE energy E or MG with group G. + !! Spectrum of the fission neutron is such as if it fission was caused by + !! incident neutron with CE energy E or MG with group G. !! Angular distribution is isotropic. !! !! Private members: - !! isMG -> is the source multi-group? (default = .false.) - !! bottom -> Bottom corner (x_min, y_min, z_min) - !! top -> Top corner (x_max, y_max, z_max) - !! E -> Fission site energy [MeV] (default = 1.0E-6) - !! G -> Fission site Group (default = 1) - !! + !! isMG -> is the source multi-group? (default = .false.) + !! bottom -> Bottom corner (x_min, y_min, z_min) + !! top -> Top corner (x_max, y_max, z_max) + !! E -> Fission site energy [MeV] (default = 1.0E-6) + !! G -> Fission site Group (default = 1) + !! attempts -> Maximum number of attempts to find a fissile material !! Interface: !! source_inter Interface !! @@ -48,6 +49,9 @@ module fissionSource_class !! #data MG; # !! #E 15.0; # !! #G 7; # + !! #attempts 100000; # (default: 10000) + !! #top (1.0 1.0 1.0); # + !! #bottom (0.0 0.0 0.0); # !! } !! type, public,extends(source) :: fissionSource @@ -57,6 +61,7 @@ module fissionSource_class real(defReal), dimension(3) :: top = ZERO real(defReal) :: E = ZERO integer(shortInt) :: G = 0 + integer(shortInt) :: attempts = 10000 contains procedure :: init procedure :: sampleParticle @@ -76,6 +81,7 @@ subroutine init(self, dict, geom) class(geometry), pointer, intent(in) :: geom character(nameLen) :: type real(defReal), dimension(6) :: bounds + real(defReal), allocatable, dimension(:) :: temp character(100), parameter :: Here = 'init (fissionSource_class.f90)' ! Provide geometry info to source @@ -98,10 +104,39 @@ subroutine init(self, dict, geom) call dict % getOrDefault(self % E, 'E', 1.0E-6_defReal) call dict % getOrDefault(self % G, 'G', 1) + ! Load the number of allowed attempts + call dict % getOrDefault(self % attempts, 'attempts', 10000) + + if (self % attempts < 1) then + call fatalError(Here, 'Number of attempts must be greater than 0. Is: ' // numToChar(self % attempts)) + end if + ! Set bounding region - bounds = self % geom % bounds() - self % bottom = bounds(1:3) - self % top = bounds(4:6) + if (dict % isPresent('top') .or. dict % isPresent('bottom')) then + ! Get top and bottom from dictionary + call dict % get(temp, 'top') + if (size(temp) /= 3) then + call fatalError(Here, "Top point must have 3 coordinates.") + end if + self % top = temp + + call dict % get(temp, 'bottom') + if (size(temp) /= 3) then + call fatalError(Here, "Bottom point must have 3 coordinates.") + end if + self % bottom = temp + + ! Check that top and bottom are valid + if (any(self % top < self % bottom)) then + call fatalError(Here, "Top point must have all coordinates greater than bottom point.") + end if + + else ! Get bounds from geometry + bounds = self % geom % bounds() + self % bottom = bounds(1:3) + self % top = bounds(4:6) + end if + end subroutine init @@ -136,9 +171,9 @@ function sampleParticle(self, rand) result(p) rejection : do ! Protect against infinite loop i = i +1 - if ( i > 200) then - call fatalError(Here, 'Infinite loop in sampling of fission sites. Please check that& - & defined volume contains fissile material.') + if (i > self % attempts) then + call fatalError(Here, "Failed to find a fissile material in: "// numToChar(self % attempts) // " attempts.& + & Increase the number of maximum attempts or verify that fissile materials are present.") end if ! Sample Position From 98b99a95a959757f3171f760cc8e29b9d8b15d32 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Mon, 20 Nov 2023 18:39:09 +0100 Subject: [PATCH 055/133] Add manual entry for fissionSource --- docs/User Manual.rst | 70 ++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index c747a05aa..a517dd452 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -25,8 +25,8 @@ eigenPhysicsPackage, used for criticality (or eigenvalue) calculations * XSdata: keyword to the name of the nuclearDataHandle used * seed (*optional*): initial seed for the pseudo random number generator * outputFile (*optional*, default = 'output'): name of the output file -* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. - Choices are ``asciiMATLAB`` and ``asciiJSON`` +* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. + Choices are ``asciiMATLAB`` and ``asciiJSON`` * printSource (*optional*, default = 0): 1 for true; 0 for false; requests to print the particle source (location, direction, energy of each particle in the particleDungeon) to a text file @@ -71,19 +71,19 @@ fixedSourcePhysicsPackage, used for fixed source calculations * XSdata: keyword to the name of the nuclearDataHandle used * seed (*optional*): initial seed for the pseudo random number generator * outputFile (*optional*, default = 'output'): name of the output file -* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. - Choices are ``asciiMATLAB`` and ``asciiJSON`` +* outputFormat (*optional*, default = ``asciiMATLAB``): type of output file. + Choices are ``asciiMATLAB`` and ``asciiJSON`` * printSource (*optional*, default = 0): 1 for true; 0 for false; requests to print the particle source (location, direction, energy of each particle in the particleDungeon) to a text file -* buffer (*optional*, default = 50): size of the particle bank used by each +* buffer (*optional*, default = 50): size of the particle bank used by each OpenMP thread to store secondary particles -* commonBufferSize (*optional*): if not included, the common buffer is not - used; if included, after each particle history the particles in each - thread-private buffer (or bank, or dungeon) are moved to a buffer +* commonBufferSize (*optional*): if not included, the common buffer is not + used; if included, after each particle history the particles in each + thread-private buffer (or bank, or dungeon) are moved to a buffer common to all threads to avoid long histories -* bufferShift (*optional*, default = 10): threshold of particles to be - stored in a thread-private buffer, after which particles are shifted to +* bufferShift (*optional*, default = 10): threshold of particles to be + stored in a thread-private buffer, after which particles are shifted to the common buffer Example: :: @@ -154,7 +154,7 @@ Example: :: Source ------ -For the moment, the only possible external **source** types in SCONE are point source +For the moment, the only possible external **source** types in SCONE are point source and material source. pointSource @@ -185,21 +185,41 @@ It is a type of volumetric source. For the moment it is constrained to neutrons. The properties of a material source are: * mat: the name of the material from which to sample (must be defined in materials). -* data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` +* data (*optional*, default = continuous energy): data type for source particles. Can be ``ce`` or ``mg``. -* E (*optional*, default = 1E-6): energy of the particles emitted, for continuous energy +* E (*optional*, default = 1E-6): energy of the particles emitted, for continuous energy calculations. [MeV] -* G (*optional*, default = 1): energy group of the particles emitted, for multi-group +* G (*optional*, default = 1): energy group of the particles emitted, for multi-group calculations. -* boundingBox (*optional*, default is the geometry bounding box): - (x_min y_min z_min x_max y_max z_max) vector describing a bounding box to improve sampling +* boundingBox (*optional*, default is the geometry bounding box): + (x_min y_min z_min x_max y_max z_max) vector describing a bounding box to improve sampling efficiency or to localise material sampling to a particular region. Hence, an input would look like: :: - source { type materialSource; mat myMat; data ce; E 2.0; + source { type materialSource; mat myMat; data ce; E 2.0; boundingBox (-5.0 -3.0 2.0 5.0 4.0 3.0); } +fissionSource +############# + +A source intended to be used in eigenvalue calculations. It is a type of volumetric source, which +uniformly distributes fission sites in the geometry. The energy spectrum of the fission neutrons +is based on a fixed incident energy provided by the user. The properties of a fission source are: + +* data (*optional*, default='ce'): data type for source particles. Can be ``ce`` + or ``mg``. +* E (*optional*, default=1E-6): energy of the incident neutron causing fission [MeV]. Makes + sense for continuous energy source only. +* G (*optional*, default=1): energy group of the incident neutron causing fission. Makes + sense for multi-group source only. +* attempts (*optional*, default=10000): number of attempts to sample a fission site in a cell + before throwing an error. +* bottom (*optional*): Lower point determining axis-aligned bounding box where to sample points. If + provided ``top`` must also be provided. +* top (*optional*): Upper point determining axis-aligned bounding box where to sample points. If + provided ``bottom`` must also be provided. + Transport Operator ------------------ @@ -638,8 +658,8 @@ vtk * corner: (x y z) array with the corner of the geometry [cm] * width: (x y z) array with the width of the mesh in each direction [cm] * vox: (x y z) array with the number of voxels requested in each direction -* what (*optional*, default = material): defines what is highlighted in the - plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` +* what (*optional*, default = material): defines what is highlighted in the + plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` highlights unique cell IDs Example: :: @@ -655,17 +675,17 @@ bmp with the width of the geometry plotted in each direction [cm] * res: (y z), (x z) or (x y) array with the resolution of the mesh in each direction * output: name of the output file, with extension ``.bmp`` -* what (*optional*, default = material): defines what is highlighted in the - plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` +* what (*optional*, default = material): defines what is highlighted in the + plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` highlights unique cell IDs Example: :: plotBMP { type bmp; axis z; centre (0.0 0.0 0.0); width (50 10); res (1000 200); output geomZ; what material; } - -.. note:: - SCONE can be run to visualise geometry without actually doing transport, by - including ``--plot`` when running the application. In this case the visualiser + +.. note:: + SCONE can be run to visualise geometry without actually doing transport, by + including ``--plot`` when running the application. In this case the visualiser has to be included in the file. Nuclear Data From 93169c34f3cb0d9caca32587e8dcc32f701c8838 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:05:24 +0100 Subject: [PATCH 056/133] Update docs/User Manual.rst Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- docs/User Manual.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index a517dd452..ef2841d4d 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -203,9 +203,10 @@ Hence, an input would look like: :: fissionSource ############# -A source intended to be used in eigenvalue calculations. It is a type of volumetric source, which -uniformly distributes fission sites in the geometry. The energy spectrum of the fission neutrons -is based on a fixed incident energy provided by the user. The properties of a fission source are: +A source intended to initialise eigenvalue calculations. If it is not defined in the input file, it is +used with the default settings. It is a type of volumetric source, which uniformly distributes fission +sites in the geometry. The energy spectrum of the fission neutrons is based on a fixed incident +energy provided by the user. The properties of a fission source are: * data (*optional*, default='ce'): data type for source particles. Can be ``ce`` or ``mg``. From 43b72b12d2cf0be0f539ff16dcfdf7324dbc4cad Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 21 Nov 2023 18:06:15 +0100 Subject: [PATCH 057/133] Fix RTD configuration YAML --- .readthedocs.yaml | 8 ++++++-- docs/requirements-rtd.txt | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 73999c162..3368a5b1a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,10 +1,14 @@ version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.11" + sphinx: configuration: docs/conf.py python: - version: 3.7 install: - - requirements: docs/requirements-rtd.txt \ No newline at end of file + - requirements: docs/requirements-rtd.txt diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt index 8286f44d4..b7a15fb98 100644 --- a/docs/requirements-rtd.txt +++ b/docs/requirements-rtd.txt @@ -1 +1,2 @@ -sphinxcontrib-katex \ No newline at end of file +sphinxcontrib-katex +sphinx-rtd-theme From 13be97b0e5514652ef0de2588a084778544e2c51 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 30 Nov 2023 13:06:04 +0000 Subject: [PATCH 058/133] Adding MGimp processor and maximum number of split per particle --- .../CollisionProcessors/CMakeLists.txt | 5 +- .../collisionProcessorFactory_func.f90 | 8 +- .../collisionProcessor_inter.f90 | 3 +- .../neutronCEimp_class.f90 | 26 +- .../neutronMGimp_class.f90 | 371 ++++++++++++++++++ ParticleObjects/particle_class.f90 | 7 +- SharedModules/universalVariables.f90 | 5 +- 7 files changed, 412 insertions(+), 13 deletions(-) create mode 100644 CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 diff --git a/CollisionOperator/CollisionProcessors/CMakeLists.txt b/CollisionOperator/CollisionProcessors/CMakeLists.txt index ee923a0ed..8b8ab513a 100644 --- a/CollisionOperator/CollisionProcessors/CMakeLists.txt +++ b/CollisionOperator/CollisionProcessors/CMakeLists.txt @@ -2,5 +2,6 @@ add_sources( ./collisionProcessor_inter.f90 ./collisionProcessorFactory_func.f90 ./neutronCEstd_class.f90 - ./neutronCEimp_class.f90 - ./neutronMGstd_class.f90) + ./neutronCEimp_class.f90 + ./neutronMGstd_class.f90 + ./neutronMGimp_class.f90) diff --git a/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 b/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 index 3f190f3a4..0ab4cb681 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessorFactory_func.f90 @@ -11,6 +11,7 @@ module collisionProcessorFactory_func use neutronCEstd_class, only : neutronCEstd use neutronCEimp_class, only : neutronCEimp use neutronMGstd_class, only : neutronMGstd + use neutronMGimp_class, only : neutronMGimp implicit none private @@ -24,7 +25,8 @@ module collisionProcessorFactory_func ! For now it is necessary to adjust trailing blanks so all enteries have the same length character(nameLen),dimension(*),parameter :: AVALIBLE_collisionProcessors = [ 'neutronCEstd',& 'neutronCEimp',& - 'neutronMGstd'] + 'neutronMGstd',& + 'neutronMGimp'] contains @@ -59,6 +61,10 @@ subroutine new_collisionProcessor(new,dict) allocate(neutronMGstd :: new) call new % init(dict) + case('neutronMGimp') + allocate(neutronMGimp :: new) + call new % init(dict) + !*** NEW COLLISION PROCESSOR TEMPLATE ***! !case('') ! allocate( :: new) diff --git a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 index b19a106b7..a6fbc7014 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 @@ -118,8 +118,9 @@ subroutine collide(self, p, tally ,thisCycle, nextCycle) ! Report in-collision & save pre-collison state ! Note: the ordering must not be changed between feeding the particle to the tally - ! and updating the particle's preCollision state, otherwise this may cause certain + ! and updating the particle's preCollision state, otherwise this may cause certain ! tallies (e.g., collisionProbability) to return dubious results + call tally % reportInColl(p) call p % savePreCollision() diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 072e367bb..3e51c7378 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -2,7 +2,7 @@ module neutronCEimp_class use numPrecision use endfConstants - use universalVariables, only : nameUFS, nameWW + use universalVariables, only : nameUFS, nameWW, maxSplit use genericProcedures, only : fatalError, rotateVector, numToChar use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -181,8 +181,8 @@ subroutine init(self, dict) end if if (self % implicitAbsorption) then - if (.not.self % roulette) call fatalError(Here,& - 'Must use Russian roulette when using implicit absorption') + if (.not.self % roulette .and. .not. self % weightWindows) call fatalError(Here,& + 'Must use Russian roulette or weight windows when using implicit absorption') if (.not.self % implicitSites) call fatalError(Here,& 'Must generate fission sites implicitly when using implicit absorption') end if @@ -500,7 +500,10 @@ subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) real(defReal), dimension(3) :: val real(defReal) :: minWgt, maxWgt, avWgt - if (p % E < self % minE) then + if (p % isDead) then + ! Do nothing ! + + elseif (p % E < self % minE) then p % isDead = .true. ! Weight Windows treatment @@ -512,7 +515,7 @@ subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) ! If a particle is outside the WW map and all the weight limits ! are zero nothing happens. NOTE: this holds for positive weights only - if ((p % w > maxWgt) .and. (maxWgt /= ZERO)) then + if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < maxSplit)) then call self % split(p, thisCycle, maxWgt) elseif (p % w < minWgt) then call self % russianRoulette(p, avWgt) @@ -554,19 +557,30 @@ subroutine split(self, p, thisCycle, maxWgt) class(particle), intent(inout) :: p class(particleDungeon), intent(inout) :: thisCycle real(defReal), intent(in) :: maxWgt - integer(shortInt) :: mult, i + integer(shortInt) :: mult, i, splitCount ! This value must be at least 2 mult = ceiling(p % w/maxWgt) + ! Limit maximum split + if (mult > maxSplit - p % splitCount + 1) then + mult = maxSplit - p % splitCount + 1 + end if + ! Decrease weight p % w = p % w/mult + ! Save current particle splitCount + splitCount = p % splitCount + ! Add split particle's to the dungeon do i = 1,mult-1 + p % splitCount = 0 call thisCycle % detain(p) end do + p % splitCount = splitCount + mult + end subroutine split !! diff --git a/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 new file mode 100644 index 000000000..3fa129cc8 --- /dev/null +++ b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 @@ -0,0 +1,371 @@ +module neutronMGimp_class + + use numPrecision + use endfConstants + use universalVariables, only : nameWW, maxSplit + use genericProcedures, only : fatalError, rotateVector, numToChar + use dictionary_class, only : dictionary + use RNG_class, only : RNG + + ! Particle types + use particle_class, only : particle, particleState, printType, P_NEUTRON + use particleDungeon_class, only : particleDungeon + + ! Abstract interface + use collisionProcessor_inter, only : collisionProcessor, collisionData ,init_super => init + + ! Nuclear Data Interface + use nuclearDataReg_mod, only : ndReg_getNeutronMG => getNeutronMG + use nuclearDatabase_inter, only : nuclearDatabase + use mgNeutronDatabase_inter, only : mgNeutronDatabase + use mgNeutronMaterial_inter, only : mgNeutronMaterial, mgNeutronMaterial_CptrCast + use reactionHandle_inter, only : reactionHandle + use multiScatterMG_class, only : multiScatterMG, multiScatterMG_CptrCast + use fissionMG_class, only : fissionMG, fissionMG_TptrCast + + ! Cross section packages + use neutronXsPackages_class, only : neutronMacroXSs + + ! Geometry and fields + use geometryReg_mod, only : gr_fieldIdx => fieldIdx, gr_fieldPtr => fieldPtr + use weightWindowsField_class, only : weightWindowsField, weightWindowsField_TptrCast + + + ! Nuclear Data + !use nuclearData_inter, only : nuclearData + !use perMaterialNuclearDataMG_inter, only : perMaterialNuclearDataMG + + ! Cross-section packages to interface with nuclear data + !use xsMacroSet_class, only : xsMacroSet, xsMacroSet_ptr + + implicit none + private + + !! + !! Standard (default) scalar collision processor for MG neutrons + !! -> Preforms implicit fission site generation + !! -> Preforms analog capture + !! -> Treats fission as capture (only implicit generation of 2nd-ary neutrons) + !! -> Does not create secondary non-neutron projectiles + !! + !! Settings: + !! NONE + !! + !! Sample dictionary input: + !! collProcName { + !! type neutronMGimp; + !! } + !! + type, public, extends(collisionProcessor) :: neutronMGimp + private + class(mgNeutronDatabase), pointer, public :: xsData => null() + class(mgNeutronMaterial), pointer, public :: mat => null() + + ! Variance reduction options + logical(defBool) :: weightWindows + type(weightWindowsField), pointer :: weightWindowsMap + + contains + ! Initialisation procedure + procedure :: init + + ! Implementation of customisable procedures + procedure :: sampleCollision + procedure :: implicit + procedure :: elastic + procedure :: inelastic + procedure :: capture + procedure :: fission + procedure :: cutoffs + + ! Variance reduction procedures + procedure, private :: split + procedure, private :: russianRoulette + + end type neutronMGimp + +contains + + !! + !! Initialise from dictionary + !! + subroutine init(self, dict) + class(neutronMGimp), intent(inout) :: self + class(dictionary), intent(in) :: dict + integer(shortInt) :: idx + character(100), parameter :: Here = 'init (neutronMGimp_class.f90)' + + ! Call superclass + call init_super(self, dict) + + ! Obtain settings for variance reduction + call dict % getOrDefault(self % weightWindows,'weightWindows', .false.) + + ! Sets up the weight windows field + if (self % weightWindows) then + idx = gr_fieldIdx(nameWW) + self % weightWindowsMap => weightWindowsField_TptrCast(gr_fieldPtr(idx)) + end if + + end subroutine init + + !! + !! Samples collision without any implicit treatment + !! + subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + type(neutronMacroXSs) :: macroXSs + real(defReal) :: r + character(100),parameter :: Here =' sampleCollision (neutronMGimp_class.f90)' + + ! Verify that particle is MG neutron + if( .not. p % isMG .or. p % type /= P_NEUTRON) then + call fatalError(Here, 'Supports only MG Neutron. Was given CE '//printType(p % type)) + end if + + ! Verify and load nuclear data pointer + self % xsData => ndReg_getNeutronMG() + if(.not.associated(self % xsData)) call fatalError(Here, "Failed to get active database for MG Neutron") + + ! Get and verify material pointer + self % mat => mgNeutronMaterial_CptrCast( self % xsData % getMaterial( p % matIdx())) + if(.not.associated(self % mat)) call fatalError(Here, "Failed to get MG Neutron Material") + + ! Select Main reaction channel + call self % mat % getMacroXSs(macroXSs, p % G, p % pRNG) + r = p % pRNG % get() + + collDat % MT = macroXSs % invert(r) + + end subroutine sampleCollision + + !! + !! Preform implicit treatment + !! + subroutine implicit(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + type(neutronMacroXSs) :: macroXSs + type(fissionMG),pointer :: fission + type(particleState) :: pTemp + real(defReal),dimension(3) :: r, dir + integer(shortInt) :: G_out, n, i + real(defReal) :: wgt, w0, rand1, mu, phi + real(defReal) :: sig_tot, k_eff, sig_nufiss + character(100),parameter :: Here = 'implicit (neutronMGimp_class.f90)' + + if ( self % mat % isFissile()) then + ! Obtain required data + wgt = p % w ! Current weight + w0 = p % preHistory % wgt ! Starting weight + k_eff = p % k_eff ! k_eff for normalisation + rand1 = p % pRNG % get() ! Random number to sample sites + + call self % mat % getMacroXSs(macroXSs, p % G, p % pRNG) + + sig_tot = macroXSs % total + sig_nuFiss = macroXSs % nuFission + + ! Sample number of fission sites generated + !n = int(wgt * sig_nuFiss/(sig_tot*k_eff) + r1, shortInt) + n = int(abs( (wgt * sig_nuFiss) / (w0 * sig_tot * k_eff)) + rand1, shortInt) + + ! Shortcut if no particles were samples + if (n < 1) return + + ! Get Fission reaction object + fission => fissionMG_TptrCast( self % xsData % getReaction(macroFission, collDat % matIdx)) + if (.not.associated(fission)) call fatalError(Here, 'Failed to getrive fissionMG reaction object') + + ! Store new sites in the next cycle dungeon + wgt = sign(w0, wgt) + r = p % rGlobal() + + do i=1,n + call fission % sampleOut(mu, phi, G_out, p % G, p % pRNG) + dir = rotateVector(p % dirGlobal(), mu, phi) + + ! Copy extra detail from parent particle (i.e. time, flags ect.) + pTemp = p + + ! Overwrite position, direction, energy group and weight + pTemp % r = r + pTemp % dir = dir + pTemp % G = G_out + pTemp % wgt = wgt + + call nextCycle % detain(pTemp) + end do + end if + + end subroutine implicit + + !! + !! Elastic Scattering + !! + subroutine elastic(self, p , collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + + ! Do nothing. Should not be called + + end subroutine elastic + + !! + !! Preform scattering + !! + subroutine inelastic(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + class(multiScatterMG),pointer :: scatter + integer(shortInt) :: G_out ! Post-collision energy group + real(defReal) :: phi ! Azimuthal scatter angle + real(defReal) :: w_mul ! Weight multiplier + character(100),parameter :: Here = "inelastic (neutronMGimp_class.f90)" + + ! Assign MT number + collDat % MT = macroIEscatter + + ! Get Scatter object + scatter => multiScatterMG_CptrCast( self % xsData % getReaction(macroIEscatter, collDat % matIdx)) + if(.not.associated(scatter)) call fatalError(Here, "Failed to get scattering reaction object for MG neutron") + + ! Sample Mu and G_out + call scatter % sampleOut(collDat % muL, phi, G_out, p % G, p % pRNG) + + ! Read scattering multiplicity + w_mul = scatter % production(p % G, G_out) + + ! Update neutron state + p % G = G_out + p % w = p % w * w_mul + call p % rotate(collDat % muL, phi) + + end subroutine inelastic + + !! + !! Preform capture + !! + subroutine capture(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + + p % isDead = .true. + + end subroutine capture + + !! + !! Preform fission + !! + subroutine fission(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + + p % isDead = .true. + + end subroutine fission + + !! + !! Applay cutoffs or post-collision implicit treatment + !! + subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + type(collisionData), intent(inout) :: collDat + class(particleDungeon),intent(inout) :: thisCycle + class(particleDungeon),intent(inout) :: nextCycle + real(defReal), dimension(3) :: val + real(defReal) :: minWgt, maxWgt, avWgt + + if (p % isDead) then + ! Do nothing ! + + ! Weight Windows treatment + elseif (self % weightWindows) then + val = self % weightWindowsMap % at(p) + minWgt = val(1) + maxWgt = val(2) + avWgt = val(3) + + ! If a particle is outside the WW map and all the weight limits + ! are zero nothing happens. NOTE: this holds for positive weights only + if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < maxSplit)) then + call self % split(p, thisCycle, maxWgt) + elseif (p % w < minWgt) then + call self % russianRoulette(p, avWgt) + end if + + end if + + end subroutine cutoffs + + !! + !! Perform Russian roulette on a particle + !! + subroutine russianRoulette(self, p, avWgt) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + real(defReal), intent(in) :: avWgt + + if (p % pRNG % get() < (ONE - p % w/avWgt)) then + p % isDead = .true. + else + p % w = avWgt + end if + + end subroutine russianRoulette + + !! + !! Split particle which has too large a weight + !! + subroutine split(self, p, thisCycle, maxWgt) + class(neutronMGimp), intent(inout) :: self + class(particle), intent(inout) :: p + class(particleDungeon), intent(inout) :: thisCycle + real(defReal), intent(in) :: maxWgt + integer(shortInt) :: mult, i, splitCount + + ! This value must be at least 2 + mult = ceiling(p % w/maxWgt) + + ! Limit maximum split + if (mult > maxSplit - p % splitCount + 1) then + mult = maxSplit - p % splitCount + 1 + end if + + ! Decrease weight + p % w = p % w/mult + + ! Save current particle splitCount + splitCount = p % splitCount + + ! Add split particle's to the dungeon + do i = 1,mult-1 + p % splitCount = 0 + call thisCycle % detain(p) + end do + + p % splitCount = splitCount + mult + + end subroutine split + +end module neutronMGimp_class diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 47556f487..2f1b34fe4 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -54,6 +54,7 @@ module particle_class integer(shortInt) :: matIdx = -1 ! Material index where particle is integer(shortInt) :: cellIdx = -1 ! Cell idx at the lowest coord level integer(shortInt) :: uniqueID = -1 ! Unique id at the lowest coord level + integer(shortInt) :: splitCount = 0 ! Counter of number of splits contains generic :: assignment(=) => fromParticle generic :: operator(.eq.) => equal_particleState @@ -112,7 +113,8 @@ module particle_class ! Particle processing information class(RNG), pointer :: pRNG => null() ! Pointer to RNG associated with the particle real(defReal) :: k_eff ! Value of default keff for implicit source generation - integer(shortInt) :: geomIdx ! Index of the geometry used by the particle + integer(shortInt) :: geomIdx ! Index of the geometry used by the particle + integer(shortInt) :: splitCount = 0 ! Counter of number of splits ! Archived snapshots of previous states type(particleState) :: preHistory @@ -269,6 +271,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % isMG = RHS % isMG LHS % type = RHS % type LHS % time = RHS % time + LHS % splitCount = RHS % splitCount end subroutine particle_fromParticleState @@ -611,6 +614,7 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % matIdx = RHS % coords % matIdx LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() + LHS % splitCount = RHS % splitCount end subroutine particleState_fromParticle @@ -699,6 +703,7 @@ elemental subroutine kill_particleState(self) self % matIdx = -1 self % cellIdx = -1 self % uniqueID = -1 + self % splitCount = 0 end subroutine kill_particleState diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index 9c133c1ee..81239996d 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -78,7 +78,8 @@ module universalVariables real(defReal), parameter :: joulesPerMeV = 1.60218e-13 ! Convert MeV to J ! Global name variables used to define specific geometry or field types - character(nameLen), parameter :: nameUFS = 'uniFissSites' - character(nameLen), parameter :: nameWW = 'WeightWindows' + character(nameLen), parameter :: nameUFS = 'uniFissSites' + character(nameLen), parameter :: nameWW = 'WeightWindows' + integer(shortInt), parameter :: maxSplit = 1000 end module universalVariables From 58f5e9f82fbb328af9d28e437eba0242e385b9ba Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:02:25 +0000 Subject: [PATCH 059/133] Typo in mgxsClerk - only affected transport xs std --- Tallies/TallyClerks/mgXsClerk_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 8ef3ad7b3..eb5ab6eda 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -552,7 +552,7 @@ pure subroutine processRes(self, mem, capt_res, fiss_res, transFL_res, transOS_r ! Store total cross section and flux for this energy group tot(i) = capt_res(1,i) + fiss_res(1,i) + scattXS - totStd(i) = sqrt(capt_res(2,i)**2 + fiss_res(1,i)**2 + scattXSstd**2) + totStd(i) = sqrt(capt_res(2,i)**2 + fiss_res(2,i)**2 + scattXSstd**2) fluxG(i) = flux fluxGstd(i) = fluxStd From 6f3aea5d6429e392eaff4a0a470fabf6e2742fa6 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Tue, 5 Dec 2023 22:02:24 +0000 Subject: [PATCH 060/133] Add xs cache for MG data optimisation --- NuclearData/mgNeutronData/CMakeLists.txt | 1 + .../baseMgNeutronDatabase_class.f90 | 34 ++++++- .../baseMgNeutronMaterial_class.f90 | 1 + .../mgNeutronData/mgNeutronCache_mod.f90 | 92 +++++++++++++++++++ .../mgNeutronData/mgNeutronMaterial_inter.f90 | 25 ++++- 5 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 NuclearData/mgNeutronData/mgNeutronCache_mod.f90 diff --git a/NuclearData/mgNeutronData/CMakeLists.txt b/NuclearData/mgNeutronData/CMakeLists.txt index 04d7a738f..3e3d4aa03 100644 --- a/NuclearData/mgNeutronData/CMakeLists.txt +++ b/NuclearData/mgNeutronData/CMakeLists.txt @@ -1,6 +1,7 @@ # Add source files for compilation add_sources(./mgNeutronMaterial_inter.f90 ./mgNeutronDatabase_inter.f90 + ./mgNeutronCache_mod.f90 ./baseMgNeutron/baseMgNeutronMaterial_class.f90 ./baseMgNeutron/baseMgNeutronDatabase_class.f90) diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 8eac6b846..078c3f2b6 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -20,6 +20,10 @@ module baseMgNeutronDatabase_class ! baseMgNeutron Objects use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial + ! MG NEUTRON CACHE + use mgNeutronCache_mod, only : cache_materialCache => materialCache, & + cache_init => init + implicit none private @@ -108,7 +112,22 @@ function getTotalMatXS(self, p, matIdx) result(xs) integer(shortInt), intent(in) :: matIdx real(defReal) :: xs - xs = self % mats(matIdx) % getTotalXS(p % G, p % pRNG) + associate (matCache => cache_materialCache(matIdx)) + + if (matCache % G_tot /= p % G) then + ! Get cross section + xs = self % mats(matIdx) % getTotalXS(p % G, p % pRNG) + ! Update cache + matCache % xss % total = xs + matCache % G_tot = p % G + + else + ! Retrieve cross section from cache + xs = matCache % xss % total + + end if + + end associate end function getTotalMatXS @@ -164,7 +183,8 @@ function getMaterial(self, matIdx) result(mat) if(matIdx < 1 .or. matIdx > size(self % mats)) then mat => null() else - mat => self % mats(matIdx) + ! Retrieve pointer from cache + mat => cache_materialCache(matIdx) % mat end if end function getMaterial @@ -328,6 +348,16 @@ subroutine activate(self, activeMat) self % majorant(g) = xs end do + ! Initialies cross section cache + call cache_init(size(self % mats)) + + ! Store the material pointer in the material cache + !$omp parallel + do idx = 1,size(self % mats) + cache_materialCache(idx) % mat => self % mats(idx) + end do + !$omp end parallel + end subroutine activate !! diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 index 0fdc1f2d3..dc98bdc35 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 @@ -154,6 +154,7 @@ function getTotalXS(self, G, rand) result(xs) ' Data has only: ' // numToChar(self % nGroups())) xs = ZERO ! Avoid warning end if + xs = self % data(TOTAL_XS, G) end function getTotalXS diff --git a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 new file mode 100644 index 000000000..17d2f441c --- /dev/null +++ b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 @@ -0,0 +1,92 @@ +!! +!! Global Cache for MG Neutron Nuclear Data +!! +!! Any active nuclear database writes XSs to this module. +!! Any material handle reads from this module +!! +!! Public Members: +!! matCache -> Array of cached data for materials +!! majorantCache -> Array of cached data for majorant XS +!! +!! NOTE: +!! Cache arrays are deliberatly not targets. This is becouse there should be no pointers to the +!! cache. Any update call can change energy of any value so it would not be possible that the +!! energy of XSs pointed by pointers would not change silently. +!! +module mgNeutronCache_mod + + use numPrecision + use genericProcedures, only : fatalError, numToChar + use neutronXsPackages_class, only : neutronMacroXSs + use materialHandle_inter, only : materialHandle + + implicit none + private + + !! + !! Structure that contains cached data for each MG Neutron Material + !! + !! Public Members: + !! G_tot -> Energy group of the total XS in xss + !! G_tail -> Energy group of all XSs in xss except total + !! xss -> Cached Cross-Section values + !! + type, public :: cacheMatDat + real(defReal) :: G_tot = ZERO + real(defReal) :: G_tail = ZERO + type(neutronMacroXSs) :: xss + class(materialHandle), pointer :: mat + end type cacheMatDat + + ! MEMBERS OF THE MODULE ARE GIVEN HERE + type(cacheMatDat), dimension(:), allocatable, public :: materialCache + !$omp threadprivate(materialCache) + + ! Public procedures + public :: init + public :: kill + + +contains + + + !! + !! Initialise Cache to given space + !! + !! Args: + !! Nmat [in] -> Number of materials + !! Nmaj [in] -> Optional. Number of majorant Xss (Default = 1) + !! + !! Errors: + !! fatalError if Nmat or Nmaj is not a +ve value + !! + subroutine init(Nmat) + integer(shortInt), intent(in) :: Nmat + character(100),parameter :: Here = 'init (ceNeutronCache_mod.f90)' + + ! Make sure memory is clean + call kill() + + ! Chack the provided data + if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) + + ! Allocate space + ! Need to do in parallel region to allocate each copy + !$omp parallel + allocate(materialCache(Nmat)) + !$omp end parallel + + end subroutine init + + !! + !! Return Cache Module (Singleton) to uninitialised state + !! + subroutine kill() + ! Need to deallocate on all threads + !$omp parallel + if(allocated(materialCache)) deallocate (materialCache) + !$omp end parallel + end subroutine kill + + +end module mgNeutronCache_mod diff --git a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 index bf5a4c5a3..4b8aa0cfa 100644 --- a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 +++ b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 @@ -10,6 +10,9 @@ module mgNeutronMaterial_inter use neutronMaterial_inter, only : neutronMaterial use neutronXsPackages_class, only : neutronMacroXSs + ! MG NEUTRON CACHE + use mgNeutronCache_mod, only : cache_materialCache => materialCache + implicit none private @@ -110,13 +113,25 @@ subroutine getMacroXSs_byP(self, xss, p) class(particle), intent(in) :: p character(100), parameter :: Here = 'getMacroXSs_byP (mgNeutronMateerial_inter.f90)' - if( p % isMG) then - call self % getMacroXSs(xss, p % G, p % pRNG) + if (.not. p % isMG) call fatalError(Here, 'CE particle was given to MG data') + + associate (matCache => cache_materialCache(p % matIdx())) + + if (matCache % G_tail /= p % G) then + ! Get cross sections + call self % getMacroXSs(xss, p % G, p % pRNG) + ! Update cache + matCache % xss = xss + matCache % G_tail = p % G + + else + ! Retrieve cross sections from cache + xss = matCache % xss + + end if - else - call fatalError(Here, 'CE particle was given to MG data') + end associate - end if end subroutine getMacroXSs_byP !! From 98ea65e5c2cb2774e23e45e9e98f37866d24009a Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:51:55 +0000 Subject: [PATCH 061/133] Add check for equal collNumber for particleState in particle_class.f90 --- ParticleObjects/particle_class.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 90f5289b1..efd8d52d1 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -638,6 +638,7 @@ function equal_particleState(LHS,RHS) result(isEqual) isEqual = isEqual .and. LHS % matIdx == RHS % matIdx isEqual = isEqual .and. LHS % cellIdx == RHS % cellIdx isEqual = isEqual .and. LHS % uniqueID == RHS % uniqueID + isEqual = isEqual .and. LHS % collisionN == RHS % collisionN if( LHS % isMG ) then isEqual = isEqual .and. LHS % G == RHS % G From 2deb8cf279c05a9e97e009ecc5dc7c703f9b32e1 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:30:32 +0000 Subject: [PATCH 062/133] Update docs in mgNeutronCache_mod.f90 --- .../mgNeutronData/mgNeutronCache_mod.f90 | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 index 17d2f441c..1a0b2aea2 100644 --- a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 +++ b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 @@ -9,9 +9,13 @@ !! majorantCache -> Array of cached data for majorant XS !! !! NOTE: -!! Cache arrays are deliberatly not targets. This is becouse there should be no pointers to the -!! cache. Any update call can change energy of any value so it would not be possible that the -!! energy of XSs pointed by pointers would not change silently. +!! Cache arrays are deliberatly not targets. This is because there should be no pointers to the +!! cache. Any update call can change energy group of any value so it would not be possible that the +!! energy group of XSs pointed by pointers changed silently. +!! +!! ALSO NOTE: +!! The MG data cache was added to improve parallel scalability. It is still not fully understood +!! why this helps, but it seemed to reduce cache misses largely !! module mgNeutronCache_mod @@ -26,10 +30,14 @@ module mgNeutronCache_mod !! !! Structure that contains cached data for each MG Neutron Material !! + !! Note: the material pointer was included in the cache because it improved parallel performance + !! by avoiding the cache misses occurring when getting the pointer on-the-fly + !! !! Public Members: !! G_tot -> Energy group of the total XS in xss !! G_tail -> Energy group of all XSs in xss except total !! xss -> Cached Cross-Section values + !! mat -> Pointer to MG material !! type, public :: cacheMatDat real(defReal) :: G_tot = ZERO @@ -55,10 +63,9 @@ module mgNeutronCache_mod !! !! Args: !! Nmat [in] -> Number of materials - !! Nmaj [in] -> Optional. Number of majorant Xss (Default = 1) !! !! Errors: - !! fatalError if Nmat or Nmaj is not a +ve value + !! fatalError if Nmat is not a +ve value !! subroutine init(Nmat) integer(shortInt), intent(in) :: Nmat @@ -70,8 +77,7 @@ subroutine init(Nmat) ! Chack the provided data if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) - ! Allocate space - ! Need to do in parallel region to allocate each copy + ! Allocate space. Need to do in parallel to allocate each copy !$omp parallel allocate(materialCache(Nmat)) !$omp end parallel @@ -82,10 +88,12 @@ end subroutine init !! Return Cache Module (Singleton) to uninitialised state !! subroutine kill() + ! Need to deallocate on all threads !$omp parallel if(allocated(materialCache)) deallocate (materialCache) !$omp end parallel + end subroutine kill From 570002301b53bf10afd35bd3524545b8d8185b5c Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:02:25 +0000 Subject: [PATCH 063/133] Typo in mgxsClerk - only affected transport xs std --- Tallies/TallyClerks/mgXsClerk_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 37673bf2c..8de338063 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -556,7 +556,7 @@ pure subroutine processRes(self, mem, capt_res, fiss_res, transFL_res, transOS_r ! Store total cross section and flux for this energy group tot(i) = capt_res(1,i) + fiss_res(1,i) + scattXS - totStd(i) = sqrt(capt_res(2,i)**2 + fiss_res(1,i)**2 + scattXSstd**2) + totStd(i) = sqrt(capt_res(2,i)**2 + fiss_res(2,i)**2 + scattXSstd**2) fluxG(i) = flux fluxGstd(i) = fluxStd From 211ff5f02740cc14ec3e6aa8519e9516a394abd8 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Tue, 5 Dec 2023 22:02:24 +0000 Subject: [PATCH 064/133] Add xs cache for MG data optimisation --- NuclearData/mgNeutronData/CMakeLists.txt | 1 + .../baseMgNeutronDatabase_class.f90 | 34 ++++++- .../baseMgNeutronMaterial_class.f90 | 1 + .../mgNeutronData/mgNeutronCache_mod.f90 | 92 +++++++++++++++++++ .../mgNeutronData/mgNeutronMaterial_inter.f90 | 25 ++++- 5 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 NuclearData/mgNeutronData/mgNeutronCache_mod.f90 diff --git a/NuclearData/mgNeutronData/CMakeLists.txt b/NuclearData/mgNeutronData/CMakeLists.txt index 04d7a738f..3e3d4aa03 100644 --- a/NuclearData/mgNeutronData/CMakeLists.txt +++ b/NuclearData/mgNeutronData/CMakeLists.txt @@ -1,6 +1,7 @@ # Add source files for compilation add_sources(./mgNeutronMaterial_inter.f90 ./mgNeutronDatabase_inter.f90 + ./mgNeutronCache_mod.f90 ./baseMgNeutron/baseMgNeutronMaterial_class.f90 ./baseMgNeutron/baseMgNeutronDatabase_class.f90) diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 8eac6b846..078c3f2b6 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -20,6 +20,10 @@ module baseMgNeutronDatabase_class ! baseMgNeutron Objects use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial + ! MG NEUTRON CACHE + use mgNeutronCache_mod, only : cache_materialCache => materialCache, & + cache_init => init + implicit none private @@ -108,7 +112,22 @@ function getTotalMatXS(self, p, matIdx) result(xs) integer(shortInt), intent(in) :: matIdx real(defReal) :: xs - xs = self % mats(matIdx) % getTotalXS(p % G, p % pRNG) + associate (matCache => cache_materialCache(matIdx)) + + if (matCache % G_tot /= p % G) then + ! Get cross section + xs = self % mats(matIdx) % getTotalXS(p % G, p % pRNG) + ! Update cache + matCache % xss % total = xs + matCache % G_tot = p % G + + else + ! Retrieve cross section from cache + xs = matCache % xss % total + + end if + + end associate end function getTotalMatXS @@ -164,7 +183,8 @@ function getMaterial(self, matIdx) result(mat) if(matIdx < 1 .or. matIdx > size(self % mats)) then mat => null() else - mat => self % mats(matIdx) + ! Retrieve pointer from cache + mat => cache_materialCache(matIdx) % mat end if end function getMaterial @@ -328,6 +348,16 @@ subroutine activate(self, activeMat) self % majorant(g) = xs end do + ! Initialies cross section cache + call cache_init(size(self % mats)) + + ! Store the material pointer in the material cache + !$omp parallel + do idx = 1,size(self % mats) + cache_materialCache(idx) % mat => self % mats(idx) + end do + !$omp end parallel + end subroutine activate !! diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 index 0fdc1f2d3..dc98bdc35 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 @@ -154,6 +154,7 @@ function getTotalXS(self, G, rand) result(xs) ' Data has only: ' // numToChar(self % nGroups())) xs = ZERO ! Avoid warning end if + xs = self % data(TOTAL_XS, G) end function getTotalXS diff --git a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 new file mode 100644 index 000000000..17d2f441c --- /dev/null +++ b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 @@ -0,0 +1,92 @@ +!! +!! Global Cache for MG Neutron Nuclear Data +!! +!! Any active nuclear database writes XSs to this module. +!! Any material handle reads from this module +!! +!! Public Members: +!! matCache -> Array of cached data for materials +!! majorantCache -> Array of cached data for majorant XS +!! +!! NOTE: +!! Cache arrays are deliberatly not targets. This is becouse there should be no pointers to the +!! cache. Any update call can change energy of any value so it would not be possible that the +!! energy of XSs pointed by pointers would not change silently. +!! +module mgNeutronCache_mod + + use numPrecision + use genericProcedures, only : fatalError, numToChar + use neutronXsPackages_class, only : neutronMacroXSs + use materialHandle_inter, only : materialHandle + + implicit none + private + + !! + !! Structure that contains cached data for each MG Neutron Material + !! + !! Public Members: + !! G_tot -> Energy group of the total XS in xss + !! G_tail -> Energy group of all XSs in xss except total + !! xss -> Cached Cross-Section values + !! + type, public :: cacheMatDat + real(defReal) :: G_tot = ZERO + real(defReal) :: G_tail = ZERO + type(neutronMacroXSs) :: xss + class(materialHandle), pointer :: mat + end type cacheMatDat + + ! MEMBERS OF THE MODULE ARE GIVEN HERE + type(cacheMatDat), dimension(:), allocatable, public :: materialCache + !$omp threadprivate(materialCache) + + ! Public procedures + public :: init + public :: kill + + +contains + + + !! + !! Initialise Cache to given space + !! + !! Args: + !! Nmat [in] -> Number of materials + !! Nmaj [in] -> Optional. Number of majorant Xss (Default = 1) + !! + !! Errors: + !! fatalError if Nmat or Nmaj is not a +ve value + !! + subroutine init(Nmat) + integer(shortInt), intent(in) :: Nmat + character(100),parameter :: Here = 'init (ceNeutronCache_mod.f90)' + + ! Make sure memory is clean + call kill() + + ! Chack the provided data + if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) + + ! Allocate space + ! Need to do in parallel region to allocate each copy + !$omp parallel + allocate(materialCache(Nmat)) + !$omp end parallel + + end subroutine init + + !! + !! Return Cache Module (Singleton) to uninitialised state + !! + subroutine kill() + ! Need to deallocate on all threads + !$omp parallel + if(allocated(materialCache)) deallocate (materialCache) + !$omp end parallel + end subroutine kill + + +end module mgNeutronCache_mod diff --git a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 index bf5a4c5a3..4b8aa0cfa 100644 --- a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 +++ b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 @@ -10,6 +10,9 @@ module mgNeutronMaterial_inter use neutronMaterial_inter, only : neutronMaterial use neutronXsPackages_class, only : neutronMacroXSs + ! MG NEUTRON CACHE + use mgNeutronCache_mod, only : cache_materialCache => materialCache + implicit none private @@ -110,13 +113,25 @@ subroutine getMacroXSs_byP(self, xss, p) class(particle), intent(in) :: p character(100), parameter :: Here = 'getMacroXSs_byP (mgNeutronMateerial_inter.f90)' - if( p % isMG) then - call self % getMacroXSs(xss, p % G, p % pRNG) + if (.not. p % isMG) call fatalError(Here, 'CE particle was given to MG data') + + associate (matCache => cache_materialCache(p % matIdx())) + + if (matCache % G_tail /= p % G) then + ! Get cross sections + call self % getMacroXSs(xss, p % G, p % pRNG) + ! Update cache + matCache % xss = xss + matCache % G_tail = p % G + + else + ! Retrieve cross sections from cache + xss = matCache % xss + + end if - else - call fatalError(Here, 'CE particle was given to MG data') + end associate - end if end subroutine getMacroXSs_byP !! From 7a5c199dfde1286147b7cb5824b6e0a4396b11e6 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:30:32 +0000 Subject: [PATCH 065/133] Update docs in mgNeutronCache_mod.f90 --- .../mgNeutronData/mgNeutronCache_mod.f90 | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 index 17d2f441c..1a0b2aea2 100644 --- a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 +++ b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 @@ -9,9 +9,13 @@ !! majorantCache -> Array of cached data for majorant XS !! !! NOTE: -!! Cache arrays are deliberatly not targets. This is becouse there should be no pointers to the -!! cache. Any update call can change energy of any value so it would not be possible that the -!! energy of XSs pointed by pointers would not change silently. +!! Cache arrays are deliberatly not targets. This is because there should be no pointers to the +!! cache. Any update call can change energy group of any value so it would not be possible that the +!! energy group of XSs pointed by pointers changed silently. +!! +!! ALSO NOTE: +!! The MG data cache was added to improve parallel scalability. It is still not fully understood +!! why this helps, but it seemed to reduce cache misses largely !! module mgNeutronCache_mod @@ -26,10 +30,14 @@ module mgNeutronCache_mod !! !! Structure that contains cached data for each MG Neutron Material !! + !! Note: the material pointer was included in the cache because it improved parallel performance + !! by avoiding the cache misses occurring when getting the pointer on-the-fly + !! !! Public Members: !! G_tot -> Energy group of the total XS in xss !! G_tail -> Energy group of all XSs in xss except total !! xss -> Cached Cross-Section values + !! mat -> Pointer to MG material !! type, public :: cacheMatDat real(defReal) :: G_tot = ZERO @@ -55,10 +63,9 @@ module mgNeutronCache_mod !! !! Args: !! Nmat [in] -> Number of materials - !! Nmaj [in] -> Optional. Number of majorant Xss (Default = 1) !! !! Errors: - !! fatalError if Nmat or Nmaj is not a +ve value + !! fatalError if Nmat is not a +ve value !! subroutine init(Nmat) integer(shortInt), intent(in) :: Nmat @@ -70,8 +77,7 @@ subroutine init(Nmat) ! Chack the provided data if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) - ! Allocate space - ! Need to do in parallel region to allocate each copy + ! Allocate space. Need to do in parallel to allocate each copy !$omp parallel allocate(materialCache(Nmat)) !$omp end parallel @@ -82,10 +88,12 @@ end subroutine init !! Return Cache Module (Singleton) to uninitialised state !! subroutine kill() + ! Need to deallocate on all threads !$omp parallel if(allocated(materialCache)) deallocate (materialCache) !$omp end parallel + end subroutine kill From e0a4ab17ba49f8fb01be57cbaf751378179f5f0f Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 14 Dec 2023 13:01:56 +0000 Subject: [PATCH 066/133] Increasing max number of fission source samples --- ParticleObjects/Source/fissionSource_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/Source/fissionSource_class.f90 b/ParticleObjects/Source/fissionSource_class.f90 index 6901c302a..04da3e0e2 100644 --- a/ParticleObjects/Source/fissionSource_class.f90 +++ b/ParticleObjects/Source/fissionSource_class.f90 @@ -136,7 +136,7 @@ function sampleParticle(self, rand) result(p) rejection : do ! Protect against infinite loop i = i +1 - if ( i > 200) then + if ( i > 10000) then call fatalError(Here, 'Infinite loop in sampling of fission sites. Please check that& & defined volume contains fissile material.') end if From 35c95030d56a1b997adda215ca1d13876390436a Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 17 Jan 2024 18:20:47 +0000 Subject: [PATCH 067/133] Adding majorant precalculation for DT --- .../aceDatabase/aceNeutronDatabase_class.f90 | 142 ++++++++++++++++-- .../baseMgNeutronDatabase_class.f90 | 48 ++++-- NuclearData/nuclearDatabase_inter.f90 | 18 ++- .../testNeutronDatabase_class.f90 | 15 ++ PhysicsPackages/eigenPhysicsPackage_class.f90 | 2 +- .../fixedSourcePhysicsPackage_class.f90 | 2 +- .../transportOperatorDT_class.f90 | 33 +++- .../transportOperatorFactory_func.f90 | 7 +- .../transportOperatorHT_class.f90 | 54 ++++--- .../transportOperatorST_class.f90 | 16 +- TransportOperator/transportOperator_inter.f90 | 8 +- 11 files changed, 282 insertions(+), 63 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 496dff341..af13bc421 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -3,7 +3,8 @@ module aceNeutronDatabase_class use numPrecision use endfConstants use universalVariables - use genericProcedures, only : fatalError, numToChar + use genericProcedures, only : fatalError, numToChar, concatenate, quickSort, & + removeDuplicatesSorted, binarySearch use dictionary_class, only : dictionary use RNG_class, only : RNG use charMap_class, only : charMap @@ -60,6 +61,8 @@ module aceNeutronDatabase_class !! nuclides -> array of aceNeutronNuclides with data !! materials -> array of ceNeutronMaterials with data !! Ebounds -> array with bottom (1) and top (2) energy bound + !! majorant -> unionised majorant cross section + !! eGrid -> unionised energy grid !! activeMat -> array of materials present in the geometry !! nucToZaid -> map to link nuclide index to zaid index !! hasUrr -> ures probability tables flag, it's false by default @@ -72,6 +75,8 @@ module aceNeutronDatabase_class type, public, extends(ceNeutronDatabase) :: aceNeutronDatabase type(aceNeutronNuclide),dimension(:),pointer :: nuclides => null() type(ceNeutronMaterial),dimension(:),pointer :: materials => null() + real(defReal), dimension(:), allocatable :: majorant + real(defReal), dimension(:), allocatable :: eGrid real(defReal), dimension(2) :: Ebounds = ZERO integer(shortInt),dimension(:),allocatable :: activeMat @@ -81,16 +86,15 @@ module aceNeutronDatabase_class logical(defBool) :: hasDBRC = .false. contains - ! nuclearData Procedures + ! nuclearDatabase Procedures procedure :: kill procedure :: matNamesMap procedure :: getMaterial procedure :: getNuclide procedure :: getReaction procedure :: init - procedure :: init_urr - procedure :: init_DBRC procedure :: activate + procedure :: initMajorant ! ceNeutronDatabase Procedures procedure :: energyBounds @@ -101,6 +105,10 @@ module aceNeutronDatabase_class procedure :: updateMicroXSs procedure :: getScattMicroMajXS + ! class Procedures + procedure :: init_urr + procedure :: init_DBRC + end type aceNeutronDatabase @@ -328,22 +336,26 @@ subroutine updateMajorantXS(self, E, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E class(RNG), intent(inout) :: rand - integer(shortInt) :: i, matIdx + integer(shortInt) :: idx + real(defReal) :: f + character(100), parameter :: Here = 'updateMajorantXS (aceNeutronDatabase_class.f90)' associate (maj => cache_majorantCache(1) ) maj % E = E - maj % xs = ZERO - do i = 1, size(self % activeMat) - matIdx = self % activeMat(i) + idx = binarySearch(self % eGrid, E) - ! Update if needed - if( cache_materialCache(matIdx) % E_tot /= E) then - call self % updateTotalMatXS(E, matIdx, rand) - end if + if(idx <= 0) then + call fatalError(Here,'Failed to find energy: '//numToChar(E)//& + ' in unionised majorant grid') + end if + + associate(E_top => self % eGrid(idx + 1), E_low => self % eGrid(idx)) + f = (E - E_low) / (E_top - E_low) + end associate + + maj % xs = self % majorant(idx+1) * f + (ONE - f) * self % majorant(idx) - maj % xs = max(maj % xs, cache_materialCache(matIdx) % xss % total) - end do end associate end subroutine updateMajorantXS @@ -771,13 +783,111 @@ subroutine activate(self, activeMat) ! Configure Cache if (self % hasUrr) then - call cache_init(size( self % materials), size(self % nuclides), 1, maxval(self % nucToZaid)) + call cache_init(size(self % materials), size(self % nuclides), 1, maxval(self % nucToZaid)) else - call cache_init(size( self % materials), size(self % nuclides)) + call cache_init(size(self % materials), size(self % nuclides)) end if end subroutine activate + !! + !! Precomputes majorant cross section + !! + !! See nuclearDatabase documentation for details + !! + subroutine initMajorant(self, rand) + class(aceNeutronDatabase), intent(inout) :: self + class(RNG), intent(inout) :: rand + real(defReal), dimension(:), allocatable :: tmpGrid + integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone + type(intMap) :: nucMap + real(defReal) :: E, maj + integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 + + print '(A)', 'Building unionised energy grid' + + ! Initialise energy grid + matIdx = self % activeMat(1) + nucIdx = self % materials(matIdx) % nuclides(1) + tmpGrid = self % nuclides(nucIdx) % eGrid + + ! Add first nuclide to map to indicate it's been added + call nucMap % add(nucIdx, IN_SET) + + ! Loop over active materials + do i = 1, size(self % activeMat) + + ! Get current material index and number of nuclides in that material + matIdx = self % activeMat(i) + nNuc = size(self % materials(matIdx) % nuclides) + + ! Loop over nuclides present in that material + do j = 1, nNuc + + ! Get index and check if it's already been added to the grid + nucIdx = self % materials(matIdx) % nuclides(j) + isDone = nucMap % getOrDefault(nucIdx, NOT_PRESENT) + + ! If it's a new nuclide, add its energy grid to the unionised one + if (isDone /= IN_SET) then + + tmpGrid = concatenate(tmpGrid, self % nuclides(nucIdx) % eGrid) + + ! Sort and remove duplicates + call quickSort(tmpGrid) + tmpGrid = removeDuplicatesSorted(tmpGrid) + + ! Add nuclide to the set + call nucMap % add(nucIdx, IN_SET) + + end if + + end do + end do + + ! Save final grid + self % eGrid = tmpGrid + + print '(A)', 'Unionised energy grid has size: '//numToChar(size(self % eGrid))//& + '. Now building unionised majorant cross section' + + ! Allocate unionised majorant + allocate(self % majorant(size(self % eGrid))) + + ! Loop over all the energies + do i = 1, size(self % eGrid) + + ! Retrieve current energy + E = self % eGrid(i) + + ! Correct for energies higher or lower than the allowed boundaries + if (E < self % EBounds(1)) E = self % EBounds(1) + if (E > self % EBounds(2)) E = self % EBounds(2) + + ! Initialise majorant value for this energy + maj = ZERO + + ! Loop over active materials + do j = 1, size(self % activeMat) + + ! Get material index + matIdx = self % activeMat(j) + + ! Calculate current material cross section and compare + call self % updateTotalMatXS(E, matIdx, rand) + maj = max(maj, cache_materialCache(matIdx) % xss % total) + + end do + + ! Save majorant for this energy + self % majorant(i) = maj + + end do + + print '(A)', 'Unionised majorant cross section completed' + + end subroutine initMajorant + !! !! Cast nuclearDatabase pointer to aceNeutronDatabase type pointer !! diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 078c3f2b6..b7a19ac8f 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -7,6 +7,7 @@ module baseMgNeutronDatabase_class use charMap_class, only : charMap use dictionary_class, only : dictionary use dictParser_func, only : fileToDict + use RNG_class, only : RNG ! Nuclear Data Interfaces use nuclearDatabase_inter, only : nuclearDatabase @@ -70,6 +71,7 @@ module baseMgNeutronDatabase_class procedure :: kill procedure :: init procedure :: activate + procedure :: initMajorant ! Local interface procedure :: nGroups @@ -330,15 +332,41 @@ end subroutine init subroutine activate(self, activeMat) class(baseMgNeutronDatabase), intent(inout) :: self integer(shortInt), dimension(:), intent(in) :: activeMat + integer(shortInt) :: idx + + if(allocated(self % activeMats)) deallocate(self % activeMats) + self % activeMats = activeMat + + ! Initialies cross section cache + call cache_init(size(self % mats)) + + ! Store the material pointer in the material cache + !$omp parallel + do idx = 1,size(self % mats) + cache_materialCache(idx) % mat => self % mats(idx) + end do + !$omp end parallel + + end subroutine activate + + !! + !! Precomputes majorant cross section + !! + !! See nuclearDatabase documentation for details + !! + subroutine initMajorant(self, rand) + class(baseMgNeutronDatabase), intent(inout) :: self + class(RNG), intent(inout) :: rand integer(shortInt) :: g, i, idx real(defReal) :: xs integer(shortInt), parameter :: TOTAL_XS = 1 - if(allocated(self % activeMats)) deallocate(self % activeMats) - self % activeMats = activeMat + print '(A)', 'Building unionised majorant cross section' - ! Precalculate majorant xs for delta tracking + ! Allocate majorant allocate (self % majorant(self % nG)) + + ! Loop over energy groups do g = 1,self % nG xs = ZERO do i = 1,size(self % activeMats) @@ -348,17 +376,9 @@ subroutine activate(self, activeMat) self % majorant(g) = xs end do - ! Initialies cross section cache - call cache_init(size(self % mats)) + print '(A)', 'Unionised majorant cross section completed' - ! Store the material pointer in the material cache - !$omp parallel - do idx = 1,size(self % mats) - cache_materialCache(idx) % mat => self % mats(idx) - end do - !$omp end parallel - - end subroutine activate + end subroutine initMajorant !! !! Return number of energy groups in this database @@ -389,7 +409,7 @@ end function nGroups !! pure function baseMgNeutronDatabase_TptrCast(source) result(ptr) class(nuclearDatabase), pointer, intent(in) :: source - type(baseMgNeutronDatabase), pointer :: ptr + type(baseMgNeutronDatabase), pointer :: ptr select type(source) type is(baseMgNeutronDatabase) diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index 0c123df8d..c4a39352e 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -4,6 +4,7 @@ module nuclearDatabase_inter use dictionary_class, only : dictionary use particle_class, only : particle use charMap_class, only : charMap + use RNG_class, only : RNG ! Nuclear Data Handles use nuclideHandle_inter, only : nuclideHandle @@ -28,6 +29,7 @@ module nuclearDatabase_inter !! getMaterial -> returns a pointer to a material handle for given matIdx !! getNuclide -> returns a pointer to a nuclide handle for given nucIdx !! getReaction -> returns a pointer to a reaction for given matidx or nucIdx and MT number + !! initMajorant -> initialises the majorant cross section for delta tracking !! kill -> return to uninitialised state, clean memory !! type, public,abstract :: nuclearDatabase @@ -41,6 +43,7 @@ module nuclearDatabase_inter procedure(getMaterial), deferred :: getMaterial procedure(getNuclide), deferred :: getNuclide procedure(getReaction), deferred :: getReaction + procedure(initMajorant), deferred :: initMajorant procedure(kill), deferred :: kill end type nuclearDatabase @@ -196,7 +199,7 @@ end function getMaterial !! Allows to retrive an access to nuclide data for all databases types !! If database does not contain nuclides (e.g. MG data) just returns null() pointer !! - !! NOTE: This function can be used to inquire abou the presence of nucIdx in the database! + !! NOTE: This function can be used to inquire about the presence of nucIdx in the database! !! !! Args: !! nucIdx [in] -> nuclide index of required material @@ -225,7 +228,7 @@ end function getNuclide !! if MT < 0 then reaction is associated with material: idx -> matIdx !! if MT > 0 then reaction is associated with nuclide: idx -> nucIdx !! - !! NOTE: This function can be used to enquire abou the presence of data. If the data is + !! NOTE: This function can be used to enquire about the presence of data. If the data is !! not present null() pointer is always returned! !! !! Args: @@ -247,6 +250,17 @@ function getReaction(self, MT, idx) result(reac) class(reactionHandle),pointer :: reac end function getReaction + !! + !! Subroutine that precomputes the majorant cross section to be used by DT + !! + !! NOTE: Assumes that the nuclear database has been initialised and activated + !! + subroutine initMajorant(self, rand) + import :: nuclearDatabase, RNG + class(nuclearDatabase), intent(inout) :: self + class(RNG), intent(inout) :: rand + end subroutine initMajorant + !! !! Return to uninitialised state !! diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index 239f9384f..81f55b0b3 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -4,6 +4,7 @@ module testNeutronDatabase_class use particle_class, only : particle use dictionary_class, only : dictionary use charMap_class, only : charMap + use RNG_class, only : RNG ! Nuclear Data Interfaces use nuclearDatabase_inter, only : nuclearDatabase @@ -51,6 +52,7 @@ module testNeutronDatabase_class procedure :: getMaterial procedure :: getNuclide procedure :: getReaction + procedure :: initMajorant procedure :: kill ! Local Procedures @@ -261,6 +263,19 @@ function getReaction(self, MT, idx) result(reac) end function getReaction + !! + !! Initialise majorant for delta tracking + !! + !! See nuclearDatabase_inter for details + !! + subroutine initMajorant(self, rand) + class(testNeutronDatabase), intent(inout) :: self + class(RNG), intent(inout) :: rand + + ! Does nothing + + end subroutine initMajorant + !! !! Return to uninitialised state !! diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index aa89111c1..ff054afeb 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -490,7 +490,7 @@ subroutine init(self, dict) ! Build transport operator tempDict => dict % getDictPtr('transportOperator') - call new_transportOperator(self % transOp, tempDict) + call new_transportOperator(self % transOp, tempDict, self % particleType, self % pRNG) ! Initialise active & inactive tally Admins tempDict => dict % getDictPtr('inactiveTally') diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 35e2ff2d3..68ad1f8d8 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -406,7 +406,7 @@ subroutine init(self, dict) ! Build transport operator tempDict => dict % getDictPtr('transportOperator') - call new_transportOperator(self % transOp, tempDict) + call new_transportOperator(self % transOp, tempDict, self % particleType, self % pRNG) ! Initialise tally Admin tempDict => dict % getDictPtr('tally') diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 30d4b1e03..2c79b3959 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -9,10 +9,10 @@ module transportOperatorDT_class use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use rng_class, only : rng + use RNG_class, only : RNG ! Superclass - use transportOperator_inter, only : transportOperator + use transportOperator_inter, only : transportOperator, init_super => init ! Geometry interfaces use geometry_inter, only : geometry @@ -22,6 +22,7 @@ module transportOperatorDT_class use tallyAdmin_class, only : tallyAdmin ! Nuclear data interfaces + use nuclearDataReg_mod, only : ndReg_get => get use nuclearDatabase_inter, only : nuclearDatabase implicit none @@ -33,10 +34,15 @@ module transportOperatorDT_class type, public, extends(transportOperator) :: transportOperatorDT contains procedure :: transit => deltaTracking + ! Override procedure + procedure :: init end type transportOperatorDT contains + !! + !! Performs delta tracking until a real collision point is found + !! subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) class(transportOperatorDT), intent(inout) :: self class(particle), intent(inout) :: p @@ -91,7 +97,30 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end do DTLoop call tally % reportTrans(p) + end subroutine deltaTracking + !! + !! Initialise DT transport operator + !! + !! See transportOperator_inter for more details + !! + subroutine init(self, dict, dataType, rand) + class(transportOperatorDT), intent(inout) :: self + class(dictionary), intent(in) :: dict + integer(shortInt), intent(in) :: dataType + class(RNG), intent(inout) :: rand + + ! Initialise superclass + call init_super(self, dict, dataType, rand) + + ! Get nuclear data pointer form the particle + self % xsData => ndReg_get(dataType) + + ! Precompute majorant cross section + call self % xsData % initMajorant(rand) + + end subroutine init + end module transportOperatorDT_class diff --git a/TransportOperator/transportOperatorFactory_func.f90 b/TransportOperator/transportOperatorFactory_func.f90 index a308ee01e..2fe492786 100644 --- a/TransportOperator/transportOperatorFactory_func.f90 +++ b/TransportOperator/transportOperatorFactory_func.f90 @@ -6,6 +6,7 @@ module transportOperatorFactory_func use numPrecision use genericProcedures, only : fatalError use dictionary_class, only : dictionary + use RNG_class, only : RNG ! Transport Operators use transportOperator_inter, only : transportOperator @@ -33,9 +34,11 @@ module transportOperatorFactory_func !! Allocate new allocatable transportOperator to a specific type !! If new is allocated it deallocates it !! - subroutine new_transportOperator(new, dict) + subroutine new_transportOperator(new, dict, dataType, rand) class(transportOperator),allocatable, intent(inout):: new class(dictionary), intent(in) :: dict + integer(shortInt), intent(in) :: dataType + class(RNG), intent(inout) :: rand character(nameLen) :: type character(100),parameter :: Here = 'new_transportOperator (transportOperatorFactory_func.f90)' @@ -62,7 +65,7 @@ subroutine new_transportOperator(new, dict) end select ! Initialise new transport operator - call new % init(dict) + call new % init(dict, dataType, rand) end subroutine new_transportOperator diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index f9cdfc378..0c4b31f8d 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -9,7 +9,7 @@ module transportOperatorHT_class use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use rng_class, only : rng + use RNG_class, only : RNG ! Tally interface use tallyCodes @@ -22,6 +22,7 @@ module transportOperatorHT_class use geometry_inter, only : geometry ! Nuclear data interfaces + use nuclearDataReg_mod, only : ndReg_get => get use nuclearDatabase_inter, only : nuclearDatabase implicit none @@ -31,29 +32,17 @@ module transportOperatorHT_class !! Transport operator that moves a particle with hybrid tracking !! type, public, extends(transportOperator) :: transportOperatorHT - !! Cutoff threshold between ST and DT - real(defReal) :: cutoff + real(defReal) :: cutoff ! Cutoff threshold between ST and DT contains - procedure :: init procedure :: transit => tracking_selection procedure, private :: deltaTracking procedure, private :: surfaceTracking + ! Override procedure + procedure :: init end type transportOperatorHT contains - subroutine init(self, dict) - class(transportOperatorHT), intent(inout) :: self - class(dictionary), intent(in) :: dict - - ! Initialise superclass - call init_super(self, dict) - - ! Initialise this class - call dict % getOrDefault(self % cutoff,'cutoff',0.9_defReal) - - end subroutine init - subroutine tracking_selection(self, p, tally, thisCycle, nextCycle) class(transportOperatorHT), intent(inout) :: self class(particle), intent(inout) :: p @@ -81,7 +70,9 @@ subroutine tracking_selection(self, p, tally, thisCycle, nextCycle) end subroutine tracking_selection - + !! + !! Performs delta tracking until a real collision point is found + !! subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) class(transportOperatorHT), intent(inout) :: self class(particle), intent(inout) :: p @@ -138,7 +129,9 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) call tally % reportTrans(p) end subroutine deltaTracking - + !! + !! Performs surface tracking until a collision point is found + !! subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) class(transportOperatorHT), intent(inout) :: self class(particle), intent(inout) :: p @@ -194,5 +187,30 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) end subroutine surfaceTracking + !! + !! Initialise HT operator from a dictionary + !! + !! See transportOperator_inter for more details + !! + subroutine init(self, dict, dataType, rand) + class(transportOperatorHT), intent(inout) :: self + class(dictionary), intent(in) :: dict + integer(shortInt), intent(in) :: dataType + class(RNG), intent(inout) :: rand + + ! Initialise superclass + call init_super(self, dict, dataType, rand) + + ! Retrieve DT-ST probability cutoff + call dict % getOrDefault(self % cutoff,'cutoff',0.9_defReal) + + ! Get nuclear data pointer form the particle + self % xsData => ndReg_get(dataType) + + ! Precompute majorant cross section for DT + call self % xsData % initMajorant(rand) + + end subroutine init + end module transportOperatorHT_class diff --git a/TransportOperator/transportOperatorST_class.f90 b/TransportOperator/transportOperatorST_class.f90 index c7eb24428..7c2927c58 100644 --- a/TransportOperator/transportOperatorST_class.f90 +++ b/TransportOperator/transportOperatorST_class.f90 @@ -1,5 +1,5 @@ !! -!! Transport operator for delta tracking +!! Transport operator for surface tracking !! module transportOperatorST_class use numPrecision @@ -28,7 +28,7 @@ module transportOperatorST_class private !! - !! Transport operator that moves a particle with delta tracking + !! Transport operator that moves a particle with surface tracking !! !! Sample Input Dictionary: !! trans { type transportOperatorST; cache 0;} @@ -37,13 +37,14 @@ module transportOperatorST_class logical(defBool) :: cache = .true. contains procedure :: transit => surfaceTracking + ! Override procedure procedure :: init end type transportOperatorST contains !! - !! Performs surface tracking + !! Performs surface tracking until a collision point is found !! subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) class(transportOperatorST), intent(inout) :: self @@ -108,13 +109,18 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) end subroutine surfaceTracking !! - !! Initialise surface operator from a dictionary + !! Initialise ST operator from a dictionary !! !! See transportOperator_inter for details !! - subroutine init(self, dict) + subroutine init(self, dict, dataType, rand) class(transportOperatorST), intent(inout) :: self class(dictionary), intent(in) :: dict + integer(shortInt), intent(in) :: dataType + class(RNG), intent(inout) :: rand + + ! Initialise superclass + call init_super(self, dict, dataType, rand) if (dict % isPresent('cache')) then call dict % get(self % cache, 'cache') diff --git a/TransportOperator/transportOperator_inter.f90 b/TransportOperator/transportOperator_inter.f90 index 8d0e30e68..53809254c 100644 --- a/TransportOperator/transportOperator_inter.f90 +++ b/TransportOperator/transportOperator_inter.f90 @@ -7,6 +7,8 @@ module transportOperator_inter use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary + use RNG_class, only : RNG + ! Geometry interfaces use geometryReg_mod, only : gr_geomPtr => geomPtr @@ -61,7 +63,7 @@ module transportOperator_inter end type transportOperator - ! Extandable procedures + ! Extendable procedures public :: init public :: kill @@ -120,9 +122,11 @@ end subroutine transport !! !! Initialise transport operator from dictionary and geometry !! - subroutine init(self, dict) + subroutine init(self, dict, dataType, rand) class(transportOperator), intent(inout) :: self class(dictionary), intent(in) :: dict + integer(shortInt), intent(in) :: dataType + class(RNG), intent(inout) :: rand ! Do nothing From 435aab702158dd3acc20c0d01d1c2c374e719be4 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 17 Jan 2024 18:45:07 +0000 Subject: [PATCH 068/133] Adjusting intTests adding majorant precalculation --- .../Tests/aceNeutronDatabase_iTest.f90 | 1 + .../aceDatabase/aceNeutronDatabase_class.f90 | 21 ++++++++++++++----- .../Tests/baseMgNeutronDatabase_iTest.f90 | 2 ++ .../baseMgNeutronDatabase_class.f90 | 15 ++++++++++--- NuclearData/nuclearDatabase_inter.f90 | 9 ++++---- .../testNeutronDatabase_class.f90 | 3 ++- 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 index a09f554d3..d1a8aef1a 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 @@ -76,6 +76,7 @@ subroutine test_aceNeutronDatabase() ptr => data call data % init(dataDict, ptr, silent = .true.) call data % activate([1,2]) + call data % initMajorant(p % pRNG, silent = .true.) !!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! Perform tests diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index af13bc421..966c5f6a8 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -795,16 +795,25 @@ end subroutine activate !! !! See nuclearDatabase documentation for details !! - subroutine initMajorant(self, rand) + subroutine initMajorant(self, rand, silent) class(aceNeutronDatabase), intent(inout) :: self class(RNG), intent(inout) :: rand + logical(defBool), intent(in), optional :: silent + logical(defBool) :: loud real(defReal), dimension(:), allocatable :: tmpGrid integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone type(intMap) :: nucMap real(defReal) :: E, maj integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 - print '(A)', 'Building unionised energy grid' + ! Set build console output flag + if(present(silent)) then + loud = .not.silent + else + loud = .true. + end if + + if (loud) print '(A)', 'Building unionised energy grid' ! Initialise energy grid matIdx = self % activeMat(1) @@ -848,8 +857,10 @@ subroutine initMajorant(self, rand) ! Save final grid self % eGrid = tmpGrid - print '(A)', 'Unionised energy grid has size: '//numToChar(size(self % eGrid))//& - '. Now building unionised majorant cross section' + if (loud) then + print '(A)', 'Unionised energy grid has size: '//numToChar(size(self % eGrid))//& + '. Now building unionised majorant cross section' + end if ! Allocate unionised majorant allocate(self % majorant(size(self % eGrid))) @@ -884,7 +895,7 @@ subroutine initMajorant(self, rand) end do - print '(A)', 'Unionised majorant cross section completed' + if (loud) print '(A)', 'Unionised majorant cross section completed' end subroutine initMajorant diff --git a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 index 13aa797d0..1d8b017e8 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 @@ -75,6 +75,7 @@ subroutine testBaseMgNeutronDatabaseWithP0() call databaseDef % store('PN','P0') call database % init(databaseDef, data_ptr, silent = .true.) call database % activate([1]) + call database % initMajorant(p % pRNG, silent = .true.) ! Varify number of groups @assertEqual(4, database % nGroups()) @@ -201,6 +202,7 @@ subroutine testBaseMgNeutronDatabaseWithP1() call databaseDef % store('PN','P1') call database % init(databaseDef, data_ptr, silent = .true.) call database % activate([1]) + call database % initMajorant(p % pRNG, silent = .true.) ! Varify number of groups @assertEqual(4, database % nGroups()) diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index b7a19ac8f..e228b2388 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -354,14 +354,23 @@ end subroutine activate !! !! See nuclearDatabase documentation for details !! - subroutine initMajorant(self, rand) + subroutine initMajorant(self, rand, silent) class(baseMgNeutronDatabase), intent(inout) :: self class(RNG), intent(inout) :: rand + logical(defBool), intent(in), optional :: silent + logical(defBool) :: loud integer(shortInt) :: g, i, idx real(defReal) :: xs integer(shortInt), parameter :: TOTAL_XS = 1 - print '(A)', 'Building unionised majorant cross section' + ! Set build console output flag + if(present(silent)) then + loud = .not.silent + else + loud = .true. + end if + + if (loud) print '(A)', 'Building unionised majorant cross section' ! Allocate majorant allocate (self % majorant(self % nG)) @@ -376,7 +385,7 @@ subroutine initMajorant(self, rand) self % majorant(g) = xs end do - print '(A)', 'Unionised majorant cross section completed' + if (loud) print '(A)', 'Unionised majorant cross section completed' end subroutine initMajorant diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index c4a39352e..6719ed8d6 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -255,10 +255,11 @@ end function getReaction !! !! NOTE: Assumes that the nuclear database has been initialised and activated !! - subroutine initMajorant(self, rand) - import :: nuclearDatabase, RNG - class(nuclearDatabase), intent(inout) :: self - class(RNG), intent(inout) :: rand + subroutine initMajorant(self, rand, silent) + import :: nuclearDatabase, RNG, defBool + class(nuclearDatabase), intent(inout) :: self + class(RNG), intent(inout) :: rand + logical(defBool), optional, intent(in) :: silent end subroutine initMajorant !! diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index 81f55b0b3..264c33e87 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -268,9 +268,10 @@ end function getReaction !! !! See nuclearDatabase_inter for details !! - subroutine initMajorant(self, rand) + subroutine initMajorant(self, rand, silent) class(testNeutronDatabase), intent(inout) :: self class(RNG), intent(inout) :: rand + logical(defBool), optional, intent(in) :: silent ! Does nothing From 18fbe55b11355df7ef2a8df4a248a3c9537021de Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 18 Jan 2024 16:52:14 +0000 Subject: [PATCH 069/133] Addressing comments --- .../Tests/aceNeutronDatabase_iTest.f90 | 3 +- .../aceDatabase/aceNeutronDatabase_class.f90 | 142 ++++++++++++------ .../ceNeutronData/ceNeutronDatabase_inter.f90 | 10 +- .../Tests/baseMgNeutronDatabase_iTest.f90 | 6 +- .../baseMgNeutronDatabase_class.f90 | 37 ++--- NuclearData/nuclearDatabase_inter.f90 | 20 +-- .../testNeutronDatabase_class.f90 | 18 +-- PhysicsPackages/eigenPhysicsPackage_class.f90 | 2 +- .../fixedSourcePhysicsPackage_class.f90 | 2 +- .../transportOperatorDT_class.f90 | 16 +- .../transportOperatorFactory_func.f90 | 11 +- .../transportOperatorHT_class.f90 | 18 +-- .../transportOperatorST_class.f90 | 9 +- TransportOperator/transportOperator_inter.f90 | 7 +- docs/User Manual.rst | 2 + 15 files changed, 151 insertions(+), 152 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 index d1a8aef1a..697cfcf9b 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 @@ -75,8 +75,7 @@ subroutine test_aceNeutronDatabase() ! Initialise data ptr => data call data % init(dataDict, ptr, silent = .true.) - call data % activate([1,2]) - call data % initMajorant(p % pRNG, silent = .true.) + call data % activate([1,2], silent = .true.) !!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! Perform tests diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 966c5f6a8..fd8bbceab 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -3,12 +3,13 @@ module aceNeutronDatabase_class use numPrecision use endfConstants use universalVariables - use genericProcedures, only : fatalError, numToChar, concatenate, quickSort, & - removeDuplicatesSorted, binarySearch - use dictionary_class, only : dictionary - use RNG_class, only : RNG - use charMap_class, only : charMap - use intMap_class, only : intMap + use errors_mod, only : fatalError + use genericProcedures, only : numToChar, concatenate, quickSort, & + removeDuplicatesSorted, binarySearch + use dictionary_class, only : dictionary + use RNG_class, only : RNG + use charMap_class, only : charMap + use intMap_class, only : intMap ! Nuclear Data Interfaces use nuclearDatabase_inter, only : nuclearDatabase @@ -55,7 +56,8 @@ module aceNeutronDatabase_class !! Sample input: !! nuclearData { !! handles { - !! ce {type aceNeutronDatabase; DBRC (92238 94242); ures <1 or 0>; aceLibrary ;} } + !! ce { type aceNeutronDatabase; DBRC (92238 94242); ures < 1 or 0 >; + !! majorant < 1 or 0 >; aceLibrary ;} } !! !! Public Members: !! nuclides -> array of aceNeutronNuclides with data @@ -76,16 +78,18 @@ module aceNeutronDatabase_class type(aceNeutronNuclide),dimension(:),pointer :: nuclides => null() type(ceNeutronMaterial),dimension(:),pointer :: materials => null() real(defReal), dimension(:), allocatable :: majorant - real(defReal), dimension(:), allocatable :: eGrid + real(defReal), dimension(:), allocatable :: eGridUnion real(defReal), dimension(2) :: Ebounds = ZERO integer(shortInt),dimension(:),allocatable :: activeMat ! Probability tables data integer(shortInt),dimension(:),allocatable :: nucToZaid - logical(defBool) :: hasUrr = .false. + logical(defBool) :: hasUrr = .false. logical(defBool) :: hasDBRC = .false. + logical(defBool) :: hasMajorant = .false. contains + ! nuclearDatabase Procedures procedure :: kill procedure :: matNamesMap @@ -94,7 +98,6 @@ module aceNeutronDatabase_class procedure :: getReaction procedure :: init procedure :: activate - procedure :: initMajorant ! ceNeutronDatabase Procedures procedure :: energyBounds @@ -108,6 +111,7 @@ module aceNeutronDatabase_class ! class Procedures procedure :: init_urr procedure :: init_DBRC + procedure :: initMajorant end type aceNeutronDatabase @@ -297,7 +301,7 @@ subroutine updateTotalMatXS(self, E, matIdx, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: matIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand integer(shortInt) :: i, nucIdx real(defReal) :: dens @@ -335,26 +339,46 @@ end subroutine updateTotalMatXS subroutine updateMajorantXS(self, E, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E - class(RNG), intent(inout) :: rand - integer(shortInt) :: idx + class(RNG), optional, intent(inout) :: rand + integer(shortInt) :: idx, i, matIdx real(defReal) :: f character(100), parameter :: Here = 'updateMajorantXS (aceNeutronDatabase_class.f90)' associate (maj => cache_majorantCache(1) ) maj % E = E - idx = binarySearch(self % eGrid, E) + ! Get majorant via the precomputed unionised cross section + if (self % hasMajorant) then + idx = binarySearch(self % eGridUnion, E) - if(idx <= 0) then - call fatalError(Here,'Failed to find energy: '//numToChar(E)//& - ' in unionised majorant grid') - end if + if(idx <= 0) then + call fatalError(Here,'Failed to find energy: '//numToChar(E)//& + ' in unionised majorant grid') + end if - associate(E_top => self % eGrid(idx + 1), E_low => self % eGrid(idx)) - f = (E - E_low) / (E_top - E_low) - end associate + associate(E_top => self % eGridUnion(idx + 1), E_low => self % eGridUnion(idx)) + f = (E - E_low) / (E_top - E_low) + end associate + + maj % xs = self % majorant(idx+1) * f + (ONE - f) * self % majorant(idx) + + else ! Compute majorant on the fly - maj % xs = self % majorant(idx+1) * f + (ONE - f) * self % majorant(idx) + maj % xs = ZERO + + ! Loop over materials + do i = 1, size(self % activeMat) + matIdx = self % activeMat(i) + + ! Update if needed + if( cache_materialCache(matIdx) % E_tot /= E) then + call self % updateTotalMatXS(E, matIdx, rand) + end if + + maj % xs = max(maj % xs, cache_materialCache(matIdx) % xss % total) + end do + + end if end associate @@ -370,7 +394,7 @@ subroutine updateMacroXSs(self, E, matIdx, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: matIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand integer(shortInt) :: i, nucIdx real(defReal) :: dens @@ -410,7 +434,7 @@ subroutine updateTotalNucXS(self, E, nucIdx, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: nucIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand logical(defBool) :: needsSab associate (nucCache => cache_nuclideCache(nucIdx), & @@ -445,7 +469,7 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) class(aceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: nucIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand associate (nucCache => cache_nuclideCache(nucIdx), & nuc => self % nuclides(nucIdx) ) @@ -665,6 +689,9 @@ subroutine init(self, dict, ptr, silent ) self % Ebounds(2) = min(self % Ebounds(2), self % nuclides(i) % eGrid(j)) end do + ! Read unionised majorant flag + call dict % getOrDefault(self % hasMajorant, 'majorant', .false.) + ! If on, initialise probability tables for ures if (self % hasUrr) then call self % init_urr() @@ -773,9 +800,11 @@ end subroutine init_DBRC !! !! See nuclearDatabase documentation for details !! - subroutine activate(self, activeMat) + subroutine activate(self, activeMat, silent) class(aceNeutronDatabase), intent(inout) :: self integer(shortInt), dimension(:), intent(in) :: activeMat + logical(defBool), optional, intent(in) :: silent + logical(defBool) :: loud ! Load active materials if(allocated(self % activeMat)) deallocate(self % activeMat) @@ -788,6 +817,36 @@ subroutine activate(self, activeMat) call cache_init(size(self % materials), size(self % nuclides)) end if + ! If unionised majorant cross section is requested, build it + if (self % hasMajorant) then + + ! Set build console output flag + if (present(silent)) then + loud = .not. silent + else + loud = .true. + end if + + ! Check if probability tables are on + if (self % hasUrr) then + + ! Switch off majorant + self % hasMajorant = .false. + + if (loud) then + print '(A)', 'Unionised majorant cross section will not be contructed & + & due to the use of URR probability tables treatment' + end if + + else + + ! Precompute majorant cross section + call self % initMajorant(loud) + + end if + + end if + end subroutine activate !! @@ -795,25 +854,16 @@ end subroutine activate !! !! See nuclearDatabase documentation for details !! - subroutine initMajorant(self, rand, silent) + subroutine initMajorant(self, loud) class(aceNeutronDatabase), intent(inout) :: self - class(RNG), intent(inout) :: rand - logical(defBool), intent(in), optional :: silent - logical(defBool) :: loud + logical(defBool), intent(in) :: loud real(defReal), dimension(:), allocatable :: tmpGrid integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone type(intMap) :: nucMap real(defReal) :: E, maj integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 - ! Set build console output flag - if(present(silent)) then - loud = .not.silent - else - loud = .true. - end if - - if (loud) print '(A)', 'Building unionised energy grid' + if (loud) print '(A)', 'Building CE unionised energy grid' ! Initialise energy grid matIdx = self % activeMat(1) @@ -855,21 +905,21 @@ subroutine initMajorant(self, rand, silent) end do ! Save final grid - self % eGrid = tmpGrid + self % eGridUnion = tmpGrid if (loud) then - print '(A)', 'Unionised energy grid has size: '//numToChar(size(self % eGrid))//& - '. Now building unionised majorant cross section' + print '(A)', 'CE unionised energy grid has size: '//numToChar(size(self % eGridUnion))//& + '. Now building CE unionised majorant cross section' end if ! Allocate unionised majorant - allocate(self % majorant(size(self % eGrid))) + allocate(self % majorant(size(self % eGridUnion))) ! Loop over all the energies - do i = 1, size(self % eGrid) + do i = 1, size(self % eGridUnion) ! Retrieve current energy - E = self % eGrid(i) + E = self % eGridUnion(i) ! Correct for energies higher or lower than the allowed boundaries if (E < self % EBounds(1)) E = self % EBounds(1) @@ -885,7 +935,7 @@ subroutine initMajorant(self, rand, silent) matIdx = self % activeMat(j) ! Calculate current material cross section and compare - call self % updateTotalMatXS(E, matIdx, rand) + call self % updateTotalMatXS(E, matIdx) maj = max(maj, cache_materialCache(matIdx) % xss % total) end do @@ -895,7 +945,7 @@ subroutine initMajorant(self, rand, silent) end do - if (loud) print '(A)', 'Unionised majorant cross section completed' + if (loud) print '(A)', 'CE unionised majorant cross section completed' end subroutine initMajorant diff --git a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 index d0c8fd1d2..4e3168956 100644 --- a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 @@ -105,7 +105,7 @@ subroutine updateTotalMatXS(self, E, matIdx, rand) class(ceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: matIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand end subroutine updateTotalMatXS !! @@ -125,7 +125,7 @@ subroutine updateMajorantXS(self, E, rand) import :: ceNeutronDatabase, defReal, RNG class(ceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand end subroutine updateMajorantXS !! @@ -147,7 +147,7 @@ subroutine updateMacroXSs(self, E, matIdx, rand) class(ceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: matIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand end subroutine updateMacroXSs !! @@ -169,7 +169,7 @@ subroutine updateTotalXS(self, E, nucIdx, rand) class(ceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: nucIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand end subroutine updateTotalXS !! @@ -191,7 +191,7 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) class(ceNeutronDatabase), intent(in) :: self real(defReal), intent(in) :: E integer(shortInt), intent(in) :: nucIdx - class(RNG), intent(inout) :: rand + class(RNG), optional, intent(inout) :: rand end subroutine updateMicroXSs !! diff --git a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 index 1d8b017e8..21b1a5438 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 @@ -74,8 +74,7 @@ subroutine testBaseMgNeutronDatabaseWithP0() call databaseDef % init(1) call databaseDef % store('PN','P0') call database % init(databaseDef, data_ptr, silent = .true.) - call database % activate([1]) - call database % initMajorant(p % pRNG, silent = .true.) + call database % activate([1], silent = .true.) ! Varify number of groups @assertEqual(4, database % nGroups()) @@ -201,8 +200,7 @@ subroutine testBaseMgNeutronDatabaseWithP1() call databaseDef % init(1) call databaseDef % store('PN','P1') call database % init(databaseDef, data_ptr, silent = .true.) - call database % activate([1]) - call database % initMajorant(p % pRNG, silent = .true.) + call database % activate([1], silent = .true.) ! Varify number of groups @assertEqual(4, database % nGroups()) diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index e228b2388..0816c345d 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -2,12 +2,12 @@ module baseMgNeutronDatabase_class use numPrecision use endfConstants - use genericProcedures, only : fatalError, numToChar + use errors_mod, only : fatalError + use genericProcedures, only : numToChar use particle_class, only : particle use charMap_class, only : charMap use dictionary_class, only : dictionary use dictParser_func, only : fileToDict - use RNG_class, only : RNG ! Nuclear Data Interfaces use nuclearDatabase_inter, only : nuclearDatabase @@ -71,9 +71,9 @@ module baseMgNeutronDatabase_class procedure :: kill procedure :: init procedure :: activate - procedure :: initMajorant ! Local interface + procedure :: initMajorant procedure :: nGroups end type baseMgNeutronDatabase @@ -329,9 +329,11 @@ end subroutine init !! !! See nuclearDatabase documentation for details !! - subroutine activate(self, activeMat) + subroutine activate(self, activeMat, silent) class(baseMgNeutronDatabase), intent(inout) :: self integer(shortInt), dimension(:), intent(in) :: activeMat + logical(defBool), optional, intent(in) :: silent + logical(defBool) :: loud integer(shortInt) :: idx if(allocated(self % activeMats)) deallocate(self % activeMats) @@ -347,6 +349,16 @@ subroutine activate(self, activeMat) end do !$omp end parallel + ! Set build console output flag + if (present(silent)) then + loud = .not. silent + else + loud = .true. + end if + + ! Build unionised majorant + call self % initMajorant(loud) + end subroutine activate !! @@ -354,23 +366,14 @@ end subroutine activate !! !! See nuclearDatabase documentation for details !! - subroutine initMajorant(self, rand, silent) + subroutine initMajorant(self, loud) class(baseMgNeutronDatabase), intent(inout) :: self - class(RNG), intent(inout) :: rand - logical(defBool), intent(in), optional :: silent - logical(defBool) :: loud + logical(defBool), intent(in) :: loud integer(shortInt) :: g, i, idx real(defReal) :: xs integer(shortInt), parameter :: TOTAL_XS = 1 - ! Set build console output flag - if(present(silent)) then - loud = .not.silent - else - loud = .true. - end if - - if (loud) print '(A)', 'Building unionised majorant cross section' + if (loud) print '(A)', 'Building MG unionised majorant cross section' ! Allocate majorant allocate (self % majorant(self % nG)) @@ -385,7 +388,7 @@ subroutine initMajorant(self, rand, silent) self % majorant(g) = xs end do - if (loud) print '(A)', 'Unionised majorant cross section completed' + if (loud) print '(A)', 'MG unionised majorant cross section completed' end subroutine initMajorant diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index 6719ed8d6..ff31af26f 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -4,7 +4,6 @@ module nuclearDatabase_inter use dictionary_class, only : dictionary use particle_class, only : particle use charMap_class, only : charMap - use RNG_class, only : RNG ! Nuclear Data Handles use nuclideHandle_inter, only : nuclideHandle @@ -29,7 +28,6 @@ module nuclearDatabase_inter !! getMaterial -> returns a pointer to a material handle for given matIdx !! getNuclide -> returns a pointer to a nuclide handle for given nucIdx !! getReaction -> returns a pointer to a reaction for given matidx or nucIdx and MT number - !! initMajorant -> initialises the majorant cross section for delta tracking !! kill -> return to uninitialised state, clean memory !! type, public,abstract :: nuclearDatabase @@ -43,7 +41,6 @@ module nuclearDatabase_inter procedure(getMaterial), deferred :: getMaterial procedure(getNuclide), deferred :: getNuclide procedure(getReaction), deferred :: getReaction - procedure(initMajorant), deferred :: initMajorant procedure(kill), deferred :: kill end type nuclearDatabase @@ -78,10 +75,11 @@ subroutine init(self, dict, ptr, silent) !! Errors: !! fatalError if activeMat contains materials not defined in the instance !! - subroutine activate(self, activeMat) - import :: nuclearDatabase, shortInt + subroutine activate(self, activeMat, silent) + import :: nuclearDatabase, shortInt, defBool class(nuclearDatabase), intent(inout) :: self integer(shortInt), dimension(:), intent(in) :: activeMat + logical(defBool), optional, intent(in) :: silent end subroutine activate !! @@ -250,18 +248,6 @@ function getReaction(self, MT, idx) result(reac) class(reactionHandle),pointer :: reac end function getReaction - !! - !! Subroutine that precomputes the majorant cross section to be used by DT - !! - !! NOTE: Assumes that the nuclear database has been initialised and activated - !! - subroutine initMajorant(self, rand, silent) - import :: nuclearDatabase, RNG, defBool - class(nuclearDatabase), intent(inout) :: self - class(RNG), intent(inout) :: rand - logical(defBool), optional, intent(in) :: silent - end subroutine initMajorant - !! !! Return to uninitialised state !! diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index 264c33e87..fa91ef9ed 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -52,7 +52,6 @@ module testNeutronDatabase_class procedure :: getMaterial procedure :: getNuclide procedure :: getReaction - procedure :: initMajorant procedure :: kill ! Local Procedures @@ -155,9 +154,10 @@ subroutine init(self, dict, ptr, silent) !! !! See nuclearDatabase_inter for details !! - subroutine activate(self, activeMat) + subroutine activate(self, activeMat, silent) class(testNeutronDatabase), intent(inout) :: self integer(shortInt), dimension(:), intent(in) :: activeMat + logical(defBool), optional, intent(in) :: silent ! Do nothing @@ -263,20 +263,6 @@ function getReaction(self, MT, idx) result(reac) end function getReaction - !! - !! Initialise majorant for delta tracking - !! - !! See nuclearDatabase_inter for details - !! - subroutine initMajorant(self, rand, silent) - class(testNeutronDatabase), intent(inout) :: self - class(RNG), intent(inout) :: rand - logical(defBool), optional, intent(in) :: silent - - ! Does nothing - - end subroutine initMajorant - !! !! Return to uninitialised state !! diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index ff054afeb..aa89111c1 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -490,7 +490,7 @@ subroutine init(self, dict) ! Build transport operator tempDict => dict % getDictPtr('transportOperator') - call new_transportOperator(self % transOp, tempDict, self % particleType, self % pRNG) + call new_transportOperator(self % transOp, tempDict) ! Initialise active & inactive tally Admins tempDict => dict % getDictPtr('inactiveTally') diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 68ad1f8d8..35e2ff2d3 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -406,7 +406,7 @@ subroutine init(self, dict) ! Build transport operator tempDict => dict % getDictPtr('transportOperator') - call new_transportOperator(self % transOp, tempDict, self % particleType, self % pRNG) + call new_transportOperator(self % transOp, tempDict) ! Initialise tally Admin tempDict => dict % getDictPtr('tally') diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 2c79b3959..3a1ab1609 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -5,11 +5,11 @@ module transportOperatorDT_class use numPrecision use universalVariables - use genericProcedures, only : fatalError, numToChar + use errors_mod, only : fatalError + use genericProcedures, only : numToChar use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use RNG_class, only : RNG ! Superclass use transportOperator_inter, only : transportOperator, init_super => init @@ -105,20 +105,12 @@ end subroutine deltaTracking !! !! See transportOperator_inter for more details !! - subroutine init(self, dict, dataType, rand) + subroutine init(self, dict) class(transportOperatorDT), intent(inout) :: self class(dictionary), intent(in) :: dict - integer(shortInt), intent(in) :: dataType - class(RNG), intent(inout) :: rand ! Initialise superclass - call init_super(self, dict, dataType, rand) - - ! Get nuclear data pointer form the particle - self % xsData => ndReg_get(dataType) - - ! Precompute majorant cross section - call self % xsData % initMajorant(rand) + call init_super(self, dict) end subroutine init diff --git a/TransportOperator/transportOperatorFactory_func.f90 b/TransportOperator/transportOperatorFactory_func.f90 index 2fe492786..549e2739b 100644 --- a/TransportOperator/transportOperatorFactory_func.f90 +++ b/TransportOperator/transportOperatorFactory_func.f90 @@ -4,9 +4,8 @@ module transportOperatorFactory_func use numPrecision - use genericProcedures, only : fatalError - use dictionary_class, only : dictionary - use RNG_class, only : RNG + use errors_mod, only : fatalError + use dictionary_class, only : dictionary ! Transport Operators use transportOperator_inter, only : transportOperator @@ -34,11 +33,9 @@ module transportOperatorFactory_func !! Allocate new allocatable transportOperator to a specific type !! If new is allocated it deallocates it !! - subroutine new_transportOperator(new, dict, dataType, rand) + subroutine new_transportOperator(new, dict) class(transportOperator),allocatable, intent(inout):: new class(dictionary), intent(in) :: dict - integer(shortInt), intent(in) :: dataType - class(RNG), intent(inout) :: rand character(nameLen) :: type character(100),parameter :: Here = 'new_transportOperator (transportOperatorFactory_func.f90)' @@ -65,7 +62,7 @@ subroutine new_transportOperator(new, dict, dataType, rand) end select ! Initialise new transport operator - call new % init(dict, dataType, rand) + call new % init(dict) end subroutine new_transportOperator diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index 0c4b31f8d..3ea03b9ae 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -5,11 +5,11 @@ module transportOperatorHT_class use numPrecision use universalVariables - use genericProcedures, only : fatalError, numToChar + use errors_mod, only : fatalError + use genericProcedures, only : numToChar use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use RNG_class, only : RNG ! Tally interface use tallyCodes @@ -89,7 +89,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") DTLoop:do - distance = -log( p% pRNG % get() ) * majorant_inv + distance = -log( p % pRNG % get() ) * majorant_inv ! Move partice in the geometry call self % geom % teleport(p % coords, distance) @@ -192,24 +192,16 @@ end subroutine surfaceTracking !! !! See transportOperator_inter for more details !! - subroutine init(self, dict, dataType, rand) + subroutine init(self, dict) class(transportOperatorHT), intent(inout) :: self class(dictionary), intent(in) :: dict - integer(shortInt), intent(in) :: dataType - class(RNG), intent(inout) :: rand ! Initialise superclass - call init_super(self, dict, dataType, rand) + call init_super(self, dict) ! Retrieve DT-ST probability cutoff call dict % getOrDefault(self % cutoff,'cutoff',0.9_defReal) - ! Get nuclear data pointer form the particle - self % xsData => ndReg_get(dataType) - - ! Precompute majorant cross section for DT - call self % xsData % initMajorant(rand) - end subroutine init diff --git a/TransportOperator/transportOperatorST_class.f90 b/TransportOperator/transportOperatorST_class.f90 index 7c2927c58..4b80605fc 100644 --- a/TransportOperator/transportOperatorST_class.f90 +++ b/TransportOperator/transportOperatorST_class.f90 @@ -5,11 +5,10 @@ module transportOperatorST_class use numPrecision use universalVariables - use genericProcedures, only : fatalError + use errors_mod, only : fatalError use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use RNG_class, only : RNG ! Superclass use transportOperator_inter, only : transportOperator, init_super => init @@ -113,14 +112,12 @@ end subroutine surfaceTracking !! !! See transportOperator_inter for details !! - subroutine init(self, dict, dataType, rand) + subroutine init(self, dict) class(transportOperatorST), intent(inout) :: self class(dictionary), intent(in) :: dict - integer(shortInt), intent(in) :: dataType - class(RNG), intent(inout) :: rand ! Initialise superclass - call init_super(self, dict, dataType, rand) + call init_super(self, dict) if (dict % isPresent('cache')) then call dict % get(self % cache, 'cache') diff --git a/TransportOperator/transportOperator_inter.f90 b/TransportOperator/transportOperator_inter.f90 index 53809254c..ddfdf5b6d 100644 --- a/TransportOperator/transportOperator_inter.f90 +++ b/TransportOperator/transportOperator_inter.f90 @@ -2,12 +2,11 @@ module transportOperator_inter use numPrecision use universalVariables - use genericProcedures, only : fatalError + use errors_mod, only : fatalError use particle_class, only : particle use particleDungeon_class, only : particleDungeon use dictionary_class, only : dictionary - use RNG_class, only : RNG ! Geometry interfaces @@ -122,11 +121,9 @@ end subroutine transport !! !! Initialise transport operator from dictionary and geometry !! - subroutine init(self, dict, dataType, rand) + subroutine init(self, dict) class(transportOperator), intent(inout) :: self class(dictionary), intent(in) :: dict - integer(shortInt), intent(in) :: dataType - class(RNG), intent(inout) :: rand ! Do nothing diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ef2841d4d..bbc12f9f4 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -725,6 +725,8 @@ from ACE files. resonance probability tables treatment * DBRC (*optional*, default = no DBRC): list of ZAIDs of nuclides for which DBRC has to be applied. +* majorant (*optional*, default = 0): 1 for true; 0 for false; flag to activate the + pre-construction of a unionised majorant cross section Example: :: From 66efce60878c244602210c068de81c892557b60c Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:05:17 +0000 Subject: [PATCH 070/133] Update aceNeutronDatabase_class.f90 Add forgotten docs --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index fd8bbceab..8357b6a78 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -53,6 +53,9 @@ module aceNeutronDatabase_class !! It's possible to use probability tables in the unresolved resonance range if !! ures is included in the input file !! + !! NOTE: the unionised majorant is not calculated and used if probability tables + !! are on + !! !! Sample input: !! nuclearData { !! handles { @@ -64,11 +67,12 @@ module aceNeutronDatabase_class !! materials -> array of ceNeutronMaterials with data !! Ebounds -> array with bottom (1) and top (2) energy bound !! majorant -> unionised majorant cross section - !! eGrid -> unionised energy grid + !! eGridUnion -> unionised energy grid !! activeMat -> array of materials present in the geometry !! nucToZaid -> map to link nuclide index to zaid index !! hasUrr -> ures probability tables flag, it's false by default !! hasDBRC -> DBRC flag, it's false by default + !! has majorant -> unionised majorant cross section flag !! !! Interface: !! nuclearData Interface From 579ad4d0d3e5b5d89f9d37f4a8240d5f38e41c98 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Tue, 23 Jan 2024 18:43:02 +0000 Subject: [PATCH 071/133] Adding a fission report to tallies and use it in mgXsClerk --- .../collisionProcessor_inter.f90 | 22 +- .../neutronCEimp_class.f90 | 33 +- .../neutronCEstd_class.f90 | 31 +- .../neutronMGstd_class.f90 | 34 +- Tallies/TallyClerks/Tests/mgXsClerk_test.f90 | 38 +- Tallies/TallyClerks/mgXsClerk_class.f90 | 69 ++- Tallies/TallyClerks/tallyClerkSlot_class.f90 | 20 +- Tallies/TallyClerks/tallyClerk_inter.f90 | 55 ++- Tallies/tallyActiveAdmin_class.f90 | 232 --------- Tallies/tallyAdminBase_class.f90 | 437 ----------------- Tallies/tallyAdmin_class.f90 | 49 +- Tallies/tallyCodes.f90 | 7 +- Tallies/tallyEstimator_class.f90 | 459 ------------------ Tallies/tallyInactiveAdmin_class.f90 | 132 ----- Tallies/tallyTimeAdmin_class.f90 | 219 --------- 15 files changed, 246 insertions(+), 1591 deletions(-) delete mode 100644 Tallies/tallyActiveAdmin_class.f90 delete mode 100644 Tallies/tallyAdminBase_class.f90 delete mode 100644 Tallies/tallyEstimator_class.f90 delete mode 100644 Tallies/tallyInactiveAdmin_class.f90 delete mode 100644 Tallies/tallyTimeAdmin_class.f90 diff --git a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 index fabc11b3b..7080301a6 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 @@ -86,13 +86,15 @@ module collisionProcessor_inter !! Procedure interface for all customisable actions associated with !! processing of sollision event (scatter, fission etc.) !! - subroutine collisionAction(self, p, collDat, thisCycle, nextCycle) + subroutine collisionAction(self, p, tally, collDat, thisCycle, nextCycle) import :: collisionProcessor, & collisionData, & + tallyAdmin, & particle,& particleDungeon class(collisionProcessor), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -104,7 +106,7 @@ end subroutine collisionAction !! !! Generic flow of collision processing !! - subroutine collide(self, p, tally ,thisCycle, nextCycle) + subroutine collide(self, p, tally, thisCycle, nextCycle) class(collisionProcessor), intent(inout) :: self class(particle), intent(inout) :: p type(tallyAdmin), intent(inout) :: tally @@ -118,30 +120,30 @@ subroutine collide(self, p, tally ,thisCycle, nextCycle) ! Report in-collision & save pre-collison state ! Note: the ordering must not be changed between feeding the particle to the tally - ! and updating the particle's preCollision state, otherwise this may cause certain + ! and updating the particle's preCollision state, otherwise this may cause certain ! tallies (e.g., collisionProbability) to return dubious results call tally % reportInColl(p, .false.) call p % savePreCollision() ! Choose collision nuclide and general type (Scatter, Capture or Fission) - call self % sampleCollision(p, collDat, thisCycle, nextCycle) + call self % sampleCollision(p, tally, collDat, thisCycle, nextCycle) ! Perform implicit treatment - call self % implicit(p, collDat, thisCycle, nextCycle) + call self % implicit(p, tally, collDat, thisCycle, nextCycle) ! Select physics to be processed based on MT number select case(collDat % MT) case(N_N_elastic, macroAllScatter) - call self % elastic(p, collDat, thisCycle, nextCycle) + call self % elastic(p, tally, collDat, thisCycle, nextCycle) case(N_N_inelastic, macroIEScatter) - call self % inelastic(p, collDat, thisCycle, nextCycle) + call self % inelastic(p, tally, collDat, thisCycle, nextCycle) case(N_DISAP, macroCapture) - call self % capture(p, collDat, thisCycle, nextCycle) + call self % capture(p, tally, collDat, thisCycle, nextCycle) case(N_FISSION, macroFission) - call self % fission(p, collDat, thisCycle, nextCycle) + call self % fission(p, tally, collDat, thisCycle, nextCycle) case(noInteraction) ! Do nothing @@ -152,7 +154,7 @@ subroutine collide(self, p, tally ,thisCycle, nextCycle) end select ! Apply post collision implicit treatments - call self % cutoffs(p, collDat, thisCycle, nextCycle) + call self % cutoffs(p, tally, collDat, thisCycle, nextCycle) ! Update particle collision counter p % collisionN = p % collisionN + 1 diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 0d4f05acb..88b93cbf7 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -38,6 +38,10 @@ module neutronCEimp_class ! Scattering procedures use scatteringKernels_func, only : asymptoticScatter, targetVelocity_constXS, & asymptoticInelasticScatter, targetVelocity_DBRCXS + + ! Tally interfaces + use tallyAdmin_class, only : tallyAdmin + implicit none private @@ -213,9 +217,10 @@ end subroutine init !! !! Samples collision without any implicit treatment !! - subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) + subroutine sampleCollision(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -252,9 +257,10 @@ end subroutine sampleCollision !! !! Perform implicit treatment !! - subroutine implicit(self, p, collDat, thisCycle, nextCycle) + subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -302,7 +308,7 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) ! Store new sites in the next cycle dungeon r = p % rGlobal() - do i=1,n + do i = 1,n call fission % sampleOut(mu, phi, E_out, p % E, p % pRNG) dir = rotateVector(p % dirGlobal(), mu, phi) @@ -321,6 +327,9 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) call nextCycle % detain(pTemp) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) + ! Report birth of new particle + call tally % reportSpawn(p, pTemp) + end do end if @@ -346,9 +355,10 @@ end subroutine implicit !! !! Process capture reaction !! - subroutine capture(self, p, collDat, thisCycle, nextCycle) + subroutine capture(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -360,9 +370,10 @@ end subroutine capture !! !! Process fission reaction !! - subroutine fission(self, p, collDat, thisCycle, nextCycle) + subroutine fission(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -426,6 +437,9 @@ subroutine fission(self, p, collDat, thisCycle, nextCycle) call nextCycle % detain(pTemp) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) + ! Report birth of new particle + call tally % reportSpawn(p, pTemp) + end do end if @@ -438,9 +452,10 @@ end subroutine fission !! !! All CE elastic scattering happens in the CM frame !! - subroutine elastic(self, p, collDat, thisCycle, nextCycle) + subroutine elastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -476,9 +491,10 @@ end subroutine elastic !! !! Process inelastic scattering !! - subroutine inelastic(self, p, collDat, thisCycle, nextCycle) + subroutine inelastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -506,9 +522,10 @@ end subroutine inelastic !! !! Apply cutoffs !! - subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) + subroutine cutoffs(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index 7070a456f..b6dc3ec78 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -32,6 +32,10 @@ module neutronCEstd_class ! Scattering procedures use scatteringKernels_func, only : asymptoticScatter, targetVelocity_constXS, & asymptoticInelasticScatter, targetVelocity_DBRCXS + + ! Tally interfaces + use tallyAdmin_class, only : tallyAdmin + implicit none private @@ -135,9 +139,10 @@ end subroutine init !! !! Samples collision without any implicit treatment !! - subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) + subroutine sampleCollision(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -174,9 +179,10 @@ end subroutine sampleCollision !! !! Perform implicit treatment !! - subroutine implicit(self, p, collDat, thisCycle, nextCycle) + subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -216,7 +222,7 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) wgt = sign(w0, wgt) r = p % rGlobal() - do i=1,n + do i = 1,n call fission % sampleOut(mu, phi, E_out, p % E, p % pRNG) dir = rotateVector(p % dirGlobal(), mu, phi) @@ -233,6 +239,10 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) pTemp % collisionN = 0 call nextCycle % detain(pTemp) + + ! Report birth of new particle + call tally % reportSpawn(p, pTemp) + end do end if @@ -241,9 +251,10 @@ end subroutine implicit !! !! Process capture reaction !! - subroutine capture(self, p, collDat, thisCycle, nextCycle) + subroutine capture(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -255,9 +266,10 @@ end subroutine capture !! !! Process fission reaction !! - subroutine fission(self, p, collDat, thisCycle, nextCycle) + subroutine fission(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -271,9 +283,10 @@ end subroutine fission !! !! All CE elastic scattering happens in the CM frame !! - subroutine elastic(self, p, collDat, thisCycle, nextCycle) + subroutine elastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -309,9 +322,10 @@ end subroutine elastic !! !! Process inelastic scattering !! - subroutine inelastic(self, p, collDat, thisCycle, nextCycle) + subroutine inelastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -339,9 +353,10 @@ end subroutine inelastic !! !! Apply cutoffs !! - subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) + subroutine cutoffs(self, p, tally, collDat, thisCycle, nextCycle) class(neutronCEstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle diff --git a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 index 0665c7891..12f51d9b0 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 @@ -25,13 +25,8 @@ module neutronMGstd_class ! Cross section packages use neutronXsPackages_class, only : neutronMacroXSs - - ! Nuclear Data - !use nuclearData_inter, only : nuclearData - !use perMaterialNuclearDataMG_inter, only : perMaterialNuclearDataMG - - ! Cross-section packages to interface with nuclear data - !use xsMacroSet_class, only : xsMacroSet, xsMacroSet_ptr + ! Tally interfaces + use tallyAdmin_class, only : tallyAdmin implicit none private @@ -87,9 +82,10 @@ end subroutine init !! !! Samples collision without any implicit treatment !! - subroutine sampleCollision(self, p, collDat, thisCycle, nextCycle) + subroutine sampleCollision(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -121,9 +117,10 @@ end subroutine sampleCollision !! !! Preform implicit treatment !! - subroutine implicit(self, p, collDat, thisCycle, nextCycle) + subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -178,6 +175,10 @@ subroutine implicit(self, p, collDat, thisCycle, nextCycle) pTemp % collisionN = 0 call nextCycle % detain(pTemp) + + ! Report birth of new particle + call tally % reportSpawn(p, pTemp) + end do end if @@ -186,9 +187,10 @@ end subroutine implicit !! !! Elastic Scattering !! - subroutine elastic(self, p , collDat, thisCycle, nextCycle) + subroutine elastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -200,9 +202,10 @@ end subroutine elastic !! !! Preform scattering !! - subroutine inelastic(self, p, collDat, thisCycle, nextCycle) + subroutine inelastic(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -235,9 +238,10 @@ end subroutine inelastic !! !! Preform capture !! - subroutine capture(self, p, collDat, thisCycle, nextCycle) + subroutine capture(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -249,9 +253,10 @@ end subroutine capture !! !! Preform fission !! - subroutine fission(self, p, collDat, thisCycle, nextCycle) + subroutine fission(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle @@ -263,9 +268,10 @@ end subroutine fission !! !! Applay cutoffs or post-collision implicit treatment !! - subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) + subroutine cutoffs(self, p, tally, collDat, thisCycle, nextCycle) class(neutronMGstd), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally type(collisionData), intent(inout) :: collDat class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle diff --git a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 index 1dbcec26a..b0bb61fb5 100644 --- a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 @@ -4,8 +4,7 @@ module mgXsClerk_test use endfConstants use genericProcedures, only : numToChar use mgXsClerk_class, only : mgXsClerk - use particle_class, only : particle - use particleDungeon_class, only : particleDungeon + use particle_class, only : particle, particleState use dictionary_class, only : dictionary use scoreMemory_class, only : scoreMemory use testNeutronDatabase_class, only : testNeutronDatabase @@ -104,7 +103,7 @@ subroutine testScoring_clerk1(this) character(:),allocatable :: case type(scoreMemory) :: mem type(particle) :: p - type(particleDungeon) :: pit + type(particleState) :: pFiss type(outputFile) :: out real(defReal), dimension(:,:), allocatable :: fiss, capt, transFL, transOS, & nu, chi, P0, P1, P2, P3, P4, & @@ -115,21 +114,24 @@ subroutine testScoring_clerk1(this) call mem % init(1000_longInt, 1) call this % clerk_test1 % setMemAddress(1_longInt) - ! Configure particle dungeon - call pit % init(3) - + ! Report fission particles p % isMG = .false. p % w = 0.5_defReal p % E = 0.3_defReal call p % setMatIdx(2) - call pit % detain(p) + + ! Scoring + pFiss = p + call this % clerk_test1 % reportSpawn(p, pFiss, this % nucData, mem) p % E = 3.0_defReal - call pit % detain(p) + + ! Scoring + pFiss = p + call this % clerk_test1 % reportSpawn(p, pFiss, this % nucData, mem) ! Scoring call this % clerk_test1 % reportInColl(p, this % nucData, mem, .false.) - call this % clerk_test1 % reportCycleEnd(pit, mem) p % preCollision % wgt = 0.2_defReal p % preCollision % E = 3.0_defReal @@ -181,7 +183,7 @@ subroutine testScoring_clerk2(this) character(:),allocatable :: case type(scoreMemory) :: mem type(particle) :: p - type(particleDungeon) :: pit + type(particleState) :: pFiss type(outputFile) :: out real(defReal), dimension(:,:), allocatable :: fiss, capt, transFL, transOS, & nu, chi, P0, P1, prod @@ -191,20 +193,24 @@ subroutine testScoring_clerk2(this) call mem % init(1000_longInt, 1) call this % clerk_test2 % setMemAddress(1_longInt) - ! Configure particle dungeon - call pit % init(3) - + ! Report fission particles p % isMG = .false. p % w = 0.5_defReal p % E = 3.0_defReal - call pit % detain(p) + call p % setMatIdx(2) + + ! Scoring + pFiss = p + call this % clerk_test2 % reportSpawn(p, pFiss, this % nucData, mem) p % E = 0.3_defReal - call pit % detain(p) + + ! Scoring + pFiss = p + call this % clerk_test2 % reportSpawn(p, pFiss, this % nucData, mem) ! Scoring call this % clerk_test2 % reportInColl(p, this % nucData, mem, .false.) - call this % clerk_test2 % reportCycleEnd(pit, mem) p % preCollision % wgt = 0.2_defReal p % preCollision % E = 0.3_defReal diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 8de338063..c85330dc0 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -99,7 +99,7 @@ module mgXsClerk_class ! File reports -> run-time procedures procedure :: reportInColl procedure :: reportOutColl - procedure :: reportCycleEnd + procedure :: reportSpawn ! Output procedures procedure :: print @@ -124,7 +124,7 @@ subroutine init(self, dict, name) ! Assign name call self % setName(name) - + ! Load energy map and bin number if (dict % isPresent('energyMap')) then call new_tallyMap(self % energyMap, dict % getDictPtr('energyMap')) @@ -186,7 +186,7 @@ function validReports(self) result(validCodes) class(mgXsClerk),intent(in) :: self integer(shortInt),dimension(:),allocatable :: validCodes - validCodes = [inColl_CODE, outColl_CODE, cycleEnd_CODE] + validCodes = [inColl_CODE, outColl_CODE, spawn_CODE] end function validReports @@ -406,48 +406,43 @@ subroutine reportOutColl(self, p, MT, muL, xsData, mem) end subroutine reportOutColl !! - !! Process end of the cycle to score fission spectrum with an analog estimator + !! Process fission report !! !! See tallyClerk_inter for details !! - subroutine reportCycleEnd(self, end, mem) - class(mgXsClerk), intent(inout) :: self - class(particleDungeon), intent(in) :: end - type(scoreMemory), intent(inout) :: mem - integer(longInt) :: addr, binIdx, enIdx, matIdx - integer(shortInt) :: N, i - - ! Loop over the whole neutron population - N = end % popSize() - do i = 1,N - - ! Find bin indexes - ! Energy - if (allocated(self % energyMap)) then - enIdx = self % energyN + 1 - self % energyMap % map(end % get(i)) - else - enIdx = 1 - end if - ! Space - if (allocated(self % spaceMap)) then - matIdx = self % spaceMap % map(end % get(i)) - else - matIdx = 1 - end if + subroutine reportSpawn(self, pOld, pNew, xsData, mem) + class(mgXsClerk), intent(inout) :: self + class(particle), intent(in) :: pOld + class(particleState), intent(in) :: pNew + class(nuclearDatabase), intent(inout) :: xsData + type(scoreMemory), intent(inout) :: mem + integer(longInt) :: addr, binIdx, enIdx, matIdx - ! Return if invalid bin index - if ((enIdx == self % energyN + 1) .or. matIdx == 0) cycle + ! Find bin indexes + ! Energy + if (allocated(self % energyMap)) then + enIdx = self % energyN + 1 - self % energyMap % map(pNew) + else + enIdx = 1 + end if + ! Space + if (allocated(self % spaceMap)) then + matIdx = self % spaceMap % map(pNew) + else + matIdx = 1 + end if - ! Calculate bin address - binIdx = self % energyN * (matIdx - 1) + enIdx - addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 + ! Return if invalid bin index + if ((enIdx == self % energyN + 1) .or. matIdx == 0) return - ! Score energy group of fission neutron - call mem % score(ONE, addr + CHI_idx) + ! Calculate bin address + binIdx = self % energyN * (matIdx - 1) + enIdx + addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 - end do + ! Score energy group of fission neutron + call mem % score(ONE, addr + CHI_idx) - end subroutine reportCycleEnd + end subroutine reportSpawn !! !! Final processing to calculate the multi-group cross sections, fission data and diff --git a/Tallies/TallyClerks/tallyClerkSlot_class.f90 b/Tallies/TallyClerks/tallyClerkSlot_class.f90 index bceba3e1a..c3a9fa6ab 100644 --- a/Tallies/TallyClerks/tallyClerkSlot_class.f90 +++ b/Tallies/TallyClerks/tallyClerkSlot_class.f90 @@ -3,7 +3,7 @@ module tallyClerkSlot_class use numPrecision use genericProcedures, only : fatalError use dictionary_class, only : dictionary - use particle_class, only : particle + use particle_class, only : particle, particleState use particleDungeon_class, only : particleDungeon use tallyClerk_inter, only : tallyClerk, setMemAddress_super => setMemAddress, & setName_super => setName, & @@ -45,6 +45,7 @@ module tallyClerkSlot_class procedure :: reportOutColl procedure :: reportPath procedure :: reportTrans + procedure :: reportSpawn procedure :: reportHist procedure :: reportCycleStart procedure :: reportCycleEnd @@ -229,6 +230,23 @@ subroutine reportTrans(self, p, xsData, mem) end subroutine reportTrans + !! + !! Process fission report + !! + !! See tallyClerk_inter for details + !! + subroutine reportSpawn(self, pOld, pNew, xsData, mem) + class(tallyClerkSlot), intent(inout) :: self + class(particle), intent(in) :: pOld + class(particleState), intent(in) :: pNew + class(nuclearDatabase), intent(inout) :: xsData + type(scoreMemory), intent(inout) :: mem + + ! Pass call to instance in the slot + call self % slot % reportSpawn(pOld, pNew, xsData, mem) + + end subroutine reportSpawn + !! !! Process history report !! diff --git a/Tallies/TallyClerks/tallyClerk_inter.f90 b/Tallies/TallyClerks/tallyClerk_inter.f90 index 602fea2cb..e55141537 100644 --- a/Tallies/TallyClerks/tallyClerk_inter.f90 +++ b/Tallies/TallyClerks/tallyClerk_inter.f90 @@ -4,7 +4,7 @@ module tallyClerk_inter use tallyCodes use dictionary_class, only : dictionary use genericProcedures, only : fatalError - use particle_class, only : particle + use particle_class, only : particle, particleState use particleDungeon_class, only : particleDungeon use outputFile_class, only : outputFile @@ -57,6 +57,7 @@ module tallyClerk_inter !! reportOutColl -> Process an outgoing from collision report !! reportPath -> Process pathlength report !! reportTrans -> Process transition report + !! reportSpawn -> Process fission report !! reportHist -> Process history report !! reportCycleStart -> Process beginning of a cycle report !! reportCycleEnd -> Process end of a cycle report (e.g. Calculate functions of scores like k-eff) @@ -91,6 +92,7 @@ module tallyClerk_inter procedure :: reportOutColl procedure :: reportPath procedure :: reportTrans + procedure :: reportSpawn procedure :: reportHist procedure :: reportCycleStart procedure :: reportCycleEnd @@ -117,6 +119,7 @@ module tallyClerk_inter !! outColl_CODE !! path_CODE !! trans_CODE + !! spawn_CODE !! hist_CODE !! cycleStart_CODE !! cycleEnd_CODE @@ -219,7 +222,7 @@ end subroutine print !! See tallyAdmin_class for implicit assumptions about the report. !! !! Args: - !! p [in] -> Partice + !! p [in] -> Particle !! xsData [inout] -> Nuclear Database with XSs data !! mem [inout] -> Score Memory to put results on !! virtual [in] -> Flag indicating virtual collision @@ -235,7 +238,7 @@ subroutine reportInColl(self,p, xsData, mem, virtual) logical(defBool), intent(in) :: virtual character(100),parameter :: Here = 'reportInColl (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportInColl @@ -246,7 +249,7 @@ end subroutine reportInColl !! See tallyAdmin_class for implicit assumptionas about the report. !! !! Args: - !! p [in] -> Partice + !! p [in] -> Particle !! MT [in] -> MT number of reaction that partilce underwent in the collision !! muL [in] -> Cosine of the collision deflection angle in LAB frame !! xsData [inout]-> Nuclear Database with XSs data @@ -264,7 +267,7 @@ subroutine reportOutColl(self, p, MT, muL, xsData, mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportOutColl (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportOutColl @@ -274,7 +277,7 @@ end subroutine reportOutColl !! See tallyAdmin_class for implicit assumptionas about the report. !! !! Args: - !! p [in] -> Partice + !! p [in] -> Particle !! L [in] -> Length of the path [cm] !! xsData [inout] -> Nuclear Database with XSs data !! mem [inout] -> Score Memory to put results on @@ -290,7 +293,7 @@ subroutine reportPath(self, p, L, xsData,mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportPath (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportPath @@ -300,7 +303,7 @@ end subroutine reportPath !! See tallyAdmin_class for implicit assumptionas about the report. !! !! Args: - !! p [in] -> Partice + !! p [in] -> Particle !! xsData [inout] -> Nuclear Database with XSs data !! mem [inout] -> Score Memory to put results on !! @@ -314,17 +317,43 @@ subroutine reportTrans(self, p, xsData, mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportTrans (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportTrans + !! + !! Process fission report + !! + !! See tallyAdmin_class for implicit assumptionas about the report. + !! + !! Args: + !! pOld [in] -> Particle that caused the fission event + !! pNew [in] -> Particle state of the fission neutron + !! xsData [inout] -> Nuclear Database with XSs data + !! mem [inout] -> Score Memory to put results on + !! + !! Errors: + !! Depend on specific Clerk + !! + subroutine reportSpawn(self, pOld, pNew, xsData, mem) + class(tallyClerk), intent(inout) :: self + class(particle), intent(in) :: pOld + class(particleState), intent(in) :: pNew + class(nuclearDatabase), intent(inout) :: xsData + type(scoreMemory), intent(inout) :: mem + character(100),parameter :: Here = 'reportSpawn (tallyClerk_inter.f90)' + + call fatalError(Here,'Report was sent to an instance that does not support it.') + + end subroutine reportSpawn + !! !! Process history report !! !! See tallyAdmin_class for implicit assumptionas about the report. !! !! Args: - !! p [in] -> Partice + !! p [in] -> Particle !! xsData [inout] -> Nuclear Database with XSs data !! mem [inout] -> Score Memory to put results on !! @@ -338,7 +367,7 @@ subroutine reportHist(self, p, xsData, mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportHist (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportHist @@ -360,7 +389,7 @@ subroutine reportCycleStart(self, start, mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportCycleStart (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportCycleStart @@ -382,7 +411,7 @@ subroutine reportCycleEnd(self, end, mem) type(scoreMemory), intent(inout) :: mem character(100),parameter :: Here = 'reportCycleEnd (tallyClerk_inter.f90)' - call fatalError(Here,'Report was send to an instance that does not support it.') + call fatalError(Here,'Report was sent to an instance that does not support it.') end subroutine reportCycleEnd diff --git a/Tallies/tallyActiveAdmin_class.f90 b/Tallies/tallyActiveAdmin_class.f90 deleted file mode 100644 index dd7f01d76..000000000 --- a/Tallies/tallyActiveAdmin_class.f90 +++ /dev/null @@ -1,232 +0,0 @@ -module tallyActiveAdmin_class - - use numPrecision - use tallyCodes - use genericProcedures, only : charCmp - use dictionary_class, only : dictionary - use tallyAdminBase_class, only : tallyAdminBase, & - reportInColl_super => reportInColl, & - reportOutColl_super => reportOutColl, & - reportHist_super => reportHist, & - reportCycleStart_super => reportCycleStart, & - reportCycleEnd_super => reportCycleEnd, & - isConverged_super => isConverged, & - init_super => init ,& - print_super => print, & - kill_super => kill ,& - display_super => display - use particle_class, only : particle, phaseCoord - use particleDungeon_class, only : particleDungeon - use keffActiveClerk_class, only : keffActiveClerk - use outputFile_class, only : outputFile - - implicit none - private - - type, public,extends(tallyAdminBase) :: tallyActiveAdmin - private - type(keffActiveClerk) :: keff_estimator - logical(defBool) :: keff_convergence = .false. - contains - ! New Interface - procedure :: keff - - ! Extend superclass procedures - procedure :: reportInColl - procedure :: reportOutColl - procedure :: reportHist - procedure :: reportCycleStart - procedure :: reportCycleEnd - procedure :: init - procedure :: print - procedure :: kill - procedure :: display - procedure :: isConverged - - end type tallyActiveAdmin - -contains - !! - !! Return estimate of k-eff to be used in a calculation for normalisation - !! - function keff(self) result(k) - class(tallyActiveAdmin), intent(in) :: self - real(defReal) :: k - - k = self % keff_estimator % keff() - - end function keff - - !! - !! Process incoming collision report - !! - subroutine reportInColl(self, p) - class(tallyActiveAdmin), intent(inout) :: self - class(particle), intent(in) :: p - - ! Process report with internal Clerk - call self % keff_estimator % reportInColl(p) - - ! Call superclass procedure on self - call reportInColl_super(self, p) - - end subroutine reportInColl - - !! - !! Process outgoing collision report - !! - subroutine reportOutColl(self,p,MT,muL) - class(tallyActiveAdmin), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt), intent(in) :: MT - real(defReal), intent(in) :: muL - - ! Process report with internal Clerk - call self % keff_estimator % reportOutColl(p, MT, muL) - - ! Call superclass procedure on self - call reportOutColl_super(self, p, MT, muL) - - end subroutine reportOutColl - - !! - !! Process history report - !! ASSUMPTIONS: - !! - subroutine reportHist(self, p) - class(tallyActiveAdmin), intent(inout) :: self - class(particle), intent(in) :: p - - ! Process report with internal Clerk - call self % keff_estimator % reportHist(p) - - ! Call superclass procedure on self - call reportHist_super(self, p) - - end subroutine reportHist - - !! - !! Process beginning of a cycle - !! - subroutine reportCycleStart(self, start) - class(tallyActiveAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: start - - ! Process report with internal Clerk - call self % keff_estimator % reportCycleStart(start) - - ! Call superclass procedure on self - call reportCycleStart_super(self, start) - - end subroutine reportCycleStart - - !! - !! Process end of the cycle - !! - subroutine reportCycleEnd(self, end) - class(tallyActiveAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: end - - ! Process report with internal Clerk - call self % keff_estimator % reportCycleEnd(end) - - ! Call superclass procedure on self - call reportCycleEnd_super(self, end) - - end subroutine reportCycleEnd - - !! - !! Initialise active admin - !! - subroutine init(self,dict) - class(tallyActiveAdmin), intent(inout) :: self - class(dictionary),intent(in) :: dict - type(dictionary) :: embDict - character(nameLen) :: entry - real(defReal) :: temp - - call embDict % init(3) - - ! Read settings for embedded clerk and put them into embDict - call dict % getOrDefault(entry,'trigger','no') - - if( charCmp(entry,'yes') ) then - self % keff_convergence = .true. - call dict % get(temp,'SDtarget') - call embDict % store('trigger','yes') - call embDict % store('SDtarget',temp) - end if - - call embDict % store('type','keffActiveClerk') - - ! Initialise embedded clerk - entry = 'A_ADMIN' - call self % keff_estimator % init(embDict,entry) - - ! Load rest of the clerks - call init_super(self,dict) - - end subroutine init - - !! - !! Add all results to outputfile - !! - subroutine print(self,output) - class(tallyActiveAdmin), intent(in) :: self - class(outputFile), intent(inout) :: output - - call self % keff_estimator % print(output) - call print_super(self,output) - - end subroutine print - - !! - !! Deallocates all content - !! - subroutine kill(self) - class(tallyActiveAdmin), intent(inout) :: self - - ! Kill internal Clerks - - ! Call superclass procedure on self - call kill_super(self) - - end subroutine kill - - !! - !! Display results at the end of a cycle - !! - subroutine display(self) - class(tallyActiveAdmin), intent(in) :: self - - print *,'Active Cycle:' - call self % keff_estimator % display() - - ! Call superclass procedure on self - call display_super(self) - - end subroutine display - - !! - !! - !! - function isConverged(self) result(isIt) - class(tallyActiveAdmin), intent(in) :: self - logical(defBool) :: isIt - - if( self % keff_convergence) then - isIt = self % keff_estimator % isConverged() - - if ( self % checkConvergence ) isIt = isIt .and. isConverged_super(self) - - else if ( self % checkConvergence ) then - isIt = isConverged_super(self) - - else - isIt = .false. - - end if - - end function isConverged - -end module tallyActiveAdmin_class diff --git a/Tallies/tallyAdminBase_class.f90 b/Tallies/tallyAdminBase_class.f90 deleted file mode 100644 index 6643e2d4d..000000000 --- a/Tallies/tallyAdminBase_class.f90 +++ /dev/null @@ -1,437 +0,0 @@ -module tallyAdminBase_class - - use numPrecision - use tallyCodes - use genericProcedures, only : fatalError, charCmp - use dictionary_class, only : dictionary - use particle_class, only : particle, phaseCoord - use particleDungeon_class, only : particleDungeon - use tallyClerk_inter, only : tallyClerk - use tallyClerkSlot_class, only : tallyClerkSlot - use tallyClerkFactory_func, only : new_tallyClerk - use outputFile_class, only : outputFile - - - implicit none - private - !! **** MOST LIKLEY CHANGE INTERFACES FOR CLERKS TO INCLUDE FLUX FOR IN COLLISION AND PATH - !! **** PRECALCULATE FLUX HERE SO THERE IS NO NEED TO WARY ABOUT DYNAMIC TYPE OF XSDATA IN CLERKS - !! - !! Base class for the tallies black box. - !! Its responsibilities are as flolow: - !! 1) Accept events reports and routes then to individual tallyClerks - !! 2) Returns k-eff estimate for a current cycle - !! 3) Controls end of calculation - !! 4) Controls printing of calculation progress (to a console) - !! 5) Controls printing of result estimators to a file (filePath and file Format) - !! - !! This class will be extended by inheritance to provide additional functionality - !! i.e. return mesh based weight windows based on fission matrix or similar - !! - !! - type, public:: tallyAdminBase - private - logical(defBool), public :: checkConvergence = .false. - - type(tallyClerkSlot),dimension(:),allocatable :: tallyClerks - - ! Lists of Clerks to be executed for each procedure - integer(shortInt),dimension(:),allocatable :: inCollClerks - integer(shortInt),dimension(:),allocatable :: outCollClerks - integer(shortInt),dimension(:),allocatable :: pathClerks - integer(shortInt),dimension(:),allocatable :: transClerks - integer(shortInt),dimension(:),allocatable :: histClerks - integer(shortInt),dimension(:),allocatable :: cycleStartClerks - integer(shortInt),dimension(:),allocatable :: cycleEndClerks - - ! List of clerks to display - integer(shortInt), dimension(:),allocatable :: displayList - integer(shortInt), dimension(:),allocatable :: triggerList - - contains - ! Report Interface - procedure :: reportInColl - procedure :: reportOutColl - procedure :: reportPath - procedure :: reportTrans - procedure :: reportHist - procedure :: reportCycleStart - procedure :: reportCycleEnd - - ! Display procedures - procedure :: display - - ! Convergance check - procedure :: isConverged - - ! File writing procedures - procedure :: print - - ! Build procedures - procedure :: init - procedure :: addTallyClerk - procedure :: kill - - procedure,private :: addToReports - - end type tallyAdminBase - - - public :: reportInColl - public :: reportOutColl - public :: reportPath - public :: reportTrans - public :: reportHist - public :: reportCycleStart - public :: reportCycleEnd - public :: display - public :: isConverged - public :: init - public :: print - public :: kill - -contains - !! - !! Process incoming collision report - !! - subroutine reportInColl(self,p) - class(tallyAdminBase), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % inCollClerks) -! idx = self % inCollClerks(i) -! call self % tallyClerks(idx) % reportInColl(p) -! -! end do - - end subroutine reportInColl - - !! - !! Display convergance progress of selected tallies on the console - !! - subroutine display(self) - class(tallyAdminBase), intent(in) :: self - integer(shortInt) :: i - -! ! Go through all clerks marked as part of the display -! do i=1,size(self % displayList) -! call self % tallyClerks(i) % display() -! -! end do - - end subroutine display - - !! - !! Perform convergence check in selected clerks - !! - function isConverged(self) result(isIt) - class(tallyAdminBase), intent(in) :: self - logical(defBool) :: isIt - integer(shortInt) :: i,N - -! N = size( self % triggerList) -! -! if( N > 0 ) then -! isIt = self % tallyClerks(1) % isConverged() -! do i = 2,N -! isIt = isIt .and. self % tallyClerks(i) % isConverged() -! -! end do -! else -! isIt = .false. -! -! end if - - end function isConverged - - !! - !! Add all results to outputfile - !! - subroutine print(self,output) - class(tallyAdminBase), intent(in) :: self - class(outputFile), intent(inout) :: output - integer(shortInt) :: i - -! do i=1,size(self % tallyClerks) -! call self % tallyClerks(i) % print(output) -! end do - - end subroutine print - - !! - !! Process outgoing collision report - !! Assume that pre is AFTER any implicit treatment (i.e. implicit capture) - !! - subroutine reportOutColl(self,p,MT,muL) - class(tallyAdminBase), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt), intent(in) :: MT - real(defReal), intent(in) :: muL - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % outCollClerks) -! idx = self % outCollClerks(i) -! call self % tallyClerks(idx) % reportOutColl(p,MT,muL) -! -! end do - - end subroutine reportOutColl - - !! - !! Process pathlength report - !! ASSUMPTIONS: - !! Pathlength must be contained within a single cell and material - !! - subroutine reportPath(self,p,L) - class(tallyAdminBase), intent(inout) :: self - class(particle), intent(in) :: p - real(defReal), intent(in) :: L - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % pathClerks) -! idx = self % pathClerks(i) -! call self % tallyClerks(idx) % reportPath(p,L) -! -! end do - - end subroutine reportPath - - !! - !! Process transition report - !! ASSUMPTIONS: - !! Transition must be a straight line - !! Pre and Post direction is assumed the same (aligned with r_pre -> r_post vector) - !! - subroutine reportTrans(self,p) - class(tallyAdminBase), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % transClerks) -! idx = self % transClerks(i) -! call self % tallyClerks(idx) % reportTrans(p) -! -! end do - - end subroutine reportTrans - - !! - !! Process history report - !! ASSUMPTIONS: - !! - subroutine reportHist(self,p) - class(tallyAdminBase), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % histClerks) -! idx = self % histClerks(i) -! call self % tallyClerks(idx) % reportHist(p) -! -! end do - - - end subroutine reportHist - - !! - !! Process beginning of a cycle - !! - subroutine reportCycleStart(self,start) - class(tallyAdminBase), intent(inout) :: self - class(particleDungeon), intent(in) :: start - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % cycleStartClerks) -! idx = self % cycleStartClerks(i) -! call self % tallyClerks(idx) % reportCycleStart(start) -! -! end do - - end subroutine reportCycleStart - - !! - !! Process end of the cycle - !! - subroutine reportCycleEnd(self,end) - class(tallyAdminBase), intent(inout) :: self - class(particleDungeon), intent(in) :: end - integer(shortInt) :: i, idx - -! ! Go through all clerks that request the report -! do i=1,size(self % cycleEndClerks) -! idx = self % cycleEndClerks(i) -! call self % tallyClerks(idx) % reportCycleEnd(end) -! -! end do - - end subroutine reportCycleEnd - - !! - !! Initialise tallyAdminBase form dictionary - !! - subroutine init(self,dict) - class(tallyAdminBase), intent(inout) :: self - class(dictionary), intent(in) :: dict - character(nameLen),dimension(:),allocatable :: clerks - type(dictionary) :: locDict - character(nameLen) :: entry - logical(defBool) :: partOfDisplay, partOfTriggers - integer(shortInt) :: i - - -! ! Deallocate -! call self % kill() -! -! ! Allocate contents -! allocate(self % inCollClerks(0) ) -! allocate(self % outCollClerks(0) ) -! allocate(self % pathClerks(0) ) -! allocate(self % transClerks(0) ) -! allocate(self % histClerks(0) ) -! allocate(self % cycleStartClerks(0) ) -! allocate(self % cycleEndClerks(0) ) -! -! allocate(self% displayList(0) ) -! allocate(self% triggerList(0) ) -! -! allocate(self % tallyClerks(0)) -! -! ! Read all dictionaries -! call dict % keysDict(clerks) -! -! ! Load all dictionaries as clerks -! do i=1,size(clerks) -! ! Copy dictionary to local copy -! call dict % get(locDict,clerks(i)) -! -! ! Check if it is part of the display -! call locDict % getOrDefault(entry,'display','no') -! partOfDisplay = charCmp(entry,'yes') -! -! ! Check if it is part of the convergance triggers -! call locDict % getOrDefault(entry,'trigger','no') -! partOfTriggers = charCmp(entry,'yes') -! -! ! Get new clerk from factory and store it ina aslot -! call self % addTallyClerk( new_tallyClerk(locDict,clerks(i)),partOfDisplay,partOfTriggers) -! -! end do - - - end subroutine init - - !! - !! Attach new tally - !! - subroutine addTallyClerk(self, clerk, partOfDisplay, partOfTriggers) - class(tallyAdminBase), intent(inout) :: self - class(tallyClerk), intent(in) :: clerk - logical(defBool),intent(in) :: partOfDisplay - logical(defBool),intent(in) :: partOfTriggers - type(tallyClerkSlot) :: localSlot - integer(shortInt),dimension(:),allocatable :: reportCodes - integer(shortInt) :: N, i - - character(100),parameter :: Here = 'addTallyClerk (tallyAdminBase_class.f90)' - -! ! Check if provided clerk is a slot. Give error if it is -! select type(clerk) -! type is (tallyClerkSlot) -! call fatalError(Here,'tallyCleakSlot was passed. It is forbidden to avoid nested slots.') -! end select -! -! ! Check if the tallyAdminBase is initialised -! if( .not. allocated(self % tallyClerks) ) then -! call fatalError(Here,'tallyAdminBase is uninitialised') -! end if -! -! ! Append tally Clerks. Automatic reallocation on assignment. F2008 feature -! localSlot = clerk -! self % tallyClerks = [self % tallyClerks, localSlot] -! -! ! Obtain list of reports requested by the loaded clerk -! N = size(self % tallyClerks) -! reportCodes = self % tallyClerks(N) % validReports() -! -! ! Append report sorting arrays with index of new tallyClerk -! do i=1,size(reportCodes) -! call self % addToReports( reportCodes(i), N ) -! end do -! -! ! If clerk is partOfDisplay append displayList -! if (partOfDisplay) self % displayList = [self % displayList, N ] -! -! ! If clerk is partOfTriggers append triggerList -! if (partOfTriggers) self % triggerList = [self % triggerList, N ] -! if (partOfTriggers) self % checkConvergence = .true. - - end subroutine addTallyClerk - - !! - !! Deallocates all content - !! - subroutine kill(self) - class(tallyAdminBase), intent(inout) :: self - -! if(allocated(self % tallyClerks)) deallocate( self % tallyClerks ) -! -! if(allocated(self % displayList)) deallocate( self % displayList) -! if(allocated(self % triggerList)) deallocate( self % triggerList) -! -! if(allocated(self % inCollClerks)) deallocate( self % inCollClerks) -! if(allocated(self % outCollClerks)) deallocate( self % outCollClerks ) -! if(allocated(self % pathClerks)) deallocate( self % pathClerks ) -! if(allocated(self % transClerks)) deallocate( self % transClerks ) -! if(allocated(self % histClerks)) deallocate( self % histClerks ) -! if(allocated(self % cycleStartClerks)) deallocate( self % cycleStartClerks ) -! if(allocated(self % cycleEndClerks)) deallocate( self % cycleEndClerks ) - - - end subroutine kill - - !! - !! Append sorrting array identified with the code with tallyClerk idx - !! - subroutine addToReports(self,reportCode,idx) - class(tallyAdminBase),intent(inout) :: self - integer(shortInt), intent(in) :: reportCode - integer(shortInt), intent(in) :: idx - character(100),parameter :: Here='addToReports (tallyAdminBase_class.f90)' - -! select case(reportCode) -! case(inColl_CODE) -! self % inCollClerks = [self % inCollClerks, idx] -! -! case(outColl_CODE) -! self % outCollClerks = [ self % outCollClerks, idx] -! -! case(path_CODE) -! self % pathClerks = [ self % pathClerks, idx] -! -! case(trans_CODE) -! self % transClerks = [ self % transClerks, idx] -! -! case(hist_CODE) -! self % histClerks = [ self % histClerks, idx] -! -! case(cycleStart_CODE) -! self % cycleStartClerks = [ self % cycleStartClerks, idx] -! -! case(cycleEnd_CODE) -! self % cycleEndClerks = [ self % cycleEndClerks, idx] -! -! case default -! call fatalError(Here, 'Undefined reportCode') -! end select - - end subroutine addToReports - - -end module tallyAdminBase_class diff --git a/Tallies/tallyAdmin_class.f90 b/Tallies/tallyAdmin_class.f90 index 0e35adfdf..f36b87dc1 100644 --- a/Tallies/tallyAdmin_class.f90 +++ b/Tallies/tallyAdmin_class.f90 @@ -6,7 +6,7 @@ module tallyAdmin_class use dictionary_class, only : dictionary use dynArray_class, only : dynIntArray use charMap_class, only : charMap - use particle_class, only : particle + use particle_class, only : particle, particleState use particleDungeon_class, only : particleDungeon use tallyClerk_inter, only : tallyClerk use tallyClerkSlot_class, only : tallyClerkSlot @@ -50,6 +50,7 @@ module tallyAdmin_class !! outCollClerks -> List of indices of all Clerks that require outCollReport !! pathClerks -> List of indices of all Clerks that require pathReport !! transClerks -> List of indices of all Clerks that require transReport + !! spawnClerks -> List of indices of all Clerks that require spawnReport !! histClerks -> List of indices of all Clerks that require histReport !! cycleStartClerks -> List of indices of all Clerks that require cycleStartReport !! cycleEndClerks -> List of indices of all Clerks that require cycleEndReport @@ -66,6 +67,7 @@ module tallyAdmin_class !! reportOutColl -> Process post-collision reports in all clerks !! reportPath -> Process pathlength reports in all clerks !! reportTrans -> Process transition reports in all clerks + !! reportSpawn -> Process fission reports in all clerks !! reportHist -> Process History reports in all clerks !! reportCycleStart -> Process Start Of Cycle reports in all clerks !! reportCycleEnd -> Process End of Cycle reports in all clerks @@ -106,6 +108,7 @@ module tallyAdmin_class type(dynIntArray) :: outCollClerks type(dynIntArray) :: pathClerks type(dynIntArray) :: transClerks + type(dynIntArray) :: spawnClerks type(dynIntArray) :: histClerks type(dynIntArray) :: cycleStartClerks type(dynIntArray) :: cycleEndClerks @@ -131,6 +134,7 @@ module tallyAdmin_class procedure :: reportOutColl procedure :: reportPath procedure :: reportTrans + procedure :: reportSpawn procedure :: reportHist procedure :: reportCycleStart procedure :: reportCycleEnd @@ -263,6 +267,7 @@ recursive subroutine kill(self) call self % outCollClerks % kill() call self % pathClerks % kill() call self % transClerks % kill() + call self % spawnClerks % kill() call self % histClerks % kill() call self % cycleStartClerks % kill() call self % cycleEndClerks % kill() @@ -472,7 +477,7 @@ end subroutine reportInColl !! Process post-collision report !! !! Assumptions: - !! PreCollision state in partice is set to just before this collision + !! PreCollision state in particle is set to just before this collision !! !! Args: !! p [in] -> Particle @@ -583,6 +588,43 @@ recursive subroutine reportTrans(self, p) end subroutine reportTrans + !! + !! Process fission report + !! + !! Assumptions: + !! TODO: Decide on the details of this report + !! + !! Args: + !! pOld [in] -> Particle that caused the fission event + !! pNew [in] -> Particle state of the fission neutron + !! + !! Errors: + !! None + !! + recursive subroutine reportSpawn(self, pOld, pNew) + class(tallyAdmin), intent(inout) :: self + class(particle), intent(in) :: pOld + class(particleState), intent(in) :: pNew + integer(shortInt) :: i, idx + class(nuclearDatabase),pointer :: xsData + character(100), parameter :: Here = "reportSpwan (tallyAdmin_class.f90)" + + ! Call attachment + if(associated(self % atch)) then + call reportSpawn(self % atch, pOld, pNew) + end if + + ! Get Data + xsData => ndReg_get(pOld % getType(), where = Here) + + ! Go through all clerks that request the report + do i=1,self % spawnClerks % getSize() + idx = self % spawnClerks % get(i) + call self % tallyClerks(idx) % reportSpawn(pOld, pNew, xsData, self % mem) + end do + + end subroutine reportSpawn + !! !! Process history report !! @@ -780,6 +822,9 @@ subroutine addToReports(self, reportCode, idx) case(trans_CODE) call self % transClerks % add(idx) + case(spawn_CODE) + call self % spawnClerks % add(idx) + case(hist_CODE) call self % histClerks % add(idx) diff --git a/Tallies/tallyCodes.f90 b/Tallies/tallyCodes.f90 index 44f7bac69..4a05d37aa 100644 --- a/Tallies/tallyCodes.f90 +++ b/Tallies/tallyCodes.f90 @@ -14,9 +14,10 @@ module tallyCodes outColl_CODE = 1001 ,& path_CODE = 1002 ,& trans_CODE = 1003 ,& - hist_CODE = 1004 ,& - cycleStart_CODE = 1005 ,& - cycleEnd_CODE = 1006 + spawn_CODE = 1004 ,& + hist_CODE = 1005 ,& + cycleStart_CODE = 1006 ,& + cycleEnd_CODE = 1007 ! List of codes for fiffrent particle fates integer(shortInt),parameter,public :: abs_FATE = 5000 ,& diff --git a/Tallies/tallyEstimator_class.f90 b/Tallies/tallyEstimator_class.f90 deleted file mode 100644 index c9cf0d36d..000000000 --- a/Tallies/tallyEstimator_class.f90 +++ /dev/null @@ -1,459 +0,0 @@ -module tallyEstimator_class - - use numPrecision - - implicit none - private - - !! - !! Class to contain a score accumulated during a cycle or history or equvalent - !! Internal counter is initialised to 0.0 on creation - !! INTERFACE: - !! add(score) -> adds argument score to internal counter score is defReal,sgortInt or longInt - !! get() -> function, returns value(defReal) of internal counter - !! reset() -> resets internal counter to 0.0 - !! NOTES: - !! This class exists to hide thread safe addition to a tally score from a user. - !! IT IS NOT THREAD SAFE YET. - !! - type, public :: tallyScore - private - real(defReal) :: score = ZERO - contains - generic :: add => add_tallyScore_defReal, & - add_tallyScore_shortInt, & - add_tallyScore_longInt - procedure :: get => get_tallyScore - procedure :: reset => reset_tallyScore - - procedure, private :: add_tallyScore_defReal - procedure, private :: add_tallyScore_shortInt - procedure, private :: add_tallyScore_longInt - - end type tallyScore - - !! - !! Class to store an estimate of a quantity provided over many cycles, histories or batches - !! Is composed and dependent on tallyScore - !! INTERFACE: - !! addEstimate(est) -> adds extra estimate to internal storage, estimate(est) can be - !! defReal, shortInt or longInt. - !! getEstimate(est,STD,N)-> calculates mean estimate and standard deviation of an estimate. - !! est & STD are defReal. N is shortInt. There is no protection - !! against N = 0. Compiler default rules for division by 0 are - !! followed. For N=1 pseudo-variance estimate is returned with N-1 - !! term dropped. This is for estetic reasons. This estimate is - !! unreliable. - !! reset() -> resets internal counters to 0.0 - !! NOTES: - !! This class exists to wrap cumulative sum and of estimate and estimate^2. - !! It is assumed it will be called beween parallel cycles. IS NOT THREAD SAFE - !! - type, public :: tallyCounter - private - type(tallyScore) :: cSum - type(tallyScore) :: cSum2 - - contains - generic :: addEstimate => addEstimate_tallyCounter_defReal, & - addEstimate_tallyCounter_shortInt, & - addEstimate_tallyCounter_longInt - generic :: getEstimate => getEstimate_tallyCounter_withSTD, & - getEstimate_tallyCounter_withoutSTD - procedure :: reset => reset_tallyCounter - - procedure,private :: getEstimate_tallyCounter_withSTD - procedure,private :: getEstimate_tallyCounter_withoutSTD - - procedure,private :: addEstimate_tallyCounter_defReal - procedure,private :: addEstimate_tallyCounter_shortInt - procedure,private :: addEstimate_tallyCounter_longInt - - end type tallyCounter - - !! - !! Class that combine tallyScore and tally Counter into one entity. - !! It is used with estimates based on a single integration (i.e. reaction rates) - !! INTERFACE: - !! add(score) -> adds argument score to internal tallyScore is defReal,sgortInt or longInt - !! get() -> function, returns value(defReal) in internal tallyScore - !! closeBatch(N)-> closes batch. Normalises value in internal tallyScore by N. - !! N can be defReal, shortInt and longInt. If no scores were accumulated - !! during a batch (exactly 0.0 value in tallyScore), batch-wise estimate is 0.0 - !! even if N=0. Otherwise Compiler default rules for division by 0 are followed. - !! getEstimate(est,STD,Nb)-> calculates mean estimate and standard deviation of an estimate. - !! Assumes that Nb batches vere closed before. - !! est & STD are defReal. Nb is shortInt. There is no protection - !! against Nb = 0. Compiler default rules for division by 0 are - !! followed. For Nb=1 pseudo-variance estimate is returned with Nb-1 - !! term dropped. This is for estetic reasons. This estimate is - !! unreliable. - !! NOTES: - !! Class does not store how many batches were closed to save memory and avoid redundunt - !! additions in each class instance. - !! - type, public :: tallyEstimator - private - type(tallyScore) :: score - type(tallyCounter) :: estimate - contains - generic :: add => add_tallyEstimator_defReal, & - add_tallyEstimator_shortInt, & - add_tallyEstimator_longInt - procedure :: get => get_tallyEstimator - generic :: closeBatch => closeBatch_tallyEstimator_defReal, & - closeBatch_tallyEstimator_shortInt, & - closeBatch_tallyEstimator_longInt - generic :: getEstimate => getEstimate_tallyEstimator_withSTD, & - getEstimate_tallyEstimator_withoutSTD - procedure :: reset => reset_tallyEstimator - - procedure, private :: add_tallyEstimator_defReal - procedure, private :: add_tallyEstimator_shortInt - procedure, private :: add_tallyEstimator_longInt - - procedure, private :: closeBatch_tallyEstimator_defReal - procedure, private :: closeBatch_tallyEstimator_shortInt - procedure, private :: closeBatch_tallyEstimator_longInt - - procedure, private :: getEstimate_tallyEstimator_withSTD - procedure, private :: getEstimate_tallyEstimator_withoutSTD - - end type tallyEstimator -contains - -!**************************************************************************************************! -!* tallyScore class procedures *! -!**************************************************************************************************! - !! - !! Add score(defReal) to a score counter - !! - elemental subroutine add_tallyScore_defReal(self,score) - class(tallyScore), intent(inout) :: self - real(defReal), intent(in) :: score - - self % score = self % score + score - - end subroutine add_tallyScore_defReal - - !! - !! Add score(shortInt) to a score counter - !! - elemental subroutine add_tallyScore_shortInt(self,score) - class(tallyScore), intent(inout) :: self - integer(shortInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert to real - score_tmp = real(score,defReal) - - ! Call procedure for real - call self % add_tallyScore_defReal(score_tmp) - - end subroutine add_tallyScore_shortInt - - !! - !! Add score(longInt) to a score counter - !! - elemental subroutine add_tallyScore_longInt(self,score) - class(tallyScore), intent(inout) :: self - integer(longInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert to real - score_tmp = real(score,defReal) - - ! Call procedure for real - call self % add_tallyScore_defReal(score_tmp) - - end subroutine add_tallyScore_longInt - - !! - !! Returns accumulated score value - !! - elemental function get_tallyScore(self) result(score) - class(tallyScore), intent(in) :: self - real(defReal) :: score - - score = self % score - - end function get_tallyScore - - !! - !! Resets score counter - !! - elemental subroutine reset_tallyScore(self) - class(tallyScore), intent(inout) :: self - - self % score = ZERO - - end subroutine reset_tallyScore - -!**************************************************************************************************! -!* tallyCounter class procedures *! -!**************************************************************************************************! - !! - !! Add a result estimate(defReal) to a tallyCounter - !! - elemental subroutine addEstimate_tallyCounter_defReal(self,score) - class(tallyCounter), intent(inout) :: self - real(defReal),intent(in) :: score - - call self % cSum % add(score) - call self % cSum2 % add(score * score ) - - end subroutine addEstimate_tallyCounter_defReal - - !! - !! Add a result estimate(shortInt) to a tallyCounter - !! - elemental subroutine addEstimate_tallyCounter_shortInt(self,score) - class(tallyCounter), intent(inout) :: self - integer(shortInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert and call procedure for defReal - score_tmp = real(score,defReal) - call self % addEstimate(score_tmp) - - end subroutine addEstimate_tallyCounter_shortInt - - !! - !! Add a result estimate(longInt) to a tallyCounter - !! - elemental subroutine addEstimate_tallyCounter_longInt(self,score) - class(tallyCounter), intent(inout) :: self - integer(longInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert and call procedure for defReal - score_tmp = real(score,defReal) - call self % addEstimate(score_tmp) - - end subroutine addEstimate_tallyCounter_longInt - - !! - !! Obtain estimate from a tally Counter. Returns standard deviation - !! Normalise assuming N (shortInt) samples were collected - !! There is no protection against -ve and N = 0 normal float arthmetic rules are followed - !! - elemental subroutine getEstimate_tallyCounter_withSTD(self,est,STD,N) - class(tallyCounter), intent(in) :: self - real(defReal), intent(out) :: est - real(defReal), intent(out) :: STD - integer(shortInt), intent(in) :: N - real(defReal) :: cSum2 - integer(shortInt) :: Nm1 - - cSum2 = self % cSum2 % get() - - ! Call getEstimate without STD to calculate mean - call self % getEstimate(est,N) - - ! Protect against STD = NaN if N == 1. Return variance equal to estimate - ! This mostly done for aesthetics. Single sample estimate is unrealible - if ( N == 1) then - STD = est - - else ! when N /= 1 - ! Precalculate denominator (N-1) - Nm1 = N - 1 - - ! Calculate the Variance of the mean - STD = cSum2 / Nm1 /N - est * est / Nm1 - - ! Calculate Standard Deviation - STD = sqrt(STD) - - end if - - end subroutine getEstimate_tallyCounter_withSTD - - !! - !! Obtain estimate from a tally Counter. Does not returns Standard Deviation. - !! Normalise assuming N (shortInt) samples were collected - !! There is no protection against -ve and N = 0 normal float arthmetic rules are followed - !! - elemental subroutine getEstimate_tallyCounter_withoutSTD(self,est,N) - class(tallyCounter), intent(in) :: self - real(defReal), intent(out) :: est - integer(shortInt), intent(in) :: N - real(defReal) :: cSum - - cSum = self % cSum % get() - - ! Calculate Mean - est = cSum / N - - end subroutine getEstimate_tallyCounter_withoutSTD - - !! - !! Reset tallyCounter - !! - elemental subroutine reset_tallyCounter(self) - class(tallyCounter), intent(inout) :: self - - call self % cSum % reset() - call self % cSum2 % reset() - - end subroutine reset_tallyCounter - -!**************************************************************************************************! -!* tallyEstimate class procedures *! -!**************************************************************************************************! - - !! - !! Add new score(defReal) to a tallyScore in the estimator - !! - elemental subroutine add_tallyEstimator_defReal(self,score) - class(tallyEstimator), intent(inout) :: self - real(defReal), intent(in) :: score - - call self % score % add(score) - - end subroutine add_tallyEstimator_defReal - - !! - !! Add new score(defReal) to a tallyScore in the estimator - !! - elemental subroutine add_tallyEstimator_shortInt(self,score) - class(tallyEstimator), intent(inout) :: self - integer(shortInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert and call procedure for defReal - score_tmp = real(score,defReal) - call self % score % add(score) - - end subroutine add_tallyEstimator_shortInt - - !! - !! Add new score(defReal) to a tallyScore in the estimator - !! - elemental subroutine add_tallyEstimator_longInt(self,score) - class(tallyEstimator), intent(inout) :: self - integer(longInt), intent(in) :: score - real(defReal) :: score_tmp - - ! Convert and call procedure for defReal - score_tmp = real(score,defReal) - call self % score % add(score) - - end subroutine add_tallyEstimator_longInt - - !! - !! Return accumulated score - !! - elemental function get_tallyEstimator(self) result (score) - class(tallyEstimator), intent(in) :: self - real(defReal) :: score - - score = self % score % get() - - end function get_tallyEstimator - - !! - !! Closes Batch - !! Normalise score assuming that total weight of the samples was N(defReal) - !! There is no protection against N == 0 - !! normal float arthmetic rules are followed - !! Special case: if score == 0.0 (exactly in floating points) - !! It corresponds (most likley) to no samples beeing collected - !! Then batch-wise mean is estimated to be 0.0 - !! - elemental subroutine closeBatch_tallyEstimator_defReal(self,N) - class(tallyEstimator), intent(inout) :: self - real(defReal), intent(in) :: N - real(defReal) :: score, mean - - ! Extract score and reset tallyScore - score = self % score % get() - call self % score % reset() - - ! Detect spetial case when no samples were collected - if( score == ZERO ) then - mean = ZERO - - else - mean = score / N - - end if - - ! Add estimate of the mean to the tallyCounter - call self % estimate % addEstimate(mean) - - end subroutine - - !! - !! Normalise score assuming that total weight of the samples was N(shortInt) - !! Converts N into defReal and calls procedure for defReal - !! - elemental subroutine closeBatch_tallyEstimator_shortInt(self,N) - class(tallyEstimator), intent(inout) :: self - integer(shortInt), intent(in) :: N - real(defReal) :: N_tmp - - ! Convert and call procedure for defReal - N_tmp = real(N,defReal) - call self % closeBatch(N_tmp) - - end subroutine closeBatch_tallyEstimator_shortInt - - !! - !! Normalise score assuming that total weight of the samples was N(longInt) - !! Converts N into defReal and calls procedure for defReal - !! - elemental subroutine closeBatch_tallyEstimator_longInt(self,N) - class(tallyEstimator), intent(inout) :: self - integer(longInt), intent(in) :: N - real(defReal) :: N_tmp - - ! Convert and call procedure for defReal - N_tmp = real(N,defReal) - call self % closeBatch(N_tmp) - - end subroutine closeBatch_tallyEstimator_longInt - - !! - !! Obtain estimate from a tally Counter. Returns Standard Deviation. - !! Normalise assuming N (shortInt) batches were collected (with closeBatch) - !! There is no protection against N < 0 and N == 0 - !! Normal float arthmetic rules are followed - !! - elemental subroutine getEstimate_tallyEstimator_withSTD(self,est,STD,Nb) - class(tallyEstimator), intent(in) :: self - real(defReal), intent(out) :: est - real(defReal), intent(out) :: STD - integer(shortInt), intent(in) :: Nb - - call self % estimate % getEstimate(est,STD,Nb) - - end subroutine getEstimate_tallyEstimator_withSTD - - !! - !! Obtain estimate from a tally Counter. Does not return Standard Deviation. - !! Normalise assuming N (shortInt) batches were collected (with closeBatch) - !! There is no protection against N < 0 and N == 0 - !! Normal float arthmetic rules are followed - !! - elemental subroutine getEstimate_tallyEstimator_withoutSTD(self,est,Nb) - class(tallyEstimator), intent(in) :: self - real(defReal), intent(out) :: est - integer(shortInt), intent(in) :: Nb - - call self % estimate % getEstimate(est,Nb) - - end subroutine getEstimate_tallyEstimator_withoutSTD - - !! - !! Resets score and estimate of tallyEstimate - !! - elemental subroutine reset_tallyEstimator(self) - class(tallyEstimator), intent(inout) :: self - - call self % score % reset() - call self % estimate % reset() - - end subroutine reset_tallyEstimator - -end module tallyEstimator_class diff --git a/Tallies/tallyInactiveAdmin_class.f90 b/Tallies/tallyInactiveAdmin_class.f90 deleted file mode 100644 index 1f7e4507a..000000000 --- a/Tallies/tallyInactiveAdmin_class.f90 +++ /dev/null @@ -1,132 +0,0 @@ -module tallyInactiveAdmin_class - - use numPrecision - use tallyCodes - use dictionary_class, only : dictionary - use tallyAdminBase_class, only : tallyAdminBase, & - reportCycleStart_super => reportCycleStart, & - reportCycleEnd_super => reportCycleEnd, & - init_super => init, & - kill_super => kill, & - display_super => display - use particle_class, only : particle, phaseCoord - use particleDungeon_class, only : particleDungeon - use keffInactiveClerk_class, only : keffInactiveClerk - - implicit none - private - - type, public,extends(tallyAdminBase) :: tallyInactiveAdmin - private - type(keffInactiveClerk) :: keff_estimator - contains - ! New interface - procedure :: keff - - ! Extend superclass procedures - procedure :: reportCycleStart - procedure :: reportCycleEnd - procedure :: init - procedure :: kill - procedure :: display - - ! Overwrite superclass procedures - - - end type tallyInactiveAdmin - -contains - - !! - !! Return estimate of k-eff to be used in a calculation for normalisation - !! - function keff(self) result(k) - class(tallyInactiveAdmin), intent(in) :: self - real(defReal) :: k - - k = self % keff_estimator % keff() - - end function keff - - !! - !! Process beginning of a cycle - !! - subroutine reportCycleStart(self,start) - class(tallyInactiveAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: start - - ! Process report with internal Clerk - call self % keff_estimator % reportCycleStart(start) - - ! Call superclass procedure on self - call reportCycleStart_super(self,start) - - end subroutine reportCycleStart - - !! - !! Process end of the cycle - !! - subroutine reportCycleEnd(self,end) - class(tallyInactiveAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: end - - ! Process report with internal Clerk - call self % keff_estimator % reportCycleEnd(end) - - ! Call superclass procedure on self - call reportCycleEnd_super(self,end) - - end subroutine reportCycleEnd - - !! - !! Initialise active admin - !! - subroutine init(self,dict) - class(tallyInactiveAdmin), intent(inout) :: self - class(dictionary),intent(in) :: dict - type(dictionary) :: embDict - character(nameLen) :: name - - ! Get settings for the embedded clerk into dictionary - call embDict % init(1) - call embDict % store('type','keffInactiveClerk') - - ! Initialise embedded clerk - name = 'IA_ADMIN' - call self % keff_estimator % init(embDict,name) - - ! Load rest of the clerks - call init_super(self,dict) - - end subroutine init - - - - !! - !! Deallocates all content - !! - subroutine kill(self) - class(tallyInactiveAdmin), intent(inout) :: self - - ! Kill internal Clerks - - ! Call superclass procedure on self - call kill_super(self) - - end subroutine kill - - !! - !! Display results at the end of a cycle - !! - subroutine display(self) - class(tallyInactiveAdmin), intent(in) :: self - - print *,'Inactive Cycle:' - call self % keff_estimator % display() - - ! Call superclass procedure on self - call display_super(self) - - end subroutine display - -end module tallyInactiveAdmin_class diff --git a/Tallies/tallyTimeAdmin_class.f90 b/Tallies/tallyTimeAdmin_class.f90 deleted file mode 100644 index 25163d72f..000000000 --- a/Tallies/tallyTimeAdmin_class.f90 +++ /dev/null @@ -1,219 +0,0 @@ -module tallyTimeAdmin_class - - use numPrecision - use tallyCodes - use genericProcedures, only : charCmp - use dictionary_class, only : dictionary - use tallyAdminBase_class, only : tallyAdminBase, & - reportInColl_super => reportInColl, & - reportHist_super => reportHist, & - reportCycleStart_super => reportCycleStart, & - reportCycleEnd_super => reportCycleEnd, & - isConverged_super => isConverged, & - init_super => init ,& - print_super => print, & - kill_super => kill ,& - display_super => display - use particle_class, only : particle, phaseCoord - use particleDungeon_class, only : particleDungeon - use timeClerk_class, only : timeClerk - use outputFile_class, only : outputFile - - implicit none - private - - type, public,extends(tallyAdminBase) :: tallyTimeAdmin - private - type(timeClerk) :: power_estimator - logical(defBool):: power_convergence = .false. - contains - ! New Interface - procedure :: power - procedure :: stepLength - procedure :: incrementStep - - ! Extend superclass procedures - procedure :: reportInColl - procedure :: reportHist - procedure :: reportCycleStart - procedure :: reportCycleEnd - procedure :: init - procedure :: print - procedure :: kill - procedure :: display - procedure :: isConverged - - end type tallyTimeAdmin - -contains - !! - !! Return estimate of power to be used in normalisation and results - !! - function power(self) result(p) - class(tallyTimeAdmin), intent(in) :: self - real(defReal) :: p - - p = self % power_estimator % power() - - end function power - - !! - !! Return timestep length given an index - !! - function stepLength(self,idx) result(dt) - class(tallyTimeAdmin), intent(in) :: self - integer(shortInt), intent(in) :: idx - real(defReal) :: dt - - dt = self % power_estimator % stepLength(idx) - - end function stepLength - - !! - !! Increment step count - !! - subroutine incrementStep(self) - class(tallyTimeAdmin), intent(inout) :: self - call self % power_estimator % incrementStep() - end subroutine incrementStep - - !! - !! Process incoming collision report - !! - subroutine reportInColl(self, p) - class(tallyTimeAdmin), intent(inout) :: self - class(particle), intent(in) :: p - - ! Process report with internal Clerk - call self % power_estimator % reportInColl(p) - - ! Call superclass procedure on self - call reportInColl_super(self, p) - - end subroutine reportInColl - - !! - !! Process history report - !! ASSUMPTIONS: - !! - subroutine reportHist(self, p) - class(tallyTimeAdmin), intent(inout) :: self - class(particle), intent(in) :: p - - ! Process report with internal Clerk - call self % power_estimator % reportHist(p) - - ! Call superclass procedure on self - call reportHist_super(self, p) - - end subroutine reportHist - - !! - !! Process beginning of a cycle - !! - subroutine reportCycleStart(self, start) - class(tallyTimeAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: start - - ! Process report with internal Clerk - call self % power_estimator % reportCycleStart(start) - - ! Call superclass procedure on self - call reportCycleStart_super(self, start) - - end subroutine reportCycleStart - - !! - !! Process end of the cycle - !! - subroutine reportCycleEnd(self, end) - class(tallyTimeAdmin), intent(inout) :: self - class(particleDungeon), intent(in) :: end - - ! Process report with internal Clerk - call self % power_estimator % reportCycleEnd(end) - - ! Call superclass procedure on self - call reportCycleEnd_super(self, end) - - end subroutine reportCycleEnd - - !! - !! Add all results to outputfile - !! - subroutine print(self,output) - class(tallyTimeAdmin), intent(in) :: self - class(outputFile), intent(inout) :: output - - print *, 'HERE' - call self % power_estimator % print(output) - call print_super(self,output) - - end subroutine print - - !! - !! Initialise time admin - !! - subroutine init(self,dict) - class(tallyTimeAdmin), intent(inout) :: self - class(dictionary),intent(in) :: dict - character(nameLen) :: entry - - ! Initialise embedded clerk - entry = 'T_ADMIN' - call self % power_estimator % init(dict,entry) - - ! Load rest of the clerks - call init_super(self,dict) - - end subroutine init - - !! - !! Deallocates all content - !! - subroutine kill(self) - class(tallyTimeAdmin), intent(inout) :: self - - ! Kill internal Clerks - - ! Call superclass procedure on self - call kill_super(self) - - end subroutine kill - - !! - !! Display results at the end of a cycle - !! - subroutine display(self) - class(tallyTimeAdmin), intent(in) :: self - - call self % power_estimator % display() - - ! Call superclass procedure on self - call display_super(self) - - end subroutine display - - !! - !! - !! - function isConverged(self) result(isIt) - class(tallyTimeAdmin), intent(in) :: self - logical(defBool) :: isIt - - if( self % power_convergence) then - isIt = self % power_estimator % isConverged() - - if ( self % checkConvergence ) isIt = isIt .and. isConverged_super(self) - - else if ( self % checkConvergence ) then - isIt = isConverged_super(self) - - else - isIt = .false. - - end if - - end function isConverged - -end module tallyTimeAdmin_class From 8c82ffb4a05f165d9e041f1865951f9a7c9a75d0 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 24 Jan 2024 22:02:35 +0000 Subject: [PATCH 072/133] Speeding up unionised majorant cross section pre calculation --- .../aceDatabase/aceNeutronDatabase_class.f90 | 90 +++++++++++++------ .../baseMgNeutronDatabase_class.f90 | 4 +- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index fd8bbceab..c475e4419 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -858,20 +858,15 @@ subroutine initMajorant(self, loud) class(aceNeutronDatabase), intent(inout) :: self logical(defBool), intent(in) :: loud real(defReal), dimension(:), allocatable :: tmpGrid - integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone - type(intMap) :: nucMap - real(defReal) :: E, maj + integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone, & + sizeGrid, eIdx, nucIdxLast, eIdxLast + type(intMap) :: nucSet + real(defReal) :: eRef, eNuc, E, maj integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 - if (loud) print '(A)', 'Building CE unionised energy grid' - - ! Initialise energy grid - matIdx = self % activeMat(1) - nucIdx = self % materials(matIdx) % nuclides(1) - tmpGrid = self % nuclides(nucIdx) % eGrid - - ! Add first nuclide to map to indicate it's been added - call nucMap % add(nucIdx, IN_SET) + ! Find the size of the unionised energy grid (with duplicates) + ! Initialise size + sizeGrid = 0 ! Loop over active materials do i = 1, size(self % activeMat) @@ -883,33 +878,76 @@ subroutine initMajorant(self, loud) ! Loop over nuclides present in that material do j = 1, nNuc - ! Get index and check if it's already been added to the grid + ! Get index and check if it's already been added to the set nucIdx = self % materials(matIdx) % nuclides(j) - isDone = nucMap % getOrDefault(nucIdx, NOT_PRESENT) + isDone = nucSet % getOrDefault(nucIdx, NOT_PRESENT) - ! If it's a new nuclide, add its energy grid to the unionised one + ! If it's a new nuclide, add it to the set and find the size of its energy grid if (isDone /= IN_SET) then - tmpGrid = concatenate(tmpGrid, self % nuclides(nucIdx) % eGrid) + ! Add nuclide to the set + call nucSet % add(nucIdx, IN_SET) + + ! Update energy grid size + sizeGrid = sizeGrid + size(self % nuclides(nucIdx) % eGrid) - ! Sort and remove duplicates - call quickSort(tmpGrid) - tmpGrid = removeDuplicatesSorted(tmpGrid) + end if - ! Add nuclide to the set - call nucMap % add(nucIdx, IN_SET) + end do + end do + + ! Allocate temporary grid vector and initialise to largest value allowed + allocate(tmpGrid(sizeGrid)) + tmpGrid = self % EBounds(2) + ! Loop over the energy grid + do i = 1, sizeGrid + + ! Loop over all nuclides in the set - here the value of the intMap is used as an energy index + j = nucSet % begin() + do while (j /= nucSet % end()) + + ! Retrieve energy in the grid and nuclide information + eRef = tmpGrid(i) + nucIdx = nucSet % atKey(j) + eIdx = nucSet % atVal(j) + + ! Check if we already added all the energy values for this nuclide + if (eIdx > size(self % nuclides(nucIdx) % eGrid)) then + j = nucSet % next(j) + cycle + end if + + ! Get energy from nuclide grid + eNuc = self % nuclides(nucIdx) % eGrid(eIdx) + + ! Check if the energy from the nuclide grid is out of bounds + if (eNuc < self % EBounds(1) .or. eNuc > self % EBounds(2)) then + j = nucSet % next(j) + cycle end if + ! Add energy value in the sorted grid, and save index of current nuclide + if (eNuc <= eRef) then + tmpGrid(i) = eNuc + nucIdxLast = nucIdx + eIdxLast = eIdx + end if + + j = nucSet % next(j) + end do + + ! Increment the energy index saved in the intMap for the nuclides whose energy was added + call nucSet % add(nucIdxLast, eIdxLast + 1) + end do - ! Save final grid - self % eGridUnion = tmpGrid + ! Save final grid and remove duplicates + self % eGridUnion = removeDuplicatesSorted(tmpGrid) if (loud) then - print '(A)', 'CE unionised energy grid has size: '//numToChar(size(self % eGridUnion))//& - '. Now building CE unionised majorant cross section' + print '(A)', 'CE unionised energy grid has size: '//numToChar(size(self % eGridUnion)) end if ! Allocate unionised majorant @@ -945,7 +983,7 @@ subroutine initMajorant(self, loud) end do - if (loud) print '(A)', 'CE unionised majorant cross section completed' + if (loud) print '(A)', 'CE unionised majorant cross section calculation completed' end subroutine initMajorant diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 0816c345d..a21280f5c 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -373,8 +373,6 @@ subroutine initMajorant(self, loud) real(defReal) :: xs integer(shortInt), parameter :: TOTAL_XS = 1 - if (loud) print '(A)', 'Building MG unionised majorant cross section' - ! Allocate majorant allocate (self % majorant(self % nG)) @@ -388,7 +386,7 @@ subroutine initMajorant(self, loud) self % majorant(g) = xs end do - if (loud) print '(A)', 'MG unionised majorant cross section completed' + if (loud) print '(A)', 'MG unionised majorant cross section calculation completed' end subroutine initMajorant From 6c2ba03223684d145f14193062beb5ec0d8398a8 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 24 Jan 2024 13:17:27 +0100 Subject: [PATCH 073/133] Eliminate Dungeon sample without replacement For a case when to little particles were generated, ones for duplication were selected using sampling with replacement. We change it to use sampling without replacement instead. --- ParticleObjects/particleDungeon_class.f90 | 56 +++++++++++++++-------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index 7d47337ec..4d77538dd 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -27,8 +27,8 @@ module particleDungeon_class !! Dungeon can work like stacks or arrays. Stack-like behaviour is not really thread safe !! so it can be utilised when collecting and processing secondary particles in history !! that should be processed during the course of one cycle. Alternatively, one can use the - !! critical variations of the stack-like procedures. - !! Array-like behaviour allows to easily distribute particles among threads. As long as indices + !! critical variations of the stack-like procedures. + !! Array-like behaviour allows to easily distribute particles among threads. As long as indices !! assigned to different threads do not overlap, reading is thread-safe (I hope-MAK). !! !! @@ -170,18 +170,18 @@ subroutine detainCritical_particle(self,p) ! Increase population and weight self % pop = self % pop + 1 pop = self % pop - + ! Check for population overflow if (pop > size(self % prisoners)) then call fatalError(Here,'Run out of space for particles.& & Max size:'//numToChar(size(self % prisoners)) //& ' Current population: ' // numToChar(self % pop)) end if - + ! Load new particle self % prisoners(pop) = p !$omp end critical (dungeon) - + end subroutine detainCritical_particle !! @@ -224,16 +224,16 @@ subroutine detainCritical_particleState(self,p_state) !$omp critical (dungeon) self % pop = self % pop + 1 pop = self % pop - + ! Check for population overflow if (pop > size(self % prisoners)) then call fatalError(Here,'Run out of space for particles.& & Max size:'//numToChar(size(self % prisoners)) //& ' Current population: ' // numToChar(self % pop)) end if - + ! Load new particle - self % prisoners(pop) = p_state + self % prisoners(pop) = p_state !$omp end critical (dungeon) end subroutine detainCritical_particleState @@ -272,11 +272,11 @@ subroutine releaseCritical(self, p) ! Decrease population pop = self % pop self % pop = self % pop - 1 - + ! Load data into the particle p = self % prisoners(pop) !$omp end critical (dungeon) - + p % isDead = .false. end subroutine releaseCritical @@ -396,18 +396,19 @@ end subroutine normWeight !! Randomly duplicate or remove particles to match the number. !! Does not take weight of a particle into account! !! - subroutine normSize(self,N,rand) + subroutine normSize(self, N, rand) class(particleDungeon), intent(inout) :: self integer(shortInt), intent(in) :: N class(RNG), intent(inout) :: rand - integer(shortInt) :: excessP + integer(shortInt) :: excessP, n_copies, n_duplicates integer(shortInt) :: i, idx + integer(shortInt), dimension(:), allocatable :: duplicates character(100), parameter :: Here =' normSize (particleDungeon_class.f90)' ! Protect against invalid N if( N > size(self % prisoners)) then call fatalError(Here,'Requested size: '//numToChar(N) //& - 'is greather then max size: '//numToChar(size(self % prisoners))) + 'is greater then max size: '//numToChar(size(self % prisoners))) else if ( N <= 0 ) then call fatalError(Here,'Requested size: '//numToChar(N) //' is not +ve') end if @@ -416,9 +417,9 @@ subroutine normSize(self,N,rand) excessP = self % pop - N if (excessP > 0 ) then ! Reduce population with reservoir sampling - do i=N,self % pop + do i = N + 1, self % pop ! Select new index. Copy data if it is in the safe zone (<= N). - idx = int(i * rand % get())+1 + idx = int(i * rand % get()) + 1 if (idx <= N) then self % prisoners(idx) = self % prisoners(i) end if @@ -426,9 +427,28 @@ subroutine normSize(self,N,rand) self % pop = N else if (excessP < 0) then ! Clone randomly selected particles - do i = self % pop, N - idx = int(self % pop * rand % get()) + 1 - self % prisoners(i) = self % prisoners(idx) + ! For a massive undersampling duplicate (or n-plicate) particles + excessP = -excessP + n_copies = excessP / self % pop + n_duplicates = modulo(excessP, self % pop) + + ! Copy all particle maximum possible number of times + do i = 1, n_copies + self % prisoners(N * i + 1 : N * (i + 1)) = self % prisoners(1:N) + end do + + ! Choose the remainder particles to duplicate without replacement + duplicates = [(i, i = 1, n_duplicates)] + do i = n_duplicates + 1, self % pop + idx = int(i * rand % get()) + 1 + if (idx <= n_duplicates) then + duplicates(idx) = i + end if + end do + + ! Copy the duplicated particles at the end + do i = 1, n_duplicates + self % prisoners(self % pop + i) = self % prisoners(duplicates(i)) end do self % pop = N From 4fbf588d883477796c4b6a12c58f952767021755 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 25 Jan 2024 15:03:30 +0000 Subject: [PATCH 074/133] Making maxSplit a modifiable property --- .../neutronCEimp_class.f90 | 30 ++++++++++--------- .../neutronMGimp_class.f90 | 12 ++++---- SharedModules/universalVariables.f90 | 1 - 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 3e51c7378..e3dd68d5f 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -2,7 +2,7 @@ module neutronCEimp_class use numPrecision use endfConstants - use universalVariables, only : nameUFS, nameWW, maxSplit + use universalVariables, only : nameUFS, nameWW use genericProcedures, only : fatalError, rotateVector, numToChar use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -102,12 +102,13 @@ module neutronCEimp_class real(defReal) :: thresh_E real(defReal) :: thresh_A ! Variance reduction options - logical(defBool) :: weightWindows - logical(defBool) :: splitting - logical(defBool) :: roulette - logical(defBool) :: implicitAbsorption ! Prevents particles dying through capture - logical(defBool) :: implicitSites ! Generates fission sites on every fissile collision - logical(defBool) :: uniFissSites + integer(shortInt) :: maxSplit + logical(defBool) :: weightWindows + logical(defBool) :: splitting + logical(defBool) :: roulette + logical(defBool) :: implicitAbsorption ! Prevents particles dying through capture + logical(defBool) :: implicitSites ! Generates fission sites on every fissile collision + logical(defBool) :: uniFissSites type(weightWindowsField), pointer :: weightWindowsMap @@ -159,6 +160,7 @@ subroutine init(self, dict) ! Obtain settings for variance reduction call dict % getOrDefault(self % weightWindows,'weightWindows', .false.) + call dict % getOrDefault(self % maxSplit,'maxSplit', 1000) call dict % getOrDefault(self % splitting,'split', .false.) call dict % getOrDefault(self % roulette,'roulette', .false.) call dict % getOrDefault(self % minWgt,'minWgt',0.25_defReal) @@ -515,7 +517,7 @@ subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) ! If a particle is outside the WW map and all the weight limits ! are zero nothing happens. NOTE: this holds for positive weights only - if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < maxSplit)) then + if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < self % maxSplit)) then call self % split(p, thisCycle, maxWgt) elseif (p % w < minWgt) then call self % russianRoulette(p, avWgt) @@ -563,23 +565,23 @@ subroutine split(self, p, thisCycle, maxWgt) mult = ceiling(p % w/maxWgt) ! Limit maximum split - if (mult > maxSplit - p % splitCount + 1) then - mult = maxSplit - p % splitCount + 1 + if (mult > self % maxSplit - p % splitCount + 1) then + mult = self % maxSplit - p % splitCount + 1 end if ! Decrease weight p % w = p % w/mult - + p % splitCount = p % splitCount + mult ! Save current particle splitCount - splitCount = p % splitCount + !splitCount = p % splitCount ! Add split particle's to the dungeon do i = 1,mult-1 - p % splitCount = 0 + !p % splitCount = 0 call thisCycle % detain(p) end do - p % splitCount = splitCount + mult + !p % splitCount = splitCount + mult end subroutine split diff --git a/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 index 3fa129cc8..7560b4587 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 @@ -2,7 +2,7 @@ module neutronMGimp_class use numPrecision use endfConstants - use universalVariables, only : nameWW, maxSplit + use universalVariables, only : nameWW use genericProcedures, only : fatalError, rotateVector, numToChar use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -62,7 +62,8 @@ module neutronMGimp_class class(mgNeutronMaterial), pointer, public :: mat => null() ! Variance reduction options - logical(defBool) :: weightWindows + integer(shortInt) :: maxSplit + logical(defBool) :: weightWindows type(weightWindowsField), pointer :: weightWindowsMap contains @@ -99,6 +100,7 @@ subroutine init(self, dict) call init_super(self, dict) ! Obtain settings for variance reduction + call dict % getOrDefault(self % maxSplit,'maxSplit', 1000) call dict % getOrDefault(self % weightWindows,'weightWindows', .false.) ! Sets up the weight windows field @@ -308,7 +310,7 @@ subroutine cutoffs(self, p, collDat, thisCycle, nextCycle) ! If a particle is outside the WW map and all the weight limits ! are zero nothing happens. NOTE: this holds for positive weights only - if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < maxSplit)) then + if ((p % w > maxWgt) .and. (maxWgt /= ZERO) .and. (p % splitCount < self % maxSplit)) then call self % split(p, thisCycle, maxWgt) elseif (p % w < minWgt) then call self % russianRoulette(p, avWgt) @@ -348,8 +350,8 @@ subroutine split(self, p, thisCycle, maxWgt) mult = ceiling(p % w/maxWgt) ! Limit maximum split - if (mult > maxSplit - p % splitCount + 1) then - mult = maxSplit - p % splitCount + 1 + if (mult > self % maxSplit - p % splitCount + 1) then + mult = self % maxSplit - p % splitCount + 1 end if ! Decrease weight diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index 81239996d..bf3997446 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -80,6 +80,5 @@ module universalVariables ! Global name variables used to define specific geometry or field types character(nameLen), parameter :: nameUFS = 'uniFissSites' character(nameLen), parameter :: nameWW = 'WeightWindows' - integer(shortInt), parameter :: maxSplit = 1000 end module universalVariables From cbc5785adfdd5d6d36285cfdfa163088c05d1da8 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 25 Jan 2024 15:35:03 +0000 Subject: [PATCH 075/133] Adding MT number to reportSpawn, and call it when splitting particles --- .../neutronCEimp_class.f90 | 25 ++++--- .../neutronCEstd_class.f90 | 2 +- .../neutronMGstd_class.f90 | 2 +- SharedModules/endfConstants.f90 | 4 +- Tallies/TallyClerks/Tests/mgXsClerk_test.f90 | 8 +-- Tallies/TallyClerks/mgXsClerk_class.f90 | 67 ++++++++++--------- Tallies/TallyClerks/tallyClerkSlot_class.f90 | 7 +- Tallies/TallyClerks/tallyClerk_inter.f90 | 12 ++-- Tallies/tallyAdmin_class.f90 | 55 ++++++++------- 9 files changed, 101 insertions(+), 81 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 88b93cbf7..280a5278d 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -328,7 +328,7 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) ! Report birth of new particle - call tally % reportSpawn(p, pTemp) + call tally % reportSpawn(N_FISSION, p, pTemp) end do end if @@ -438,7 +438,7 @@ subroutine fission(self, p, tally, collDat, thisCycle, nextCycle) if (self % uniFissSites) call self % ufsField % storeFS(pTemp) ! Report birth of new particle - call tally % reportSpawn(p, pTemp) + call tally % reportSpawn(N_FISSION, p, pTemp) end do end if @@ -548,14 +548,14 @@ subroutine cutoffs(self, p, tally, collDat, thisCycle, nextCycle) ! If a particle is outside the WW map and all the weight limits ! are zero nothing happens. NOTE: this holds for positive weights only if ((p % w > maxWgt) .and. (maxWgt /= ZERO)) then - call self % split(p, thisCycle, maxWgt) + call self % split(p, tally, thisCycle, maxWgt) elseif (p % w < minWgt) then call self % russianRoulette(p, avWgt) end if ! Splitting with fixed threshold elseif ((self % splitting) .and. (p % w > self % maxWgt)) then - call self % split(p, thisCycle, self % maxWgt) + call self % split(p, tally, thisCycle, self % maxWgt) ! Roulette with fixed threshold and survival weight elseif ((self % roulette) .and. (p % w < self % minWgt)) then @@ -584,24 +584,31 @@ end subroutine russianRoulette !! !! Split particle which has too large a weight !! - subroutine split(self, p, thisCycle, maxWgt) + subroutine split(self, p, tally, thisCycle, maxWgt) class(neutronCEimp), intent(inout) :: self class(particle), intent(inout) :: p + type(tallyAdmin), intent(inout) :: tally class(particleDungeon), intent(inout) :: thisCycle real(defReal), intent(in) :: maxWgt + type(particleState) :: pTemp integer(shortInt) :: mult, i ! This value must be at least 2 mult = ceiling(p % w/maxWgt) - ! Decrease weight - p % w = p % w/mult + ! Copy particle to a particle state + pTemp = p + pTemp % wgt = p % w/mult ! Add split particle's to the dungeon - do i = 1,mult-1 - call thisCycle % detain(p) + do i = 1, mult-1 + call thisCycle % detain(pTemp) + call tally % reportSpawn(N_N_SPLIT, p, pTemp) end do + ! Decrease original particle weight + p % w = p % w/mult + end subroutine split !! diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index b6dc3ec78..e2ddf2f44 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -241,7 +241,7 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) call nextCycle % detain(pTemp) ! Report birth of new particle - call tally % reportSpawn(p, pTemp) + call tally % reportSpawn(N_FISSION, p, pTemp) end do end if diff --git a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 index 12f51d9b0..b816c6fe6 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 @@ -177,7 +177,7 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) call nextCycle % detain(pTemp) ! Report birth of new particle - call tally % reportSpawn(p, pTemp) + call tally % reportSpawn(N_FISSION, p, pTemp) end do end if diff --git a/SharedModules/endfConstants.f90 b/SharedModules/endfConstants.f90 index 2197c3274..4a3414fa6 100644 --- a/SharedModules/endfConstants.f90 +++ b/SharedModules/endfConstants.f90 @@ -85,7 +85,9 @@ module endfConstants N_da = 117 ,& ! SCONE's fake MT for thermal inelastic scattering N_N_ThermEL = 1002 ,& - N_N_ThermINEL = 1004 + N_N_ThermINEL = 1004 ,& + ! SCONE's fake MT for particle splitting event + N_N_SPLIT = 1005 integer(shortInt),private :: i ! Local, private integer to use array constructor integer(shortInt),parameter :: N_Nl(40) = [(50+i, i =1,40)] diff --git a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 index b0bb61fb5..85a93fdd6 100644 --- a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 @@ -122,13 +122,13 @@ subroutine testScoring_clerk1(this) ! Scoring pFiss = p - call this % clerk_test1 % reportSpawn(p, pFiss, this % nucData, mem) + call this % clerk_test1 % reportSpawn(N_FISSION, p, pFiss, this % nucData, mem) p % E = 3.0_defReal ! Scoring pFiss = p - call this % clerk_test1 % reportSpawn(p, pFiss, this % nucData, mem) + call this % clerk_test1 % reportSpawn(N_FISSION, p, pFiss, this % nucData, mem) ! Scoring call this % clerk_test1 % reportInColl(p, this % nucData, mem, .false.) @@ -201,13 +201,13 @@ subroutine testScoring_clerk2(this) ! Scoring pFiss = p - call this % clerk_test2 % reportSpawn(p, pFiss, this % nucData, mem) + call this % clerk_test2 % reportSpawn(N_FISSION, p, pFiss, this % nucData, mem) p % E = 0.3_defReal ! Scoring pFiss = p - call this % clerk_test2 % reportSpawn(p, pFiss, this % nucData, mem) + call this % clerk_test2 % reportSpawn(N_FISSION, p, pFiss, this % nucData, mem) ! Scoring call this % clerk_test2 % reportInColl(p, this % nucData, mem, .false.) diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index c85330dc0..fdeda347a 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -283,16 +283,16 @@ end subroutine reportInColl !! See tallyClerk_inter for details !! subroutine reportOutColl(self, p, MT, muL, xsData, mem) - class(mgXsClerk), intent(inout) :: self - class(particle), intent(in) :: p - integer(shortInt), intent(in) :: MT - real(defReal), intent(in) :: muL - class(nuclearDatabase),intent(inout) :: xsData - type(scoreMemory), intent(inout) :: mem - type(particleState) :: preColl, postColl - real(defReal) :: score, prod, mu, mu2, mu3, mu4, mu5 - integer(shortInt) :: enIdx, matIdx, binIdx, binEnOut - integer(longInt) :: addr + class(mgXsClerk), intent(inout) :: self + class(particle), intent(in) :: p + integer(shortInt), intent(in) :: MT + real(defReal), intent(in) :: muL + class(nuclearDatabase),intent(inout) :: xsData + type(scoreMemory), intent(inout) :: mem + type(particleState) :: preColl, postColl + real(defReal) :: score, prod, mu, mu2, mu3, mu4, mu5 + integer(shortInt) :: enIdx, matIdx, binIdx, binEnOut + integer(longInt) :: addr ! Get pre and post collision particle state preColl = p % preCollision @@ -410,37 +410,42 @@ end subroutine reportOutColl !! !! See tallyClerk_inter for details !! - subroutine reportSpawn(self, pOld, pNew, xsData, mem) + subroutine reportSpawn(self, MT, pOld, pNew, xsData, mem) class(mgXsClerk), intent(inout) :: self + integer(shortInt), intent(in) :: MT class(particle), intent(in) :: pOld class(particleState), intent(in) :: pNew class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem integer(longInt) :: addr, binIdx, enIdx, matIdx - ! Find bin indexes - ! Energy - if (allocated(self % energyMap)) then - enIdx = self % energyN + 1 - self % energyMap % map(pNew) - else - enIdx = 1 - end if - ! Space - if (allocated(self % spaceMap)) then - matIdx = self % spaceMap % map(pNew) - else - matIdx = 1 - end if + if (MT == N_FISSION) then - ! Return if invalid bin index - if ((enIdx == self % energyN + 1) .or. matIdx == 0) return + ! Find bin indexes + ! Energy + if (allocated(self % energyMap)) then + enIdx = self % energyN + 1 - self % energyMap % map(pNew) + else + enIdx = 1 + end if + ! Space + if (allocated(self % spaceMap)) then + matIdx = self % spaceMap % map(pNew) + else + matIdx = 1 + end if - ! Calculate bin address - binIdx = self % energyN * (matIdx - 1) + enIdx - addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 + ! Return if invalid bin index + if ((enIdx == self % energyN + 1) .or. matIdx == 0) return - ! Score energy group of fission neutron - call mem % score(ONE, addr + CHI_idx) + ! Calculate bin address + binIdx = self % energyN * (matIdx - 1) + enIdx + addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 + + ! Score energy group of fission neutron + call mem % score(ONE, addr + CHI_idx) + + end if end subroutine reportSpawn diff --git a/Tallies/TallyClerks/tallyClerkSlot_class.f90 b/Tallies/TallyClerks/tallyClerkSlot_class.f90 index c3a9fa6ab..860ca71b2 100644 --- a/Tallies/TallyClerks/tallyClerkSlot_class.f90 +++ b/Tallies/TallyClerks/tallyClerkSlot_class.f90 @@ -231,19 +231,20 @@ subroutine reportTrans(self, p, xsData, mem) end subroutine reportTrans !! - !! Process fission report + !! Process particle creation report !! !! See tallyClerk_inter for details !! - subroutine reportSpawn(self, pOld, pNew, xsData, mem) + subroutine reportSpawn(self, MT, pOld, pNew, xsData, mem) class(tallyClerkSlot), intent(inout) :: self + integer(shortInt), intent(in) :: MT class(particle), intent(in) :: pOld class(particleState), intent(in) :: pNew class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem ! Pass call to instance in the slot - call self % slot % reportSpawn(pOld, pNew, xsData, mem) + call self % slot % reportSpawn(MT, pOld, pNew, xsData, mem) end subroutine reportSpawn diff --git a/Tallies/TallyClerks/tallyClerk_inter.f90 b/Tallies/TallyClerks/tallyClerk_inter.f90 index e55141537..9eea9eba7 100644 --- a/Tallies/TallyClerks/tallyClerk_inter.f90 +++ b/Tallies/TallyClerks/tallyClerk_inter.f90 @@ -57,7 +57,7 @@ module tallyClerk_inter !! reportOutColl -> Process an outgoing from collision report !! reportPath -> Process pathlength report !! reportTrans -> Process transition report - !! reportSpawn -> Process fission report + !! reportSpawn -> Process particle generation report !! reportHist -> Process history report !! reportCycleStart -> Process beginning of a cycle report !! reportCycleEnd -> Process end of a cycle report (e.g. Calculate functions of scores like k-eff) @@ -322,21 +322,23 @@ subroutine reportTrans(self, p, xsData, mem) end subroutine reportTrans !! - !! Process fission report + !! Process particle creation report !! !! See tallyAdmin_class for implicit assumptionas about the report. !! !! Args: - !! pOld [in] -> Particle that caused the fission event - !! pNew [in] -> Particle state of the fission neutron + !! MT [in] -> MT number of the reaction the particle has undergone + !! pOld [in] -> Particle that caused the branching event + !! pNew [in] -> Particle state of the newly created neutron !! xsData [inout] -> Nuclear Database with XSs data !! mem [inout] -> Score Memory to put results on !! !! Errors: !! Depend on specific Clerk !! - subroutine reportSpawn(self, pOld, pNew, xsData, mem) + subroutine reportSpawn(self, MT, pOld, pNew, xsData, mem) class(tallyClerk), intent(inout) :: self + integer(shortInt), intent(in) :: MT class(particle), intent(in) :: pOld class(particleState), intent(in) :: pNew class(nuclearDatabase), intent(inout) :: xsData diff --git a/Tallies/tallyAdmin_class.f90 b/Tallies/tallyAdmin_class.f90 index f36b87dc1..a81b530f0 100644 --- a/Tallies/tallyAdmin_class.f90 +++ b/Tallies/tallyAdmin_class.f90 @@ -42,20 +42,20 @@ module tallyAdmin_class !! Private Members: !! atch -> Pointer to an attachment tallyClerk (implements linked-list) !! normBinAddr -> Address of a bin used for normalisation - !! normValue -> Target Value for normalisation - !! normClerkName -> Name of a Clerk used for normalisation - !! tallyClerks -> Array of all defined tally Clerks - !! clerksNameMap -> CharMap that maps Clerk Name to its index in tallyClerks - !! inCollClerks -> List of indices of all Clerks that require inCollReport - !! outCollClerks -> List of indices of all Clerks that require outCollReport - !! pathClerks -> List of indices of all Clerks that require pathReport - !! transClerks -> List of indices of all Clerks that require transReport - !! spawnClerks -> List of indices of all Clerks that require spawnReport - !! histClerks -> List of indices of all Clerks that require histReport - !! cycleStartClerks -> List of indices of all Clerks that require cycleStartReport - !! cycleEndClerks -> List of indices of all Clerks that require cycleEndReport - !! displayList -> List of indices of all Clerks that are registered for display - !! mem -> Score Memory for all defined Clerks + !! normValue -> Target value for normalisation + !! normClerkName -> Name of a clerk used for normalisation + !! tallyClerks -> Array of all defined tally clerks + !! clerksNameMap -> CharMap that maps clerk name to its index in tallyClerks + !! inCollClerks -> List of indices of all clerks that require inCollReport + !! outCollClerks -> List of indices of all clerks that require outCollReport + !! pathClerks -> List of indices of all clerks that require pathReport + !! transClerks -> List of indices of all clerks that require transReport + !! spawnClerks -> List of indices of all clerks that require spawnReport + !! histClerks -> List of indices of all clerks that require histReport + !! cycleStartClerks -> List of indices of all clerks that require cycleStartReport + !! cycleEndClerks -> List of indices of all clerks that require cycleEndReport + !! displayList -> List of indices of all clerks that are registered for display + !! mem -> Score Memory for all defined clerks !! !! Interface: !! init -> Initialise from dictionary @@ -67,12 +67,12 @@ module tallyAdmin_class !! reportOutColl -> Process post-collision reports in all clerks !! reportPath -> Process pathlength reports in all clerks !! reportTrans -> Process transition reports in all clerks - !! reportSpawn -> Process fission reports in all clerks - !! reportHist -> Process History reports in all clerks - !! reportCycleStart -> Process Start Of Cycle reports in all clerks - !! reportCycleEnd -> Process End of Cycle reports in all clerks + !! reportSpawn -> Process particle generation reports in all clerks + !! reportHist -> Process history reports in all clerks + !! reportCycleStart -> Process start of cycle reports in all clerks + !! reportCycleEnd -> Process end of cycle reports in all clerks !! getResult -> Return tallyResult object from a named Clerk - !! display -> Call "display" on all Clerks registered to display + !! display -> Call "display" on all clerks registered to display !! isConverged -> Return .true. if all convergance targets have been reached !! print -> Prints results to an output file object !! @@ -589,20 +589,23 @@ recursive subroutine reportTrans(self, p) end subroutine reportTrans !! - !! Process fission report + !! Process report for the creation of a new particle !! !! Assumptions: - !! TODO: Decide on the details of this report + !! It should be sent each time a new particle is created in the simulation + !! by a nuclear reaction or some other mechanism (e.g. splitting) !! !! Args: - !! pOld [in] -> Particle that caused the fission event - !! pNew [in] -> Particle state of the fission neutron + !! MT [in] -> MT number of the reaction the particle has undergone + !! pOld [in] -> Particle that caused the branching event + !! pNew [in] -> Particle state of the newly created neutron !! !! Errors: !! None !! - recursive subroutine reportSpawn(self, pOld, pNew) + recursive subroutine reportSpawn(self, MT, pOld, pNew) class(tallyAdmin), intent(inout) :: self + integer(shortInt), intent(in) :: MT class(particle), intent(in) :: pOld class(particleState), intent(in) :: pNew integer(shortInt) :: i, idx @@ -611,7 +614,7 @@ recursive subroutine reportSpawn(self, pOld, pNew) ! Call attachment if(associated(self % atch)) then - call reportSpawn(self % atch, pOld, pNew) + call reportSpawn(self % atch, MT, pOld, pNew) end if ! Get Data @@ -620,7 +623,7 @@ recursive subroutine reportSpawn(self, pOld, pNew) ! Go through all clerks that request the report do i=1,self % spawnClerks % getSize() idx = self % spawnClerks % get(i) - call self % tallyClerks(idx) % reportSpawn(pOld, pNew, xsData, self % mem) + call self % tallyClerks(idx) % reportSpawn(MT, pOld, pNew, xsData, self % mem) end do end subroutine reportSpawn From a82280072742b46eae2958cfad5215d80f57e6cc Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 21 Nov 2023 11:48:50 +0100 Subject: [PATCH 076/133] Add offset for material colour visualisation Adds a parameter that allows to move the color map around to avoid the infamous 'brown' --- Visualisation/visualiser_class.f90 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index 9641f7758..cd1f668ff 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -211,6 +211,7 @@ end subroutine makeVTK !! centre (0.0 0.0 0.0); // Coordinates of the centre of the plot !! axis x; // Must be 'x', 'y' or 'z' !! res (300 300); // Resolution of the image + !! #offset 978; # // Parameter to 'randomize' the colour map !! #width (1.0 2.0);# // Width of the plot from the centre !! } !! @@ -230,6 +231,7 @@ subroutine makeBmpImg(self, dict) real(defReal), dimension(:), allocatable :: temp integer(shortInt), dimension(:), allocatable :: tempInt integer(shortInt), dimension(:,:), allocatable :: img + integer(shortInt) :: offset = 0 character(100), parameter :: Here = 'makeBmpImg (visualiser_class.f90)' ! Get plot parameters @@ -286,6 +288,9 @@ subroutine makeBmpImg(self, dict) end if + ! Colourmap offset + call dict % getOrDefault(offset, 'offset', 0) + ! Get plot if (useWidth) then call self % geom % slicePlot(img, centre, dir, what, width) @@ -296,7 +301,7 @@ subroutine makeBmpImg(self, dict) ! Translate to an image select case (what) case ('material') - img = materialColor(img) + img = materialColor(img, offset) case ('uniqueID') img = uniqueIDColor(img) @@ -339,13 +344,15 @@ end subroutine kill !! !! Args: !! matIdx [in] -> Value of the material index + !! offset [in] -> Offset to be used in the hash function !! !! Result: !! A 24-bit color specifing the material !! - elemental function materialColor(matIdx) result(color) + elemental function materialColor(matIdx, offset) result(color) integer(shortInt), intent(in) :: matIdx integer(shortInt) :: color + integer(shortInt), intent(in) :: offset integer(shortInt), parameter :: COL_OUTSIDE = int(z'ffffff', shortInt) integer(shortInt), parameter :: COL_VOID = int(z'000000', shortInt) integer(shortInt), parameter :: COL_UNDEF = int(z'00ff00', shortInt) @@ -361,7 +368,7 @@ elemental function materialColor(matIdx) result(color) color = COL_UNDEF case default - color = knuthHash(matIdx, 24) + color = knuthHash(matIdx + offset, 24) end select From a117d3792bb09c16b7de9d423df04db8d12bb2c7 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 21 Nov 2023 12:03:24 +0100 Subject: [PATCH 077/133] Fix line endings and spelling --- Visualisation/visualiser_class.f90 | 802 ++++++++++++++--------------- 1 file changed, 401 insertions(+), 401 deletions(-) diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index cd1f668ff..9d8f0bf5b 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -1,401 +1,401 @@ -module visualiser_class - - use numPrecision - use universalVariables - use genericProcedures, only : fatalError, numToChar - use hashFunctions_func, only : knuthHash - use imgBmp_func, only : imgBmp_toFile - use commandLineUI, only : getInputFile - use dictionary_class, only : dictionary - use geometry_inter, only : geometry - use outputVTK_class - - implicit none - private - - !! - !! Object responsible for controlling visualisation - !! - !! Object that creates images relating to SCONE geometries - !! Should be extensible for adding different visualisation methods - !! Recieves and generates data for visualisation - !! Requires a dictionary input which specifies the procedures to call - !! Presently supports: VTK voxel mesh creation - !! - !! Private members: - !! name -> name to be used for generating output files (corresponding to input) - !! geom -> pointer to geometry - !! vizDict -> dictionary containing visualisations to be generated - !! - !! Interface: - !! init -> initialises visualiser - !! makeViz -> constructs requested visualisations - !! kill -> cleans up visualiser - !! - !! Sample dictionary input: - !! viz{ - !! vizDict1{ } - !! #vizDict2{ }# - !! } - !! - !! NOTE: For details regarding contents of the vizDict dictionaries see the documentation - !! of 'makeVTK' and 'makeBmpImg' functions - !! - type, public :: visualiser - character(nameLen), private :: name - class(geometry), pointer, private :: geom => null() - type(dictionary), private :: vizDict - contains - procedure :: init - procedure :: makeViz - procedure :: kill - procedure, private :: makeVTK - procedure, private :: makeBmpImg - end type - -contains - - !! - !! Initialises visualiser - !! - !! Provides visualiser with filename for output, - !! geometry information, and the dictionary decribing - !! what is to be plotted - !! - !! Args: - !! geom [inout] -> pointer to the geometry - !! vizDict[in] -> dictionary containing what is to be visualised - !! - !! Result: - !! Initialised visualiser - !! - subroutine init(self, geom, vizDict) - class(visualiser), intent(inout) :: self - class(geometry), pointer, intent(inout) :: geom - class(dictionary), intent(in) :: vizDict - character(:), allocatable :: string - - ! Obtain file name - call getInputFile(string) - self % name = string - - ! Point to geometry - self % geom => geom - - ! Store visualisation dictionary - self % vizDict = vizDict - - end subroutine init - - !! - !! Generate all visualisations specified by vizDict - !! - !! Proceed through all dictionaries contained within vizDict - !! and perform all corresponding visualisations - !! - !! Result: - !! Visualisation outputs corresponding to dictionary contents - !! - !! Errors: - !! Returns an error if an unrecognised visualisation is requested - !! - subroutine makeViz(self) - class(visualiser), intent(inout) :: self - class(dictionary), pointer :: tempDict - character(nameLen),dimension(:), allocatable :: keysArr - integer(shortInt) :: i - character(nameLen) :: type - character(nameLen) :: here ='makeViz (visualiser_class.f90)' - - ! Loop through each sub-dictionary and generate visualisation - ! (if the visualisation method is available) - call self % vizDict % keys(keysArr,'dict') - - do i=1,size(keysArr) - tempDict => self % vizDict % getDictPtr(keysArr(i)) - call tempDict % get(type,'type') - select case(type) - case('vtk') - call self % makeVTK(tempDict) - - case('bmp') - call self % makeBmpImg(tempDict) - - case default - call fatalError(here, 'Unrecognised visualisation - presently only accept vtk') - - end select - - end do - - end subroutine makeViz - - !! - !! Generate a VTK output - !! - !! Creates the VTK file corresponding to the contents of dict - !! - !! Args: - !! dict [in] -> dictionary containing description of VTK file to be made - !! - !! Sample input dictionary: - !! VTK { - !! type vtk; - !! corner (-1.0 -1.0 -1.0); // lower corner of the plot volume - !! width (2.0 2.0 2.0); // width in each direction - !! vox (300 300 300); // Resolution in each direction - !! #what uniqueId;# // Plot target. 'material' or 'uniqueId'. Default: 'material' - !! } - !! - !! TODO: VTK output is placed in a input filename appended by '.vtk' extension. - !! This prevents multiple VTK visualistions (due to overriding). Might also become - !! weird for input files with extension e.g. 'input.dat'. - !! DEMAND USER TO GIVE OUTPUT NAME - !! - subroutine makeVTK(self, dict) - class(visualiser), intent(inout) :: self - class(dictionary), intent(in) :: dict - type(outputVTK) :: vtk - integer(shortInt), dimension(:,:,:), allocatable:: voxelMat - real(defReal), dimension(:), allocatable :: corner ! corner of the mesh - real(defReal), dimension(:), allocatable :: center ! center of the mesh - real(defReal), dimension(:), allocatable :: width ! corner of the mesh - integer(shortInt), dimension(:), allocatable :: nVox ! number of mesh voxels - character(nameLen) :: what - character(nameLen) :: here ='makeVTK (visualiser_class.f90)' - - call vtk % init(dict) - - ! Identify whether plotting 'material' or 'cellID' - call dict % getOrDefault(what, 'what', 'material') - - ! Obtain geometry data - call dict % get(corner, 'corner') - call dict % get(width, 'width') - center = corner + width/TWO - call dict % get(nVox, 'vox') - - if (size(corner) /= 3) then - call fatalError(here,'Voxel plot requires corner to have 3 values') - endif - if (size(width) /= 3) then - call fatalError(here,'Voxel plot requires width to have 3 values') - endif - if (size(nVox) /= 3) then - call fatalError(here,'Voxel plot requires vox to have 3 values') - endif - allocate(voxelMat(nVox(1), nVox(2), nVox(3))) - - ! Have geometry obtain data - call self % geom % voxelPlot(voxelMat, center, what, width) - - ! In principle, can add multiple data sets to VTK - not done here yet - ! VTK data set will use 'what' variable as a name - call vtk % addData(voxelMat, what) - call vtk % output(self % name) - call vtk % kill() - - end subroutine makeVTK - - !! - !! Generate a BMP slice image of the geometry - !! - !! Args: - !! dict [in] -> Dictionary with settings - !! - !! Sample dictionary input: - !! bmp_img { - !! type bmp; - !! #what uniqueID;# // Target of the plot. 'uniqueId' or 'material'. Default: 'material' - !! output img; // Name of output file without extension - !! centre (0.0 0.0 0.0); // Coordinates of the centre of the plot - !! axis x; // Must be 'x', 'y' or 'z' - !! res (300 300); // Resolution of the image - !! #offset 978; # // Parameter to 'randomize' the colour map - !! #width (1.0 2.0);# // Width of the plot from the centre - !! } - !! - !! NOTE: If 'width' is not given, the plot will extend to the bounds of the geometry. - !! This may result in the provided centre beeing moved to the center of the geoemtry in the - !! plot plane. However, the position on the plot axis will be unchanged. - !! - subroutine makeBmpImg(self, dict) - class(visualiser), intent(inout) :: self - class(dictionary), intent(in) :: dict - real(defReal), dimension(3) :: centre - real(defReal), dimension(2) :: width - character(1) :: dir - character(nameLen) :: tempChar - logical(defBool) :: useWidth - character(nameLen) :: what, outputFile - real(defReal), dimension(:), allocatable :: temp - integer(shortInt), dimension(:), allocatable :: tempInt - integer(shortInt), dimension(:,:), allocatable :: img - integer(shortInt) :: offset = 0 - character(100), parameter :: Here = 'makeBmpImg (visualiser_class.f90)' - - ! Get plot parameters - - ! Identify whether plotting 'material' or 'cellID' - call dict % getOrDefault(what, 'what', 'material') - - ! Get name of the output file - call dict % get(outputFile, 'output') - outputFile = trim(outputFile) // '.bmp' - - ! Central point - call dict % get(temp, 'centre') - - if (size(temp) /= 3) then - call fatalError(Here, "'center' must have size 3. Has: "//numToChar(size(temp))) - end if - - centre = temp - - ! Axis - call dict % get(tempChar, 'axis') - - if (len_trim(tempChar) /= 1) then - call fatalError(Here, "'axis' must be x,y or z. Not: "//tempChar) - end if - - dir = tempChar(1:1) - - ! Resolution - call dict % get(tempInt, 'res') - - if (size(tempInt) /= 2) then - call fatalError(Here, "'res' must have size 2. Has: "//numToChar(size(tempInt))) - else if (any(tempInt <= 0)) then - call fatalError(Here, "Resolution must be +ve. There is 0 or -ve entry!") - end if - - allocate(img(tempInt(1), tempInt(2))) - - ! Optional width - useWidth = dict % isPresent('width') - if (useWidth) then - call dict % get(temp, 'width') - - ! Check for errors - if (size(temp) /= 2) then - call fatalError(Here, "'width' must have size 2. Has: "//numToChar((size(temp)))) - else if (any(temp <= ZERO)) then - call fatalError(Here, "'width' must be +ve. It isn't.") - end if - - width = temp - - end if - - ! Colourmap offset - call dict % getOrDefault(offset, 'offset', 0) - - ! Get plot - if (useWidth) then - call self % geom % slicePlot(img, centre, dir, what, width) - else - call self % geom % slicePlot(img, centre, dir, what) - end if - - ! Translate to an image - select case (what) - case ('material') - img = materialColor(img, offset) - - case ('uniqueID') - img = uniqueIDColor(img) - - case default - call fatalError(Here, "Invalid request for plot target. Must be 'material' or 'uniqueID'& - & is: "//what) - end select - - ! Print image - call imgBmp_toFile(img, outputFile) - - end subroutine makeBmpImg - - !! - !! Terminates visualiser - !! - !! Cleans up remnants of visualiser once it is no longer needed - !! - !! Result: - !! An empty visualiser object - !! - subroutine kill(self) - class(visualiser), intent(inout) :: self - - self % name ='' - self % geom => null() - call self % vizDict % kill() - - end subroutine kill - - - !! - !! Convert matIdx to a 24bit color - !! - !! Special materials are associeted with special colors: - !! OUTSIDE_MAT -> white (#ffffff) - !! VOID_MAT -> black (#000000) - !! UNDEF_MAT -> green (#00ff00) - !! - !! Args: - !! matIdx [in] -> Value of the material index - !! offset [in] -> Offset to be used in the hash function - !! - !! Result: - !! A 24-bit color specifing the material - !! - elemental function materialColor(matIdx, offset) result(color) - integer(shortInt), intent(in) :: matIdx - integer(shortInt) :: color - integer(shortInt), intent(in) :: offset - integer(shortInt), parameter :: COL_OUTSIDE = int(z'ffffff', shortInt) - integer(shortInt), parameter :: COL_VOID = int(z'000000', shortInt) - integer(shortInt), parameter :: COL_UNDEF = int(z'00ff00', shortInt) - - select case (matIdx) - case (OUTSIDE_MAT) - color = COL_OUTSIDE - - case (VOID_MAT) - color = COL_VOID - - case (UNDEF_MAT) - color = COL_UNDEF - - case default - color = knuthHash(matIdx + offset, 24) - - end select - - end function materialColor - - !! - !! Convert uniqueID to 24bit color - !! - !! An elemental wrapper over Knuth Hash - !! - !! We use a hash function to scatter colors accross all available. - !! Knuth multiplicative hash is very good at scattering integer - !! sequences e.g. {1, 2, 3...}. Thus, it is ideal for a colormap. - !! - !! Args: - !! uniqueID [in] -> Value of the uniqueID - !! - !! Result: - !! A 24-bit color specifing the uniqueID - !! - elemental function uniqueIDColor(uniqueID) result(color) - integer(shortInt), intent(in) :: uniqueID - integer(shortInt) :: color - - color = knuthHash(uniqueID, 24) - - end function uniqueIDColor - - -end module visualiser_class +module visualiser_class + + use numPrecision + use universalVariables + use genericProcedures, only : fatalError, numToChar + use hashFunctions_func, only : knuthHash + use imgBmp_func, only : imgBmp_toFile + use commandLineUI, only : getInputFile + use dictionary_class, only : dictionary + use geometry_inter, only : geometry + use outputVTK_class + + implicit none + private + + !! + !! Object responsible for controlling visualisation + !! + !! Object that creates images relating to SCONE geometries + !! Should be extensible for adding different visualisation methods + !! Receives and generates data for visualisation + !! Requires a dictionary input which specifies the procedures to call + !! Presently supports: VTK voxel mesh creation + !! + !! Private members: + !! name -> name to be used for generating output files (corresponding to input) + !! geom -> pointer to geometry + !! vizDict -> dictionary containing visualisations to be generated + !! + !! Interface: + !! init -> initialises visualiser + !! makeViz -> constructs requested visualisations + !! kill -> cleans up visualiser + !! + !! Sample dictionary input: + !! viz{ + !! vizDict1{ } + !! #vizDict2{ }# + !! } + !! + !! NOTE: For details regarding contents of the vizDict dictionaries see the documentation + !! of 'makeVTK' and 'makeBmpImg' functions + !! + type, public :: visualiser + character(nameLen), private :: name + class(geometry), pointer, private :: geom => null() + type(dictionary), private :: vizDict + contains + procedure :: init + procedure :: makeViz + procedure :: kill + procedure, private :: makeVTK + procedure, private :: makeBmpImg + end type + +contains + + !! + !! Initialises visualiser + !! + !! Provides visualiser with filename for output, + !! geometry information, and the dictionary describing + !! what is to be plotted + !! + !! Args: + !! geom [inout] -> pointer to the geometry + !! vizDict[in] -> dictionary containing what is to be visualised + !! + !! Result: + !! Initialised visualiser + !! + subroutine init(self, geom, vizDict) + class(visualiser), intent(inout) :: self + class(geometry), pointer, intent(inout) :: geom + class(dictionary), intent(in) :: vizDict + character(:), allocatable :: string + + ! Obtain file name + call getInputFile(string) + self % name = string + + ! Point to geometry + self % geom => geom + + ! Store visualisation dictionary + self % vizDict = vizDict + + end subroutine init + + !! + !! Generate all visualisations specified by vizDict + !! + !! Proceed through all dictionaries contained within vizDict + !! and perform all corresponding visualisations + !! + !! Result: + !! Visualisation outputs corresponding to dictionary contents + !! + !! Errors: + !! Returns an error if an unrecognised visualisation is requested + !! + subroutine makeViz(self) + class(visualiser), intent(inout) :: self + class(dictionary), pointer :: tempDict + character(nameLen),dimension(:), allocatable :: keysArr + integer(shortInt) :: i + character(nameLen) :: type + character(nameLen) :: here ='makeViz (visualiser_class.f90)' + + ! Loop through each sub-dictionary and generate visualisation + ! (if the visualisation method is available) + call self % vizDict % keys(keysArr,'dict') + + do i=1,size(keysArr) + tempDict => self % vizDict % getDictPtr(keysArr(i)) + call tempDict % get(type,'type') + select case(type) + case('vtk') + call self % makeVTK(tempDict) + + case('bmp') + call self % makeBmpImg(tempDict) + + case default + call fatalError(here, 'Unrecognised visualisation - presently only accept vtk') + + end select + + end do + + end subroutine makeViz + + !! + !! Generate a VTK output + !! + !! Creates the VTK file corresponding to the contents of dict + !! + !! Args: + !! dict [in] -> dictionary containing description of VTK file to be made + !! + !! Sample input dictionary: + !! VTK { + !! type vtk; + !! corner (-1.0 -1.0 -1.0); // lower corner of the plot volume + !! width (2.0 2.0 2.0); // width in each direction + !! vox (300 300 300); // Resolution in each direction + !! #what uniqueId;# // Plot target. 'material' or 'uniqueId'. Default: 'material' + !! } + !! + !! TODO: VTK output is placed in a input filename appended by '.vtk' extension. + !! This prevents multiple VTK visualisations (due to overriding). Might also become + !! weird for input files with extension e.g. 'input.dat'. + !! DEMAND USER TO GIVE OUTPUT NAME + !! + subroutine makeVTK(self, dict) + class(visualiser), intent(inout) :: self + class(dictionary), intent(in) :: dict + type(outputVTK) :: vtk + integer(shortInt), dimension(:,:,:), allocatable:: voxelMat + real(defReal), dimension(:), allocatable :: corner ! corner of the mesh + real(defReal), dimension(:), allocatable :: center ! center of the mesh + real(defReal), dimension(:), allocatable :: width ! corner of the mesh + integer(shortInt), dimension(:), allocatable :: nVox ! number of mesh voxels + character(nameLen) :: what + character(nameLen) :: here ='makeVTK (visualiser_class.f90)' + + call vtk % init(dict) + + ! Identify whether plotting 'material' or 'cellID' + call dict % getOrDefault(what, 'what', 'material') + + ! Obtain geometry data + call dict % get(corner, 'corner') + call dict % get(width, 'width') + center = corner + width/TWO + call dict % get(nVox, 'vox') + + if (size(corner) /= 3) then + call fatalError(here,'Voxel plot requires corner to have 3 values') + endif + if (size(width) /= 3) then + call fatalError(here,'Voxel plot requires width to have 3 values') + endif + if (size(nVox) /= 3) then + call fatalError(here,'Voxel plot requires vox to have 3 values') + endif + allocate(voxelMat(nVox(1), nVox(2), nVox(3))) + + ! Have geometry obtain data + call self % geom % voxelPlot(voxelMat, center, what, width) + + ! In principle, can add multiple data sets to VTK - not done here yet + ! VTK data set will use 'what' variable as a name + call vtk % addData(voxelMat, what) + call vtk % output(self % name) + call vtk % kill() + + end subroutine makeVTK + + !! + !! Generate a BMP slice image of the geometry + !! + !! Args: + !! dict [in] -> Dictionary with settings + !! + !! Sample dictionary input: + !! bmp_img { + !! type bmp; + !! #what uniqueID;# // Target of the plot. 'uniqueId' or 'material'. Default: 'material' + !! output img; // Name of output file without extension + !! centre (0.0 0.0 0.0); // Coordinates of the centre of the plot + !! axis x; // Must be 'x', 'y' or 'z' + !! res (300 300); // Resolution of the image + !! #offset 978; # // Parameter to 'randomize' the colour map + !! #width (1.0 2.0);# // Width of the plot from the centre + !! } + !! + !! NOTE: If 'width' is not given, the plot will extend to the bounds of the geometry. + !! This may result in the provided centre being moved to the center of the geometry in the + !! plot plane. However, the position on the plot axis will be unchanged. + !! + subroutine makeBmpImg(self, dict) + class(visualiser), intent(inout) :: self + class(dictionary), intent(in) :: dict + real(defReal), dimension(3) :: centre + real(defReal), dimension(2) :: width + character(1) :: dir + character(nameLen) :: tempChar + logical(defBool) :: useWidth + character(nameLen) :: what, outputFile + real(defReal), dimension(:), allocatable :: temp + integer(shortInt), dimension(:), allocatable :: tempInt + integer(shortInt), dimension(:,:), allocatable :: img + integer(shortInt) :: offset = 0 + character(100), parameter :: Here = 'makeBmpImg (visualiser_class.f90)' + + ! Get plot parameters + + ! Identify whether plotting 'material' or 'cellID' + call dict % getOrDefault(what, 'what', 'material') + + ! Get name of the output file + call dict % get(outputFile, 'output') + outputFile = trim(outputFile) // '.bmp' + + ! Central point + call dict % get(temp, 'centre') + + if (size(temp) /= 3) then + call fatalError(Here, "'center' must have size 3. Has: "//numToChar(size(temp))) + end if + + centre = temp + + ! Axis + call dict % get(tempChar, 'axis') + + if (len_trim(tempChar) /= 1) then + call fatalError(Here, "'axis' must be x,y or z. Not: "//tempChar) + end if + + dir = tempChar(1:1) + + ! Resolution + call dict % get(tempInt, 'res') + + if (size(tempInt) /= 2) then + call fatalError(Here, "'res' must have size 2. Has: "//numToChar(size(tempInt))) + else if (any(tempInt <= 0)) then + call fatalError(Here, "Resolution must be +ve. There is 0 or -ve entry!") + end if + + allocate(img(tempInt(1), tempInt(2))) + + ! Optional width + useWidth = dict % isPresent('width') + if (useWidth) then + call dict % get(temp, 'width') + + ! Check for errors + if (size(temp) /= 2) then + call fatalError(Here, "'width' must have size 2. Has: "//numToChar((size(temp)))) + else if (any(temp <= ZERO)) then + call fatalError(Here, "'width' must be +ve. It isn't.") + end if + + width = temp + + end if + + ! Colourmap offset + call dict % getOrDefault(offset, 'offset', 0) + + ! Get plot + if (useWidth) then + call self % geom % slicePlot(img, centre, dir, what, width) + else + call self % geom % slicePlot(img, centre, dir, what) + end if + + ! Translate to an image + select case (what) + case ('material') + img = materialColour(img, offset) + + case ('uniqueID') + img = uniqueIDColour(img) + + case default + call fatalError(Here, "Invalid request for plot target. Must be 'material' or 'uniqueID'& + & is: "//what) + end select + + ! Print image + call imgBmp_toFile(img, outputFile) + + end subroutine makeBmpImg + + !! + !! Terminates visualiser + !! + !! Cleans up remnants of visualiser once it is no longer needed + !! + !! Result: + !! An empty visualiser object + !! + subroutine kill(self) + class(visualiser), intent(inout) :: self + + self % name ='' + self % geom => null() + call self % vizDict % kill() + + end subroutine kill + + + !! + !! Convert matIdx to a 24bit colour + !! + !! Special materials are associated with special colours: + !! OUTSIDE_MAT -> white (#ffffff) + !! VOID_MAT -> black (#000000) + !! UNDEF_MAT -> green (#00ff00) + !! + !! Args: + !! matIdx [in] -> Value of the material index + !! offset [in] -> Offset to be used in the hash function + !! + !! Result: + !! A 24-bit colour specifying the material + !! + elemental function materialColour(matIdx, offset) result(colour) + integer(shortInt), intent(in) :: matIdx + integer(shortInt) :: colour + integer(shortInt), intent(in) :: offset + integer(shortInt), parameter :: COL_OUTSIDE = int(z'ffffff', shortInt) + integer(shortInt), parameter :: COL_VOID = int(z'000000', shortInt) + integer(shortInt), parameter :: COL_UNDEF = int(z'00ff00', shortInt) + + select case (matIdx) + case (OUTSIDE_MAT) + colour = COL_OUTSIDE + + case (VOID_MAT) + colour = COL_VOID + + case (UNDEF_MAT) + colour = COL_UNDEF + + case default + colour = knuthHash(matIdx + offset, 24) + + end select + + end function materialColour + + !! + !! Convert uniqueID to 24bit colour + !! + !! An elemental wrapper over Knuth Hash + !! + !! We use a hash function to scatter colours across all available. + !! Knuth multiplicative hash is very good at scattering integer + !! sequences e.g. {1, 2, 3...}. Thus, it is ideal for a colourmap. + !! + !! Args: + !! uniqueID [in] -> Value of the uniqueID + !! + !! Result: + !! A 24-bit colour specifying the uniqueID + !! + elemental function uniqueIDColour(uniqueID) result(colour) + integer(shortInt), intent(in) :: uniqueID + integer(shortInt) :: colour + + colour = knuthHash(uniqueID, 24) + + end function uniqueIDColour + + +end module visualiser_class From 36a186c439430b55c590edd8238d448041b1dc65 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 21 Nov 2023 17:48:26 +0100 Subject: [PATCH 078/133] Add colour-int conversion --- SharedModules/CMakeLists.txt | 6 ++-- SharedModules/Tests/colours_test.f90 | 26 +++++++++++++++ SharedModules/colours_func.f90 | 48 ++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 SharedModules/Tests/colours_test.f90 create mode 100644 SharedModules/colours_func.f90 diff --git a/SharedModules/CMakeLists.txt b/SharedModules/CMakeLists.txt index dcd1633ec..2a8baa4ce 100644 --- a/SharedModules/CMakeLists.txt +++ b/SharedModules/CMakeLists.txt @@ -12,7 +12,8 @@ add_sources( ./genericProcedures.f90 ./timer_mod.f90 ./charLib_func.f90 ./openmp_func.f90 - ./errors_mod.f90) + ./errors_mod.f90 + ./colours_func.f90) add_unit_tests( ./Tests/grid_test.f90 ./Tests/energyGrid_test.f90 @@ -21,4 +22,5 @@ add_unit_tests( ./Tests/grid_test.f90 ./Tests/hashFunctions_test.f90 ./Tests/timer_test.f90 ./Tests/conversions_test.f90 - ./Tests/charLib_test.f90) + ./Tests/charLib_test.f90 + ./Tests/colours_test.f90) diff --git a/SharedModules/Tests/colours_test.f90 b/SharedModules/Tests/colours_test.f90 new file mode 100644 index 000000000..3aba28b02 --- /dev/null +++ b/SharedModules/Tests/colours_test.f90 @@ -0,0 +1,26 @@ +module colours_test + use numPrecision + use colours_func, only : rgb24bit + use pFUnit_mod + + implicit none + +contains + + +@Test + subroutine testColourConversions() + + ! Test by comparison with some hex values + @assertEqual(int(z"123456"), rgb24bit(18, 52, 86)) + + @assertEqual(int(z"000000"), rgb24bit(0, 0, 0)) + @assertEqual(int(z"ffffff"), rgb24bit(255, 255, 255)) + + @assertEqual(int(z"ff0000"), rgb24bit(255, 0, 0)) + @assertEqual(int(z"00ff00"), rgb24bit(0, 255, 0)) + @assertEqual(int(z"0000ff"), rgb24bit(0, 0, 255)) + + end subroutine testColourConversions + +end module colours_test diff --git a/SharedModules/colours_func.f90 b/SharedModules/colours_func.f90 new file mode 100644 index 000000000..5e7fec61a --- /dev/null +++ b/SharedModules/colours_func.f90 @@ -0,0 +1,48 @@ +!! +!! Contains function to deal with colours +!! +module colours_func + use numPrecision + use genericProcedures, only: numToChar + use errors_mod, only: fatalError + implicit none + + public :: rgb24bit + +contains + + + !! + !! Return integer with 24bit colour value from r,g,b components + !! + !! Args: + !! r [in] -> red component in [0-255] range + !! g [in] -> green component in [0-255] range + !! b [in] -> blue component in [0-255] range + !! + function rgb24bit(r, g, b) result(col) + integer(shortInt), intent(in) :: r + integer(shortInt), intent(in) :: g + integer(shortInt), intent(in) :: b + integer(shortInt) :: col + character(100), parameter :: Here = "rgb24bit (colours_func.f90)" + + ! Check that the values are in the correct range + if (r < 0 .or. r > 255) then + call fatalError(Here, "Red value is out of [0-255] range: " // numToChar(r)) + end if + if (g < 0 .or. g > 255) then + call fatalError(Here, "Green value is out of [0-255] range: " // numToChar(g)) + end if + if (b < 0 .or. b > 255) then + call fatalError(Here, "Blue value is out of [0-255] range: " // numToChar(b)) + end if + + ! Compute the 24 bit colour + ! Note inversion, blue is the least significant bits + col = b + 256 * g + 256 * 256 * r + + end function rgb24bit + + +end module colours_func From 3f0155e930c20862d16eefe314b9630a3080489b Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 22 Nov 2023 11:05:04 +0100 Subject: [PATCH 079/133] Add user defined colours for materials A new entery in material definition allows to specify the colour the material will use in the visualisation. --- NuclearData/materialMenu_mod.f90 | 58 ++++++++++++++++++++++-------- Visualisation/visualiser_class.f90 | 21 +++-------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/NuclearData/materialMenu_mod.f90 b/NuclearData/materialMenu_mod.f90 index 3236083d2..0ad803a8a 100644 --- a/NuclearData/materialMenu_mod.f90 +++ b/NuclearData/materialMenu_mod.f90 @@ -8,6 +8,7 @@ !! Public Members: !! materialDefs -> array of material definitions of type materialItem !! nameMap -> Map that maps material name to matIdx +!! colourMap -> Map that maps matIdx to 24bit colour (to use for visualisation) !! !! Interface: !! init -> Load material definitions from a dictionary @@ -21,8 +22,10 @@ module materialMenu_mod use numPrecision - use universalVariables, only : NOT_FOUND, VOID_MAT, OUTSIDE_MAT + use universalVariables, only : NOT_FOUND, VOID_MAT, OUTSIDE_MAT, UNDEF_MAT use genericProcedures, only : fatalError, charToInt, numToChar + use colours_func, only : rgb24bit + use intMap_class, only : intMap use charMap_class, only : charMap use dictionary_class, only : dictionary @@ -83,6 +86,7 @@ module materialMenu_mod !! 5010.03 2.0E-005; !! } !! xsFile /home/uberMoffTarkin/XS/mat1.xs; + !! #rgb (255 0 0); # // RGB colour to be used in visualisation !! } !! !! NOTE: the moder dictionary is optional, necessary only if S(a,b) thermal scattering @@ -102,9 +106,16 @@ module materialMenu_mod procedure :: display => display_materialItem end type materialItem -!! MODULE COMPONENTS + !! Parameters + integer(shortInt), parameter :: COL_OUTSIDE = int(z'ffffff', shortInt) + integer(shortInt), parameter :: COL_VOID = int(z'000000', shortInt) + integer(shortInt), parameter :: COL_UNDEF = int(z'00ff00', shortInt) + + + !! MODULE COMPONENTS type(materialItem),dimension(:),allocatable,target,public :: materialDefs - type(charMap),target,public :: nameMap + type(charMap), target, public :: nameMap + type(intMap), public :: colourMap public :: init public :: kill @@ -142,17 +153,20 @@ subroutine init(dict) ! Load definitions do i=1,size(matNames) - call materialDefs(i) % init(matNames(i), dict % getDictPtr(matNames(i))) - materialDefs(i) % matIdx = i + call materialDefs(i) % init(matNames(i), i, dict % getDictPtr(matNames(i))) call nameMap % add(matNames(i), i) end do - ! Add special Material keywords to thedictionary + ! Add special Material keywords to the dictionary temp = 'void' call nameMap % add(temp, VOID_MAT) temp = 'outside' call nameMap % add(temp, OUTSIDE_MAT) + !! Load colours for the special materials + call colourMap % add(VOID_MAT, COL_VOID) + call colourMap % add(OUTSIDE_MAT, COL_OUTSIDE) + call colourMap % add(UNDEF_MAT, COL_UNDEF) end subroutine init @@ -250,25 +264,30 @@ end function matIdx !! !! Args: !! name [in] -> character with material name + !! idx [in] -> material index !! dict [in] -> dictionary with material definition !! !! Errors: !! FatalError if dictionary does not contain valid material definition. !! - subroutine init_materialItem(self, name, dict) - class(materialItem), intent(inout) :: self - character(nameLen),intent(in) :: name - class(dictionary), intent(in) :: dict - character(nameLen),dimension(:),allocatable :: keys, moderKeys - integer(shortInt) :: i - class(dictionary),pointer :: compDict, moderDict - logical(defBool) :: hasSab + subroutine init_materialItem(self, name, idx, dict) + class(materialItem), intent(inout) :: self + character(nameLen), intent(in) :: name + integer(shortInt), intent(in) :: idx + class(dictionary), intent(in) :: dict + character(nameLen), dimension(:), allocatable :: keys, moderKeys + integer(shortInt), dimension(:), allocatable :: temp + integer(shortInt) :: i + class(dictionary),pointer :: compDict, moderDict + logical(defBool) :: hasSab + character(100), parameter :: Here = 'init_materialItem (materialMenu_mod.f90)' ! Return to initial state call self % kill() ! Load easy components c self % name = name + self % matIdx = idx call dict % get(self % T,'temp') ! Get composition dictionary and load composition @@ -300,6 +319,17 @@ subroutine init_materialItem(self, name, dict) call self % nuclides(i) % init(keys(i)) end do + ! Add colour info if present + if(dict % isPresent('rgb')) then + call dict % get(temp, 'rgb') + + if (size(temp) /= 3) then + call fatalError(Here, "'rgb' keyword must have 3 values") + end if + + call colourMap % add(idx, rgb24bit(temp(1), temp(2), temp(3))) + end if + ! Save dictionary self % extraInfo = dict diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index 9d8f0bf5b..78b7d301a 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -8,6 +8,7 @@ module visualiser_class use commandLineUI, only : getInputFile use dictionary_class, only : dictionary use geometry_inter, only : geometry + use materialMenu_mod, only : mm_colourMap => colourMap use outputVTK_class implicit none @@ -353,24 +354,10 @@ elemental function materialColour(matIdx, offset) result(colour) integer(shortInt), intent(in) :: matIdx integer(shortInt) :: colour integer(shortInt), intent(in) :: offset - integer(shortInt), parameter :: COL_OUTSIDE = int(z'ffffff', shortInt) - integer(shortInt), parameter :: COL_VOID = int(z'000000', shortInt) - integer(shortInt), parameter :: COL_UNDEF = int(z'00ff00', shortInt) - select case (matIdx) - case (OUTSIDE_MAT) - colour = COL_OUTSIDE - - case (VOID_MAT) - colour = COL_VOID - - case (UNDEF_MAT) - colour = COL_UNDEF - - case default - colour = knuthHash(matIdx + offset, 24) - - end select + ! Since Knuth hash is cheap we can compute it anyway even if colour from + ! the map will end up being used + colour = mm_colourMap % getOrDefault(matIdx, knuthHash(matIdx + offset, 24)) end function materialColour From a481235a41a8ca9d85bfa15a2acb11d55237a53e Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 22 Nov 2023 11:11:35 +0100 Subject: [PATCH 080/133] Fix spelling and style --- NuclearData/materialMenu_mod.f90 | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/NuclearData/materialMenu_mod.f90 b/NuclearData/materialMenu_mod.f90 index 0ad803a8a..729e209da 100644 --- a/NuclearData/materialMenu_mod.f90 +++ b/NuclearData/materialMenu_mod.f90 @@ -1,9 +1,9 @@ !! -!! Material Menu is a module (Singleton) that contains global definitions of diffrent materials +!! Material Menu is a module (Singleton) that contains global definitions of different materials !! !! It exists to make it easier for all databases to refer to the same materials by the same -!! name and index. This is necessary to avoid confusion resulting from diffrent materials with the -!! same name or index in diffrent databases. +!! name and index. This is necessary to avoid confusion resulting from different materials with the +!! same name or index in different databases. !! !! Public Members: !! materialDefs -> array of material definitions of type materialItem @@ -36,9 +36,9 @@ module materialMenu_mod !! Information about a single nuclide !! !! Based somewhat on MCNP conventions. - !! Atomic and Mass number identify cleary a nuclide species + !! Atomic and Mass number identify clearly a nuclide species !! Evaluation number T allows to refer to multiple states/evaluations of the same nuclide species - !! E.G. at a Diffrent temperature as in MCNP Library. + !! E.G. at a Different temperature as in MCNP Library. !! !! Public members: !! Z -> Atomic number @@ -142,7 +142,7 @@ subroutine init(dict) integer(shortInt) :: i character(nameLen) :: temp - ! Clean whatever may be alrady present + ! Clean whatever may be already present call kill() ! Load all material names @@ -218,7 +218,7 @@ end subroutine display !! Result: !! nameLen long character with material name !! - !! Erorrs: + !! Error: !! If idx is -ve or larger then number of defined materials !! Empty string '' is returned as its name !! @@ -422,7 +422,7 @@ function isNucDefinition(key) result(isIt) za = verify(key(1:L),'0123456789') tt = verify(key(1:L),'0123456789', back = .true.) - ! Verify that the location of the dot is consistant + ! Verify that the location of the dot is consistent isIt = dot == za .and. dot == tt end function isNucDefinition @@ -467,7 +467,7 @@ end subroutine init_nuclideInfo !! None !! !! Result: - !! Character in format ZZAAA.TT that dscribes nuclide definition + !! Character in format ZZAAA.TT that describes nuclide definition !! !! Errors: !! None @@ -491,17 +491,17 @@ end function toChar_nuclideInfo !! Get pointer to a material definition under matIdx !! !! Args: - !! matIdx [in] -> Index of the material + !! idx [in] -> Index of the material !! !! Result: !! Pointer to a materialItem with the definition !! !! Errors: - !! FatalError if matIdx does not correspond to any defined material + !! FatalError if idx does not correspond to any defined material !! FatalError if material definitions were not loaded !! - function getMatPtr(matIdx) result(ptr) - integer(shortInt), intent(in) :: matIdx + function getMatPtr(idx) result(ptr) + integer(shortInt), intent(in) :: idx type(materialItem), pointer :: ptr character(100), parameter :: Here = 'getMatPtr (materialMenu_mod.f90)' @@ -511,13 +511,13 @@ function getMatPtr(matIdx) result(ptr) end if ! Verify matIdx - if( matIdx <= 0 .or. matIdx > nMat()) then - call fatalError(Here,"matIdx: "//numToChar(matIdx)// & + if( idx <= 0 .or. idx > nMat()) then + call fatalError(Here,"matIdx: "//numToChar(idx)// & " does not correspond to any defined material") end if ! Attach pointer - ptr => materialDefs(matIdx) + ptr => materialDefs(idx) end function getMatPtr From 32be08719b73fb78aecb22dcfd7d7d9cd80037cd Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 22 Nov 2023 11:57:35 +0100 Subject: [PATCH 081/133] Update documentation and examples --- InputFiles/c5g7_mox | 2 ++ docs/User Manual.rst | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/InputFiles/c5g7_mox b/InputFiles/c5g7_mox index b8e86a4af..dbb696fc8 100644 --- a/InputFiles/c5g7_mox +++ b/InputFiles/c5g7_mox @@ -106,6 +106,7 @@ viz { centre (0.0 0.0 0.0); //width (25.0 25.0); axis z; + offset -17; res (500 500); } } @@ -119,6 +120,7 @@ nuclearData { water { temp 75675; + rgb (0 0 139); // Colour of water is dark blue moder { 1001.03 h-h2o.42; } composition { 1001.03 6.700E-002; diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ef2841d4d..f2005c358 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -275,9 +275,9 @@ neutronCEstd, to perform analog collision processing target nuclide movement. Target movement is sampled if target mass A < massThreshold. [Mn] * DBRCeMin (*optional*, default = 1.0e-08): minimum DBRC energy. [MeV] * DBRCeMax (*optional*, default = 2.0e-04): maximum DBRC energy. [MeV] - + Example: :: - + collisionOperator { neutronCE { type neutronCEstd; minEnergy 1.0e-12; maxEnergy 30.0; energyThreshold 200; massThreshold 2; DBRCeMin 1.0e-06; DBRCeMax 0.001; } } @@ -679,6 +679,9 @@ bmp * what (*optional*, default = material): defines what is highlighted in the plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` highlights unique cell IDs +* offset (*optional*, default = 0) An integer (positive or negative) that + shifts the sequence of colours assigned to materials. Allows to change colours + from the default sequence in parametric way. Example: :: @@ -725,7 +728,7 @@ from ACE files. resonance probability tables treatment * DBRC (*optional*, default = no DBRC): list of ZAIDs of nuclides for which DBRC has to be applied. - + Example: :: ceData { type aceNuclearDatabase; aceLibrary ./myFolder/ACElib/JEF311.aceXS; @@ -734,7 +737,7 @@ Example: :: .. note:: If DBRC is applied, the 0K cross section ace files of the relevant nuclides must be included in the aceLibrary file. - + baseMgNeutronDatabase ##################### @@ -790,6 +793,9 @@ Other options are: * xsFile: needed for multi-group simulations. Must contain the path to the file where the multi-group cross sections are stored. +* rgb (*optional*): An array of three integers specifying the RGB colour e.g. ``(255 0 0)``. The + colour defined in this way will be used for visualisation of the material in the geometry plots. + Example 1: :: materials { @@ -800,6 +806,7 @@ Example 1: :: 8016.03 0.018535464; } } water { temp 273; + rgb (0 0 200); composition { 1001.03 0.0222222; 8016.03 0.00535; } @@ -1073,7 +1080,7 @@ Example: :: } } -.. note:: +.. note:: To calculate the average weight, one should divide weight moment 1 (weight1) by weight moment 0 (weight0). To calculate the variance of the weights, the tally results have to be post-processed as: var = weight2/weight0 - (weight1/weight0)^2 From 3fc43ae7329b941da446b3634615cda8889e95b5 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 25 Jan 2024 16:16:44 +0000 Subject: [PATCH 082/133] Completing documentation --- .../neutronCEimp_class.f90 | 14 +++++++----- .../neutronMGimp_class.f90 | 22 +++++++++---------- .../neutronMGstd_class.f90 | 8 ------- ParticleObjects/particle_class.f90 | 4 ---- docs/User Manual.rst | 14 ++++++++++++ 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index e3dd68d5f..98bd500ee 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -58,6 +58,7 @@ module neutronCEimp_class !! impAbs -> is implicit capture performed? (off by default) !! impGen -> are fission sites generated implicitly? (on by default) !! UFS -> uniform fission sites variance reduction + !! maxSplit -> maximum number of splits allowed per particle (default = 1000) !! thresh_E -> Energy threshold for explicit treatment of target nuclide movement [-]. !! Target movment is sampled if neutron energy E < kT * thresh_E where !! kT is target material temperature in [MeV]. (default = 400.0) @@ -83,6 +84,7 @@ module neutronCEimp_class !! #impGen ;# !! #UFS ;# !! #weightWindows ;# + !! #maxSplit ;# !! } !! type, public, extends(collisionProcessor) :: neutronCEimp @@ -101,8 +103,8 @@ module neutronCEimp_class real(defReal) :: avWgt real(defReal) :: thresh_E real(defReal) :: thresh_A - ! Variance reduction options integer(shortInt) :: maxSplit + ! Variance reduction options logical(defBool) :: weightWindows logical(defBool) :: splitting logical(defBool) :: roulette @@ -565,23 +567,23 @@ subroutine split(self, p, thisCycle, maxWgt) mult = ceiling(p % w/maxWgt) ! Limit maximum split - if (mult > self % maxSplit - p % splitCount + 1) then + if (mult + p % splitCount > self % maxSplit) then mult = self % maxSplit - p % splitCount + 1 end if ! Decrease weight p % w = p % w/mult - p % splitCount = p % splitCount + mult + ! Save current particle splitCount - !splitCount = p % splitCount + splitCount = p % splitCount ! Add split particle's to the dungeon do i = 1,mult-1 - !p % splitCount = 0 + p % splitCount = 0 call thisCycle % detain(p) end do - !p % splitCount = splitCount + mult + p % splitCount = splitCount + mult end subroutine split diff --git a/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 index 7560b4587..b685b15c5 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGimp_class.f90 @@ -30,30 +30,26 @@ module neutronMGimp_class use geometryReg_mod, only : gr_fieldIdx => fieldIdx, gr_fieldPtr => fieldPtr use weightWindowsField_class, only : weightWindowsField, weightWindowsField_TptrCast - - ! Nuclear Data - !use nuclearData_inter, only : nuclearData - !use perMaterialNuclearDataMG_inter, only : perMaterialNuclearDataMG - - ! Cross-section packages to interface with nuclear data - !use xsMacroSet_class, only : xsMacroSet, xsMacroSet_ptr - implicit none private !! - !! Standard (default) scalar collision processor for MG neutrons + !! Scalar collision processor for MG neutrons !! -> Preforms implicit fission site generation !! -> Preforms analog capture !! -> Treats fission as capture (only implicit generation of 2nd-ary neutrons) !! -> Does not create secondary non-neutron projectiles + !! -> Supports the use of weight windows !! !! Settings: - !! NONE + !! weightWindows -> uses a weight windows field (off by default) + !! maxSplit -> maximum number of splits allowed per particle (default = 1000) !! !! Sample dictionary input: !! collProcName { !! type neutronMGimp; + !! #weightWindows ;# + !! #maxSplit ;# !! } !! type, public, extends(collisionProcessor) :: neutronMGimp @@ -61,8 +57,10 @@ module neutronMGimp_class class(mgNeutronDatabase), pointer, public :: xsData => null() class(mgNeutronMaterial), pointer, public :: mat => null() - ! Variance reduction options + !! Settings - private integer(shortInt) :: maxSplit + + ! Variance reduction options logical(defBool) :: weightWindows type(weightWindowsField), pointer :: weightWindowsMap @@ -350,7 +348,7 @@ subroutine split(self, p, thisCycle, maxWgt) mult = ceiling(p % w/maxWgt) ! Limit maximum split - if (mult > self % maxSplit - p % splitCount + 1) then + if (mult + p % splitCount > self % maxSplit) then mult = self % maxSplit - p % splitCount + 1 end if diff --git a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 index b357319cb..019b694ce 100644 --- a/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronMGstd_class.f90 @@ -25,14 +25,6 @@ module neutronMGstd_class ! Cross section packages use neutronXsPackages_class, only : neutronMacroXSs - - ! Nuclear Data - !use nuclearData_inter, only : nuclearData - !use perMaterialNuclearDataMG_inter, only : perMaterialNuclearDataMG - - ! Cross-section packages to interface with nuclear data - !use xsMacroSet_class, only : xsMacroSet, xsMacroSet_ptr - implicit none private diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 2f1b34fe4..3a295cc66 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -54,7 +54,6 @@ module particle_class integer(shortInt) :: matIdx = -1 ! Material index where particle is integer(shortInt) :: cellIdx = -1 ! Cell idx at the lowest coord level integer(shortInt) :: uniqueID = -1 ! Unique id at the lowest coord level - integer(shortInt) :: splitCount = 0 ! Counter of number of splits contains generic :: assignment(=) => fromParticle generic :: operator(.eq.) => equal_particleState @@ -271,7 +270,6 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % isMG = RHS % isMG LHS % type = RHS % type LHS % time = RHS % time - LHS % splitCount = RHS % splitCount end subroutine particle_fromParticleState @@ -614,7 +612,6 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % matIdx = RHS % coords % matIdx LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() - LHS % splitCount = RHS % splitCount end subroutine particleState_fromParticle @@ -703,7 +700,6 @@ elemental subroutine kill_particleState(self) self % matIdx = -1 self % cellIdx = -1 self % uniqueID = -1 - self % splitCount = 0 end subroutine kill_particleState diff --git a/docs/User Manual.rst b/docs/User Manual.rst index e1512e501..3ea998af8 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -278,6 +278,7 @@ neutronCEimp, to perform implicit collision processing * minWgt (*optional*, default = 0.25): minimum particle weight for rouletting * maxWgt (*optional*, default = 1.25): maximum particle weight for splitting * avgWgt (*optional*, default = 0.5): weight of a particle on surviving rouletting +* maxSplit (*optional*, default = 1000): maximum number of splits allowed per particle * impAbs (*optional*, default = 0): 1 for true; 0 for false; enables implicit capture * impGen (*optional*, default = 1): 1 for true; 0 for false; enables implicit fission sites generation @@ -302,6 +303,19 @@ Example: :: collisionOperator { neutronMG { type neutronMGstd; } } +neutronMGimp +############ + +neutronMGimp, to perform implicit collision processing + +* maxSplit (*optional*, default = 1000): maximum number of splits allowed per particle +* weightWindows (*optional*, default = 0): 1 for true; 0 for false; enables the use of + weight windows + +Example: :: + + collisionOperator { neutronMG { type neutronMGimp; weightWindows 1; maxSplit 50; } } + Weight Windows -------------- From 96773f1622d5db26f7062b5df57ea7d44cd5ba73 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Thu, 25 Jan 2024 17:35:14 +0100 Subject: [PATCH 083/133] Use random value for the default offset --- Visualisation/visualiser_class.f90 | 16 +++++++++++++--- docs/User Manual.rst | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index 78b7d301a..1d0886686 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -3,7 +3,7 @@ module visualiser_class use numPrecision use universalVariables use genericProcedures, only : fatalError, numToChar - use hashFunctions_func, only : knuthHash + use hashFunctions_func, only : knuthHash, FNV_1 use imgBmp_func, only : imgBmp_toFile use commandLineUI, only : getInputFile use dictionary_class, only : dictionary @@ -232,7 +232,9 @@ subroutine makeBmpImg(self, dict) real(defReal), dimension(:), allocatable :: temp integer(shortInt), dimension(:), allocatable :: tempInt integer(shortInt), dimension(:,:), allocatable :: img - integer(shortInt) :: offset = 0 + integer(shortInt) :: offset + character(10) :: time + character(8) :: date character(100), parameter :: Here = 'makeBmpImg (visualiser_class.f90)' ! Get plot parameters @@ -290,7 +292,15 @@ subroutine makeBmpImg(self, dict) end if ! Colourmap offset - call dict % getOrDefault(offset, 'offset', 0) + ! If not given select randomly + if (dict % isPresent('offset')) then + call dict % get(offset, 'offset') + + else + call date_and_time(date, time) + call FNV_1(date // time, offset) + + end if ! Get plot if (useWidth) then diff --git a/docs/User Manual.rst b/docs/User Manual.rst index f2005c358..0bbd2939d 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -679,9 +679,9 @@ bmp * what (*optional*, default = material): defines what is highlighted in the plot; options are ``material`` and ``uniqueID``, where ``uniqueID`` highlights unique cell IDs -* offset (*optional*, default = 0) An integer (positive or negative) that +* offset (*optional*, default = random) An integer (positive or negative) that shifts the sequence of colours assigned to materials. Allows to change colours - from the default sequence in parametric way. + from the default sequence in a parametric way. Example: :: From 76e12511c5ef3be4f1816d5e3fa1e4a66012a80f Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> Date: Thu, 25 Jan 2024 18:15:12 +0100 Subject: [PATCH 084/133] Update Visualisation/visualiser_class.f90 Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- Visualisation/visualiser_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index 1d0886686..a0cdcd768 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -250,7 +250,7 @@ subroutine makeBmpImg(self, dict) call dict % get(temp, 'centre') if (size(temp) /= 3) then - call fatalError(Here, "'center' must have size 3. Has: "//numToChar(size(temp))) + call fatalError(Here, "'centre' must have size 3. Has: "//numToChar(size(temp))) end if centre = temp From 98d145a27aad3d08f93218487c665e3765d6b890 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:46:44 +0000 Subject: [PATCH 085/133] Fix bug in particle_class.f90 --- ParticleObjects/particle_class.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 05ada7ba6..92367c550 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -274,6 +274,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % type = RHS % type LHS % time = RHS % time LHS % collisionN = RHS % collisionN + LHS & splitCount = 0 ! Reinitialise counter for number of splits end subroutine particle_fromParticleState From c0b1ef52cd96133a278211ddebcdeefe94a42a80 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:49:22 +0000 Subject: [PATCH 086/133] typo --- ParticleObjects/particle_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 92367c550..69021c389 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -274,7 +274,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % type = RHS % type LHS % time = RHS % time LHS % collisionN = RHS % collisionN - LHS & splitCount = 0 ! Reinitialise counter for number of splits + LHS % splitCount = 0 ! Reinitialise counter for number of splits end subroutine particle_fromParticleState From 0ce4496cd11a8c3947f5b67d4b8f8dc612ee2f3b Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:46:44 +0000 Subject: [PATCH 087/133] Fix bug in particle_class.f90 --- ParticleObjects/particle_class.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 05ada7ba6..92367c550 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -274,6 +274,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % type = RHS % type LHS % time = RHS % time LHS % collisionN = RHS % collisionN + LHS & splitCount = 0 ! Reinitialise counter for number of splits end subroutine particle_fromParticleState From 10130ce55440b00755a7715bcf7a7dddd76799d0 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:49:22 +0000 Subject: [PATCH 088/133] typo --- ParticleObjects/particle_class.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 92367c550..69021c389 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -274,7 +274,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % type = RHS % type LHS % time = RHS % time LHS % collisionN = RHS % collisionN - LHS & splitCount = 0 ! Reinitialise counter for number of splits + LHS % splitCount = 0 ! Reinitialise counter for number of splits end subroutine particle_fromParticleState From e0682f12b9449563498171d258a7b9962a5e6bc9 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Fri, 30 Jun 2023 19:12:34 +0200 Subject: [PATCH 089/133] Print the output on finalisation of output file Allows the outputFile to print to disk anytime between initialisation and finalisation. Thus, will allow to reduce memory usage. --- PhysicsPackages/eigenPhysicsPackage_class.f90 | 4 +- .../fixedSourcePhysicsPackage_class.f90 | 4 +- .../fileOutput/dummyPrinter_class.f90 | 13 --- UserInterface/fileOutput/outputFile_class.f90 | 101 ++++++++++++------ 4 files changed, 68 insertions(+), 54 deletions(-) diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index aa89111c1..d67603e8a 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -323,7 +323,7 @@ subroutine collectResults(self) type(outputFile) :: out character(nameLen) :: name - call out % init(self % outputFormat) + call out % init(self % outputFormat, filename=self % outputFile) name = 'seed' call out % printValue(self % pRNG % getSeed(),name) @@ -359,8 +359,6 @@ subroutine collectResults(self) call self % activeTally % print(out) call out % endBlock() - call out % writeToFile(self % outputFile) - end subroutine collectResults diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 35e2ff2d3..b1dbb4e86 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -269,7 +269,7 @@ subroutine collectResults(self) type(outputFile) :: out character(nameLen) :: name - call out % init(self % outputFormat) + call out % init(self % outputFormat, filename=self % outputFile) name = 'seed' call out % printValue(self % pRNG % getSeed(),name) @@ -290,8 +290,6 @@ subroutine collectResults(self) ! Print tally call self % tally % print(out) - call out % writeToFile(self % outputFile) - end subroutine collectResults diff --git a/UserInterface/fileOutput/dummyPrinter_class.f90 b/UserInterface/fileOutput/dummyPrinter_class.f90 index 890883d4d..17b14114e 100644 --- a/UserInterface/fileOutput/dummyPrinter_class.f90 +++ b/UserInterface/fileOutput/dummyPrinter_class.f90 @@ -24,7 +24,6 @@ module dummyPrinter_class contains procedure :: init procedure :: extension - procedure :: writeToFile procedure :: startBlock procedure :: endBlock @@ -64,18 +63,6 @@ pure function extension(self) result(str) end function extension - !! - !! Print the output to the given unit - !! - !! See asciiOutput_inter for details - !! - subroutine writeToFile(self, unit) - class(dummyPrinter), intent(inout) :: self - integer(shortInt), intent(in) :: unit - - - end subroutine writeToFile - !! !! Change state to writing new block with "name" !! diff --git a/UserInterface/fileOutput/outputFile_class.f90 b/UserInterface/fileOutput/outputFile_class.f90 index 6585580e0..6612ebf4b 100644 --- a/UserInterface/fileOutput/outputFile_class.f90 +++ b/UserInterface/fileOutput/outputFile_class.f90 @@ -69,7 +69,7 @@ module outputFile_class !! is called root !! -> Each entry in a block (including sub-blocks) must have a unique name !! -> Each entry is either a raw "Name - Value" pair or an array - !! -> Arrays can have unlimited rank (dimension), but values of the enteries must be given in a + !! -> Arrays can have unlimited rank (dimension), but values of the entries must be given in a !! sequence in a COLUMN-MAJOR ORDER !! -> Arrays can store RESULTS, REALS, INTS or CHARACTERS. !! -> RESULT is a pair of reals. MEAN and STANDARD DEVIATION @@ -81,14 +81,14 @@ module outputFile_class !! !! Handling errors: !! If `fatalError` is true (default) then on wrong sequence of calls fatalError will be raised. - !! Otherwise the flag `noErrors` will be set to false and error massege saved in the `errorLog` + !! Otherwise the flag `noErrors` will be set to false and error massage saved in the `errorLog` !! !! Repeated Names: - !! If name in a block is repeted bahviour is governed by `logNameReuse` function. If `fatalError` - !! is true, the nwarning message is produced. Otherwise error is logged in `errorLog` and + !! If name in a block is repeated behaviour is governed by `logNameReuse` function. If `fatalError` + !! is true, the warning message is produced. Otherwise error is logged in `errorLog` and !! `noErrors` flag set to FALSE. !! - !! Private Memebers: + !! Private Members: !! output -> Output printer that determines the format !! type -> Type of the output printer !! fatalErrors -> True (default) makes all errors fatal @@ -107,8 +107,7 @@ module outputFile_class !! !! Interface: !! init -> Initialise the output file with format - !! writeToFile -> Write the output to a file - !! writeToConsole -> Write the output to the console + !! finalise -> Finalise the output file. Ensures all data is written. !! reset -> Discard already written output. !! isValid -> Return true if no errors were raised since initialisation !! getErrorLog -> Get the error log @@ -124,8 +123,9 @@ module outputFile_class !! type, public :: outputFile private - class(asciiOutput),allocatable :: output - character(nameLen) :: type + class(asciiOutput), allocatable :: output + character(nameLen) :: type + character(:), allocatable :: outputFileName ! Error handling settings logical(defBool) :: fatalErrors = .true. ! Enable fatalErrors on wrong logic @@ -151,9 +151,10 @@ module outputFile_class contains procedure :: init - procedure :: writeToFile - procedure :: writeToConsole + procedure, private :: writeToConsole procedure :: reset + final :: finalisation + procedure, private :: writeToFile ! Error Handling procedure, private :: logError @@ -210,17 +211,28 @@ module outputFile_class !! !! Args: !! type [in] -> Character to specify the format of the output file - !! fatalErrors [in] -> Optional. Set on/off fatalErrors oninvalid use of output file. + !! fatalErrors [in] -> Optional. Set on/off fatalErrors on invalid use of output file. !! Default is ON. + !! filename [in] -> Optional. Set the name of the output file. If none is given no output is + !! written. Must be given without extension. It will be added automatically + !! based on the format of the output file. !! - subroutine init(self, type, fatalErrors) - class(outputFile), intent(inout) :: self - character(*),intent(in) :: type - logical(defBool),optional,intent(in) :: fatalErrors + subroutine init(self, type, fatalErrors, filename) + class(outputFile), intent(inout) :: self + character(*), intent(in) :: type + logical(defBool), optional,intent(in) :: fatalErrors + character(*), optional, intent(in) :: filename self % type = type allocate( self % output, source = new_asciiOutput(self % type)) + ! Set output file name + if (present(filename)) then + ! Because GFotran hates implicit allocation + ! It causes buggy warnings to appear in compilation + allocate(self % outputFileName, source = filename) + end if + ! Initialise name stack call self % usedNames % init() call self % usedNames % push() @@ -239,7 +251,7 @@ end subroutine init !! !! Args: !! file [in] -> Path to the output file. Must be given WITHOUT extension - !! Approperiate extension will recived from the printer + !! Appropriate extension will be received from the printer !! !! Errors: !! fatalError if there is a problem opening the file. @@ -286,6 +298,23 @@ subroutine writeToConsole(self) end subroutine writeToConsole + !! + !! Upon the destruction of the object, write the output to file + !! + !! NOTE: + !! This subroutine WILL NOT be called if the `end program` statement is + !! reached! [Only `end subroutine`, `end block` etc.]. In that case + !! one needs to call `finalisation` manually + !! + subroutine finalisation(self) + type(outputFile), intent(inout) :: self + + if (allocated(self % outputFileName)) then + call self % writeToFile(self % outputFileName) + end if + + end subroutine finalisation + !! !! Discards all results and sets output file to an initialised state !! @@ -296,6 +325,8 @@ subroutine reset(self) deallocate(self % output) allocate( self % output, source = new_asciiOutput(self % type)) + if (allocated(self % outputFileName)) deallocate(self % outputFileName) + ! Clean error log an reset flag call self % errorLog % clean() self % noErrors = .true. @@ -341,10 +372,10 @@ subroutine logError(self, where, what) end subroutine logError !! - !! Deal with an event when entry name is resued in a block + !! Deal with an event when entry name is reused in a block !! !! Currently is fatalError is TRUE -> Prints warning to the screen - !! If fatalError is False markes error flagto true and appends a log + !! If fatalError is False marks error flag to true and appends the log !! !! Args: !! name [in] -> Name that has been reused @@ -403,7 +434,7 @@ end function getErrorLog !! !! Errors: !! Calls logError if: - !! -Called when writting an array + !! -Called when writing an array !! Calls logNameReuse if name is not unique !! subroutine startBlock(self, name) @@ -422,7 +453,7 @@ subroutine startBlock(self, name) if ( self % arrayType /= NOT_ARRAY) then call self % logError(Here,'In block: '// self % current_block_name // & ' Cannot begin new block: '//name// & - ' Becouse is writing array: '// self % current_array_name) + ' Because is writing array: '// self % current_array_name) end if ! Update state @@ -443,7 +474,7 @@ end subroutine startBlock !! !! Errors: !! Calls logError if: - !! -Called when writting an array + !! -Called when writing an array !! -Tries to end the root block. !! subroutine endBlock(self) @@ -454,7 +485,7 @@ subroutine endBlock(self) if ( self % arrayType /= NOT_ARRAY) then call self % logError(Here,'In block: '// self % current_block_name // & ' Cannot exit from block: '// & - ' Becouse is writing array: '// self % current_array_name) + ' Because is writing array: '// self % current_array_name) end if ! Check that is not in root block @@ -485,7 +516,7 @@ end subroutine endBlock !! !! Errors: !! Calls logError if: - !! -Called when writting another array + !! -Called when writing another array !! -Shape is invalid !! Calls logNameReuse if name is not unique !! @@ -505,14 +536,14 @@ subroutine startArray(self, name, shape) if ( self % arrayType /= NOT_ARRAY) then call self % logError(Here,'In block: '// self % current_block_name // & ' Cannot start new array: '//name// & - ' Becouse is writing array: '// self % current_array_name) + ' Because is writing array: '// self % current_array_name) end if ! Check whether shape is degenerate if (size(shape) == 0 .or. product(shape) == 0) then call self % logError(Here,'In block: '// self % current_block_name // & ' Cannot start new array: '//name// & - ' Becouse the shape is degenerate') + ' Because the shape is degenerate') end if ! Load shape information into buffer @@ -524,8 +555,8 @@ subroutine startArray(self, name, shape) ! Update State -> Array is present but has undefined type self % arrayType = UNDEF_ARRAY - ! Print begining of new entry - ! We don't know the shape of array becouse if has results its rank will increase + ! Print beginning of new entry + ! We don't know the shape of array because if has results its rank will increase call self % output % startEntry(name) end subroutine startArray @@ -548,7 +579,7 @@ subroutine endArray(self) if(self % arrayTop /= self % arrayLimit) then call self % logError(Here, 'Cannot close array: ' // trim(self % current_array_name) // & ' in block: ' // trim(self % current_block_name) // & - ' Becouse only: '// numToChar(self % arrayTop) // & + ' Because only: '// numToChar(self % arrayTop) // & ' of '// numToChar(self % arrayLimit)//' were provided') end if @@ -615,10 +646,10 @@ end subroutine addResult_scalar !! Add results to the array !! !! Args: - !! val [in] -> Array of mean valuse + !! val [in] -> Array of mean values !! std [in] -> Associated standard deviations !! - !! Erorrs: + !! Errors: !! Calls logError if: !! -Called before an array is opened !! -Currently opened array has different type @@ -632,7 +663,7 @@ subroutine addResult_rank1(self, val, std) character(100),parameter :: Here ='addResult_rank1 (outputFile_class.f90)' N = size(val) - if (N /= size(std)) call self % logError(Here,'val and std have diffrent size.') + if (N /= size(std)) call self % logError(Here, 'val and std have different size.') ! Add all individual entries do i = 1, N @@ -1203,7 +1234,7 @@ end subroutine push_charMapStack !! None !! !! Errors: - !! Poping empty stack does nothing! + !! Popping empty stack does nothing! !! subroutine pop_charMapStack(self) class(charMapStack), intent(inout) :: self @@ -1218,7 +1249,7 @@ subroutine pop_charMapStack(self) end subroutine pop_charMapStack !! - !! Add new entery at the given block level + !! Add new entry at the given block level !! !! Args: !! name [in] -> Entry name @@ -1246,7 +1277,7 @@ end subroutine add_charMapStack !! b_lvl [in] -> Block level (idx = b_lvl + 1) !! !! Result: - !! True if it is. False otherwsie + !! True if it is. False otherwise !! !! Errors: !! Returns FALSE is b_lvl is out of range From 46aa0f152fa0506207050867b1583c880d46d7e2 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Tue, 4 Jul 2023 18:41:42 +0200 Subject: [PATCH 090/133] Write output through a buffer to a file A delay buffer is needed to be able to make small modifications to already written data (e.g. remove a trailing comma), which makes the implementation of output formats much easier. --- UserInterface/fileOutput/CMakeLists.txt | 3 +- UserInterface/fileOutput/asciiJSON_class.f90 | 85 ++++---- .../fileOutput/asciiMATLAB_class.f90 | 101 +++------- .../fileOutput/asciiOutput_inter.f90 | 119 +++++++++-- .../fileOutput/delayedStream_class.f90 | 185 ++++++++++++++++++ .../fileOutput/dummyPrinter_class.f90 | 13 ++ UserInterface/fileOutput/outputFile_class.f90 | 123 ++++++------ docs/Output.rst | 12 +- 8 files changed, 429 insertions(+), 212 deletions(-) create mode 100644 UserInterface/fileOutput/delayedStream_class.f90 diff --git a/UserInterface/fileOutput/CMakeLists.txt b/UserInterface/fileOutput/CMakeLists.txt index bf913adf4..3ad697235 100644 --- a/UserInterface/fileOutput/CMakeLists.txt +++ b/UserInterface/fileOutput/CMakeLists.txt @@ -4,6 +4,7 @@ add_sources( ./outputFile_class.f90 ./asciiOutputFactory_func.f90 ./asciiMATLAB_class.f90 ./asciiJSON_class.f90 - ./dummyPrinter_class.f90) + ./dummyPrinter_class.f90 + ./delayedStream_class.f90) add_unit_tests (./Tests/outputFile_test.f90) diff --git a/UserInterface/fileOutput/asciiJSON_class.f90 b/UserInterface/fileOutput/asciiJSON_class.f90 index 18ddf36eb..f1e0ee859 100644 --- a/UserInterface/fileOutput/asciiJSON_class.f90 +++ b/UserInterface/fileOutput/asciiJSON_class.f90 @@ -21,7 +21,7 @@ module asciiJSON_class !! There is indentation for each block and entry, but long multi-dimensional (N-D) arrays !! are printed on a single line. Also N-D arrays are represented as a JSON array of arrays. !! - !! JSON output is fairly standard so it can be easlily read into Python and other enviroments + !! JSON output is fairly standard so it can be easily read into Python and other environments !! !! TODO: !! Currently there is a dirty fix to remove commas at the end of a block, which requires to @@ -39,7 +39,6 @@ module asciiJSON_class !! type, public, extends(asciiOutput) :: asciiJSON private - type(charTape) :: output integer(shortInt) :: ind_lvl = 0 integer(shortInt), dimension(:), allocatable :: shapeBuffer @@ -49,8 +48,8 @@ module asciiJSON_class contains procedure :: init + procedure :: endFile procedure :: extension - procedure :: writeToFile procedure :: startBlock procedure :: endBlock @@ -71,51 +70,43 @@ subroutine init(self) class(asciiJSON), intent(inout) :: self ! Add the initial bracket - call self % output % append( "{" // NEWLINE) + call self % append( "{" // NEWLINE) self % ind_lvl = 1 end subroutine init !! - !! Return approperiate extension for the file + !! Finalise the printer !! !! See asciiOutput_inter for details !! - pure function extension(self) result(str) - class(asciiJSON), intent(in) :: self - character(:), allocatable :: str - - str = 'json' - - end function extension - - !! - !! Print the output to the given unit - !! - !! See asciiOutput_inter for details - !! - subroutine writeToFile(self, unit) + subroutine endFile(self) class(asciiJSON), intent(inout) :: self - integer(shortInt), intent(in) :: unit - character(:),allocatable :: form ! Dirty fix ! Remove comma from the last entry by rewind ! Need to check that the character is a comma to avoid removing { when there is an empty block ! TODO: Find better way. Will clash with any proper stream output - if (self % output % get(self % output % length() - 1) == ",") then - call self % output % cut(2) - call self % output % append(NEWLINE) + if (self % peek(2) == ",") then + call self % cut(2) + call self % append(NEWLINE) end if + call self % append("}" // NEWLINE) - ! Close the file - call self % output % append("}") + end subroutine endFile - form = '(A' // numToChar(self % output % length()) // ')' + !! + !! Return approperiate extension for the file + !! + !! See asciiOutput_inter for details + !! + pure function extension(self) result(str) + class(asciiJSON), intent(in) :: self + character(:), allocatable :: str - write(unit,form) self % output % expose() + str = 'json' - end subroutine writeToFile + end function extension !! !! Change state to writing new block with "name" @@ -127,10 +118,10 @@ subroutine startBlock(self, name) character(nameLen), intent(in) :: name ! Write indentation - call self % output % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) + call self % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) ! Open new block and increase indentation - call self % output % append(QUOTE // trim(name) // QUOTE // ":" // "{" // NEWLINE) + call self % append(QUOTE // trim(name) // QUOTE // ":" // "{" // NEWLINE) self % ind_lvl = self % ind_lvl + 1 end subroutine startBlock @@ -147,17 +138,17 @@ subroutine endBlock(self) ! Remove comma from the last entry by rewind ! Need to check that the character is a comma to avoid removing { when there is an empty block ! TODO: Find better way. Will clash with any proper stream output - if (self % output % get(self % output % length() - 1) == ",") then - call self % output % cut(2) - call self % output % append(NEWLINE) + if (self % peek(2) == ",") then + call self % cut(2) + call self % append(NEWLINE) end if ! Decrease and write indentation self % ind_lvl = self % ind_lvl - 1 - call self % output % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) + call self % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) ! Close the block - call self % output % append("}" // ","// NEWLINE) + call self % append("}" // ","// NEWLINE) end subroutine endBlock @@ -171,10 +162,10 @@ subroutine startEntry(self, name) character(*), intent(in) :: name ! Print indentation - call self % output % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) + call self % append(repeat(BLANK, self % ind_lvl * IND_SIZE)) ! Write the name - call self % output % append(QUOTE // trim(name) // QUOTE // ":") + call self % append(QUOTE // trim(name) // QUOTE // ":") end subroutine startEntry @@ -188,7 +179,7 @@ subroutine endEntry(self) ! End with NEWLINE ! Comma will be written together with a number/char - call self % output % append(NEWLINE) + call self % append(NEWLINE) end subroutine endEntry @@ -235,12 +226,12 @@ subroutine printNum(self, val) mul = 1 do i = 1, size(self % shapeBuffer) mul = mul * self % shapeBuffer(i) - if (modulo(self % count, mul) == 0) call self % output % append("[") + if (modulo(self % count, mul) == 0) call self % append("[") end do end if ! Print the number - call self % output % append(val) + call self % append(val) if (self % in_array) then ! Append the count @@ -250,12 +241,12 @@ subroutine printNum(self, val) mul = 1 do i = 1, size(self % shapeBuffer) mul = mul * self % shapeBuffer(i) - if (modulo(self % count, mul) == 0) call self % output % append("]") + if (modulo(self % count, mul) == 0) call self % append("]") end do end if ! Finish entry with a comma - call self % output % append(",") + call self % append(",") end subroutine printNum @@ -274,12 +265,12 @@ subroutine printChar(self, val) mul = 1 do i = 1, size(self % shapeBuffer) mul = mul * self % shapeBuffer(i) - if (modulo(self % count, mul) == 0) call self % output % append("[") + if (modulo(self % count, mul) == 0) call self % append("[") end do end if ! Print the character - call self % output % append(QUOTE // val // QUOTE) + call self % append(QUOTE // val // QUOTE) if (self % in_array) then ! Append the count @@ -289,12 +280,12 @@ subroutine printChar(self, val) mul = 1 do i = 1, size(self % shapeBuffer) mul = mul * self % shapeBuffer(i) - if (modulo(self % count, mul) == 0) call self % output % append("]") + if (modulo(self % count, mul) == 0) call self % append("]") end do end if ! Finish entry with a comma - call self % output % append(",") + call self % append(",") end subroutine printChar diff --git a/UserInterface/fileOutput/asciiMATLAB_class.f90 b/UserInterface/fileOutput/asciiMATLAB_class.f90 index eeb232789..670a740ee 100644 --- a/UserInterface/fileOutput/asciiMATLAB_class.f90 +++ b/UserInterface/fileOutput/asciiMATLAB_class.f90 @@ -23,8 +23,8 @@ module asciiMATLAB_class !! !! Printer for ASCII MATLAB output file !! - !! Creates a computer-readable matalab ".m" file. - !! Despite beeing in ASCII it is not intended for human-readability: + !! Creates a computer-readable matlab ".m" file. + !! Despite being in ASCII it is not intended for human-readability: !! -> Each entry is a single line. !! -> Furthermore every array is printed as RANK 1 array and a reshape function. !! @@ -40,7 +40,7 @@ module asciiMATLAB_class !! blockLevel -> Current block level !! output -> Character that contain the output !! prefix -> Current prefix for the block - !! shapeBuffer -> Buffored shape of the current array + !! shapeBuffer -> Buffered shape of the current array !! !! Interface: !! asciiOutput Interface @@ -52,17 +52,14 @@ module asciiMATLAB_class type(stackChar) :: blockNameStack integer(shortInt) :: blockLevel = 0 - ! Outputfile - type(charTape) :: output - ! Buffers type(charTape) :: prefix integer(shortInt), dimension(:), allocatable :: shapeBuffer contains procedure :: init + procedure :: endFile procedure :: extension - procedure :: writeToFile procedure :: startBlock procedure :: endBlock @@ -90,33 +87,29 @@ subroutine init(self) end subroutine init !! - !! Return approperiate extension for the file + !! Finalise the printer !! !! See asciiOutput_inter for details !! - pure function extension(self) result(str) - class(asciiMATLAB), intent(in) :: self - character(:), allocatable :: str + subroutine endFile(self) + class(asciiMATLAB), intent(inout) :: self - str = 'm' + ! Nothing to do - end function extension + end subroutine endFile !! - !! Print the output to the given unit + !! Return approperiate extension for the file !! !! See asciiOutput_inter for details !! - subroutine writeToFile(self, unit) - class(asciiMATLAB), intent(inout) :: self - integer(shortInt), intent(in) :: unit - character(:),allocatable :: form - - form = '(A' // numToChar(self % output % length()) // ')' + pure function extension(self) result(str) + class(asciiMATLAB), intent(in) :: self + character(:), allocatable :: str - write(unit,form) self % output % expose() + str = 'm' - end subroutine writeToFile + end function extension !! !! Change state to writing new block with "name" @@ -128,11 +121,6 @@ subroutine startBlock(self, name) character(nameLen), intent(in) :: name character(100), parameter :: Here ='startBlock (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state == IN_ENTRY .or. self % state == IN_ARRAY) then - ! call fatalError(Here,'Cannot start writing new block inside entry or array') - ! end if - ! Update state - change current prefix call self % blockNameStack % push(name) call self % prefix % append(trim(name) // '_') @@ -151,15 +139,6 @@ subroutine endBlock(self) integer(shortInt) :: N character(100), parameter :: Here ='endBlock (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state == IN_ENTRY .or. self % state == IN_ARRAY) then - ! call fatalError(Here,'Cannot end writing new block inside entry or array') - ! end if - ! - ! if ( self % blockLevel == 0) then - ! call fatalError(Here,'Cannot exit from root block') - ! end if - ! Update state - change current prefix call self % blockNameStack % pop(temp) @@ -180,17 +159,12 @@ subroutine startEntry(self, name) character(*), intent(in) :: name character(100), parameter :: Here ='startEntry (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state == IN_ENTRY .or. self % state == IN_ARRAY) then - ! call fatalError(Here,'Cannot star writing new entry inside entry or array') - ! end if - ! Update state self % state = IN_ENTRY ! Write variable name with prefix - call self % output % append( trim(self % prefix % expose()) // trim(name)) - call self % output % append( ' = ') + call self % append( trim(self % prefix % expose()) // trim(name)) + call self % append( ' = ') end subroutine startEntry @@ -204,16 +178,11 @@ subroutine endEntry(self) class(asciiMATLAB), intent(inout) :: self character(100), parameter :: Here ='endEntry (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state == IN_BLOCK .or. self % state == IN_ARRAY) then - ! call fatalError(Here,'Cannot finish entry in block or array') - ! end if - ! Update state self % state = IN_BLOCK ! Write semicolon and newline - call self % output % append( ';' // NEWLINE) + call self % append( ';' // NEWLINE) end subroutine endEntry @@ -227,11 +196,6 @@ subroutine startArray(self, shape) integer(shortInt),dimension(:),intent(in) :: shape character(100), parameter :: Here ='startArray (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state /= IN_ENTRY) then - ! call fatalError(Here,'Cannot finish entry in block or array') - ! end if - ! Update state self % state = IN_ARRAY @@ -240,10 +204,10 @@ subroutine startArray(self, shape) ! Write start of array if( size(self % shapeBuffer) == 1) then - call self % output % append('[ ') + call self % append('[ ') else - call self % output % append('reshape([ ') + call self % append('reshape([ ') end if @@ -259,24 +223,19 @@ subroutine endArray(self) integer(shortInt) :: i character(100), parameter :: Here ='endArray (asciiMATLAB_class.f90)' - ! Check if state support acction - ! if (self % state /= IN_ARRAY) then - ! call fatalError(Here,'Cannot finish array inside an entry') - ! end if - ! Update state self % state = IN_ENTRY ! Write end of array - call self % output % cut(1) - call self % output % append(']') + call self % cut(1) + call self % append(']') ! Finish reshape function for higher rank arrays if( size(self % shapeBuffer) > 1) then do i=1,size(self % shapeBuffer) - call self % output % append(',' // numToChar(self % shapeBuffer(i))) + call self % append(',' // numToChar(self % shapeBuffer(i))) end do - call self % output % append(')') + call self % append(')') end if end subroutine endArray @@ -292,13 +251,11 @@ subroutine printNum(self, val) character(100), parameter :: Here ='printNum (asciiMATLAB_class.f90)' if(self % state == IN_ARRAY) then - call self % output % append(val//',') + call self % append(val//',') else if( self % state == IN_ENTRY) then - call self % output % append(val) + call self % append(val) - ! else - ! call fatalError(Here,'Cannot print number directly into block') end if end subroutine printNum @@ -314,13 +271,11 @@ subroutine printChar(self, val) character(100), parameter :: Here ='printChar (asciiMATLAB_class.f90)' if(self % state == IN_ARRAY) then - call self % output % append(BRAKET_L // APOS // val // APOS // BRAKET_R // ",") + call self % append(BRAKET_L // APOS // val // APOS // BRAKET_R // ",") else if( self % state == IN_ENTRY) then - call self % output % append(BRAKET_L // APOS // val // APOS // BRAKET_R ) + call self % append(BRAKET_L // APOS // val // APOS // BRAKET_R ) - ! else - ! call fatalError(Here,'Cannot print number directly into block') end if end subroutine printChar diff --git a/UserInterface/fileOutput/asciiOutput_inter.f90 b/UserInterface/fileOutput/asciiOutput_inter.f90 index 0b491d921..e60a7b8b2 100644 --- a/UserInterface/fileOutput/asciiOutput_inter.f90 +++ b/UserInterface/fileOutput/asciiOutput_inter.f90 @@ -1,6 +1,7 @@ module asciiOutput_inter use numPrecision + use delayedStream_class, only : delayedStream implicit none private @@ -10,7 +11,7 @@ module asciiOutput_inter !! !! Allows stream-like output to multiple formats (e.g. MATLAB, CSV, JSON) !! - !! They recive the sequence of calls from the `outputFile` and conver them to the output file. + !! They receive the sequence of calls from the `outputFile` and convert them to the output file. !! !! Printers do no error checking. It is responsibility of the `outputFile` to ensure that !! the sequence is correct. @@ -21,7 +22,7 @@ module asciiOutput_inter !! !! Interface: !! init -> Initialise - !! extension -> Return file extension approperiate for the format + !! extension -> Return file extension appropriate for the format !! writeToFile -> Print the output to the provided unit !! startBlock -> Start new block !! endBlock -> End a block @@ -32,10 +33,16 @@ module asciiOutput_inter !! type, public,abstract :: asciiOutput private + type(delayedStream) :: stream contains + procedure :: append + procedure :: cut + procedure :: peek + procedure :: close + procedure :: setUnit procedure(init), deferred :: init + procedure(init), deferred :: endFile procedure(extension), deferred :: extension - procedure(writeToFile),deferred :: writeToFile procedure(startBlock),deferred :: startBlock procedure(endBlock),deferred :: endBlock procedure(startEntry),deferred :: startEntry @@ -61,7 +68,21 @@ subroutine init(self) end subroutine init !! - !! Return approperiate extension for the file + !! End the file + !! + !! Format may require to print some characters at the end, so the printer + !! needs to be notified that no more data will be provided. + !! + !! Args: + !! None + !! + subroutine endFile(self) + import :: asciiOutput + class(asciiOutput), intent(inout) :: self + end subroutine endFile + + !! + !! Return appropriate extension for the file !! !! Must be without any "." Thus "exe" instead of ".exe"! !! @@ -74,19 +95,6 @@ pure function extension(self) result(str) character(:), allocatable :: str end function extension - !! - !! Print the output to the given unit - !! - !! Args: - !! unit [in] -> Unit number of the output - !! - subroutine writeToFile(self, unit) - import :: asciiOutput, & - shortInt - class(asciiOutput), intent(inout) :: self - integer(shortInt), intent(in) :: unit - end subroutine writeToFile - !! !! Change state to writing new block with "name" !! @@ -111,7 +119,7 @@ end subroutine endBlock !! !! Change state to writing a new entry !! - !! Can recive single value or array next + !! Can receive single value or array next !! !! Args: !! name [in] -> name of the entry @@ -134,7 +142,7 @@ end subroutine endEntry !! !! Start writing array with the given shape !! - !! Name should alrady be provided by "startEntry" + !! Name should already be provided by "startEntry" !! !! Args: !! shape [in] -> Shape of the array (in column-major order) @@ -183,4 +191,77 @@ subroutine printChar(self, val) end subroutine printChar end interface +contains + + + !! + !! Write data to the output + !! + !! Args: + !! text [in] -> Text to be written + !! + subroutine append(self, text) + class(asciiOutput), intent(inout) :: self + character(*), intent(in) :: text + + call self % stream % write(text) + + end subroutine append + + !! + !! Remove n characters from the output + !! + !! Args: + !! n [in] -> Number of characters to be removed + !! + subroutine cut(self, n) + class(asciiOutput), intent(inout) :: self + integer, intent(in) :: n + + call self % stream % cut(n) + + end subroutine cut + + !! + !! Get the nth last character from the output + !! + !! Args: + !! n [in] -> How many characters back to peak + !! + function peek(self, n) result(c) + class(asciiOutput), intent(inout) :: self + integer, intent(in) :: n + character(1) :: c + + c = self % stream % peek(n) + + end function peek + + !! + !! Close the stream + !! + !! Signals to the output that no more data will be provided, so the + !! closing characters can be printed. In addition flushes remaining characters + !! in the buffer to the output. + !! + subroutine close(self) + class(asciiOutput), intent(inout) :: self + + call self % endFile() + call self % stream % close() + + end subroutine close + + !! + !! Set the unit to write to + !! + subroutine setUnit(self, unit) + class(asciiOutput), intent(inout) :: self + integer(shortInt), intent(in) :: unit + + call self % stream % setUnit(unit) + + end subroutine setUnit + + end module asciiOutput_inter diff --git a/UserInterface/fileOutput/delayedStream_class.f90 b/UserInterface/fileOutput/delayedStream_class.f90 new file mode 100644 index 000000000..86869fec0 --- /dev/null +++ b/UserInterface/fileOutput/delayedStream_class.f90 @@ -0,0 +1,185 @@ +module delayedStream_class + + use numPrecision + use errors_mod, only : fatalError + + implicit none + private + + integer(shortInt), parameter :: MAX_DELAY = 1024 + integer(shortInt), parameter :: MIN_DELAY = 16 + + !! + !! Writes characters to a file with a delay to allow for backtracking. + !! + !! It is required to make writing of output format in stream-like fashion + !! easier to implement. For example, in JSON, it allows to backtrack and + !! remove trailing comma when closing a JSON dictionary. + !! + !! NOTE: We need to be careful to check if the file is open before writing + !! to it. Otherwise, we will get an error. + !! + !! Private Member: + !! unit -> Unit to which the output file is connected + !! bufferPos -> Position in the buffer + !! buffer -> Buffer of characters + !! + !! Interface: + !! write -> Write some characters to the buffer/file + !! cut -> Remove last N characters from the buffer + !! peek -> Inspect the Nth last character in the buffer + !! close -> Write all characters remaining in the buffer to the file + !! setUnit -> Set the unit to which the output file is connected + !! + type, public :: delayedStream + private + integer(shortInt) :: unit = -8 + integer(shortInt) :: bufferPos = 0 + character(MAX_DELAY) :: buffer + contains + procedure :: write + procedure :: cut + procedure :: peek + procedure :: close + procedure :: setUnit + + procedure, private :: flush + end type delayedStream + +contains + + !! + !! Write to a delayed stream + !! + !! Args: + !! text [in] -> text to write + !! + subroutine write(self, text) + class(delayedStream), intent(inout) :: self + character(*), intent(in) :: text + integer(shortInt) :: i + + ! Write to buffer + do i = 1, len(text) + self % bufferPos = self % bufferPos + 1 + self % buffer(self % bufferPos:self % bufferPos) = text(i:i) + if (self % bufferPos == MAX_DELAY) then + call flush(self) + end if + end do + + end subroutine write + + !! + !! Remove last characters from a delayed stream + !! + !! Args: + !! n [in] -> number of characters to remove. Must be less than the MIN_DELAY. + !! If n is larger than the number of characters in buffer, everything is removed. + !! + subroutine cut(self, n) + class(delayedStream), intent(inout) :: self + integer(shortInt), intent(in) :: n + character(100), parameter :: HERE = "cut (delayedStream_class.f90)" + + if (n > MIN_DELAY) then + call fatalError(HERE, "n must be less than MIN_DELAY") + end if + + self % bufferPos = max(0, self % bufferPos - n) + + end subroutine cut + + !! + !! Inspect the nth last character in the buffer + !! + !! Args: + !! n [in] -> The number of characters to peek back. + !! + function peek(self, n) result(c) + class(delayedStream), intent(inout) :: self + integer(shortInt), intent(in) :: n + character(n) :: c + character(100), parameter :: HERE = "peek (delayedStream_class.f90)" + + if (n > self % bufferPos) then + call fatalError(HERE, "n is larger than the buffer") + else + c = self % buffer(self % bufferPos - n + 1: self % bufferPos - n + 1) + end if + + end function peek + + !! + !! Flush contents of the buffer + !! + subroutine flush(self) + class(delayedStream), intent(inout) :: self + integer(shortInt) :: to_file + logical(defBool) :: isOpen + + ! Do not write anything if the file is not opened + inquire(unit=self % unit, opened=isOpen) + if (.not. isOpen) then + return + end if + + ! Do nothing if the buffer is below minimum length + if (self % bufferPos <= MIN_DELAY) then + return + end if + to_file = self % bufferPos - MIN_DELAY + + ! Write to file only if it is open + if (isOpen) then + write(self % unit, "(A)", advance="no") self % buffer(1 : to_file) + end if + + self % buffer(1:MIN_DELAY) = self % buffer(to_file + 1 : self % bufferPos) + + self % bufferPos = MIN_DELAY + + end subroutine flush + + !! + !! Close the delayed stream + !! + subroutine close(self) + class(delayedStream), intent(inout) :: self + logical(defBool) :: isOpen + + ! Do not write anything if the file is not opened + inquire(unit=self % unit, opened=isOpen) + if (.not. isOpen) then + return + end if + + ! Does nothing if empty + if (self % bufferPos == 0) then + return + end if + + ! Write the remaining buffer + ! Write to file only if it is open + if (isOpen) then + write(self % unit, "(A)", advance="no") self % buffer(1:self % bufferPos) + end if + self % bufferPos = 0 + + end subroutine close + + !! + !! Set the unit to which the output file is connected + !! + !! Args: + !! unit [in] -> Unit to which the output file is connected. May be opened or not. + !! Both are fine. If it is not opened, nothing will be written to it. + subroutine setUnit(self, unit) + class(delayedStream), intent(inout) :: self + integer(shortInt), intent(in) :: unit + + self % unit = unit + + end subroutine setUnit + +end module delayedStream_class diff --git a/UserInterface/fileOutput/dummyPrinter_class.f90 b/UserInterface/fileOutput/dummyPrinter_class.f90 index 17b14114e..de2f84442 100644 --- a/UserInterface/fileOutput/dummyPrinter_class.f90 +++ b/UserInterface/fileOutput/dummyPrinter_class.f90 @@ -23,6 +23,7 @@ module dummyPrinter_class contains procedure :: init + procedure :: endFile procedure :: extension procedure :: startBlock @@ -50,6 +51,18 @@ subroutine init(self) end subroutine init + !! + !! End the file + !! + !! See asciiOutput_inter for details + !! + subroutine endFile(self) + class(dummyPrinter), intent(inout) :: self + + ! Nothing to do + + end subroutine endFile + !! !! Return approperiate extension for the file !! diff --git a/UserInterface/fileOutput/outputFile_class.f90 b/UserInterface/fileOutput/outputFile_class.f90 index 6612ebf4b..48fb2011d 100644 --- a/UserInterface/fileOutput/outputFile_class.f90 +++ b/UserInterface/fileOutput/outputFile_class.f90 @@ -1,7 +1,8 @@ module outputFile_class use numPrecision - use genericProcedures, only : fatalError, numToChar + use errors_mod, only : fatalError + use genericProcedures, only : numToChar use stack_class, only : stackChar use charTape_class, only : charTape use charMap_class, only : charMap @@ -28,10 +29,10 @@ module outputFile_class !! !! Stack to store the dictionaries with occupied entries !! - !! Note that blocks in outputFile are enumarated from 0 + !! Note that blocks in outputFile are enumerated from 0 !! So index in stack is idx = blockLevel + 1 !! - !! Imlementation must be rebust to avoid segmentation errors if outut is used + !! Implementation must be robust to avoid segmentation errors if output is used !! in incorrect sequence (e.g. closing more blocks then were open) !! !! Interface @@ -126,6 +127,7 @@ module outputFile_class class(asciiOutput), allocatable :: output character(nameLen) :: type character(:), allocatable :: outputFileName + integer(shortInt) :: outputUnit = -97875674 ! Hopefully this does not exist for any internal units ! Error handling settings logical(defBool) :: fatalErrors = .true. ! Enable fatalErrors on wrong logic @@ -141,7 +143,7 @@ module outputFile_class character(nameLen) :: current_array_name = '' type(stackChar) :: block_name_stack - ! Buffors + ! Buffers integer(shortInt),dimension(:), allocatable :: shapeBuffer type(charMapStack) :: usedNames @@ -151,10 +153,8 @@ module outputFile_class contains procedure :: init - procedure, private :: writeToConsole procedure :: reset final :: finalisation - procedure, private :: writeToFile ! Error Handling procedure, private :: logError @@ -222,17 +222,45 @@ subroutine init(self, type, fatalErrors, filename) character(*), intent(in) :: type logical(defBool), optional,intent(in) :: fatalErrors character(*), optional, intent(in) :: filename + integer(shortInt) :: error + character(99) :: errorMsg + logical(defBool) :: isOpen + character(100), parameter :: Here = "init (outputFile_class.f90)" self % type = type allocate( self % output, source = new_asciiOutput(self % type)) - ! Set output file name + ! Open file if given + ! Otherwise make sure that the unit is not opened if (present(filename)) then ! Because GFotran hates implicit allocation ! It causes buggy warnings to appear in compilation - allocate(self % outputFileName, source = filename) + allocate(self % outputFileName, source = trim(filename) // "." // self % output % extension()) + + open(newunit = self % outputUnit, & + file = self % outputFileName, & + status = "replace", & + action = "write", & + access = "stream", & + form = "formatted",& + iostat = error, & + iomsg = errorMsg) + + ! Catch error + if (error /= 0 ) call fatalError(Here, errorMsg) + else + ! Set unit to some unused, unopened unit + ! delayedStream will not write anything if given an unopened file + do + inquire(self % outputUnit, opened = isOpen) + if (.not. isOpen) exit + self % outputUnit = self % outputUnit + 1 + end do end if + ! Set output unit + call self % output % setUnit(self % outputUnit) + ! Initialise name stack call self % usedNames % init() call self % usedNames % push() @@ -244,73 +272,34 @@ subroutine init(self, type, fatalErrors, filename) end subroutine init - !! - !! Dump collected results to file - !! - !! Writes the output stored in memory to a file - !! - !! Args: - !! file [in] -> Path to the output file. Must be given WITHOUT extension - !! Appropriate extension will be received from the printer - !! - !! Errors: - !! fatalError if there is a problem opening the file. - !! - subroutine writeToFile(self, file) - class(outPutFile), intent(inout) :: self - character(*), intent(in) :: file - integer(shortInt) :: unitNum - integer(shortInt) :: error - character(:), allocatable :: file_loc - character(99) :: errorMsg - character(100), parameter :: Here = 'writeToFile (outputFile_class.f90)' - - file_loc = trim(file) // "." // self % output % extension() - - ! Open file to write - open ( newunit = unitNum, & - file = file_loc, & - action = 'write', & - iostat = error , & - iomsg = errorMsg ) - - ! Catch error - if (error /= 0 ) call fatalError(Here, errorMsg) - - ! Write to file - call self % output % writeToFile(unitNum) - - ! Close file - close(unitNum) - - end subroutine writeToFile - - !! - !! Print output file to the console (default output) - !! - !! Args: - !! None - !! - subroutine writeToConsole(self) - class(outputFile), intent(inout) :: self - - call self % output % writeToFile(OUTPUT_UNIT) - - end subroutine writeToConsole - !! !! Upon the destruction of the object, write the output to file !! !! NOTE: - !! This subroutine WILL NOT be called if the `end program` statement is - !! reached! [Only `end subroutine`, `end block` etc.]. In that case - !! one needs to call `finalisation` manually + !! Being marked `final`(a deconstructor) this subroutine will be normally implicitly called by + !! by the compiler whenever a variable of `type(outputFile)` goes out of scope (e.g. when program + !! execution reaches `end subroutine`, `end function` or `end block` statement. However, the rule in + !! Fortran is that the decostructors are NOT called at the end of the program `end program`. In that case + !! if one uses the output file as a module variable or defines it inside the program block, the `finalisation` + !! must be called explicitly to ensure or data from the buffer is written to the disk + !! !! subroutine finalisation(self) type(outputFile), intent(inout) :: self + logical(defBool) :: isOpen + + !! Deallocate the printer + !! Needs to be done before closing the file + !! So remaining contents of the buffer are flushed + if (allocated(self % output)) then + call self % output % close() + deallocate(self % output) + end if + + inquire(unit = self % outputUnit, opened = isOpen) - if (allocated(self % outputFileName)) then - call self % writeToFile(self % outputFileName) + if (isOpen) then + close(self % outputUnit) end if end subroutine finalisation diff --git a/docs/Output.rst b/docs/Output.rst index 7349deb8d..2e999b083 100644 --- a/docs/Output.rst +++ b/docs/Output.rst @@ -38,8 +38,9 @@ Writing to an output file in SCONE is done through a series of calls to appropri character(nameLen) :: name type(outputFile) :: out - !! Initialise output by choosing the format - call out % init('asciiMatlab') + !! Initialise output by choosing the format and output file + !! If no file name is provided, the output will not be printed + call out % init('asciiMatlab', filename="./path/to/output/without_any_extension") !! Write an integer of 7 name = 'int' @@ -76,9 +77,10 @@ Writing to an output file in SCONE is done through a series of calls to appropri !! Same goes for blocks call out % endBlock() - !! When done, we can write output to a file - !! Extension will be determined by the format printer - call out % writeToFile("./path/to/output/without_any_extension") + !! We need to make sure that output file is properly finalised. We can skip + !! this line if we we are not in a `program` block e.g. in `subroutine` or `function` + call out % finalise() + The need to write name to a `character(nameLen)` variable before calling the procedure is a quirk caused by the fact that the output file expects character of `nameLen` as a variable. If one were to From 128f3efa5c4f4928cad9e900884c4b62cf828397 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> Date: Fri, 26 Jan 2024 11:21:03 +0100 Subject: [PATCH 091/133] Apply suggestions from code review Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- UserInterface/fileOutput/asciiJSON_class.f90 | 2 +- UserInterface/fileOutput/asciiMATLAB_class.f90 | 2 +- docs/Output.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UserInterface/fileOutput/asciiJSON_class.f90 b/UserInterface/fileOutput/asciiJSON_class.f90 index f1e0ee859..4fd6fa66c 100644 --- a/UserInterface/fileOutput/asciiJSON_class.f90 +++ b/UserInterface/fileOutput/asciiJSON_class.f90 @@ -96,7 +96,7 @@ subroutine endFile(self) end subroutine endFile !! - !! Return approperiate extension for the file + !! Return appropriate extension for the file !! !! See asciiOutput_inter for details !! diff --git a/UserInterface/fileOutput/asciiMATLAB_class.f90 b/UserInterface/fileOutput/asciiMATLAB_class.f90 index 670a740ee..b844dc710 100644 --- a/UserInterface/fileOutput/asciiMATLAB_class.f90 +++ b/UserInterface/fileOutput/asciiMATLAB_class.f90 @@ -99,7 +99,7 @@ subroutine endFile(self) end subroutine endFile !! - !! Return approperiate extension for the file + !! Return appropriate extension for the file !! !! See asciiOutput_inter for details !! diff --git a/docs/Output.rst b/docs/Output.rst index 2e999b083..9d3108e3b 100644 --- a/docs/Output.rst +++ b/docs/Output.rst @@ -78,7 +78,7 @@ Writing to an output file in SCONE is done through a series of calls to appropri call out % endBlock() !! We need to make sure that output file is properly finalised. We can skip - !! this line if we we are not in a `program` block e.g. in `subroutine` or `function` + !! this line if we are not in a `program` block e.g. in `subroutine` or `function` call out % finalise() From 0dc9791cd00deff48b2a7cb9c09b1ec5ad242ad1 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:51:12 +0000 Subject: [PATCH 092/133] Add nthCollTally to User Manual.rst --- docs/User Manual.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ef2841d4d..d95e63983 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1232,6 +1232,14 @@ Example: :: map1 { type cylindricalMap; orientation y; origin (7.0 0.0); rGrid lin; Rmax 5.0; rN 10; } map2 { type cylindricalMap; rGrid unstruct; bins (2.0 3.0 4.5 5.0); axGrid lin; axMin 0.0; axMax 6.0 axN 24; azimuthalN 8; } +* collNumMap (1D map), filters the particles tallied over number of collisions they underwent + + - collNumbers: list of collision numbers (integers) to be used as map bins + +Examples: :: + + map1 { type collNumMap; collNumbers ( 0 1 2 3 4 5 10 20); } + * weightMap (1D map), divides weight into number of discrete bins - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins From cb9a623144c24ce21f6de8448fe365e2df7bbcfc Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:52:52 +0000 Subject: [PATCH 093/133] Remove unused procedures in aceNeutronDatabase --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 37139a2f7..3fc8a3104 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -4,8 +4,7 @@ module aceNeutronDatabase_class use endfConstants use universalVariables use errors_mod, only : fatalError - use genericProcedures, only : numToChar, concatenate, quickSort, & - removeDuplicatesSorted, binarySearch + use genericProcedures, only : numToChar, removeDuplicatesSorted, binarySearch use dictionary_class, only : dictionary use RNG_class, only : RNG use charMap_class, only : charMap From fdc8824997fda772fc04893df119a37e4595b96c Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 31 Jan 2024 23:15:16 +0000 Subject: [PATCH 094/133] Fix bug --- ParticleObjects/particle_class.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 05ada7ba6..2055d1454 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -274,6 +274,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % type = RHS % type LHS % time = RHS % time LHS % collisionN = RHS % collisionN + LHS % splitCount = 0 end subroutine particle_fromParticleState From 0072e914780f8cc57f0136a4003571759308faf7 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 31 Jan 2024 23:25:46 +0000 Subject: [PATCH 095/133] Typos and small fixes to DT majorant --- .../aceDatabase/aceNeutronDatabase_class.f90 | 22 +++++++++---------- NuclearData/nuclearDatabase_inter.f90 | 6 ++--- .../transportOperatorHT_class.f90 | 2 +- docs/User Manual.rst | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 37139a2f7..21ac73d11 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -63,16 +63,16 @@ module aceNeutronDatabase_class !! majorant < 1 or 0 >; aceLibrary ;} } !! !! Public Members: - !! nuclides -> array of aceNeutronNuclides with data - !! materials -> array of ceNeutronMaterials with data - !! Ebounds -> array with bottom (1) and top (2) energy bound - !! majorant -> unionised majorant cross section - !! eGridUnion -> unionised energy grid - !! activeMat -> array of materials present in the geometry - !! nucToZaid -> map to link nuclide index to zaid index - !! hasUrr -> ures probability tables flag, it's false by default - !! hasDBRC -> DBRC flag, it's false by default - !! has majorant -> unionised majorant cross section flag + !! nuclides -> array of aceNeutronNuclides with data + !! materials -> array of ceNeutronMaterials with data + !! Ebounds -> array with bottom (1) and top (2) energy bound + !! majorant -> unionised majorant cross section + !! eGridUnion -> unionised energy grid + !! activeMat -> array of materials present in the geometry + !! nucToZaid -> map to link nuclide index to zaid index + !! hasUrr -> ures probability tables flag, it's false by default + !! hasDBRC -> DBRC flag, it's false by default + !! hasMajorant -> unionised majorant cross section flag !! !! Interface: !! nuclearData Interface @@ -694,7 +694,7 @@ subroutine init(self, dict, ptr, silent ) end do ! Read unionised majorant flag - call dict % getOrDefault(self % hasMajorant, 'majorant', .false.) + call dict % getOrDefault(self % hasMajorant, 'majorant', .true.) ! If on, initialise probability tables for ures if (self % hasUrr) then diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index ff31af26f..e3a8eeff2 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -171,7 +171,7 @@ end function matNamesMap !! !! Return pointer to material in a database !! - !! Allows to retrive an access to material data for all databases types + !! Allows to retrieve an access to material data for all databases types !! !! NOTE: This function can be used to inquire about the presence of matIdx in the database! !! @@ -194,7 +194,7 @@ end function getMaterial !! !! Return pointer to nuclide in a database !! - !! Allows to retrive an access to nuclide data for all databases types + !! Allows to retrieve an access to nuclide data for all databases types !! If database does not contain nuclides (e.g. MG data) just returns null() pointer !! !! NOTE: This function can be used to inquire about the presence of nucIdx in the database! @@ -218,7 +218,7 @@ end function getNuclide !! !! Return a pointer to a reaction !! - !! Allows to retrive an access to reaction data for all databases types + !! Allows to retrieve an access to reaction data for all databases types !! Reactions can be associated either with nuclides or materials. Thus, there is ambiguity !! whether material or nuclide should be asked to provide reaction data (using matIdx or nuIdx) !! diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index 3ea03b9ae..95ffaef94 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -91,7 +91,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) DTLoop:do distance = -log( p % pRNG % get() ) * majorant_inv - ! Move partice in the geometry + ! Move particle in the geometry call self % geom % teleport(p % coords, distance) ! If particle has leaked exit diff --git a/docs/User Manual.rst b/docs/User Manual.rst index bbc12f9f4..65da84db2 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -725,7 +725,7 @@ from ACE files. resonance probability tables treatment * DBRC (*optional*, default = no DBRC): list of ZAIDs of nuclides for which DBRC has to be applied. -* majorant (*optional*, default = 0): 1 for true; 0 for false; flag to activate the +* majorant (*optional*, default = 1): 1 for true; 0 for false; flag to activate the pre-construction of a unionised majorant cross section Example: :: From 04a37746f800d6cb2011526febefc0b56aa0d1b0 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Mon, 5 Feb 2024 17:17:57 +0000 Subject: [PATCH 096/133] Add routines to calculate majorant also with ures on --- .../Tests/aceNeutronDatabase_iTest.f90 | 9 + .../Tests/thermalScatteringData_iTest.f90 | 2 +- .../Tests/urrProbabilityTables_iTest.f90 | 2 +- .../aceDatabase/aceNeutronDatabase_class.f90 | 188 ++++++++++++++---- .../aceDatabase/aceNeutronNuclide_class.f90 | 35 ++-- .../urrProbabilityTables_class.f90 | 56 +++++- NuclearData/nuclearDatabase_inter.f90 | 1 + .../testNeutronDatabase_class.f90 | 1 - 8 files changed, 234 insertions(+), 60 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 index 697cfcf9b..69a08e08d 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 @@ -223,6 +223,15 @@ subroutine test_aceNeutronDatabase() p % E = 19.9_defReal @assertEqual(ONE, data % getMajorantXS(p)/0.21869599644_defReal , TOL) + ! Check that results are the same with on-the-fly majorant + data % hasMajorant = .false. + + p % E = 1.1E-6_defReal + @assertEqual(ONE, data % getMajorantXS(p) /4.4149556129495560_defReal , TOL) + + p % E = 19.9_defReal + @assertEqual(ONE, data % getMajorantXS(p)/0.21869599644_defReal , TOL) + !<><><><><><><><><><><><><><><><><><><><> ! Test getting Macroscopic XSs ! diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 index 447a5ed8d..61c75c77a 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 @@ -66,7 +66,7 @@ subroutine test_thermalScatteringData() ! Initialise data ptr => data call data % init(dataDict, ptr, silent = .true.) - call data % activate(([1,2])) + call data % activate(([1,2]), silent = .true.) !!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! Perform tests diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 index 149c6fa2d..6afb16e30 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 @@ -57,7 +57,7 @@ subroutine test_urrProbabilityTables() ! Initialise data ptr => data call data % init(dataDict, ptr, silent = .true.) - call data % activate([1]) + call data % activate([1], silent = .true.) !!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! Perform tests diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 78280d7d0..a60c49b0a 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -52,9 +52,6 @@ module aceNeutronDatabase_class !! It's possible to use probability tables in the unresolved resonance range if !! ures is included in the input file !! - !! NOTE: the unionised majorant is not calculated and used if probability tables - !! are on - !! !! Sample input: !! nuclearData { !! handles { @@ -112,8 +109,8 @@ module aceNeutronDatabase_class procedure :: getScattMicroMajXS ! class Procedures - procedure :: init_urr - procedure :: init_DBRC + procedure :: initUrr + procedure :: initDBRC procedure :: initMajorant end type aceNeutronDatabase @@ -446,16 +443,18 @@ subroutine updateTotalNucXS(self, E, nucIdx, rand) ! Check if the nuclide needs ures probability tables at this energy nucCache % needsUrr = (nuc % hasProbTab .and. E >= nuc % urrE(1) .and. E <= nuc % urrE(2)) ! Check if the nuclide needs S(a,b) at this energy - nucCache % needsSabEl = (nuc % hasThData .and. E >= nuc % SabEl(1) .and. E < nuc % SabEl(2)) - nucCache % needsSabInel = (nuc % hasThData .and. E >= nuc % SabInel(1) .and. E < nuc % SabInel(2)) + nucCache % needsSabEl = (nuc % hasThData .and. E >= nuc % SabEl(1) .and. E <= nuc % SabEl(2)) + nucCache % needsSabInel = (nuc % hasThData .and. E >= nuc % SabInel(1) .and. E <= nuc % SabInel(2)) needsSab = (nucCache % needsSabEl .or. nucCache % needsSabInel) if (nucCache % needsUrr .or. needsSab) then call self % updateMicroXSs(E, nucIdx, rand) + else nucCache % E_tot = E call nuc % search(nucCache % idx, nucCache % f, E) nucCache % xss % total = nuc % totalXS(nucCache % idx, nucCache % f) + end if end associate @@ -489,17 +488,23 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) ! Check if probability tables should be read if (nucCache % needsUrr) then associate(zaidCache => cache_zaidCache(self % nucToZaid(nucIdx))) + if (zaidCache % E /= E) then ! Save random number for temperature correlation zaidCache % xi = rand % get() zaidCache % E = E end if + call nuc % getUrrXSs(nucCache % xss, nucCache % idx, nucCache % f, E, zaidCache % xi) + end associate + elseif (nucCache % needsSabEl .or. nucCache % needsSabInel) then call nuc % getThXSs(nucCache % xss, nucCache % idx, nucCache % f, E) + else call nuc % microXSs(nucCache % xss, nucCache % idx, nucCache % f) + end if end associate @@ -642,11 +647,11 @@ subroutine init(self, dict, ptr, silent ) ! Initialise S(alpha,beta) tables if (idx /= 0 ) then call new_moderACE(ACE_Sab, name_file) - call self % nuclides(nucIdx) % init_Sab(ACE_Sab) + call self % nuclides(nucIdx) % initSab(ACE_Sab) end if ! Initialise probability tables - if (self % hasUrr) call self % nuclides(nucIdx) % init_urr(ACE) + if (self % hasUrr) call self % nuclides(nucIdx) % initUrr(ACE) ! Store nucIdx in the dictionary call nucSet % atSet(nucIdx, i) @@ -697,12 +702,12 @@ subroutine init(self, dict, ptr, silent ) ! If on, initialise probability tables for ures if (self % hasUrr) then - call self % init_urr() + call self % initUrr() end if ! If on, initialise DBRC if (self % hasDBRC) then - call self % init_DBRC(nucDBRC, nucSet, self % mapDBRCnuc) + call self % initDBRC(nucDBRC, nucSet, self % mapDBRCnuc) end if !! Clean up @@ -716,7 +721,7 @@ end subroutine init !! NOTE: compares the first 5 letters of the ZAID.TT. It would be wrong with isotopes !! with Z > 99 !! - subroutine init_urr(self) + subroutine initUrr(self) class(aceNeutronDatabase), intent(inout) :: self integer(shortInt) :: i, j character(nameLen) :: zaid @@ -747,12 +752,12 @@ subroutine init_urr(self) end if end do - end subroutine init_urr + end subroutine initUrr !! !! Checks through all nuclides, creates map with nuclides present and corresponding 0K nuclide !! - subroutine init_DBRC(self, nucDBRC, nucSet, map) + subroutine initDBRC(self, nucDBRC, nucSet, map) class(aceNeutronDatabase), intent(inout) :: self character(nameLen), dimension(:), intent(in) :: nucDBRC type(charMap), intent(in) :: nucSet @@ -796,7 +801,7 @@ subroutine init_DBRC(self, nucDBRC, nucSet, map) end do - end subroutine init_DBRC + end subroutine initDBRC !! !! Activate this nuclearDatabase @@ -830,23 +835,8 @@ subroutine activate(self, activeMat, silent) loud = .true. end if - ! Check if probability tables are on - if (self % hasUrr) then - - ! Switch off majorant - self % hasMajorant = .false. - - if (loud) then - print '(A)', 'Unionised majorant cross section will not be contructed & - & due to the use of URR probability tables treatment' - end if - - else - - ! Precompute majorant cross section - call self % initMajorant(loud) - - end if + ! Precompute majorant cross section + call self % initMajorant(loud) end if @@ -861,11 +851,15 @@ subroutine initMajorant(self, loud) class(aceNeutronDatabase), intent(inout) :: self logical(defBool), intent(in) :: loud real(defReal), dimension(:), allocatable :: tmpGrid - integer(shortInt) :: i, j, matIdx, nNuc, nucIdx, isDone, & - sizeGrid, eIdx, nucIdxLast, eIdxLast + integer(shortInt) :: i, j, k, matIdx, nNuc, nucIdx, isDone, & + sizeGrid, eIdx, nucIdxLast, eIdxLast, & + urrIdx type(intMap) :: nucSet - real(defReal) :: eRef, eNuc, E, maj + real(defReal) :: eRef, eNuc, E, maj, total, dens, urrMaj, & + nucXS, f, eMax, eMin + logical(defBool) :: needsUrr integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 + real(defReal), parameter :: NUDGE = 1.0e-06_defReal ! Find the size of the unionised energy grid (with duplicates) ! Initialise size @@ -894,6 +888,11 @@ subroutine initMajorant(self, loud) ! Update energy grid size sizeGrid = sizeGrid + size(self % nuclides(nucIdx) % eGrid) + ! If URR probability tables or S(a,b) tables are used, add their energy + ! boundary values to the grid to minimise interpolation errors + if (self % nuclides(nucIdx) % hasProbTab) sizeGrid = sizeGrid + 2 + if (self % nuclides(nucIdx) % hasThData) sizeGrid = sizeGrid + 3 + end if end do @@ -904,7 +903,8 @@ subroutine initMajorant(self, loud) tmpGrid = self % EBounds(2) ! Loop over the energy grid - do i = 1, sizeGrid + i = 1 + do while (i < sizeGrid) ! Loop over all nuclides in the set - here the value of the intMap is used as an energy index j = nucSet % begin() @@ -944,6 +944,76 @@ subroutine initMajorant(self, loud) ! Increment the energy index saved in the intMap for the nuclides whose energy was added call nucSet % add(nucIdxLast, eIdxLast + 1) + ! Loop over all nuclides again to add S(a,b) and ures energy boundaries to grid + j = nucSet % begin() + do while (j /= nucSet % end()) + + ! Retrieve energy in the grid and nuclide information + eMin = tmpGrid(i - 1) + eMax = tmpGrid(i) + nucIdx = nucSet % atKey(j) + + ! Check for URR probability tables + if (self % nuclides(nucIdx) % hasProbTab) then + + ! Lower energy boundary + E = self % nuclides(nucIdx) % urrE(1) + if (E >= eMin .and. E < eMax) then + tmpGrid(i) = E + tmpGrid(i + 1) = eMax + ! Update counter + i = i + 1 + end if + + ! Upper energy boundary + E = self % nuclides(nucIdx) % urrE(2) + if (E >= eMin .and. E < eMax) then + tmpGrid(i) = E + tmpGrid(i + 1) = eMax + ! Update counter + i = i + 1 + end if + + end if + + ! Check for Sab tables + if (self % nuclides(nucIdx) % hasThData) then + + ! Elastic upper energy boundary (NOTE: lower boundary is fixed) + E = self % nuclides(nucIdx) % SabEl(2) + if (E >= eMin .and. E < eMax ) then + tmpGrid(i) = E + tmpGrid(i + 1) = eMax + ! Update counter + i = i + 1 + end if + + ! Inelastic lower energy boundary + E = self % nuclides(nucIdx) % SabInel(1) + if (E >= eMin .and. E < eMax ) then + tmpGrid(i) = E + tmpGrid(i + 1) = eMax + ! Update counter + i = i + 1 + end if + + ! Inelastic upper energy boundary + E = self % nuclides(nucIdx) % SabInel(2) + if (E >= eMin .and. E < eMax ) then + tmpGrid(i) = E + tmpGrid(i + 1) = eMax + ! Update counter + i = i + 1 + end if + + end if + + j = nucSet % next(j) + + end do + + i = i + 1 + end do ! Save final grid and remove duplicates @@ -974,15 +1044,51 @@ subroutine initMajorant(self, loud) ! Get material index matIdx = self % activeMat(j) + total = ZERO + + ! Loop over nuclides + do k = 1, size(self % materials(matIdx) % nuclides) + dens = self % materials(matIdx) % dens(k) + nucIdx = self % materials(matIdx) % nuclides(k) + + associate (nuc => self % nuclides(nucIdx)) + + needsUrr = (nuc % hasProbTab .and. E >= nuc % urrE(1) .and. E <= nuc % urrE(2)) + + ! Check if present nuclide uses URR tabes + if (needsUrr) then + + ! Find maximum URR table total XS + urrIdx = binarySearch(nuc % probTab % eGrid, E) + urrMaj = nuc % probTab % majorant(urrIdx) + + ! Check if URR tables contain xs or multiplicative factor + if (nuc % IFF == 1) then + call nuc % search(eIdx, f, E) + nucXS = nuc % totalXS(eIdx, f) * urrMaj + else + nucXS = urrMaj + end if + + else + call self % updateTotalNucXS(E, nucIdx) + nucXS = cache_nuclideCache(nucIdx) % xss % total + + end if + + end associate + + ! Update total material cross section + total = total + dens * nucXS + + end do - ! Calculate current material cross section and compare - call self % updateTotalMatXS(E, matIdx) - maj = max(maj, cache_materialCache(matIdx) % xss % total) + maj = max(maj, total) end do - ! Save majorant for this energy - self % majorant(i) = maj + ! Save majorant for this energy. Nudge it up to avoid small discrepancies + self % majorant(i) = maj * (ONE + NUDGE) end do diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 27481891b..2438812e3 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -103,9 +103,9 @@ module aceNeutronNuclide_class !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment !! elScatteringMaj -> returns the elastic scattering majorant within an energy range given as input !! init -> build nuclide from aceCard - !! init_urr -> build list and mapping of nuclides to maintain temperature correlation + !! initUrr -> build list and mapping of nuclides to maintain temperature correlation !! when reading ures probability tables - !! init_Sab -> builds S(a,b) propertied from aceCard + !! initSab -> builds S(a,b) propertied from aceCard !! display -> print information about the nuclide to the console !! type, public, extends(ceNeutronNuclide) :: aceNeutronNuclide @@ -147,8 +147,8 @@ module aceNeutronNuclide_class procedure :: getThXSs procedure :: elScatteringMaj procedure :: init - procedure :: init_urr - procedure :: init_Sab + procedure :: initUrr + procedure :: initSab procedure :: display end type aceNeutronNuclide @@ -476,6 +476,7 @@ elemental subroutine getThXSs(self, xss, idx, f, E) ! Retrieve capture and fission cross sections as usual xss % capture = data(CAPTURE_XS, 2) * f + (ONE-f) * data(CAPTURE_XS, 1) + if (self % isFissile()) then xss % fission = data(FISSION_XS, 2) * f + (ONE-f) * data(FISSION_XS, 1) xss % nuFission = data(NU_FISSION, 2) * f + (ONE-f) * data(NU_FISSION, 1) @@ -741,14 +742,14 @@ subroutine init(self, ACE, nucIdx, database) ! Create a stack of MT reactions, devide them into ones that produce 2nd-ary ! particlues and pure absorbtion associate (MTs => ACE % getScatterMTs()) - do i=1,size(MTs) + do i = 1,size(MTs) if (MTs(i) == N_ANYTHING) cycle call scatterMT % push(MTs(i)) end do end associate associate (MTs => [ACE % getFissionMTs(), ACE % getCaptureMTs()]) - do i=1,size(MTs) + do i = 1,size(MTs) if(MTs(i) == N_FISSION) cycle ! MT=18 is already included with FIS block call absMT % push(MTs(i)) end do @@ -760,7 +761,7 @@ subroutine init(self, ACE, nucIdx, database) ! Load scattering reactions N = scatterMT % size() self % nMT = N - do i =1,N + do i = 1,N call scatterMT % pop(MT) self % MTdata(i) % MT = MT self % MTdata(i) % firstIdx = ACE % firstIdxMT(MT) @@ -783,7 +784,7 @@ subroutine init(self, ACE, nucIdx, database) end do ! Calculate Inelastic scattering XS - do i=1,self % nMT + do i = 1,self % nMT do j=1,size(self % mainData, 2) ! Find bottom and Top of the grid bottom = self % MTdata(i) % firstIdx @@ -804,7 +805,7 @@ subroutine init(self, ACE, nucIdx, database) self % mainData(TOTAL_XS, :) = sum(self % mainData(ESCATTER_XS:K,:),1) ! Load Map of MT -> local index of a reaction - do i=1,size(self % MTdata) + do i = 1,size(self % MTdata) call self % idxMT % add(self % MTdata(i) % MT, i) end do @@ -830,7 +831,7 @@ end subroutine init !! Args: !! ACE [inout] -> ACE card !! - subroutine init_urr(self, ACE) + subroutine initUrr(self, ACE) class(aceNeutronNuclide), intent(inout) :: self class(aceCard), intent(inout) :: ACE @@ -841,19 +842,24 @@ subroutine init_urr(self, ACE) ! Initialise probability tables call self % probTab % init(ACE) ! Check if probability tables were read correctly + if (allocated(self % probTab % eGrid)) then self % urrE = self % probTab % getEbounds() self % IFF = self % probTab % getIFF() + else ! Something went wrong! self % hasProbTab = .false. self % urrE = ZERO + end if + else self % urrE = ZERO + end if - end subroutine init_urr + end subroutine initUrr !! !! Initialise thermal scattering tables from ACE card @@ -865,14 +871,15 @@ end subroutine init_urr !! fatalError if the inelastic scattering S(a,b) energy grid starts at a !! lower energy than the nuclide energy grid !! - subroutine init_Sab(self, ACE) + subroutine initSab(self, ACE) class(aceNeutronNuclide), intent(inout) :: self class(aceSabCard), intent(inout) :: ACE - character(100), parameter :: Here = "init_Sab (aceNeutronNuclide_class.f90)" + character(100), parameter :: Here = "initSab (aceNeutronNuclide_class.f90)" ! Initialise S(a,b) class from ACE file call self % thData % init(ACE) self % hasThData = .true. + ! Initialise energy boundaries self % SabInel = self % thData % getEbounds('inelastic') self % SabEl = self % thData % getEbounds('elastic') @@ -882,7 +889,7 @@ subroutine init_Sab(self, ACE) call fatalError(Here, 'S(a,b) low energy boundary is lower than nuclide first energy point') end if - end subroutine init_Sab + end subroutine initSab !! !! A Procedure that displays information about the nuclide to the screen diff --git a/NuclearData/ceNeutronData/aceDatabase/urrProbabilityTables_class.f90 b/NuclearData/ceNeutronData/aceDatabase/urrProbabilityTables_class.f90 index 87f8ce93d..42e292aff 100644 --- a/NuclearData/ceNeutronData/aceDatabase/urrProbabilityTables_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/urrProbabilityTables_class.f90 @@ -35,8 +35,9 @@ module urrProbabilityTables_class !! ILF -> Inelatic competition flag (only used to check if inelatic scattering is zero) !! IOA -> Other absorption flag. NOTE: not used in the code !! IFF -> Multiplication factor flag - !! eGrid -> Energy grid - !! table -> Array of probability tables + !! majorant -> Array of maximum table total xs entry per each energy + !! eGrid -> Energy grid + !! table -> Array of probability tables !! !! type, public :: urrProbabilityTables @@ -46,12 +47,14 @@ module urrProbabilityTables_class integer(shortInt) :: ILF integer(shortInt) :: IOA integer(shortInt) :: IFF + real(defReal), dimension(:), allocatable :: majorant real(defReal), dimension(:), allocatable :: eGrid type(urrTable), dimension(:), allocatable :: table contains procedure :: init + procedure :: computeMajorant procedure :: kill procedure :: getEbounds procedure :: getIFF @@ -85,6 +88,9 @@ subroutine init(self, data) call fatalError(Here,'Probability tables cannot be build from '//data % myType()) end select + ! Find majorant + if (allocated(self % table)) call self % computeMajorant + end subroutine init !! @@ -215,21 +221,67 @@ subroutine buildFromACE(self, ACE) print '(A)', "Probability table discarded because CDF is not sorted" call self % kill() return + elseif (abs(self % table(i) % CDF(self % nTable) - ONE) > 1.0E-6_defReal) then print '(A)', "Probability table discarded because CDF does not end with 1.0 " call self % kill() return + elseif (self % table(i) % CDF(self % nTable) < ONE) then ! Adjust CDF if it is within tolerance but smaller than 1 due to floating point error self % table(i) % CDF(self % nTable) = ONE + elseif (any(self % table(i) % tot < ZERO) .or. any(self % table(i) % el < ZERO) .or. & any(self % table(i) % fiss < ZERO) .or. any(self % table(i) % capt < ZERO) ) then print '(A)', "Probability table discarded because negative cross-sections present " call self % kill() return + end if end do end subroutine buildFromACE + !! + !! Build majorant + !! + !! Finds the largest entry stored in each probability table (i.e., per each energy). + !! Each table entry is also compared with the equivalent entry for the following + !! energy; this is done so that interpolation between energies will not be needed + !! when using this majorant to compute the overall cross section majorant + !! + subroutine computeMajorant(self) + class(urrProbabilityTables), intent(inout) :: self + real(defReal) :: majorant + integer(shortInt) :: i, j + + ! Allocate majorant + allocate(self % majorant(self % nGrid)) + + ! Loop over energy grid + do i = 1,self % nGrid + + ! Initialise majorant value + majorant = ZERO + + ! Loop over table elements + do j = 1,self % nTable + + ! Update majorant if needed + majorant = max(majorant,self % table(i) % tot(j)) + + ! Check energy above (avoids the need for energy interpolation later) + if (i < self % nGrid) then + majorant = max(majorant,self % table(i + 1) % tot(j)) + end if + + end do + + ! Save majorant for this energy + self % majorant(i) = majorant + + end do + + end subroutine computeMajorant + end module urrProbabilityTables_class diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index e3a8eeff2..ba70e7bce 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -71,6 +71,7 @@ subroutine init(self, dict, ptr, silent) !! !! Args: !! activeMat [in] -> Array of matIdx of materials active in the simulation + !! silent [in] -> Optional. If set to .true. disables console output !! !! Errors: !! fatalError if activeMat contains materials not defined in the instance diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index fa91ef9ed..fcfacf7f2 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -4,7 +4,6 @@ module testNeutronDatabase_class use particle_class, only : particle use dictionary_class, only : dictionary use charMap_class, only : charMap - use RNG_class, only : RNG ! Nuclear Data Interfaces use nuclearDatabase_inter, only : nuclearDatabase From b97e613b935dc01983db5281725f8f135d929549 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Mon, 5 Feb 2024 17:31:56 +0000 Subject: [PATCH 097/133] Typos and preventing out of bound array access --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 6 +++++- .../ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index a60c49b0a..a95dc0b44 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -949,7 +949,11 @@ subroutine initMajorant(self, loud) do while (j /= nucSet % end()) ! Retrieve energy in the grid and nuclide information - eMin = tmpGrid(i - 1) + if (i /= 1) then + eMin = tmpGrid(i - 1) + else + eMin = ZERO + end if eMax = tmpGrid(i) nucIdx = nucSet % atKey(j) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 2438812e3..95086e572 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -105,7 +105,7 @@ module aceNeutronNuclide_class !! init -> build nuclide from aceCard !! initUrr -> build list and mapping of nuclides to maintain temperature correlation !! when reading ures probability tables - !! initSab -> builds S(a,b) propertied from aceCard + !! initSab -> builds S(a,b) properties from aceCard !! display -> print information about the nuclide to the console !! type, public, extends(ceNeutronNuclide) :: aceNeutronNuclide From a65100108421aeaf131b499dba43af68da498c6e Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Mon, 5 Feb 2024 19:01:33 +0000 Subject: [PATCH 098/133] Typos --- .../ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 | 2 +- .../ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 | 4 ++-- NuclearData/nuclearDatabase_inter.f90 | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index a95dc0b44..d1bc37e9d 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -1059,7 +1059,7 @@ subroutine initMajorant(self, loud) needsUrr = (nuc % hasProbTab .and. E >= nuc % urrE(1) .and. E <= nuc % urrE(2)) - ! Check if present nuclide uses URR tabes + ! Check if present nuclide uses URR tables if (needsUrr) then ! Find maximum URR table total XS diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 95086e572..343bc6b0e 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -739,8 +739,8 @@ subroutine init(self, ACE, nucIdx, database) ! Read data for MT reaction - ! Create a stack of MT reactions, devide them into ones that produce 2nd-ary - ! particlues and pure absorbtion + ! Create a stack of MT reactions, divide them into ones that produce 2nd-ary + ! particles and pure absorption associate (MTs => ACE % getScatterMTs()) do i = 1,size(MTs) if (MTs(i) == N_ANYTHING) cycle diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index ba70e7bce..0c8712fd0 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -221,7 +221,7 @@ end function getNuclide !! !! Allows to retrieve an access to reaction data for all databases types !! Reactions can be associated either with nuclides or materials. Thus, there is ambiguity - !! whether material or nuclide should be asked to provide reaction data (using matIdx or nuIdx) + !! whether material or nuclide should be asked to provide reaction data (using matIdx or nucIdx) !! !! This ambiguity is resolved by following convenction: !! if MT < 0 then reaction is associated with material: idx -> matIdx From 702c12ae8f9ba97502250f801a303aac4c756162 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 7 Feb 2024 16:37:00 +0000 Subject: [PATCH 099/133] Adding getTrackingXS procedure for virtual collision handling --- .../aceDatabase/aceNeutronDatabase_class.f90 | 7 +- .../ceNeutronData/ceNeutronCache_mod.f90 | 80 ++++++++++--------- .../ceNeutronData/ceNeutronDatabase_inter.f90 | 39 ++++++--- .../ceNeutronData/ceNeutronMaterial_class.f90 | 2 +- .../baseMgNeutronDatabase_class.f90 | 41 +++++++--- .../mgNeutronData/mgNeutronCache_mod.f90 | 41 +++++++--- NuclearData/nuclearDatabase_inter.f90 | 23 +++--- SharedModules/universalVariables.f90 | 4 + Tallies/TallyClerks/collisionClerk_class.f90 | 43 ++++++++-- .../collisionProbabilityClerk_class.f90 | 18 ++--- .../TallyClerks/keffImplicitClerk_class.f90 | 61 +++++++++++--- Tallies/TallyClerks/mgXsClerk_class.f90 | 53 +++++++++--- Tallies/TallyClerks/simpleFMClerk_class.f90 | 60 +++++++++++--- .../transportOperatorDT_class.f90 | 6 +- .../transportOperatorHT_class.f90 | 16 ++-- .../transportOperatorST_class.f90 | 8 +- 16 files changed, 355 insertions(+), 147 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 496dff341..f9bc85da2 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -306,7 +306,7 @@ subroutine updateTotalMatXS(self, E, matIdx, rand) nucIdx = self % materials(matIdx) % nuclides(i) ! Update if needed - if(cache_nuclideCache(nucIdx) % E_tot /= E) then + if (cache_nuclideCache(nucIdx) % E_tot /= E) then call self % updateTotalNucXS(E, nucIdx, rand) end if @@ -338,7 +338,7 @@ subroutine updateMajorantXS(self, E, rand) matIdx = self % activeMat(i) ! Update if needed - if( cache_materialCache(matIdx) % E_tot /= E) then + if (cache_materialCache(matIdx) % E_tot /= E) then call self % updateTotalMatXS(E, matIdx, rand) end if @@ -457,10 +457,13 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) end if call nuc % getUrrXSs(nucCache % xss, nucCache % idx, nucCache % f, E, zaidCache % xi) end associate + elseif (nucCache % needsSabEl .or. nucCache % needsSabInel) then call nuc % getThXSs(nucCache % xss, nucCache % idx, nucCache % f, E) + else call nuc % microXSs(nucCache % xss, nucCache % idx, nucCache % f) + end if end associate diff --git a/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 b/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 index bf06e638b..345b96b39 100644 --- a/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 +++ b/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 @@ -6,8 +6,9 @@ !! !! Public Members: !! nuclideCache -> Array of cached data for nuclides -!! matCache -> Array of cached data for materials +!! materialCache -> Array of cached data for materials !! majorantCache -> Array of cached data for majorant XS +!! trackingCache -> Array of cached data for tracking XS !! zaidCache -> Array of cached data for ZAID numbers (used for URR probability tables) !! !! NOTE: @@ -70,16 +71,16 @@ module ceNeutronCache_mod end type cacheNucDat !! - !! Structure that contains a Majorant XS + !! Structure that contains a cross section value !! !! Public Members: - !! E -> energy of the majorant - !! xs -> value of the majorant + !! E -> energy of the cross section + !! xs -> value of the cross section !! - type, public :: cacheMajorant + type, public :: cacheSingleXS real(defReal) :: E real(defReal) :: xs - end type cacheMajorant + end type cacheSingleXS !! !! Structure that contains a ZAID random number for probability tables @@ -96,9 +97,10 @@ module ceNeutronCache_mod ! MEMBERS OF THE MODULE ARE GIVEN HERE type(cacheMatDat), dimension(:), allocatable, public :: materialCache type(cacheNucDat), dimension(:), allocatable, public :: nuclideCache - type(cacheMajorant), dimension(:), allocatable, public :: majorantCache + type(cacheSingleXS), dimension(:), allocatable, public :: majorantCache + type(cacheSingleXS), dimension(:), allocatable, public :: trackingCache type(cacheZAID), dimension(:), allocatable, public :: zaidCache - !$omp threadprivate(materialCache, nuclideCache, majorantCache, zaidCache) + !$omp threadprivate(materialCache, nuclideCache, majorantCache, trackingCache, zaidCache) ! Public procedures public :: init @@ -112,49 +114,50 @@ module ceNeutronCache_mod !! Initialise Cache to given space !! !! Args: - !! Nmat [in] -> Number of materials - !! Nnuc [in] -> Number of nuclides - !! Nmaj [in] -> Optional. Number of majorant Xss (Default = 1) - !! Nzaid [in] -> Optional. Number of nuclides with same ZAID + !! nMat [in] -> Number of materials + !! nNuc [in] -> Number of nuclides + !! nMaj [in] -> Optional. Number of majorant Xss (Default = 1) + !! nZaid [in] -> Optional. Number of nuclides with same ZAID !! !! Errors: - !! fatalError if Nmat, Nnuc or Nmaj is not a +ve value - !! - subroutine init(Nmat, Nnuc, Nmaj, Nzaid) - integer(shortInt), intent(in) :: Nmat - integer(shortInt), intent(in) :: Nnuc - integer(shortInt),optional, intent(in) :: Nmaj - integer(shortInt),optional, intent(in) :: Nzaid - integer(shortInt) :: Nloc + !! fatalError if nMat, nNuc or Nmaj is not a +ve value + !! + subroutine init(nMat, nNuc, nMaj, nZaid) + integer(shortInt), intent(in) :: nMat + integer(shortInt), intent(in) :: nNuc + integer(shortInt), optional, intent(in) :: nMaj + integer(shortInt), optional, intent(in) :: nZaid + integer(shortInt) :: nLoc character(100),parameter :: Here = 'init (ceNeutronCache_mod.f90)' ! Make sure memory is clean call kill() ! Read default value of majorant XSs - if(present(Nmaj)) then - Nloc = Nmaj + if (present(nMaj)) then + nLoc = nMaj else - Nloc = 1 + nLoc = 1 end if ! Chack the provided data - if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) - if(Nnuc < 1) call fatalError(Here,'Number of nuclides must be +ve! Not: '//numToChar(Nmat)) - if(Nloc < 1) call fatalError(Here,'Number of majorant XSs must be +ve! Not: '//numToChar(Nmat)) + if (nMat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(nMat)) + if (nNuc < 1) call fatalError(Here,'Number of nuclides must be +ve! Not: '//numToChar(nMat)) + if (nLoc < 1) call fatalError(Here,'Number of majorant XSs must be +ve! Not: '//numToChar(nMat)) ! Allocate space ! Need to do in parallel region to allocate each copy !$omp parallel - allocate(materialCache(Nmat)) - allocate(nuclideCache(Nnuc)) - allocate(majorantCache(Nloc)) - - if(present(Nzaid)) then - if (Nzaid > 0) then - allocate(zaidCache(Nzaid)) + allocate(materialCache(nMat)) + allocate(nuclideCache(nNuc)) + allocate(majorantCache(nLoc)) + allocate(trackingCache(1)) + + if (present(nZaid)) then + if (nZaid > 0) then + allocate(zaidCache(nZaid)) else - call fatalError(Here,'Number of zaids must be +ve! Not: '//numToChar(Nzaid)) + call fatalError(Here,'Number of zaids must be +ve! Not: '//numToChar(nZaid)) end if end if !$omp end parallel @@ -167,10 +170,11 @@ end subroutine init subroutine kill() ! Need to deallocate on all threads !$omp parallel - if(allocated(materialCache)) deallocate (materialCache) - if(allocated(nuclideCache)) deallocate (nuclideCache) - if(allocated(majorantCache)) deallocate (majorantCache) - if(allocated(zaidCache)) deallocate (zaidCache) + if (allocated(materialCache)) deallocate (materialCache) + if (allocated(nuclideCache)) deallocate (nuclideCache) + if (allocated(majorantCache)) deallocate (majorantCache) + if (allocated(trackingCache)) deallocate (trackingCache) + if (allocated(zaidCache)) deallocate (zaidCache) !$omp end parallel end subroutine kill diff --git a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 index d0c8fd1d2..0f13871df 100644 --- a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 @@ -1,6 +1,7 @@ module ceNeutronDatabase_inter use numPrecision + use universalVariables use genericProcedures, only : fatalError use RNG_class, only : RNG use particle_class, only : particle, P_NEUTRON, printType @@ -14,7 +15,7 @@ module ceNeutronDatabase_inter use nuclearDatabase_inter, only : nuclearDatabase ! Cache - use ceNeutronCache_mod, only : materialCache, majorantCache + use ceNeutronCache_mod, only : materialCache, majorantCache, trackingCache implicit none private @@ -51,7 +52,7 @@ module ceNeutronDatabase_inter contains ! nuclearDatabase Interface Implementation - procedure :: getTransMatXS + procedure :: getTrackingXS procedure :: getTotalMatXS procedure :: getMajorantXS @@ -222,22 +223,40 @@ end function getScattMicroMajXS contains !! - !! Return transport XS for material matIdx + !! Return tracking XS requested !! !! See nuclearDatabase_inter for details! !! !! Error: !! fatalError if particle is not CE Neutron !! - function getTransMatXS(self, p, matIdx) result(xs) + function getTrackingXS(self, p, matIdx, what) result(xs) class(ceNeutronDatabase), intent(inout) :: self class(particle), intent(in) :: p integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(in) :: what real(defReal) :: xs + character(100),parameter :: Here = 'getTrackingXS (ceNeutronDatabase_inter.f90)' - xs = self % getTotalMatXS(p, matIdx) + ! Process request + select case(what) - end function getTransMatXS + case (MATERIAL_XS) + xs = self % getTotalMatXS(p, matIdx) + + case (MAJORANT_XS) + xs = self % getMajorantXS(p) + + case default + call fatalError(Here, 'Neither material xs nor majorant xs was asked') + + end select + + ! Update Cache + trackingCache(1) % E = p % E + trackingCache(1) % xs = xs + + end function getTrackingXS !! !! Return Total XS for matIdx @@ -255,12 +274,12 @@ function getTotalMatXS(self, p, matIdx) result(xs) character(100),parameter :: Here = 'getTotalMatXS (ceNeutronDatabase_inter.f90)' ! Check dynamic type of the particle - if(p % isMG .or. p % type /= P_NEUTRON) then + if (p % isMG .or. p % type /= P_NEUTRON) then call fatalError(Here, 'Dynamic type of the partcle is not CE Neutron but:'//p % typeToChar()) end if ! Check Cache and update if needed - if(materialCache(matIdx) % E_tot /= p % E) call self % updateTotalMatXS(p % E, matIdx, p % pRNG) + if (materialCache(matIdx) % E_tot /= p % E) call self % updateTotalMatXS(p % E, matIdx, p % pRNG) ! Return Cross-Section xs = materialCache(matIdx) % xss % total @@ -282,12 +301,12 @@ function getMajorantXS(self, p) result(xs) character(100),parameter :: Here = 'getMajorantXS (ceNeutronDatabase_inter.f90)' ! Check dynamic type of the particle - if(p % isMG .or. p % type /= P_NEUTRON) then + if (p % isMG .or. p % type /= P_NEUTRON) then call fatalError(Here, 'Dynamic type of the partcle is not CE Neutron but:'//p % typeToChar()) end if ! Check Cache and update if needed - if(majorantCache(1) % E /= p % E) call self % updateMajorantXS(p % E, p % pRNG) + if (majorantCache(1) % E /= p % E) call self % updateMajorantXS(p % E, p % pRNG) ! Return Cross-Section xs = majorantCache(1) % xs diff --git a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 index d80a94b84..e8088fc3e 100644 --- a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 +++ b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 @@ -98,7 +98,7 @@ subroutine getMacroXSs_byP(self, xss, p) class(particle), intent(in) :: p character(100), parameter :: Here = 'getMacroXSs_byP (ceNeutronMaterial_class.f90)' - if(.not.p % isMG) then + if (.not.p % isMG) then call self % getMacroXSs(xss, p % E, p % pRNG) else diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 078c3f2b6..f5331a9ac 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -2,6 +2,7 @@ module baseMgNeutronDatabase_class use numPrecision use endfConstants + use universalVariables use genericProcedures, only : fatalError, numToChar use particle_class, only : particle use charMap_class, only : charMap @@ -20,8 +21,8 @@ module baseMgNeutronDatabase_class ! baseMgNeutron Objects use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial - ! MG NEUTRON CACHE - use mgNeutronCache_mod, only : cache_materialCache => materialCache, & + ! Cache + use mgNeutronCache_mod, only : materialCache, trackingCache, & cache_init => init implicit none @@ -60,7 +61,7 @@ module baseMgNeutronDatabase_class contains ! Superclass Interface - procedure :: getTransMatXS + procedure :: getTrackingXS procedure :: getTotalMatXS procedure :: getMajorantXS procedure :: matNamesMap @@ -79,7 +80,7 @@ module baseMgNeutronDatabase_class contains !! - !! Get Transport XS given a particle + !! Get tracking XS requested !! !! See nuclearDatabase documentation for details !! @@ -87,15 +88,33 @@ module baseMgNeutronDatabase_class !! DOES NOT check if particle is MG. Will refer to G in the particle and give error !! if the value is invalid !! - function getTransMatXS(self, p, matIdx) result(xs) + function getTrackingXS(self, p, matIdx, what) result(xs) class(baseMgNeutronDatabase), intent(inout) :: self class(particle), intent(in) :: p integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(in) :: what real(defReal) :: xs + character(100),parameter :: Here = 'getTrackingXS (baseMgNeutronDatabase_class.f90)' - xs = self % getTotalMatXS(p, matIdx) + ! Process request + select case(what) - end function getTransMatXS + case (MATERIAL_XS) + xs = self % getTotalMatXS(p, matIdx) + + case (MAJORANT_XS) + xs = self % getMajorantXS(p) + + case default + call fatalError(Here, 'Neither material xs nor majorant xs was asked') + + end select + + ! Update Cache + trackingCache(1) % G = p % G + trackingCache(1) % xs = xs + + end function getTrackingXS !! !! Get Total XS given a particle @@ -112,7 +131,7 @@ function getTotalMatXS(self, p, matIdx) result(xs) integer(shortInt), intent(in) :: matIdx real(defReal) :: xs - associate (matCache => cache_materialCache(matIdx)) + associate (matCache => materialCache(matIdx)) if (matCache % G_tot /= p % G) then ! Get cross section @@ -180,11 +199,11 @@ function getMaterial(self, matIdx) result(mat) integer(shortInt), intent(in) :: matIdx class(materialHandle), pointer :: mat - if(matIdx < 1 .or. matIdx > size(self % mats)) then + if (matIdx < 1 .or. matIdx > size(self % mats)) then mat => null() else ! Retrieve pointer from cache - mat => cache_materialCache(matIdx) % mat + mat => materialCache(matIdx) % mat end if end function getMaterial @@ -354,7 +373,7 @@ subroutine activate(self, activeMat) ! Store the material pointer in the material cache !$omp parallel do idx = 1,size(self % mats) - cache_materialCache(idx) % mat => self % mats(idx) + materialCache(idx) % mat => self % mats(idx) end do !$omp end parallel diff --git a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 index 1a0b2aea2..28a7e3974 100644 --- a/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 +++ b/NuclearData/mgNeutronData/mgNeutronCache_mod.f90 @@ -6,15 +6,15 @@ !! !! Public Members: !! matCache -> Array of cached data for materials -!! majorantCache -> Array of cached data for majorant XS +!! trackingCache -> Array of cached data for tracking XS !! !! NOTE: !! Cache arrays are deliberatly not targets. This is because there should be no pointers to the !! cache. Any update call can change energy group of any value so it would not be possible that the !! energy group of XSs pointed by pointers changed silently. !! -!! ALSO NOTE: -!! The MG data cache was added to improve parallel scalability. It is still not fully understood +!! ALSO NOTE: +!! The MG data cache was added to improve parallel scalability. It is still not fully understood !! why this helps, but it seemed to reduce cache misses largely !! module mgNeutronCache_mod @@ -30,7 +30,7 @@ module mgNeutronCache_mod !! !! Structure that contains cached data for each MG Neutron Material !! - !! Note: the material pointer was included in the cache because it improved parallel performance + !! Note: the material pointer was included in the cache because it improved parallel performance !! by avoiding the cache misses occurring when getting the pointer on-the-fly !! !! Public Members: @@ -40,15 +40,28 @@ module mgNeutronCache_mod !! mat -> Pointer to MG material !! type, public :: cacheMatDat - real(defReal) :: G_tot = ZERO - real(defReal) :: G_tail = ZERO + integer(shortInt) :: G_tot = ZERO + integer(shortInt) :: G_tail = ZERO type(neutronMacroXSs) :: xss class(materialHandle), pointer :: mat end type cacheMatDat + !! + !! Structure that contains a cross section value + !! + !! Public Members: + !! G -> energy group of the cross section + !! xs -> value of the cross section + !! + type, public :: cacheSingleXS + integer(shortInt) :: G + real(defReal) :: xs + end type cacheSingleXS + ! MEMBERS OF THE MODULE ARE GIVEN HERE type(cacheMatDat), dimension(:), allocatable, public :: materialCache - !$omp threadprivate(materialCache) + type(cacheSingleXS), dimension(:), allocatable, public :: trackingCache + !$omp threadprivate(materialCache, trackingCache) ! Public procedures public :: init @@ -62,24 +75,25 @@ module mgNeutronCache_mod !! Initialise Cache to given space !! !! Args: - !! Nmat [in] -> Number of materials + !! nMat [in] -> Number of materials !! !! Errors: - !! fatalError if Nmat is not a +ve value + !! fatalError if nMat is not a +ve value !! - subroutine init(Nmat) - integer(shortInt), intent(in) :: Nmat + subroutine init(nMat) + integer(shortInt), intent(in) :: nMat character(100),parameter :: Here = 'init (ceNeutronCache_mod.f90)' ! Make sure memory is clean call kill() ! Chack the provided data - if(Nmat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(Nmat)) + if (nMat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(nMat)) ! Allocate space. Need to do in parallel to allocate each copy !$omp parallel - allocate(materialCache(Nmat)) + allocate(materialCache(nMat)) + allocate(trackingCache(1)) !$omp end parallel end subroutine init @@ -92,6 +106,7 @@ subroutine kill() ! Need to deallocate on all threads !$omp parallel if(allocated(materialCache)) deallocate (materialCache) + if(allocated(trackingCache)) deallocate (trackingCache) !$omp end parallel end subroutine kill diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index 0c123df8d..8aaf0f306 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -21,8 +21,8 @@ module nuclearDatabase_inter !! subclasses of this type. !! !! Interface: - !! getTransMatXS -> returns transport Material XS given a particle - !! getTotalMatXS -> returns total Material XS fiven a particle + !! getTrackingXS -> returns XS used to sample track lenght + !! getTotalMatXS -> returns total Material XS given a particle !! getMajorantXS -> returns majorant XS given particle and list of active materials !! matNamesMap -> returns pointer to map of material names to matIdx !! getMaterial -> returns a pointer to a material handle for given matIdx @@ -34,7 +34,7 @@ module nuclearDatabase_inter contains procedure(init), deferred :: init procedure(activate), deferred :: activate - procedure(getTransMatXS), deferred :: getTransMatXS + procedure(getTrackingXS), deferred :: getTrackingXS procedure(getTotalMatXS), deferred :: getTotalMatXS procedure(getMajorantXS), deferred :: getMajorantXS procedure(matNamesMap), deferred :: matNamesMap @@ -82,29 +82,32 @@ subroutine activate(self, activeMat) end subroutine activate !! - !! Return value of Material Transport XS for a particle + !! Return value of Tracking XS for a particle and a given request !! - !! Reads all relevalnt state information from the particle (e.g. E or G) - !! Usually is the same as material total XS, but it may be not always the case + !! Reads all relevant state information from the particle (e.g. E or G) + !! It is the XS used to sample track length: it might be the same as the + !! material total XS, the majorant XS, or a temperature majorant !! !! Args: - !! p [in] -> particle at a given state + !! p [in] -> Particle at a given state !! matIdx [in] -> Material index + !! what [in] -> Request index !! !! Result: - !! Value of a material transport XS [1/cm] + !! Value of XS used to sample path length [1/cm] !! !! Errors: !! Undefined behaviour if the state of the particle is invalid e.g. -ve energy !! Undefined behavior if matIdx does not correspond to a defined material !! - function getTransMatXS(self, p, matIdx) result(xs) + function getTrackingXS(self, p, matIdx, what) result(xs) import :: nuclearDatabase, particle, shortInt, defReal class(nuclearDatabase), intent(inout) :: self class(particle), intent(in) :: p integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(in) :: what real(defReal) :: xs - end function getTransMatXS + end function getTrackingXS !! !! Return value of Material Total XS for a particle diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index bf3997446..3fda3f0dc 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -69,6 +69,10 @@ module universalVariables targetNotFound = -3, & NOT_FOUND = -3 + ! Integer indexes for type of tracking cross section requested + integer(shortInt), parameter :: MATERIAL_XS = 1, & + MAJORANT_XS = 2 + ! Physical constants real(defReal), parameter :: neutronMass = 939.5654133_defReal, & ! Neutron mass in MeV/c^2 lightSpeed = 2.99792458e10_defReal, & ! Light speed in cm/s diff --git a/Tallies/TallyClerks/collisionClerk_class.f90 b/Tallies/TallyClerks/collisionClerk_class.f90 index dd5dd66df..d51db3acc 100644 --- a/Tallies/TallyClerks/collisionClerk_class.f90 +++ b/Tallies/TallyClerks/collisionClerk_class.f90 @@ -23,6 +23,10 @@ module collisionClerk_class ! Tally Responses use tallyResponseSlot_class, only : tallyResponseSlot + ! Cache + use ceNeutronCache_mod, only : ceTrackingCache => trackingCache + use mgNeutronCache_mod, only : mgTrackingCache => trackingCache + implicit none private @@ -59,6 +63,8 @@ module collisionClerk_class ! Useful data integer(shortInt) :: width = 0 + + ! Settings logical(defBool) :: virtual = .false. contains @@ -146,7 +152,8 @@ elemental subroutine kill(self) deallocate(self % response) end if - self % width = 0 + self % width = 0 + self % virtual = .false. end subroutine kill @@ -191,15 +198,35 @@ subroutine reportInColl(self, p, xsData, mem, virtual) type(particleState) :: state integer(shortInt) :: binIdx, i integer(longInt) :: adrr - real(defReal) :: scoreVal, flx - character(100), parameter :: Here =' reportInColl (collisionClerk_class.f90)' + real(defReal) :: scoreVal, flux + character(100), parameter :: Here = 'reportInColl (collisionClerk_class.f90)' - ! Calculate flux sample based on physical or virtual collision + ! Return if collision is virtual but virtual collision handling is off if (self % virtual) then - flx = ONE / xsData % getMajorantXS(p) + + ! Retrieve tracking cross section from cache + ! Select over CE and MG cache, and give error if cache was not updated properly + if (p % isMG) then + if (mgTrackingCache(1) % G == p % G) then + flux = p % w / mgTrackingCache(1) % xs + else + call fatalError(Here, 'MG tracking cache failed to update during tracking') + end if + + else + if (ceTrackingCache(1) % E == p % E) then + flux = p % w / ceTrackingCache(1) % xs + else + call fatalError(Here, 'CE tracking cache failed to update during tracking') + end if + + end if + else + if (virtual) return - flx = ONE / xsData % getTotalMatXS(p, p % matIdx()) + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) + end if ! Get current particle state @@ -224,8 +251,8 @@ subroutine reportInColl(self, p, xsData, mem, virtual) adrr = self % getMemAddress() + self % width * (binIdx -1) - 1 ! Append all bins - do i=1,self % width - scoreVal = self % response(i) % get(p, xsData) * p % w *flx + do i = 1,self % width + scoreVal = self % response(i) % get(p, xsData) * flux call mem % score(scoreVal, adrr + i) end do diff --git a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 index b4b33fd73..06da8f2d8 100644 --- a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 +++ b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 @@ -45,13 +45,13 @@ module collisionProbabilityClerk_class !! -> CPM is stored in column-major order [prodBin, startBin]. !! -> CPs are only non-zero within an energy group. It may be more efficient to !! define a slightly different CPClerk which has a separate map for energy. - !! With a fine energy and space discretisation, a large sparse matrix will be + !! With a fine energy and space discretisation, a large sparse matrix will be !! produced by the current clerk which could be avoided with a slightly different !! implementation. !! !! Private Members: !! map -> Map to divide phase-space into bins - !! resp -> Response for transfer function + !! resp -> Response for transfer function !! (Not presently used, would be macroTotal by default) !! N -> Number of Bins !! @@ -185,13 +185,13 @@ subroutine reportInColl(self, p, xsData, mem, virtual) if (virtual) return ! Get material or return if it is not a neutron - mat => neutronMaterial_CptrCast( xsData % getMaterial(p % matIdx())) + mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) - if(.not.associated(mat)) return + if (.not.associated(mat)) return ! Find starting index in the map ! It is important that preCollision is not changed by a collisionProcessor - !before the particle is fed to the tally, otherwise results will be meaningless + ! before the particle is fed to the tally, otherwise results will be meaningless sIdx = self % map % map( p % preCollision) ! Find collision index in the map @@ -202,7 +202,7 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! neutrons which collide outside the mapped region of phase space ! These correspond to index = 0 - ! Calculate collision probability + ! Calculate collision probability ! Used the simple estimator - the commented line can allow CP to generalise to ! other responses ! For collision probability, top and bottom will cancel -- for other probabilities, @@ -230,7 +230,7 @@ subroutine reportCycleEnd(self, end, mem) integer(longInt) :: addrCPM, addrCPM0 real(defReal) :: val, normFactor - if(mem % lastCycle()) then + if (mem % lastCycle()) then ! Set address to the start of collision probability matrix ! Decrease by 1 to get correct address on the first iteration of the loop addrCPM = self % getMemAddress() - 1 @@ -248,7 +248,7 @@ subroutine reportCycleEnd(self, end, mem) normFactor = normFactor + val end do - if(normFactor /= ZERO) normFactor = ONE / normFactor + if (normFactor /= ZERO) normFactor = ONE / normFactor ! Normalise CPM column do j = 1, self % N @@ -280,7 +280,7 @@ pure subroutine getResult(self, res, mem) ! Allocate result to CPMresult ! Do not deallocate if already allocated to CPMresult ! Its not too nice -> clean up - if(allocated(res)) then + if (allocated(res)) then select type(res) class is (CPMresult) ! Do nothing diff --git a/Tallies/TallyClerks/keffImplicitClerk_class.f90 b/Tallies/TallyClerks/keffImplicitClerk_class.f90 index 501359270..33d34c769 100644 --- a/Tallies/TallyClerks/keffImplicitClerk_class.f90 +++ b/Tallies/TallyClerks/keffImplicitClerk_class.f90 @@ -3,6 +3,7 @@ module keffImplicitClerk_class use numPrecision use tallyCodes use endfConstants + use universalVariables use genericProcedures, only : fatalError, charCmp use dictionary_class, only : dictionary use particle_class, only : particle @@ -21,6 +22,10 @@ module keffImplicitClerk_class use tallyClerk_inter, only : tallyClerk, kill_super => kill use keffAnalogClerk_class, only : keffResult + ! Cache + use ceNeutronCache_mod, only : ceTrackingCache => trackingCache + use mgNeutronCache_mod, only : mgTrackingCache => trackingCache + implicit none private @@ -54,7 +59,9 @@ module keffImplicitClerk_class !! type, public,extends(tallyClerk) :: keffImplicitClerk private - real(defReal) :: targetSTD = ZERO + real(defReal) :: targetSTD = ZERO + ! Settings + logical(defBool) :: virtual = .false. contains ! Duplicate interface of the tallyClerk ! Procedures used during build @@ -102,6 +109,9 @@ subroutine init(self, dict, name) end if + ! Handle virtual collisions + call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + end subroutine init !! @@ -115,6 +125,7 @@ elemental subroutine kill(self) ! Kill self self % targetSTD = ZERO + self % virtual = .false. end subroutine kill @@ -157,25 +168,53 @@ subroutine reportInColl(self, p, xsData, mem, virtual) logical(defBool), intent(in) :: virtual type(neutronMacroXSs) :: xss class(neutronMaterial), pointer :: mat - real(defReal) :: totalXS, nuFissXS, absXS, flux + real(defReal) :: nuFissXS, absXS, flux real(defReal) :: s1, s2 character(100), parameter :: Here = 'reportInColl (keffImplicitClerk_class.f90)' - ! This clerk does not handle virtual scoring yet - if (virtual) return + ! Return if collision is virtual but virtual collision handling is off + if (self % virtual) then + + ! Retrieve tracking cross section from cache + ! Select over CE and MG cache, and give error if cache was not updated properly + if (p % isMG) then + if (mgTrackingCache(1) % G == p % G) then + flux = p % w / mgTrackingCache(1) % xs + else + call fatalError(Here, 'MG tracking cache failed to update during tracking') + end if + + else + if (ceTrackingCache(1) % E == p % E) then + flux = p % w / ceTrackingCache(1) % xs + else + call fatalError(Here, 'CE tracking cache failed to update during tracking') + end if + + end if + + else + + if (virtual) return + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - ! Obtain XSs - mat => neutronMaterial_CptrCast(xsData % getMaterial( p % matIdx())) - if(.not.associated(mat)) call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') + end if + + ! Ensure we're not in void (could happen when scoring virtual collisions) + if (p % matIdx() == VOID_MAT) return + + ! Get material pointer + mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) + if (.not.associated(mat)) then + call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') + end if + + ! Obtain xss call mat % getMacroXSs(xss, p) - totalXS = xss % total nuFissXS = xss % nuFission absXS = xss % capture + xss % fission - ! Calculate flux and scores - flux = p % w / totalXS - s1 = nuFissXS * flux s2 = absXS * flux diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index fdeda347a..277676c07 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -3,6 +3,7 @@ module mgXsClerk_class use numPrecision use tallyCodes use endfConstants + use universalVariables use genericProcedures, only : fatalError use dictionary_class, only : dictionary use particle_class, only : particle, particleState @@ -22,6 +23,10 @@ module mgXsClerk_class use scoreMemory_class, only : scoreMemory use tallyClerk_inter, only : tallyClerk, kill_super => kill + ! Cache + use ceNeutronCache_mod, only : ceTrackingCache => trackingCache + use mgNeutronCache_mod, only : mgTrackingCache => trackingCache + implicit none private @@ -89,6 +94,9 @@ module mgXsClerk_class integer(shortInt) :: width = 0 logical(defBool) :: PN = .false. + ! Settings + logical(defBool) :: virtual = .false. + contains ! Procedures used during build procedure :: init @@ -170,10 +178,11 @@ elemental subroutine kill(self) end if ! Reset parameters - self % matN = 0 + self % matN = 0 self % energyN = 0 - self % width = 0 - self % PN = .false. + self % width = 0 + self % PN = .false. + self % virtual = .false. end subroutine kill @@ -217,13 +226,38 @@ subroutine reportInColl(self, p, xsData, mem, virtual) type(particleState) :: state type(neutronMacroXSs) :: xss class(neutronMaterial), pointer :: mat - real(defReal) :: totalXS, nuFissXS, captXS, fissXS, scattXS, flux + real(defReal) :: nuFissXS, captXS, fissXS, scattXS, flux integer(shortInt) :: enIdx, matIdx, binIdx integer(longInt) :: addr character(100), parameter :: Here =' reportInColl (mgXsClerk_class.f90)' - ! This clerk does not handle virtual scoring yet - if (virtual) return + ! Return if collision is virtual but virtual collision handling is off + if (self % virtual) then + + ! Retrieve tracking cross section from cache + ! Select over CE and MG cache, and give error if cache was not updated properly + if (p % isMG) then + if (mgTrackingCache(1) % G == p % G) then + flux = p % w / mgTrackingCache(1) % xs + else + call fatalError(Here, 'MG tracking cache failed to update during tracking') + end if + + else + if (ceTrackingCache(1) % E == p % E) then + flux = p % w / ceTrackingCache(1) % xs + else + call fatalError(Here, 'CE tracking cache failed to update during tracking') + end if + + end if + + else + + if (virtual) return + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) + + end if ! Get current particle state state = p @@ -249,6 +283,9 @@ subroutine reportInColl(self, p, xsData, mem, virtual) binIdx = self % energyN * (matIdx - 1) + enIdx addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 + ! Ensure we're not in void (could happen when scoring virtual collisions) + if (p % matIdx() == VOID_MAT) return + ! Get material pointer mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) if (.not.associated(mat)) then @@ -258,10 +295,6 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Retrieve material cross sections call mat % getMacroXSs(xss, p) - ! Calculate flux - totalXS = xss % total - flux = p % w / totalXS - ! Calculate reaction rates nuFissXS = xss % nuFission * flux captXS = xss % capture * flux diff --git a/Tallies/TallyClerks/simpleFMClerk_class.f90 b/Tallies/TallyClerks/simpleFMClerk_class.f90 index bade1c62b..678317d11 100644 --- a/Tallies/TallyClerks/simpleFMClerk_class.f90 +++ b/Tallies/TallyClerks/simpleFMClerk_class.f90 @@ -3,6 +3,7 @@ module simpleFMClerk_class use numPrecision use tallyCodes use endfConstants + use universalVariables use genericProcedures, only : fatalError use dictionary_class, only : dictionary use particle_class, only : particle, particleState @@ -25,6 +26,10 @@ module simpleFMClerk_class ! Tally Response use macroResponse_class, only : macroResponse + ! Cache + use ceNeutronCache_mod, only : ceTrackingCache => trackingCache + use mgNeutronCache_mod, only : mgTrackingCache => trackingCache + implicit none private @@ -63,6 +68,8 @@ module simpleFMClerk_class type(macroResponse) :: resp real(defReal),dimension(:),allocatable :: startWgt integer(shortInt) :: N = 0 !! Number of bins + ! Settings + logical(defBool) :: virtual = .false. contains ! Procedures used during build @@ -125,6 +132,9 @@ subroutine init(self, dict, name) ! Initialise response call self % resp % build(macroNuFission) + ! Handle virtual collisions + call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + end subroutine init !! @@ -191,23 +201,52 @@ subroutine reportInColl(self, p, xsData, mem, virtual) type(particleState) :: state integer(shortInt) :: sIdx, cIdx integer(longInt) :: addr - real(defReal) :: score + real(defReal) :: score, flux class(neutronMaterial), pointer :: mat character(100), parameter :: Here = 'reportInColl simpleFMClear_class.f90' - ! This clerk does not handle virtual scoring yet - if (virtual) return + ! Return if collision is virtual but virtual collision handling is off + if (self % virtual) then - ! Get material or return if it is not a neutron - mat => neutronMaterial_CptrCast( xsData % getMaterial(p % matIdx())) + ! Retrieve tracking cross section from cache + ! Select over CE and MG cache, and give error if cache was not updated properly + if (p % isMG) then + if (mgTrackingCache(1) % G == p % G) then + flux = p % w / mgTrackingCache(1) % xs + else + call fatalError(Here, 'MG tracking cache failed to update during tracking') + end if - if(.not.associated(mat)) return + else + if (ceTrackingCache(1) % E == p % E) then + flux = p % w / ceTrackingCache(1) % xs + else + call fatalError(Here, 'CE tracking cache failed to update during tracking') + end if + + end if + + else + + if (virtual) return + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) + + end if + + ! Ensure we're not in void (could happen when scoring virtual collisions) + if (p % matIdx() == VOID_MAT) return + + ! Get material pointer + mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) + if (.not.associated(mat)) then + call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') + end if ! Return if material is not fissile - if(.not.mat % isFissile()) return + if (.not. mat % isFissile()) return ! Find starting index in the map - sIdx = self % map % map( p % preHistory) + sIdx = self % map % map(p % preHistory) ! Find collision index in the map state = p @@ -217,7 +256,7 @@ subroutine reportInColl(self, p, xsData, mem, virtual) if(cIdx == 0 .or. sIdx == 0 ) return ! Calculate fission neutron production - score = self % resp % get(p, xsData) * p % w / xsData % getTotalMatXS(p, p % matIdx()) + score = self % resp % get(p, xsData) * flux ! Score element of the matrix addr = self % getMemAddress() + (sIdx - 1) * self % N + cIdx - 1 @@ -387,7 +426,10 @@ elemental subroutine kill(self) if(allocated(self % map)) deallocate(self % map) if(allocated(self % startWgt)) deallocate(self % startWgt) + self % N = 0 + self % virtual = .false. + call self % resp % kill() end subroutine kill diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 30d4b1e03..5fbdb624c 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -47,7 +47,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) character(100), parameter :: Here = 'deltaTracking (transportOperatorDT_class.f90)' ! Get majorant XS inverse: 1/Sigma_majorant - majorant_inv = ONE / self % xsData % getMajorantXS(p) + majorant_inv = ONE / self % xsData % getTrackingXS(p, p % matIdx(), MAJORANT_XS) ! Should never happen! Prevents Inf distances if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") @@ -66,7 +66,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Check for void - if(p % matIdx() == VOID_MAT) then + if (p % matIdx() == VOID_MAT) then call tally % reportInColl(p, .true.) cycle DTLoop end if @@ -78,7 +78,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Obtain the local cross-section - sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual ! Exit the loop if the collision is real, report collision if virtual diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index f9cdfc378..3fc60ee1a 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -64,10 +64,10 @@ subroutine tracking_selection(self, p, tally, thisCycle, nextCycle) character(100), parameter :: Here = 'hybridTracking (transportOIperatorHT_class.f90)' ! Get majornat XS inverse: 1/Sigma_majorant - majorant_inv = ONE / self % xsData % getMajorantXS(p) + majorant_inv = ONE / self % xsData % getTrackingXS(p, p % matIdx(), MAJORANT_XS) ! Obtain the local cross-section - sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) ! Calculate ratio between local cross-section and majorant ratio = sigmaT*majorant_inv @@ -92,7 +92,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) character(100), parameter :: Here = 'deltaTracking (transportOperatorHT_class.f90)' ! Get majorant XS inverse: 1/Sigma_majorant - majorant_inv = ONE / self % xsData % getMajorantXS(p) + majorant_inv = ONE / self % xsData % getTrackingXS(p, p % matIdx(), MAJORANT_XS) ! Should never happen! Prevents Inf distances if (abs(majorant_inv) > huge(majorant_inv)) call fatalError(Here, "Majorant is 0") @@ -123,7 +123,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Obtain the local cross-section - sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual ! Exit the loop if the collision is real, report collision if virtual @@ -152,11 +152,11 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) STLoop: do ! Obtain the local cross-section - if( p % matIdx() == VOID_MAT) then + if (p % matIdx() == VOID_MAT) then dist = INFINITY else - sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTrackingXS(p, p % matIdx(), MATERIAL_XS) dist = -log( p % pRNG % get()) / sigmaT ! Should never happen! Catches NaN distances @@ -174,7 +174,7 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) call tally % reportPath(p, dist) ! Kill particle if it has leaked - if( p % matIdx() == OUTSIDE_FILL) then + if (p % matIdx() == OUTSIDE_FILL) then p % isDead = .true. p % fate = LEAK_FATE end if @@ -186,7 +186,7 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) end if ! Return if particle stoped at collision (not cell boundary) - if( event == COLL_EV .or. p % isDead) exit STLoop + if (event == COLL_EV .or. p % isDead) exit STLoop end do STLoop diff --git a/TransportOperator/transportOperatorST_class.f90 b/TransportOperator/transportOperatorST_class.f90 index c7eb24428..0d3571542 100644 --- a/TransportOperator/transportOperatorST_class.f90 +++ b/TransportOperator/transportOperatorST_class.f90 @@ -59,11 +59,11 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) STLoop: do ! Obtain the local cross-section - if( p % matIdx() == VOID_MAT) then + if (p % matIdx() == VOID_MAT) then dist = INFINITY else - sigmaT = self % xsData % getTransMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTrackingXS(p, p % matIdx(), MATERIAL_XS) dist = -log( p % pRNG % get()) / sigmaT ! Should never happen! Catches NaN distances @@ -87,7 +87,7 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) call tally % reportPath(p, dist) ! Kill particle if it has leaked - if( p % matIdx() == OUTSIDE_FILL) then + if (p % matIdx() == OUTSIDE_FILL) then p % isDead = .true. p % fate = LEAK_FATE end if @@ -99,7 +99,7 @@ subroutine surfaceTracking(self, p, tally, thisCycle, nextCycle) end if ! Return if particle stoped at collision (not cell boundary) - if( event == COLL_EV .or. p % isDead) exit STLoop + if (event == COLL_EV .or. p % isDead) exit STLoop end do STLoop From baf1e3e9c7bf668876b5ee7669ce55f04881faf8 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 7 Feb 2024 17:19:23 +0000 Subject: [PATCH 100/133] Update tests related to virtual collisions --- .../aceDatabase/Tests/aceNeutronDatabase_iTest.f90 | 6 ++++-- .../baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 | 9 +++++---- .../testNeutronData/testNeutronDatabase_class.f90 | 9 +++++---- Tallies/TallyClerks/Tests/collisionClerk_test.f90 | 7 +++++++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 index a09f554d3..eaf870a0c 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 @@ -206,7 +206,7 @@ subroutine test_aceNeutronDatabase() @assertEqual(ONE, data % getTotalMatXS(p , 1)/1.1406745607419302_defReal , TOL) p % E = 19.9_defReal - @assertEqual(ONE, data % getTransMatXS(p , 1)/6.539039844E-02_defReal , TOL) + @assertEqual(ONE, data % getTrackingXS(p, 1, MATERIAL_XS)/6.539039844E-02_defReal , TOL) ! Total XS of UO2 @@ -214,14 +214,16 @@ subroutine test_aceNeutronDatabase() @assertEqual(ONE, data % getTotalMatXS(p , 2)/4.4149556129495560_defReal , TOL) p % E = 19.9_defReal - @assertEqual(ONE, data % getTransMatXS(p , 2)/0.21869599644_defReal , TOL) + @assertEqual(ONE, data % getTrackingXS(p , 2, MATERIAL_XS)/0.21869599644_defReal , TOL) ! Majorant p % E = 1.1E-6_defReal @assertEqual(ONE, data % getMajorantXS(p) /4.4149556129495560_defReal , TOL) + @assertEqual(ONE, data % getTrackingXS(p , 3, MAJORANT_XS) /4.4149556129495560_defReal , TOL) p % E = 19.9_defReal @assertEqual(ONE, data % getMajorantXS(p)/0.21869599644_defReal , TOL) + @assertEqual(ONE, data % getTrackingXS(p , 3, MAJORANT_XS) /0.21869599644_defReal , TOL) !<><><><><><><><><><><><><><><><><><><><> ! Test getting Macroscopic XSs diff --git a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 index 13aa797d0..d08a1b1fd 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/Tests/baseMgNeutronDatabase_iTest.f90 @@ -3,6 +3,7 @@ module baseMgNeutronDatabase_iTest use numPrecision use endfConstants use pFUnit_mod + use universalVariables use dictionary_class, only : dictionary use dictParser_func, only : charToDict use particle_class, only : particle @@ -81,7 +82,7 @@ subroutine testBaseMgNeutronDatabaseWithP0() ! Test getting Transport XS p % G = 1 - @assertEqual(2.1_defReal, database % getTransMatXS(p, 1), TOL) + @assertEqual(2.1_defReal, database % getTrackingXS(p, 1, MATERIAL_XS), TOL) ! Test getting Total XS p % G = 1 @@ -93,7 +94,7 @@ subroutine testBaseMgNeutronDatabaseWithP0() ! Test getting Majorant p % G = 1 @assertEqual(2.1_defReal, database % getMajorantXS(p), TOL) - + @assertEqual(2.1_defReal, database % getTrackingXS(p, 1, MAJORANT_XS), TOL) ! Get a material and verify macroXSS mat => baseMgNeutronMaterial_TptrCast(database % getMaterial(2)) @@ -207,7 +208,7 @@ subroutine testBaseMgNeutronDatabaseWithP1() ! Test getting Transport XS p % G = 1 - @assertEqual(2.1_defReal, database % getTransMatXS(p, 1), TOL) + @assertEqual(2.1_defReal, database % getTrackingXS(p, 1, MATERIAL_XS), TOL) ! Test getting Total XS p % G = 1 @@ -219,7 +220,7 @@ subroutine testBaseMgNeutronDatabaseWithP1() ! Test getting Majorant p % G = 1 @assertEqual(2.1_defReal, database % getMajorantXS(p), TOL) - + @assertEqual(2.1_defReal, database % getTrackingXS(p, 1, MAJORANT_XS), TOL) ! Get a material and verify macroXSS mat => baseMgNeutronMaterial_TptrCast(database % getMaterial(2)) diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index 239f9384f..74b56b201 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -44,7 +44,7 @@ module testNeutronDatabase_class ! Superclass Interface procedure :: init procedure :: activate - procedure :: getTransMatXS + procedure :: getTrackingXS procedure :: getTotalMatXS procedure :: getMajorantXS procedure :: matNamesMap @@ -162,19 +162,20 @@ subroutine activate(self, activeMat) end subroutine activate !! - !! Return value of Material Transport XS for a particle + !! Return value of Tracking XS for a particle and a given request !! !! See nuclearDatabase_inter for details !! - function getTransMatXS(self, p, matIdx) result(xs) + function getTrackingXS(self, p, matIdx, what) result(xs) class(testNeutronDatabase), intent(inout) :: self class(particle), intent(in) :: p integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(in) :: what real(defReal) :: xs xs = self % xsVal - end function getTransMatXS + end function getTrackingXS !! !! Return value of Material Total XS for a particle diff --git a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 index 210178c8e..d688c8bfd 100644 --- a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 @@ -8,6 +8,7 @@ module collisionClerk_test use scoreMemory_class, only : scoreMemory use testNeutronDatabase_class, only : testNeutronDatabase use outputFile_class, only : outputFile + use ceNeutronCache_mod, only: cache_init => init, trackingCache use pFUnit_mod implicit none @@ -321,10 +322,16 @@ subroutine testScoringVirtual(this) ! Build nuclear data call nucData % build(0.3_defReal) + ! Build cache + call cache_init(1, 1, 1) + trackingCache % xs = 0.3_defReal + trackingCache % E = 10.0_defReal ! Perform scoring, both virtual and physical should contribute call p % setMatIdx(1) p % w = 0.7_defReal + p % E = 10.0_defReal + p % isMG = .false. call clerk % reportInColl(p, nucData, mem, .true.) call p % setMatIdx(6) From 5434e5803029ab8d57badbe7f85f1640e7ab8642 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:45:30 +0000 Subject: [PATCH 101/133] Update User Manual.rst --- docs/User Manual.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index b772dab77..1d97726f4 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -951,12 +951,14 @@ Example: :: * keffAnalogClerk, analog k_eff estimator * keffImplicitClerk, implicit k_eff estimator + - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions + are tallied with a collisionClerk as well as physical collisions Example: :: tally { k_eff1 { type keffAnalogClerk; } - k_eff2 { type keffImplicitClerk; } + k_eff2 { type keffImplicitClerk; handleVirtual 1; } } * centreOfMassClerk, geometrical 3D center of mass estimator @@ -1003,6 +1005,8 @@ Example: :: tally map - PN (*optional*, default = 0): 1 for true; 0 for false; flag that indicates whether to calculate scattering matrices only up to P1 (``PN 0``) or P7 (``PN 1``) + - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions + are tallied with a collisionClerk as well as physical collisions Example: :: @@ -1031,6 +1035,8 @@ Example: :: - map: contains a dictionary with the ``tallyMap`` definition, that defines the bins of the matrix + - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions + are tallied with a collisionClerk as well as physical collisions Example: :: From bd1417bcd9030332c614b2d42b7bae48b5e6da18 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Wed, 14 Feb 2024 16:29:45 +0000 Subject: [PATCH 102/133] Simplifying logic to read tracking xs --- .../ceNeutronData/ceNeutronDatabase_inter.f90 | 9 +++++++ .../baseMgNeutronDatabase_class.f90 | 11 +++++++- SharedModules/universalVariables.f90 | 3 ++- Tallies/TallyClerks/collisionClerk_class.f90 | 26 ++----------------- .../TallyClerks/keffImplicitClerk_class.f90 | 25 +----------------- Tallies/TallyClerks/mgXsClerk_class.f90 | 25 +----------------- Tallies/TallyClerks/simpleFMClerk_class.f90 | 25 +----------------- 7 files changed, 26 insertions(+), 98 deletions(-) diff --git a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 index c80397660..1050c5d5b 100644 --- a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 @@ -247,6 +247,15 @@ function getTrackingXS(self, p, matIdx, what) result(xs) case (MAJORANT_XS) xs = self % getMajorantXS(p) + case (TRACKING_XS) + + ! READ ONLY - read from previously updated cache + if (p % E == trackingCache(1) % E) then + xs = trackingCache(1) % xs + else + call fatalError(Here, 'Tracking cache failed to update during tracking') + end if + case default call fatalError(Here, 'Neither material xs nor majorant xs was asked') diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index ad58c8753..771d0b730 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -107,8 +107,17 @@ function getTrackingXS(self, p, matIdx, what) result(xs) case (MAJORANT_XS) xs = self % getMajorantXS(p) + case (TRACKING_XS) + + ! READ ONLY - read from previously updated cache + if (p % G == trackingCache(1) % G) then + xs = trackingCache(1) % xs + else + call fatalError(Here, 'Tracking cache failed to update during tracking') + end if + case default - call fatalError(Here, 'Neither material xs nor majorant xs was asked') + call fatalError(Here, 'Neither material nor majorant xs was asked') end select diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index 3fda3f0dc..81250f3f5 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -71,7 +71,8 @@ module universalVariables ! Integer indexes for type of tracking cross section requested integer(shortInt), parameter :: MATERIAL_XS = 1, & - MAJORANT_XS = 2 + MAJORANT_XS = 2, & + TRACKING_XS = 3 ! Physical constants real(defReal), parameter :: neutronMass = 939.5654133_defReal, & ! Neutron mass in MeV/c^2 diff --git a/Tallies/TallyClerks/collisionClerk_class.f90 b/Tallies/TallyClerks/collisionClerk_class.f90 index d51db3acc..0c37c9c11 100644 --- a/Tallies/TallyClerks/collisionClerk_class.f90 +++ b/Tallies/TallyClerks/collisionClerk_class.f90 @@ -2,6 +2,7 @@ module collisionClerk_class use numPrecision use tallyCodes + use universalVariables use genericProcedures, only : fatalError use dictionary_class, only : dictionary use particle_class, only : particle, particleState @@ -23,10 +24,6 @@ module collisionClerk_class ! Tally Responses use tallyResponseSlot_class, only : tallyResponseSlot - ! Cache - use ceNeutronCache_mod, only : ceTrackingCache => trackingCache - use mgNeutronCache_mod, only : mgTrackingCache => trackingCache - implicit none private @@ -203,30 +200,11 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if collision is virtual but virtual collision handling is off if (self % virtual) then - ! Retrieve tracking cross section from cache - ! Select over CE and MG cache, and give error if cache was not updated properly - if (p % isMG) then - if (mgTrackingCache(1) % G == p % G) then - flux = p % w / mgTrackingCache(1) % xs - else - call fatalError(Here, 'MG tracking cache failed to update during tracking') - end if - - else - if (ceTrackingCache(1) % E == p % E) then - flux = p % w / ceTrackingCache(1) % xs - else - call fatalError(Here, 'CE tracking cache failed to update during tracking') - end if - - end if - + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) else - if (virtual) return flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if ! Get current particle state diff --git a/Tallies/TallyClerks/keffImplicitClerk_class.f90 b/Tallies/TallyClerks/keffImplicitClerk_class.f90 index 33d34c769..ad5f52e21 100644 --- a/Tallies/TallyClerks/keffImplicitClerk_class.f90 +++ b/Tallies/TallyClerks/keffImplicitClerk_class.f90 @@ -22,10 +22,6 @@ module keffImplicitClerk_class use tallyClerk_inter, only : tallyClerk, kill_super => kill use keffAnalogClerk_class, only : keffResult - ! Cache - use ceNeutronCache_mod, only : ceTrackingCache => trackingCache - use mgNeutronCache_mod, only : mgTrackingCache => trackingCache - implicit none private @@ -174,30 +170,11 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if collision is virtual but virtual collision handling is off if (self % virtual) then - ! Retrieve tracking cross section from cache - ! Select over CE and MG cache, and give error if cache was not updated properly - if (p % isMG) then - if (mgTrackingCache(1) % G == p % G) then - flux = p % w / mgTrackingCache(1) % xs - else - call fatalError(Here, 'MG tracking cache failed to update during tracking') - end if - - else - if (ceTrackingCache(1) % E == p % E) then - flux = p % w / ceTrackingCache(1) % xs - else - call fatalError(Here, 'CE tracking cache failed to update during tracking') - end if - - end if - + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) else - if (virtual) return flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if ! Ensure we're not in void (could happen when scoring virtual collisions) diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index 277676c07..b3199f117 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -23,10 +23,6 @@ module mgXsClerk_class use scoreMemory_class, only : scoreMemory use tallyClerk_inter, only : tallyClerk, kill_super => kill - ! Cache - use ceNeutronCache_mod, only : ceTrackingCache => trackingCache - use mgNeutronCache_mod, only : mgTrackingCache => trackingCache - implicit none private @@ -233,30 +229,11 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if collision is virtual but virtual collision handling is off if (self % virtual) then - ! Retrieve tracking cross section from cache - ! Select over CE and MG cache, and give error if cache was not updated properly - if (p % isMG) then - if (mgTrackingCache(1) % G == p % G) then - flux = p % w / mgTrackingCache(1) % xs - else - call fatalError(Here, 'MG tracking cache failed to update during tracking') - end if - - else - if (ceTrackingCache(1) % E == p % E) then - flux = p % w / ceTrackingCache(1) % xs - else - call fatalError(Here, 'CE tracking cache failed to update during tracking') - end if - - end if - + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) else - if (virtual) return flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if ! Get current particle state diff --git a/Tallies/TallyClerks/simpleFMClerk_class.f90 b/Tallies/TallyClerks/simpleFMClerk_class.f90 index 678317d11..93c72fe2e 100644 --- a/Tallies/TallyClerks/simpleFMClerk_class.f90 +++ b/Tallies/TallyClerks/simpleFMClerk_class.f90 @@ -26,10 +26,6 @@ module simpleFMClerk_class ! Tally Response use macroResponse_class, only : macroResponse - ! Cache - use ceNeutronCache_mod, only : ceTrackingCache => trackingCache - use mgNeutronCache_mod, only : mgTrackingCache => trackingCache - implicit none private @@ -207,30 +203,11 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if collision is virtual but virtual collision handling is off if (self % virtual) then - ! Retrieve tracking cross section from cache - ! Select over CE and MG cache, and give error if cache was not updated properly - if (p % isMG) then - if (mgTrackingCache(1) % G == p % G) then - flux = p % w / mgTrackingCache(1) % xs - else - call fatalError(Here, 'MG tracking cache failed to update during tracking') - end if - - else - if (ceTrackingCache(1) % E == p % E) then - flux = p % w / ceTrackingCache(1) % xs - else - call fatalError(Here, 'CE tracking cache failed to update during tracking') - end if - - end if - + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) else - if (virtual) return flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if ! Ensure we're not in void (could happen when scoring virtual collisions) From 2117644fde748f8469ff1e9dcb34e3308af89648 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Fri, 5 Apr 2024 10:35:17 +0100 Subject: [PATCH 103/133] Add OECD source convergence benchmark problem 1 --- .../MCNP}/BIGTEN | 0 .../MCNP}/Falstaff | 0 .../MCNP}/Flattop23 | 0 .../MCNP}/Flattop25 | 0 .../MCNP}/FlattopPu | 0 .../MCNP}/Godiva | 0 .../MCNP}/IEUMF03 | 0 .../MCNP}/IEUMF04 | 0 .../MCNP}/Jezebel | 0 .../MCNP}/Jezebel233 | 0 .../MCNP}/Jezebel240 | 0 .../MCNP}/LEUST02 | 0 .../MCNP}/ORNL10 | 0 .../MCNP}/ORNL11 | 0 .../{BenchmarksMCNP => Benchmarks/MCNP}/PNL2 | 0 .../MCNP}/PUMF11 | 0 .../{BenchmarksMCNP => Benchmarks/MCNP}/SB212 | 0 .../MCNP}/Tinkertoy2 | 0 .../MCNP}/U233MF05 | 0 .../Benchmarks/SourceConvergence/checkerboard | 221 ++++++++++++++++++ 20 files changed, 221 insertions(+) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/BIGTEN (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Falstaff (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Flattop23 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Flattop25 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/FlattopPu (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Godiva (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/IEUMF03 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/IEUMF04 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Jezebel (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Jezebel233 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Jezebel240 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/LEUST02 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/ORNL10 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/ORNL11 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/PNL2 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/PUMF11 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/SB212 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/Tinkertoy2 (100%) rename InputFiles/{BenchmarksMCNP => Benchmarks/MCNP}/U233MF05 (100%) create mode 100644 InputFiles/Benchmarks/SourceConvergence/checkerboard diff --git a/InputFiles/BenchmarksMCNP/BIGTEN b/InputFiles/Benchmarks/MCNP/BIGTEN similarity index 100% rename from InputFiles/BenchmarksMCNP/BIGTEN rename to InputFiles/Benchmarks/MCNP/BIGTEN diff --git a/InputFiles/BenchmarksMCNP/Falstaff b/InputFiles/Benchmarks/MCNP/Falstaff similarity index 100% rename from InputFiles/BenchmarksMCNP/Falstaff rename to InputFiles/Benchmarks/MCNP/Falstaff diff --git a/InputFiles/BenchmarksMCNP/Flattop23 b/InputFiles/Benchmarks/MCNP/Flattop23 similarity index 100% rename from InputFiles/BenchmarksMCNP/Flattop23 rename to InputFiles/Benchmarks/MCNP/Flattop23 diff --git a/InputFiles/BenchmarksMCNP/Flattop25 b/InputFiles/Benchmarks/MCNP/Flattop25 similarity index 100% rename from InputFiles/BenchmarksMCNP/Flattop25 rename to InputFiles/Benchmarks/MCNP/Flattop25 diff --git a/InputFiles/BenchmarksMCNP/FlattopPu b/InputFiles/Benchmarks/MCNP/FlattopPu similarity index 100% rename from InputFiles/BenchmarksMCNP/FlattopPu rename to InputFiles/Benchmarks/MCNP/FlattopPu diff --git a/InputFiles/BenchmarksMCNP/Godiva b/InputFiles/Benchmarks/MCNP/Godiva similarity index 100% rename from InputFiles/BenchmarksMCNP/Godiva rename to InputFiles/Benchmarks/MCNP/Godiva diff --git a/InputFiles/BenchmarksMCNP/IEUMF03 b/InputFiles/Benchmarks/MCNP/IEUMF03 similarity index 100% rename from InputFiles/BenchmarksMCNP/IEUMF03 rename to InputFiles/Benchmarks/MCNP/IEUMF03 diff --git a/InputFiles/BenchmarksMCNP/IEUMF04 b/InputFiles/Benchmarks/MCNP/IEUMF04 similarity index 100% rename from InputFiles/BenchmarksMCNP/IEUMF04 rename to InputFiles/Benchmarks/MCNP/IEUMF04 diff --git a/InputFiles/BenchmarksMCNP/Jezebel b/InputFiles/Benchmarks/MCNP/Jezebel similarity index 100% rename from InputFiles/BenchmarksMCNP/Jezebel rename to InputFiles/Benchmarks/MCNP/Jezebel diff --git a/InputFiles/BenchmarksMCNP/Jezebel233 b/InputFiles/Benchmarks/MCNP/Jezebel233 similarity index 100% rename from InputFiles/BenchmarksMCNP/Jezebel233 rename to InputFiles/Benchmarks/MCNP/Jezebel233 diff --git a/InputFiles/BenchmarksMCNP/Jezebel240 b/InputFiles/Benchmarks/MCNP/Jezebel240 similarity index 100% rename from InputFiles/BenchmarksMCNP/Jezebel240 rename to InputFiles/Benchmarks/MCNP/Jezebel240 diff --git a/InputFiles/BenchmarksMCNP/LEUST02 b/InputFiles/Benchmarks/MCNP/LEUST02 similarity index 100% rename from InputFiles/BenchmarksMCNP/LEUST02 rename to InputFiles/Benchmarks/MCNP/LEUST02 diff --git a/InputFiles/BenchmarksMCNP/ORNL10 b/InputFiles/Benchmarks/MCNP/ORNL10 similarity index 100% rename from InputFiles/BenchmarksMCNP/ORNL10 rename to InputFiles/Benchmarks/MCNP/ORNL10 diff --git a/InputFiles/BenchmarksMCNP/ORNL11 b/InputFiles/Benchmarks/MCNP/ORNL11 similarity index 100% rename from InputFiles/BenchmarksMCNP/ORNL11 rename to InputFiles/Benchmarks/MCNP/ORNL11 diff --git a/InputFiles/BenchmarksMCNP/PNL2 b/InputFiles/Benchmarks/MCNP/PNL2 similarity index 100% rename from InputFiles/BenchmarksMCNP/PNL2 rename to InputFiles/Benchmarks/MCNP/PNL2 diff --git a/InputFiles/BenchmarksMCNP/PUMF11 b/InputFiles/Benchmarks/MCNP/PUMF11 similarity index 100% rename from InputFiles/BenchmarksMCNP/PUMF11 rename to InputFiles/Benchmarks/MCNP/PUMF11 diff --git a/InputFiles/BenchmarksMCNP/SB212 b/InputFiles/Benchmarks/MCNP/SB212 similarity index 100% rename from InputFiles/BenchmarksMCNP/SB212 rename to InputFiles/Benchmarks/MCNP/SB212 diff --git a/InputFiles/BenchmarksMCNP/Tinkertoy2 b/InputFiles/Benchmarks/MCNP/Tinkertoy2 similarity index 100% rename from InputFiles/BenchmarksMCNP/Tinkertoy2 rename to InputFiles/Benchmarks/MCNP/Tinkertoy2 diff --git a/InputFiles/BenchmarksMCNP/U233MF05 b/InputFiles/Benchmarks/MCNP/U233MF05 similarity index 100% rename from InputFiles/BenchmarksMCNP/U233MF05 rename to InputFiles/Benchmarks/MCNP/U233MF05 diff --git a/InputFiles/Benchmarks/SourceConvergence/checkerboard b/InputFiles/Benchmarks/SourceConvergence/checkerboard new file mode 100644 index 000000000..06efea5ac --- /dev/null +++ b/InputFiles/Benchmarks/SourceConvergence/checkerboard @@ -0,0 +1,221 @@ +type eigenPhysicsPackage; + +pop 100000; +active 200; +inactive 3000; +XSdata ce; +dataType ce; + +// Specify output format default asciiMATLAB +//outputFormat asciiJSON; + +collisionOperator { neutronCE {type neutronCEstd;} } + +transportOperator { //type transportOperatorDT; + cache 1; + // type transportOperatorST; + type transportOperatorHT; + } + +inactiveTally { + shannon { + type shannonEntropyClerk; + map {type multiMap; + maps (xax yax zax); + xax { type spaceMap; grid lin; min -324; max 324; N 24; axis x;} + yax { type spaceMap; grid lin; min -45.5; max 35.5; N 3; axis y;} + zax { type spaceMap; grid lin; min -180.0; max 180; N 10; axis z;} + } + cycles 3000; + } + +} + +activeTally { + totalPow { type collisionClerk; response (fission); fission { type macroResponse; MT -6;}} + ResMap {type collisionClerk; + map {type multiMap; + maps (xax yax); + xax { type spaceMap; grid lin; min -324; max 324; N 24; axis x;} + yax { type spaceMap; grid lin; min -45.5; max 35.5; N 3; axis y;} + } + response (fission); + fission { type macroResponse; MT -6;} + } +} + +geometry { + type geometryStd; + boundary ( 0 0 0 0 0 0); + graph {type shrunk;} + + surfaces { + ! Geometry boundary + boundary { id 1; type box; origin (0.0 0.0 0.0); halfwidth (364 75.5 210.0);} + + ! Lattice boundary + checkerBoundary {id 2; type box; origin (0.0 -0.5 0.0); halfwidth (324 40.5 180 );} + + ! Boundary of the wet region + wetBoundary {id 3; type box; origin (0.0 -15.5 0.0); halfwidth (324 55.5 210);} + + ! Assembly surfaces + assemblyOuter {id 4; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (10.5 10.5 0.0);} + waterOuter {id 5; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (13.0 13.0 0.0);} + + + } + + cells { + checker {id 1; type simpleCell; surfaces ( -2); filltype uni; universe 11;} + water {id 2; type simpleCell; surfaces (2); filltype mat; material water;} + concrete {id 3; type simpleCell; surfaces (3); filltype mat; material concrete;} + wetCell {id 4; type simpleCell; surfaces (-3); filltype uni; universe 9;} + + ! Assembly cells + assemblyInner {id 5; type simpleCell; surfaces (-4); filltype uni; universe 10;} + waterGap {id 6; type simpleCell; surfaces (4 -5); filltype mat; material water;} + steelLiner {id 7; type simpleCell; surfaces (5); filltype mat; material steel;} + waterOnly {id 8; type simpleCell; surfaces (-5); filltype mat; material water;} + + } + + universes { + root { id 1; type rootUniverse; border 1; fill u<8>; } + + // Cell universes + everything {id 8; type cellUniverse; cells (3 4);} + wetUni {id 9; type cellUniverse; cells (1 2);} + assemblyUni {id 7; type cellUniverse; cells (5 6 7 );} + channelUni {id 6; type cellUniverse; cells (7 8);} + + + // Pin universes + pin { id 5; type pinUniverse; radii (0.440 0.49 0.0 ); fills (fuel clad water);} + + // Lattices + assembly { + id 10; + type latUniverse; + origin (0.0 0 0.0); + pitch (1.4 1.4 0.0); + shape (15 15 0); + padMat water; + map ( + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + ); } + + checker { + id 11; + type latUniverse; + origin (0.0 -0.5 0.0); + pitch (27 27 0); + shape (24 3 0); + padMat steel; + map ( + 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 + 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 + 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 + ); + } + + + + + } + +} + + +viz { + myVTK { + type vtk; + corner (-364 -75.5 -210); + width (728 151 420); + vox (300 100 200); + } + bmp { + type bmp; + output xy; + what material; + centre (0.0 0.0 0.0); + //width (25.0 25.0); + axis z; + //offset -17; + res (5000 1000); + } + bmp2 { + type bmp; + output xz; + what material; + centre (0.0 0.0 0.0); + //width (25.0 25.0); + axis y; + //offset -17; + res (5000 3000); + } +} + + +nuclearData { + handles { + ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE;} + } + materials { + + water { + temp 75675; + rgb (0 0 139); // Colour of water is dark blue + moder { 1001.03 lwj3.00; } + composition { + 1001.03 6.6706E-002; + 8016.03 3.350E-002; + } + } + + clad { + temp 12345; + composition { + 40000.03 4.291E-002; + } + } + + fuel { + temp 87476; + composition { + 92235.03 8.2213E-004; + 92238.03 2.238E-002; + 8016.03 4.6054E-002; } + } + concrete { + temp 6786; + composition { + 1001.03 5.5437E-03; + 6012.03 6.9793E-03; + 14000.03 7.7106E-03; + 20000.03 8.9591E-03; + 8016.03 4.3383E-002;} + } + steel { + temp 8765; + composition { + 26000.03 8.377E-02; + } + } + +} +} From fffd655c524692d0da0d99a4119df15208abc46b Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Fri, 5 Apr 2024 22:54:55 +0100 Subject: [PATCH 104/133] Add BEAVRS (2/3D) and Source Conv. Benchmark 1 --- InputFiles/Benchmarks/BEAVRS/BEAVRS | 2262 +++++++++++++++++ InputFiles/Benchmarks/BEAVRS/BEAVRS2D | 1581 ++++++++++++ .../Benchmarks/SourceConvergence/checkerboard | 10 +- 3 files changed, 3852 insertions(+), 1 deletion(-) create mode 100644 InputFiles/Benchmarks/BEAVRS/BEAVRS create mode 100644 InputFiles/Benchmarks/BEAVRS/BEAVRS2D diff --git a/InputFiles/Benchmarks/BEAVRS/BEAVRS b/InputFiles/Benchmarks/BEAVRS/BEAVRS new file mode 100644 index 000000000..3c7cb89de --- /dev/null +++ b/InputFiles/Benchmarks/BEAVRS/BEAVRS @@ -0,0 +1,2262 @@ +!! +!! 3D BEAVRS benchmark +!! This is not a fully faithful replica of BEAVRS at HZP: +!! all rods are fully out and the temperature is 600K. +!! In reality, some rods are partially inserted and the +!! isothermal temperature is 566K. +!! TODO: add rods in the appropriate assemblies at the +!! correct heights! +!! TODO: modify fuel temperature data to 300K and +!! Doppler broaden to 566K. +!! +type eigenPhysicsPackage; + +pop 10000000; +active 50; +inactive 200; +XSdata ce; +dataType ce; + +collisionOperator { neutronCE {type neutronCEstd;}} + +transportOperator { + !type transportOperatorDT; + type transportOperatorHT; cache 1; + } + +inactiveTally { + shannon { + type shannonEntropyClerk; + map {type multiMap; + maps (xax yax zax); + xax { type spaceMap; grid lin; min -161.2773; max 161.2773; N 15; axis x;} + yax { type spaceMap; grid lin; min -161.2773; max 161.2773; N 15; axis y;} + zax { type spaceMap; grid lin; min 36.748; max 402.508; N 15; axis z;} + } + cycles 200; + } + +} + +activeTally { + pinFissRadial { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax); + xax {type spaceMap; axis x; grid lin; N 255; min -161.2773; max 161.2773; } + yax {type spaceMap; axis y; grid lin; N 255; min -161.2773; max 161.2773; } + } + } + assemblyFissRadial { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax); + xax {type spaceMap; axis x; grid lin; N 15; min -161.2773; max 161.2773; } + yax {type spaceMap; axis y; grid lin; N 15; min -161.2773; max 161.2773; } + } + } + fissionAxial { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type spaceMap; axis z; grid lin; N 60; min 36.748; max 402.508;} + } + fissionYZ { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (yax zax); + yax {type spaceMap; axis y; grid lin; N 255; min -161.2773; max 161.2773; } + zax {type spaceMap; axis z; grid lin; N 60; min 36.748; max 402.508;} + } + } +} + +geometry { + type geometryStd; + boundary ( 0 0 0 0 0 0); + graph {type shrunk;} + + surfaces { + + // thickness specifications for RPV and RPV liner + outerRPV { id 1; type zTruncCylinder; radius 241.3; origin (0.0 0.0 230.0); halfwidth 230; } + innerRPV { id 2; type zCylinder; radius 219.710; origin (0.0 0.0 0.0); } + innerRPVLiner { id 3; type zCylinder; radius 219.150; origin (0.0 0.0 0.0); } + + // thickness specifications for neutron shield + outerBoundNS { id 4; type zCylinder; radius 201.630; origin (0.0 0.0 0.0); } + innerBoundNS { id 5; type zCylinder; radius 194.84; origin (0.0 0.0 0.0); } + + // thickness specifications for core barrel + outerCoreBarrel { id 6; type zCylinder; radius 193.675; origin (0.0 0.0 0.0); } + innerCoreBarrel { id 7; type zCylinder; radius 187.96; origin (0.0 0.0 0.0); } + + // four planes that intersect to bound the Neutron shield panel + P1 { id 8; type plane; coeffs (-0.48480962025 0.87461970714 0.0 0.0);} + P2 { id 9; type plane; coeffs (-0.87461970714 0.48480962025 0.0 0.0);} + P3 { id 10; type plane; coeffs (-0.87461970714 -0.48480962025 0.0 0.0);} + P4 { id 11; type plane; coeffs (-0.48480962025 -0.87461970714 0.0 0.0);} + + // bounding widths for baffle on various sides + // right & left refers to the side of the reactor that it is on + // close/away refers to its location in relation to the LATTICE it is a part of + // (NOT the reactor itself) + rightClose { id 50; type plane; coeffs (1.0 0.0 0.0 8.36662);} + rightAway { id 51; type plane; coeffs (1.0 0.0 0.0 10.58912);} + leftClose { id 52; type plane; coeffs (-1.0 0.0 0.0 8.36662);} + leftAway { id 53; type plane; coeffs (-1.0 0.0 0.0 10.58912);} + bottomClose { id 54; type plane; coeffs (0.0 -1.0 0.0 8.36662);} + bottomAway { id 55; type plane; coeffs (0.0 -1.0 0.0 10.58912);} + topClose { id 56; type plane; coeffs (0.0 1.0 0.0 8.36662);} + topAway { id 57; type plane; coeffs (0.0 1.0 0.0 10.58912);} + + // thickness specifications for grid with thickness of 0.0198cm (Inconel) + pinThickGridInner { id 90; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.61015 0.61015 0.0); } + pinThickGridOuter { id 91; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.62992 0.62992 0.0); } + + // thickness specifications for grid with thickness of 0.0194cm (Zircaloy) + pinThinGridInner { id 92; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.61049 0.61049 0.0); } + pinThinGridOuter { id 93; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.62992 0.62992 0.0); } + + // inner and outer surfaces of assembly sleeves (both SS and Zircaloy) + assemblySleeveInner { id 94; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (10.70864 10.70864 0.0); } + assemblySleeveOuter { id 95; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (10.74798 10.74798 0.0); } + + + // Axial planes across core height + // Names are based on axial heights + plane460 { id 100; type plane; coeffs (0.0 0.0 1.0 460.0 ); } + plane431p876 { id 101; type plane; coeffs (0.0 0.0 1.0 431.876); } + plane423p049 { id 102; type plane; coeffs (0.0 0.0 1.0 423.049); } + plane421p532 { id 103; type plane; coeffs (0.0 0.0 1.0 421.532); } + plane419p704 { id 104; type plane; coeffs (0.0 0.0 1.0 419.704); } + plane417p164 { id 105; type plane; coeffs (0.0 0.0 1.0 417.164); } + plane415p164 { id 106; type plane; coeffs (0.0 0.0 1.0 415.164); } + plane411p806 { id 107; type plane; coeffs (0.0 0.0 1.0 411.806); } + plane403p778 { id 108; type plane; coeffs (0.0 0.0 1.0 403.778); } + plane402p508 { id 109; type plane; coeffs (0.0 0.0 1.0 402.508); } + plane401p238 { id 110; type plane; coeffs (0.0 0.0 1.0 401.238); } + plane364p725 { id 111; type plane; coeffs (0.0 0.0 1.0 364.725); } + plane359p01 { id 112; type plane; coeffs (0.0 0.0 1.0 359.01 ); } + plane312p528 { id 113; type plane; coeffs (0.0 0.0 1.0 312.528); } + plane306p813 { id 114; type plane; coeffs (0.0 0.0 1.0 306.813); } + plane260p331 { id 115; type plane; coeffs (0.0 0.0 1.0 260.331); } + plane254p616 { id 116; type plane; coeffs (0.0 0.0 1.0 254.616); } + plane208p134 { id 117; type plane; coeffs (0.0 0.0 1.0 208.134); } + plane202p419 { id 118; type plane; coeffs (0.0 0.0 1.0 202.419); } + plane155p937 { id 119; type plane; coeffs (0.0 0.0 1.0 155.937); } + plane150p222 { id 120; type plane; coeffs (0.0 0.0 1.0 150.222); } + plane143p428 { id 121; type plane; coeffs (0.0 0.0 1.0 143.428); } + plane103p74 { id 122; type plane; coeffs (0.0 0.0 1.0 103.74 ); } + plane98p025 { id 123; type plane; coeffs (0.0 0.0 1.0 98.025 ); } + plane41p828 { id 124; type plane; coeffs (0.0 0.0 1.0 41.828 ); } + plane40p558 { id 125; type plane; coeffs (0.0 0.0 1.0 40.558 ); } + plane40p52 { id 126; type plane; coeffs (0.0 0.0 1.0 40.52 ); } + plane39p958 { id 127; type plane; coeffs (0.0 0.0 1.0 39.958 ); } + plane38p66 { id 128; type plane; coeffs (0.0 0.0 1.0 38.66 ); } + plane37p1621 { id 129; type plane; coeffs (0.0 0.0 1.0 37.1621); } + plane36p748 { id 130; type plane; coeffs (0.0 0.0 1.0 36.748 ); } + plane35 { id 131; type plane; coeffs (0.0 0.0 1.0 35.0 ); } + plane20 { id 132; type plane; coeffs (0.0 0.0 1.0 20.0 ); } + plane0 { id 133; type plane; coeffs (0.0 0.0 1.0 0.0 ); } + + planeSteelBottom { id 134; type plane; coeffs (0.0 0.0 1.0 400.638); } + planeCRLowerBottom { id 135; type plane; coeffs (0.0 0.0 1.0 402.508); } // same as 109 on withdrawal + planeCRUpperBottom { id 136; type plane; coeffs (0.0 0.0 1.0 504.108); } // out of core on withdrawal + + + } + + cells { + + // assembly wrappers and surrounding water at various heights + wrapper1 {type simpleCell; id 2001; surfaces (94 -95 129 -126); filltype mat; material SS304;} + wrapper2 {type simpleCell; id 2002; surfaces (94 -95 123 -122); filltype mat; material Zircaloy;} + wrapper3 {type simpleCell; id 2003; surfaces (94 -95 120 -119); filltype mat; material Zircaloy;} + wrapper4 {type simpleCell; id 2004; surfaces (94 -95 118 -117); filltype mat; material Zircaloy;} + wrapper5 {type simpleCell; id 2005; surfaces (94 -95 116 -115); filltype mat; material Zircaloy;} + wrapper6 {type simpleCell; id 2006; surfaces (94 -95 114 -113); filltype mat; material Zircaloy;} + wrapper7 {type simpleCell; id 2007; surfaces (94 -95 112 -111); filltype mat; material Zircaloy;} + wrapper8 {type simpleCell; id 2008; surfaces (94 -95 107 -106); filltype mat; material SS304;} + + assemWater0 {type simpleCell; id 2009; surfaces (94 -129); filltype mat; material Water;} + assemWater1 {type simpleCell; id 2010; surfaces (94 -95 126 -123); filltype mat; material Water;} + assemWater2 {type simpleCell; id 2011; surfaces (94 -95 122 -120); filltype mat; material Water;} + assemWater3 {type simpleCell; id 2012; surfaces (94 -95 119 -118); filltype mat; material Water;} + assemWater4 {type simpleCell; id 2013; surfaces (94 -95 117 -116); filltype mat; material Water;} + assemWater5 {type simpleCell; id 2014; surfaces (94 -95 115 -114); filltype mat; material Water;} + assemWater6 {type simpleCell; id 2015; surfaces (94 -95 113 -112); filltype mat; material Water;} + assemWater7 {type simpleCell; id 2016; surfaces (94 -95 111 -107); filltype mat; material Water;} + assemWater8 {type simpleCell; id 2017; surfaces (94 -95 106); filltype mat; material Water;} + assemWaterEx {type simpleCell; id 2018; surfaces (95); filltype mat; material Water;} + + // assemblies inside the wrappers + assem1424 {type simpleCell; id 2019; surfaces (-94); filltype uni; universe 1424;} + assem1416 {type simpleCell; id 2020; surfaces (-94); filltype uni; universe 1416;} + assem1431 {type simpleCell; id 2021; surfaces (-94); filltype uni; universe 1431;} + assem60316 {type simpleCell; id 2022; surfaces (-94); filltype uni; universe 60316;} + assem603112 {type simpleCell; id 2023; surfaces (-94); filltype uni; universe 603112;} + assem60313 {type simpleCell; id 2024; surfaces (-94); filltype uni; universe 60313;} + assem60319 {type simpleCell; id 2025; surfaces (-94); filltype uni; universe 60319;} + assem15315 {type simpleCell; id 2026; surfaces (-94); filltype uni; universe 15315;} + assem15317 {type simpleCell; id 2027; surfaces (-94); filltype uni; universe 15317;} + assem15311 {type simpleCell; id 2028; surfaces (-94); filltype uni; universe 15311;} + assem153111 {type simpleCell; id 2029; surfaces (-94); filltype uni; universe 153111;} + assem1631 {type simpleCell; id 2030; surfaces (-94); filltype uni; universe 1631;} + assem2031 {type simpleCell; id 2031; surfaces (-94); filltype uni; universe 2031;} + assem1224 {type simpleCell; id 2032; surfaces (-94); filltype uni; universe 1224;} + assem1624 {type simpleCell; id 2033; surfaces (-94); filltype uni; universe 1624;} + + // unrodded assemblies in wrappers + assem2424 {type simpleCell; id 2034; surfaces (-94); filltype uni; universe 2424;} + assem2416 {type simpleCell; id 2035; surfaces (-94); filltype uni; universe 2416;} + assem2431 {type simpleCell; id 2036; surfaces (-94); filltype uni; universe 2431;} + assem70316 {type simpleCell; id 2037; surfaces (-94); filltype uni; universe 70316;} + assem703112 {type simpleCell; id 2038; surfaces (-94); filltype uni; universe 703112;} + assem70313 {type simpleCell; id 2039; surfaces (-94); filltype uni; universe 70313;} + assem70319 {type simpleCell; id 2040; surfaces (-94); filltype uni; universe 70319;} + assem25315 {type simpleCell; id 2041; surfaces (-94); filltype uni; universe 25315;} + assem25317 {type simpleCell; id 2042; surfaces (-94); filltype uni; universe 25317;} + assem25311 {type simpleCell; id 2043; surfaces (-94); filltype uni; universe 25311;} + assem253111 {type simpleCell; id 2044; surfaces (-94); filltype uni; universe 253111;} + assem2631 {type simpleCell; id 2045; surfaces (-94); filltype uni; universe 2631;} + assem3031 {type simpleCell; id 2046; surfaces (-94); filltype uni; universe 3031;} + assem2224 {type simpleCell; id 2047; surfaces (-94); filltype uni; universe 2224;} + assem2624 {type simpleCell; id 2048; surfaces (-94); filltype uni; universe 2624;} + + // pin grids - thick at the top and bottom, thin in fuelled region + thickGrid {type simpleCell; id 555; surfaces (90 ); filltype mat; material Inconel;} + thinGrid {type simpleCell; id 556; surfaces (92 ); filltype mat; material Zircaloy;} + + pressureVessel { type simpleCell; id 7; surfaces (-1 2); filltype mat; material CarbonSteel;} + RPVLiner { type simpleCell; id 8; surfaces (-2 3); filltype mat; material SS304;} + outerWater1 {type simpleCell; id 9; surfaces (-3 4 ); filltype mat; material Water;} + + // Neutron shields + NS1 { type simpleCell; id 10; surfaces (-4 5 -8 9); filltype mat; material SS304;} + NS2 { type simpleCell; id 11; surfaces (-4 5 8 -9); filltype mat; material SS304;} + NS3 { type simpleCell; id 12; surfaces (-4 5 -10 11); filltype mat; material SS304;} + NS4 { type simpleCell; id 13; surfaces (-4 5 10 -11); filltype mat; material SS304;} + + // Water in the arc between neutron shields + outerWaterSeg1 {type simpleCell; id 14; surfaces (-4 5 ); filltype mat; material Water;} + outerWater2 {type simpleCell; id 15; surfaces (-5 6 ); filltype mat; material Water;} + + // Outer core + coreBarrel { type simpleCell; id 16; surfaces (-6 7); filltype mat; material SS304;} + core {type simpleCell; id 17; surfaces (-5); filltype uni; universe 9999;} + + + // Gridded pins + + // THICK GRID + // 2.4% in grid + grid24Thick {type simpleCell; id 253; surfaces (-90); filltype uni; universe 24000;} + // guide tube in grid + gridGTThick {type simpleCell; id 254; surfaces (-90); filltype uni; universe 12000;} + // 3.1% in grid + grid31Thick {type simpleCell; id 255; surfaces (-90); filltype uni; universe 31000;} + // 1.6 % in grid + grid16Thick {type simpleCell; id 256; surfaces (-90); filltype uni; universe 16000;} + // instrumentation tube in grid + gridITThick {type simpleCell; id 257; surfaces (-90); filltype uni; universe 14000;} + // empty GT at dashpot in grid + gridGTDPThick {type simpleCell; id 258; surfaces (-90); filltype uni; universe 1010;} + // pin upper fuel plenum in grid + gridFPPThick {type simpleCell; id 259; surfaces (-90); filltype uni; universe 1008;} + // stainless steel in guide tube in grid + gridSSGThick {type simpleCell; id 260; surfaces (-90); filltype uni; universe 1023;} + // stainless steel in dash pot in grid + gridSSDPThick {type simpleCell; id 261; surfaces (-90); filltype uni; universe 1024;} + // BP plenum in grid + gridBPPThick {type simpleCell; id 262; surfaces (-90); filltype uni; universe 1012;} + // Rodded GT in grid + gridRGTThick {type simpleCell; id 263; surfaces (-90); filltype uni; universe 1014;} + + // THIN GRID + // 2.4% in grid + grid24Thin {type simpleCell; id 264; surfaces (-92); filltype uni; universe 24000;} + // guide tube in grid + gridGTThin {type simpleCell; id 265; surfaces (-92); filltype uni; universe 12000;} + // burnable poison in grid + gridBPThin {type simpleCell; id 266; surfaces (-92); filltype uni; universe 1000;} + // 3.1% in grid + grid31Thin {type simpleCell; id 267; surfaces (-92); filltype uni; universe 31000;} + // 1.6 % in grid + grid16Thin {type simpleCell; id 268; surfaces (-92); filltype uni; universe 16000;} + // instrumentation tube in grid + gridITThin {type simpleCell; id 269; surfaces (-92); filltype uni; universe 14000;} + // empty GT at dashpot in grid + gridGTDPThin {type simpleCell; id 270; surfaces (-92); filltype uni; universe 1010;} + // pin upper fuel plenum in grid + gridFPPThin {type simpleCell; id 271; surfaces (-92); filltype uni; universe 1008;} + // stainless steel in guide tube in grid + gridSSGTThin {type simpleCell; id 272; surfaces (-92); filltype uni; universe 1023;} + // stainless steel in dash pot in grid + gridSSDPThin {type simpleCell; id 273; surfaces (-92); filltype uni; universe 1024;} + // BP plenum in grid + gridBPPThin {type simpleCell; id 274; surfaces (-92); filltype uni; universe 1012;} + // Rodded GT in grid (not used when rods fully withdrawn) + gridRGTThin {type simpleCell; id 275; surfaces (-92); filltype uni; universe 1014;} + + + // 3.1% enriched pins, axial layering + 31FP460 {type simpleCell; id 100; surfaces ( 101); filltype uni; universe 1001;} + 31FP431 {type simpleCell; id 101; surfaces (-101 102); filltype uni; universe 1003;} + 31FP423 {type simpleCell; id 102; surfaces (-102 104); filltype uni; universe 1001;} + 31FP419 {type simpleCell; id 103; surfaces (-104 105); filltype uni; universe 1006;} + 31FP417 {type simpleCell; id 104; surfaces (-105 106); filltype uni; universe 1008;} + 31FP415 {type simpleCell; id 105; surfaces (-106 107); filltype uni; universe 1017;} + 31FP411 {type simpleCell; id 106; surfaces (-107 109); filltype uni; universe 1008;} + 31FP402 {type simpleCell; id 107; surfaces (-109 111); filltype uni; universe 31000;} + 31FP364 {type simpleCell; id 108; surfaces (-111 112); filltype uni; universe 9231;} + 31FP359 {type simpleCell; id 109; surfaces (-112 113); filltype uni; universe 31000;} + 31FP312 {type simpleCell; id 110; surfaces (-113 114); filltype uni; universe 9231;} + 31FP306 {type simpleCell; id 111; surfaces (-114 115); filltype uni; universe 31000;} + 31FP260 {type simpleCell; id 112; surfaces (-115 116); filltype uni; universe 9231;} + 31FP254 {type simpleCell; id 113; surfaces (-116 117); filltype uni; universe 31000;} + 31FP208 {type simpleCell; id 114; surfaces (-117 118); filltype uni; universe 9231;} + 31FP202 {type simpleCell; id 115; surfaces (-118 119); filltype uni; universe 31000;} + 31FP155 {type simpleCell; id 116; surfaces (-119 120); filltype uni; universe 9231;} + 31FP150 {type simpleCell; id 117; surfaces (-120 122); filltype uni; universe 31000;} + 31FP103 {type simpleCell; id 118; surfaces (-122 123); filltype uni; universe 9231;} + 31FP98 {type simpleCell; id 119; surfaces (-123 126); filltype uni; universe 31000;} + 31FP4052 {type simpleCell; id 120; surfaces (-126 129); filltype uni; universe 1131;} + 31FP37 {type simpleCell; id 121; surfaces (-129 130); filltype uni; universe 31000;} + 31FP36 {type simpleCell; id 122; surfaces (-130 131); filltype uni; universe 1006;} + 31FP35 {type simpleCell; id 123; surfaces (-131 132); filltype uni; universe 1003;} + 31FP20 {type simpleCell; id 124; surfaces (-132 ); filltype uni; universe 1001;} + + + //2.4% enriched pins, axial layering + 24FP460 {type simpleCell; id 125; surfaces ( 101); filltype uni; universe 1001;} + 24FP431 {type simpleCell; id 126; surfaces (-101 102); filltype uni; universe 1003;} + 24FP423 {type simpleCell; id 127; surfaces (-102 104); filltype uni; universe 1001;} + 24FP419 {type simpleCell; id 128; surfaces (-104 105); filltype uni; universe 1006;} + 24FP417 {type simpleCell; id 129; surfaces (-105 106); filltype uni; universe 1008;} + 24FP415 {type simpleCell; id 130; surfaces (-106 107); filltype uni; universe 1017;} + 24FP411 {type simpleCell; id 131; surfaces (-107 109); filltype uni; universe 1008;} + 24FP402 {type simpleCell; id 132; surfaces (-109 111); filltype uni; universe 24000;} + 24FP364 {type simpleCell; id 133; surfaces (-111 112); filltype uni; universe 9224;} + 24FP359 {type simpleCell; id 134; surfaces (-112 113); filltype uni; universe 24000;} + 24FP312 {type simpleCell; id 135; surfaces (-113 114); filltype uni; universe 9224;} + 24FP306 {type simpleCell; id 136; surfaces (-114 115); filltype uni; universe 24000;} + 24FP260 {type simpleCell; id 137; surfaces (-115 116); filltype uni; universe 9224;} + 24FP254 {type simpleCell; id 138; surfaces (-116 117); filltype uni; universe 24000;} + 24FP208 {type simpleCell; id 139; surfaces (-117 118); filltype uni; universe 9224;} + 24FP202 {type simpleCell; id 140; surfaces (-118 119); filltype uni; universe 24000;} + 24FP155 {type simpleCell; id 141; surfaces (-119 120); filltype uni; universe 9224;} + 24FP150 {type simpleCell; id 142; surfaces (-120 122); filltype uni; universe 24000;} + 24FP103 {type simpleCell; id 143; surfaces (-122 123); filltype uni; universe 9224;} + 24FP98 {type simpleCell; id 144; surfaces (-123 126); filltype uni; universe 24000;} + 24FP4052 {type simpleCell; id 145; surfaces (-126 129); filltype uni; universe 1124;} + 24FP37 {type simpleCell; id 146; surfaces (-129 130); filltype uni; universe 24000;} + 24FP36 {type simpleCell; id 147; surfaces (-130 131); filltype uni; universe 1006;} + 24FP35 {type simpleCell; id 148; surfaces (-131 132); filltype uni; universe 1003;} + 24FP20 {type simpleCell; id 149; surfaces (-132); filltype uni; universe 1001;} + + //1.6% enriched pins, axial layering + 16FP460 {type simpleCell; id 150; surfaces ( 101); filltype uni; universe 1001;} + 16FP431 {type simpleCell; id 151; surfaces (-101 102); filltype uni; universe 1003;} + 16FP423 {type simpleCell; id 152; surfaces (-102 104); filltype uni; universe 1001;} + 16FP419 {type simpleCell; id 153; surfaces (-104 105); filltype uni; universe 1006;} + 16FP417 {type simpleCell; id 154; surfaces (-105 106); filltype uni; universe 1008;} + 16FP415 {type simpleCell; id 155; surfaces (-106 107); filltype uni; universe 1017;} + 16FP411 {type simpleCell; id 156; surfaces (-107 109); filltype uni; universe 1008;} + 16FP402 {type simpleCell; id 157; surfaces (-109 111); filltype uni; universe 16000;} + 16FP364 {type simpleCell; id 158; surfaces (-111 112); filltype uni; universe 9216;} + 16FP359 {type simpleCell; id 159; surfaces (-112 113); filltype uni; universe 16000;} + 16FP312 {type simpleCell; id 160; surfaces (-113 114); filltype uni; universe 9216;} + 16FP306 {type simpleCell; id 161; surfaces (-114 115); filltype uni; universe 16000;} + 16FP260 {type simpleCell; id 162; surfaces (-115 116); filltype uni; universe 9216;} + 16FP254 {type simpleCell; id 163; surfaces (-116 117); filltype uni; universe 16000;} + 16FP208 {type simpleCell; id 164; surfaces (-117 118); filltype uni; universe 9216;} + 16FP202 {type simpleCell; id 165; surfaces (-118 119); filltype uni; universe 16000;} + 16FP155 {type simpleCell; id 166; surfaces (-119 120); filltype uni; universe 9216;} + 16FP150 {type simpleCell; id 167; surfaces (-120 122); filltype uni; universe 16000;} + 16FP103 {type simpleCell; id 168; surfaces (-122 123); filltype uni; universe 9216;} + 16FP98 {type simpleCell; id 169; surfaces (-123 126); filltype uni; universe 16000;} + 16FP4052 {type simpleCell; id 170; surfaces (-126 129); filltype uni; universe 1116;} + 16FP37 {type simpleCell; id 171; surfaces (-129 130); filltype uni; universe 16000;} + 16FP36 {type simpleCell; id 172; surfaces (-130 131); filltype uni; universe 1006;} + 16FP35 {type simpleCell; id 173; surfaces (-131 132); filltype uni; universe 1003;} + 16FP20 {type simpleCell; id 174; surfaces (-132); filltype uni; universe 1001;} + + + //guide tube, with CR, axial layering + GC460 {type simpleCell; id 175; surfaces ( 101); filltype uni; universe 1014;} + GC431 {type simpleCell; id 176; surfaces (-101 106); filltype uni; universe 1014;} // Nozzle/support plate BW? Replaced just with rod + GC415 {type simpleCell; id 177; surfaces (-106 107); filltype uni; universe 1018;} // Rodded w/ grid + GC411 {type simpleCell; id 178; surfaces (-107 109); filltype uni; universe 1014;} + GC402 {type simpleCell; id 179; surfaces (-109 134); filltype uni; universe 1015;} + GC400 {type simpleCell; id 180; surfaces (-134 111); filltype uni; universe 12000;} + GC364 {type simpleCell; id 181; surfaces (-111 112); filltype uni; universe 9112;} + GC359 {type simpleCell; id 182; surfaces (-112 113); filltype uni; universe 12000;} + GC312 {type simpleCell; id 183; surfaces (-113 114); filltype uni; universe 9112;} + GC306 {type simpleCell; id 184; surfaces (-114 115); filltype uni; universe 12000;} + GC260 {type simpleCell; id 185; surfaces (-115 116); filltype uni; universe 9112;} + GC254 {type simpleCell; id 186; surfaces (-116 117); filltype uni; universe 12000;} + GC208 {type simpleCell; id 187; surfaces (-117 118); filltype uni; universe 9112;} + GC202 {type simpleCell; id 188; surfaces (-118 119); filltype uni; universe 12000;} + GC155 {type simpleCell; id 189; surfaces (-119 120); filltype uni; universe 9112;} + GC150 {type simpleCell; id 190; surfaces (-120 122); filltype uni; universe 12000;} + GC103 {type simpleCell; id 191; surfaces (-122 123); filltype uni; universe 9112;} + GC98 {type simpleCell; id 192; surfaces (-123 126); filltype uni; universe 1010;} + GC4052 {type simpleCell; id 193; surfaces (-126 127); filltype uni; universe 12000;} + GC39 {type simpleCell; id 194; surfaces (-127 129); filltype uni; universe 1019;} + GC37 {type simpleCell; id 195; surfaces (-129 131); filltype uni; universe 1010;} + GC35 {type simpleCell; id 196; surfaces (-131 132); filltype uni; universe 1005;} + GC20 {type simpleCell; id 197; surfaces (-132); filltype uni; universe 1001;} + + + // instrumentation tube, axial layering + IT460 {type simpleCell; id 198; surfaces ( 102); filltype uni; universe 1001;} + IT423 {type simpleCell; id 199; surfaces (-102 106); filltype uni; universe 14000;} + IT415 {type simpleCell; id 200; surfaces (-106 107); filltype uni; universe 1114;} + IT411 {type simpleCell; id 201; surfaces (-107 111); filltype uni; universe 14000;} + IT364 {type simpleCell; id 202; surfaces (-111 112); filltype uni; universe 9114;} + IT359 {type simpleCell; id 203; surfaces (-112 113); filltype uni; universe 14000;} + IT312 {type simpleCell; id 204; surfaces (-113 114); filltype uni; universe 9114;} + IT306 {type simpleCell; id 205; surfaces (-114 115); filltype uni; universe 14000;} + IT260 {type simpleCell; id 206; surfaces (-115 116); filltype uni; universe 9114;} + IT254 {type simpleCell; id 207; surfaces (-116 117); filltype uni; universe 14000;} + IT208 {type simpleCell; id 208; surfaces (-117 118); filltype uni; universe 9114;} + IT202 {type simpleCell; id 209; surfaces (-118 119); filltype uni; universe 14000;} + IT155 {type simpleCell; id 210; surfaces (-119 120); filltype uni; universe 9114;} + IT150 {type simpleCell; id 211; surfaces (-120 122); filltype uni; universe 14000;} + IT103 {type simpleCell; id 212; surfaces (-122 123); filltype uni; universe 9114;} + IT98 {type simpleCell; id 213; surfaces (-123 126); filltype uni; universe 14000;} + IT4052 {type simpleCell; id 214; surfaces (-126 129); filltype uni; universe 1114;} + IT37 {type simpleCell; id 215; surfaces (-129 131); filltype uni; universe 14000;} + IT35 {type simpleCell; id 216; surfaces (-131 132); filltype uni; universe 1005;} + IT20 {type simpleCell; id 217; surfaces (-132 ); filltype uni; universe 1011;} + + + // burnable absorber, axial layering + BA460 {type simpleCell; id 218; surfaces ( 101); filltype uni; universe 1001;} + BA431 {type simpleCell; id 219; surfaces (-101 102); filltype uni; universe 1002;} + BA423 {type simpleCell; id 220; surfaces (-102 103); filltype uni; universe 1023;} + BA421 {type simpleCell; id 230; surfaces (-103 106); filltype uni; universe 1012;} + BA415 {type simpleCell; id 231; surfaces (-106 107); filltype uni; universe 1027;} + BA411 {type simpleCell; id 232; surfaces (-107 110); filltype uni; universe 1012;} + BA401 {type simpleCell; id 233; surfaces (-110 111); filltype uni; universe 1000;} + BA364 {type simpleCell; id 234; surfaces (-111 112); filltype uni; universe 1110;} + BA359 {type simpleCell; id 235; surfaces (-112 113); filltype uni; universe 1000;} + BA312 {type simpleCell; id 236; surfaces (-113 114); filltype uni; universe 1110;} + BA306 {type simpleCell; id 237; surfaces (-114 115); filltype uni; universe 1000;} + BA260 {type simpleCell; id 238; surfaces (-115 116); filltype uni; universe 1110;} + BA254 {type simpleCell; id 239; surfaces (-116 117); filltype uni; universe 1000;} + BA208 {type simpleCell; id 240; surfaces (-117 118); filltype uni; universe 1110;} + BA202 {type simpleCell; id 241; surfaces (-118 119); filltype uni; universe 1000;} + BA155 {type simpleCell; id 242; surfaces (-119 120); filltype uni; universe 1110;} + BA150 {type simpleCell; id 243; surfaces (-120 122); filltype uni; universe 1000;} + BA103 {type simpleCell; id 244; surfaces (-122 123); filltype uni; universe 1110;} + BA98 {type simpleCell; id 245; surfaces (-123 125); filltype uni; universe 1000;} + BA4055 {type simpleCell; id 246; surfaces (-125 126); filltype uni; universe 1023;} + BA4052 {type simpleCell; id 247; surfaces (-126 127); filltype uni; universe 1021;} + BA39 {type simpleCell; id 248; surfaces (-127 128); filltype uni; universe 1025;} + BA38 {type simpleCell; id 249; surfaces (-128 129); filltype uni; universe 1019;} + BA37 {type simpleCell; id 250; surfaces (-129 131); filltype uni; universe 1010;} + BA35 {type simpleCell; id 251; surfaces (-131 132); filltype uni; universe 1005;} + BA20 {type simpleCell; id 252; surfaces (-132 ); filltype uni; universe 1001;} + + //guide tube, no CR, axial layering + GT460 {type simpleCell; id 353; surfaces ( 101); filltype uni; universe 1001;} + GT431 {type simpleCell; id 354; surfaces (-101 102); filltype uni; universe 1005;} + GT423 {type simpleCell; id 355; surfaces (-102 106); filltype uni; universe 12000;} + GT415 {type simpleCell; id 356; surfaces (-106 107); filltype uni; universe 1112;} + GT411 {type simpleCell; id 357; surfaces (-107 111); filltype uni; universe 12000;} + GT364 {type simpleCell; id 358; surfaces (-111 112); filltype uni; universe 9112;} + GT359 {type simpleCell; id 359; surfaces (-112 113); filltype uni; universe 12000;} + GT312 {type simpleCell; id 360; surfaces (-113 114); filltype uni; universe 9112;} + GT306 {type simpleCell; id 361; surfaces (-114 115); filltype uni; universe 12000;} + GT260 {type simpleCell; id 362; surfaces (-115 116); filltype uni; universe 9112;} + GT254 {type simpleCell; id 363; surfaces (-116 117); filltype uni; universe 12000;} + GT208 {type simpleCell; id 364; surfaces (-117 118); filltype uni; universe 9112;} + GT202 {type simpleCell; id 365; surfaces (-118 119); filltype uni; universe 12000;} + GT155 {type simpleCell; id 366; surfaces (-119 120); filltype uni; universe 9112;} + GT150 {type simpleCell; id 367; surfaces (-120 122); filltype uni; universe 12000;} + GT103 {type simpleCell; id 368; surfaces (-122 123); filltype uni; universe 9112;} + GT98 {type simpleCell; id 369; surfaces (-123 126); filltype uni; universe 1010;} + GT4052 {type simpleCell; id 370; surfaces (-126 127); filltype uni; universe 12000;} + GT39 {type simpleCell; id 371; surfaces (-127 129); filltype uni; universe 1019;} + GT37 {type simpleCell; id 372; surfaces (-129 131); filltype uni; universe 1010;} + GT35 {type simpleCell; id 373; surfaces (-131 132); filltype uni; universe 1005;} + GT20 {type simpleCell; id 374; surfaces (-132); filltype uni; universe 1001;} + + // control rod, axial layering + // Used (probably with some modification) only when fully inserted + //CR460 {type simpleCell; id 448; surfaces (-120 121); filltype uni; universe 1002;} + //CR415 {type simpleCell; id 449; surfaces (-126 403); filltype uni; universe 1013;} + //CR403 {type simpleCell; id 450; surfaces (-403 402); filltype uni; universe 1015;} + //CR402 {type simpleCell; id 451; surfaces (-402 1430); filltype uni; universe 1013;} + //CR143 {type simpleCell; id 452; surfaces (-1430 41); filltype uni; universe 1014;} + //CR41 {type simpleCell; id 453; surfaces (-41 143); filltype uni; universe 1002;} + //CR39 {type simpleCell; id 454; surfaces (-143 147); filltype uni; universe 1001;} + //CR35 {type simpleCell; id 455; surfaces (-147 148); filltype uni; universe 1005;} + //CR20 {type simpleCell; id 456; surfaces (-148 149); filltype uni; universe 1001;} + + + + outsideLeftBaffle { type simpleCell; id 52; surfaces (-50); filltype mat; material Water;} + leftBaffle { type simpleCell; id 53; surfaces (50 -51); filltype mat; material SS304;} + insideLeftBaffle { type simpleCell; id 54; surfaces (51); filltype mat; material Water;} + + outsideRightBaffle { type simpleCell; id 55; surfaces (-52); filltype mat; material Water;} + RightBaffle { type simpleCell; id 56; surfaces (52 -53); filltype mat; material SS304;} + insideRightBaffle { type simpleCell; id 57; surfaces (53); filltype mat; material Water;} + + outsideTopBaffle { type simpleCell; id 58; surfaces (-54); filltype mat; material Water;} + TopBaffle { type simpleCell; id 59; surfaces (54 -55); filltype mat; material SS304;} + insideTopBaffle { type simpleCell; id 60; surfaces (55); filltype mat; material Water;} + + outsideBottomBaffle { type simpleCell; id 61; surfaces (-56); filltype mat; material Water;} + BottomBaffle { type simpleCell; id 62; surfaces (56 -57); filltype mat; material SS304;} + insideBottomBaffle { type simpleCell; id 63; surfaces (57); filltype mat; material Water;} + + topLeftCornerBaffle1 { type simpleCell; id 64; surfaces (52 -53 -57); filltype mat; material SS304;} + topLeftCornerBaffle2 { type simpleCell; id 65; surfaces (56 -57 -52); filltype mat; material SS304;} + topLeftCornerGap1 { type simpleCell; id 66; surfaces (57); filltype mat; material Water;} + topLeftCornerGap2 { type simpleCell; id 67; surfaces (53); filltype mat; material Water;} + topLeftMajorGap { type simpleCell; id 68; surfaces (-56 -52); filltype mat; material Water;} + + topRightCornerBaffle1 { type simpleCell; id 69; surfaces (-57 50 -51); filltype mat; material SS304;} + topRightCornerBaffle2 { type simpleCell; id 70; surfaces (-50 56 -57); filltype mat; material SS304;} + topRightCornerGap1 { type simpleCell; id 71; surfaces (57); filltype mat; material Water;} + topRightCornerGap2 { type simpleCell; id 72; surfaces (51); filltype mat; material Water;} + topRightMajorGap { type simpleCell; id 73; surfaces (-56 -50); filltype mat; material Water;} + + bottomLeftCornerBaffle1 { type simpleCell; id 74; surfaces (-55 52 -53); filltype mat; material SS304;} + bottomLeftCornerBaffle2 { type simpleCell; id 75; surfaces (-55 54 -52); filltype mat; material SS304;} + bottomLeftCornerGap1 { type simpleCell; id 76; surfaces (55); filltype mat; material Water;} + bottomLeftCornerGap2 { type simpleCell; id 77; surfaces (53); filltype mat; material Water;} + bottomLeftMajorGap { type simpleCell; id 78; surfaces (-54 -52); filltype mat; material Water;} + + bottomRightCornerBaffle1 { type simpleCell; id 79; surfaces (-51 50 -55); filltype mat; material SS304;} + bottomRightCornerBaffle2 { type simpleCell; id 80; surfaces (-55 54 -50); filltype mat; material SS304;} + bottomRightCornerGap1 { type simpleCell; id 81; surfaces (51); filltype mat; material Water;} + bottomRightCornerGap2 { type simpleCell; id 82; surfaces (55); filltype mat; material Water;} + bottomRightMajorGap { type simpleCell; id 83; surfaces (-50 -54); filltype mat; material Water;} + + + TLSG1 { type simpleCell; id 84; surfaces (-56 -52); filltype mat; material Water;} + TLSG2 { type simpleCell; id 85; surfaces (-56 52); filltype mat; material Water;} + TLSG3 { type simpleCell; id 86; surfaces (56 -52); filltype mat; material Water;} + topLeftSquare { type simpleCell; id 87; surfaces (56 52); filltype mat; material SS304;} + + TRSG1 { type simpleCell; id 88; surfaces (-56 50); filltype mat; material Water;} + TRSG2 { type simpleCell; id 89; surfaces (-56 -50); filltype mat; material Water;} + TRSG3 { type simpleCell; id 90; surfaces (56 -50); filltype mat; material Water;} + topRightSquare { type simpleCell; id 91; surfaces (56 50); filltype mat; material SS304;} + + BLSG1 { type simpleCell; id 92; surfaces (54 -52); filltype mat; material Water;} + BLSG2 { type simpleCell; id 93; surfaces (-54 52); filltype mat; material Water;} + BLSG3 { type simpleCell; id 94; surfaces (-54 -52); filltype mat; material Water;} + bottomLeftSquare { type simpleCell; id 95; surfaces (54 52); filltype mat; material SS304;} + + BRSG1 { type simpleCell; id 96; surfaces (-54 50); filltype mat; material Water;} + BRSG2 { type simpleCell; id 97; surfaces (54 -50); filltype mat; material Water;} + BRSG3 { type simpleCell; id 98; surfaces (-54 -50); filltype mat; material Water;} + bottomRightSquare { type simpleCell; id 99; surfaces (54 50); filltype mat; material SS304;} + } + + universes { + root { id 1; type rootUniverse; border 1; fill u<8888>; } + + // Pin universes + + //Burnable poison + pinBPaboveDP { id 1000; type pinUniverse; radii (0.21400 0.23051 0.24130 0.42672 0.43688 0.48387 0.56134 0.60198 0.0); + fills (Air SS304 Helium BorosilicateGlass Helium SS304 Water Zircaloy Water);} + pinBPPlenumGeometry { id 1012; type pinUniverse; radii ( 0.21400 0.23051 0.43688 0.48387 0.50419 0.54610 0.0); + fills (Air SS304 Helium SS304 Water Zircaloy Water);} + + //guide tubes + pinGTaboveDP { id 12000; type pinUniverse; radii (0.56134 0.60198 0.0 ); fills (Water Zircaloy Water);} + pinGTatDP { id 1010; type pinUniverse; radii (0.50419 0.54610 0.0); fills (Water Zircaloy Water);} + + //INST Tube + pinIT { id 14000; type pinUniverse; radii (0.43688 0.48387 0.56134 0.60198 0.0 ); + fills (Air Zircaloy Water Zircaloy Water);} + pinBareInstrumentThimble { id 1011; type pinUniverse; radii (0.43688 0.48387 0.0); fills (Air Zircaloy Water);} + + // Fuel pins + pin16 { id 16000; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-16 Helium Zircaloy Water);} + pin24 { id 24000; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-24 Helium Zircaloy Water);} + pin31 { id 31000; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-31 Helium Zircaloy Water);} + // Higher enrichments not used + //pin32 { id 32000; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + // fills (UO2-32 Helium Zircaloy Water);} + //pin34 { id 34000; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + // fills (UO2-34 Helium Zircaloy Water);} + + pinWater { id 1001; type pinUniverse; radii ( 0.0); fills (Water);} + + + // Solid pins, assumed radius to be that of a fuel pin (0.45720) + pinNozzle_SupportSteel { id 1003; type pinUniverse; radii ( 0.45720 0.0); fills (SupportPlateSS Water);} + pinSupportPlateBW { id 1005; type pinUniverse; radii ( 0.45720 0.0); fills (SupportPlateBW Water);} + pinZircaloy { id 1006; type pinUniverse; radii ( 0.45720 0.0); fills (Zircaloy Water);} + + + SSinDashPot { id 1024; type pinUniverse; radii (0.50419 0.54610 0.0); fills (SS304 Zircaloy Water);} + SSinGuideTube { id 1023; type pinUniverse; radii ( 0.56134 0.60198 0.0); fills (SS304 Zircaloy Water);} + SSnoGuideTube { id 1002; type pinUniverse; radii ( 0.56134 0.0); fills (SS304 Water);} + + + pinUpperFuelPlenum { id 1008; type pinUniverse; radii ( 0.06459 0.40005 0.45720 0.0); + fills (Inconel Helium Zircaloy Water);} + + // Control rod pins + pinControlRodUpper { id 1013; type pinUniverse; radii ( 0.37338 0.38608 0.48387 0.56134 0.60198 0.0); + fills (B4C Helium SS304 Water Zircaloy Water);} + pinControlRodLower { id 1014; type pinUniverse; radii ( 0.38227 0.38608 0.48387 0.56134 0.60198 0.0); + fills (Ag-In-Cd Helium SS304 Water Zircaloy Water);} + pinControlRodSpacer { id 1015; type pinUniverse; radii ( 0.37845 0.38608 0.48387 0.56134 0.60198 0.0); + fills (SS304 Helium SS304 Water Zircaloy Water);} + pinControlRodPlenum { id 1016; type pinUniverse; radii ( 0.06459 0.38608 0.48387 0.56134 0.60198 0.0); + fills (Inconel Helium SS304 Water Zircaloy Water);} + + // pins that have grids + fuelRodPlenumWithGridThick { + id 1017; + type cellUniverse; + cells ( 259 555);} + + GTRodThick { + id 1018; + type cellUniverse; + cells (263 555);} + + dashPotGuideTubeGridThick { + id 1019; + type cellUniverse; + cells ( 258 555);} + + dashPotGuideTubeGridThin { + id 1020; + type cellUniverse; + cells ( 270 556);} + + SSinGuideTubeThick { + id 1021; + type cellUniverse; + cells ( 260 555);} + + SSinGuideTubeThin { + id 1022; + type cellUniverse; + cells ( 272 556);} + + SSinDashPotThick { + id 1025; + type cellUniverse; + cells ( 261 555);} + + SSinDashPotThin { + id 1026; + type cellUniverse; + cells ( 273 556);} + + BPPlenumThick { + id 1027; + type cellUniverse; + cells ( 262 555);} + + BPPlenumThin { + id 1028; + type cellUniverse; + cells ( 274 556);} + + BPaboveDPThin { + id 1110; + type cellUniverse; + cells (266 556);} + + GTThick { + id 1112; + type cellUniverse; + cells (254 555);} + + ITThick { + id 1114; + type cellUniverse; + cells (257 555);} + + pin16Thick { + id 1116; + type cellUniverse; + cells (256 555);} + + pin24Thick { + id 1124; + type cellUniverse; + cells (253 555);} + + pin31Thick { + id 1131; + type cellUniverse; + cells (255 555);} + + BPThin { // Is this necessary given 1110, BPaboveDPThin??? + id 9110; + type cellUniverse; + cells (266 556);} + + GTThin { + id 9112; + type cellUniverse; + cells (265 556);} + + ITThin { + id 9114; + type cellUniverse; + cells (269 556);} + + pin16Thin { + id 9216; + type cellUniverse; + cells (268 556);} + + pin24Thin { + id 9224; + type cellUniverse; + cells (264 556);} + + pin31Thin { + id 9231; + type cellUniverse; + cells (267 556);} + + // Axial stacks of universes to make up full pins + + // 3.1 % + fuelPin31 { + id 31; + type cellUniverse; + cells ( 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124);} + + // 2.4 % + fuelPin24 { + id 24; + type cellUniverse; + cells ( 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149);} + + //1.6 % + fuelPin16 { + id 16; + type cellUniverse; + cells ( 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174);} + + // guide tube, with CR + GuideTubeRodded { + id 12; + type cellUniverse; + cells (175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197);} + + //control rod, fully retracted + GuideTubeEmpty { + id 13; + type cellUniverse; + cells (353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374);} + + //instr. tube + instrumentTube { + id 14; + type cellUniverse; + cells (198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217);} + + //burnable absorber + BP { + id 10; + type cellUniverse; + cells (218 219 220 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252);} + + + + + // Lattices w/o grid + // Names represent AE + A0E24 { + id 1424; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 12 24 24 12 24 24 12 24 24 24 24 24 + 24 24 24 12 24 24 24 24 24 24 24 24 24 12 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 12 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 14 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 12 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 12 24 24 24 24 24 24 24 24 24 12 24 24 24 + 24 24 24 24 24 12 24 24 12 24 24 12 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + // assembly with sleeves at different heights + A0E24Sleeve { + id 14240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2019 + );} + + A0E16 { + id 1416; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 12 16 16 12 16 16 12 16 16 16 16 16 + 16 16 16 12 16 16 16 16 16 16 16 16 16 12 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 12 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 14 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 12 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 12 16 16 16 16 16 16 16 16 16 12 16 16 16 + 16 16 16 16 16 12 16 16 12 16 16 12 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16); } + + A0E16Sleeve { + id 14160; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2020 + ); + } + + A0E31 { + id 1431; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A0E31Sleeve { + id 14310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2021 + ); + } + + + A6BE31B { + id 60316; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A6BE31BSleeve { + id 603160; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2022 + ); + } + + A6BE31T { + id 603112; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31TSleeve { + id 6031120; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2023 + ); + } + + A6BE31R { + id 60313; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31RSleeve { + id 603130; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2024 + ); + } + + A6BE31L { + id 60319; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31LSleeve { + id 603190; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2025 + ); + } + + A15BE31BR { + id 15315; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31BRSleeve { + id 153150; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2026 + ); + } + + A15BE31BL { + id 15317; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31BLSleeve { + id 153170; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2027 + ); + } + + A15BE31TR { + id 15311; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31TRSleeve { + id 153110; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2028 + ); + } + + A15BE31TL { + id 153111; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31TLSleeve { + id 1531110; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2029 + ); + } + + A16BE31 { + id 1631; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 14 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A16BE31Sleeve { + id 16310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2030 + ); + } + + A20BE31 { + id 2031; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 12 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 14 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 12 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A20BE31Sleeve { + id 20310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2031 + ); + } + + A12BE24 { + id 1224; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 12 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 14 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 12 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A12BE24Sleeve { + id 12240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2032 + ); + } + + A16BE24 { + id 1624; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 14 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A16BE24Sleeve { + id 16240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2033 + ); + } + + // Unrodded assemblies + A0E24U { + id 2424; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 13 24 24 13 24 24 13 24 24 24 24 24 + 24 24 24 13 24 24 24 24 24 24 24 24 24 13 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 13 24 24 13 24 24 13 24 24 13 24 24 13 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 13 24 24 13 24 24 14 24 24 13 24 24 13 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 13 24 24 13 24 24 13 24 24 13 24 24 13 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 13 24 24 24 24 24 24 24 24 24 13 24 24 24 + 24 24 24 24 24 13 24 24 13 24 24 13 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A0E24USleeve { + id 24240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2034 + );} + + A0E16U { + id 2416; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 13 16 16 13 16 16 13 16 16 16 16 16 + 16 16 16 13 16 16 16 16 16 16 16 16 16 13 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 13 16 16 13 16 16 13 16 16 13 16 16 13 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 13 16 16 13 16 16 14 16 16 13 16 16 13 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 13 16 16 13 16 16 13 16 16 13 16 16 13 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 13 16 16 16 16 16 16 16 16 16 13 16 16 16 + 16 16 16 16 16 13 16 16 13 16 16 13 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16); } + + // sleeved + A0E16USleeve { + id 24160; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2035 + ); + } + + A0E31U { + id 2431; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 14 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A0E31USleeve { + id 24310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2036 + ); + } + + + A6BE31BU { + id 70316; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 13 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 14 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A6BE31BUSleeve { + id 703160; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2037 + ); + } + + A6BE31TU { + id 703112; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 14 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 13 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31TUSleeve { + id 7031120; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2038 + ); + } + + A6BE31RU { + id 70313; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 14 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 10 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31RUSleeve { + id 703130; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2039 + ); + } + + A6BE31LU { + id 70319; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 10 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 14 31 31 13 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A6BE31LUSleeve { + id 703190; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2040 + ); + } + + A15BE31BRU { + id 25315; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31BRUSleeve { + id 253150; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2041 + ); + } + + A15BE31BLU { + id 25317; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31BLUSleeve { + id 253170; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2042 + ); + } + + A15BE31TRU { + id 25311; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 13 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31TRUSleeve { + id 253110; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2043 + ); + } + + A15BE31TLU { + id 253111; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 13 31 31 13 31 31 13 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 13 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 13 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 13 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15BE31TLUSleeve { + id 2531110; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2044 + ); + } + + A16BE31U { + id 2631; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 14 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 13 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A16BE31USleeve { + id 26310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2045 + ); + } + + A20BE31U { + id 3031; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 13 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 13 31 31 14 31 31 13 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 13 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A20BE31USleeve { + id 30310; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2046 + ); + } + + A12BE24U { + id 2224; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 13 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 13 24 24 13 24 24 13 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 13 24 24 13 24 24 14 24 24 13 24 24 13 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 13 24 24 13 24 24 13 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 13 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A12BE24USleeve { + id 22240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2047 + ); + } + + A16BE24U { + id 2624; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 13 24 24 13 24 24 13 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 13 24 24 14 24 24 13 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 13 24 24 13 24 24 13 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A16BE24USleeve { + id 26240; + type cellUniverse; + cells ( + 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 + 2016 2017 2018 2048 + ); + } + + + leftBaffleUni { + id 5222; + type cellUniverse; + cells (52 53 54);} + + + rightBaffleUni { + id 5223; + type cellUniverse; + cells (55 56 57);} + + topBaffleUni { + id 5224; + type cellUniverse; + cells (58 59 60);} + + bottomBaffleUni { + id 5225; + type cellUniverse; + cells (61 62 63);} + + + topLeft { + id 5226; + type cellUniverse; + cells (64 65 66 67 68);} + + topRight { + id 5227; + type cellUniverse; + cells ( 69 70 71 72 73);} + + BottomLeft { + id 5228; + type cellUniverse; + cells ( 74 75 76 77 78);} + + BottomRight { + id 5229; + type cellUniverse; + cells ( 79 80 81 82 83);} + + + SQTL { + id 1500; + type cellUniverse; + cells (84 85 86 87);} + + + SQTR { + id 1600; + type cellUniverse; + cells (88 89 90 91);} + + SQBL { + id 1700; + type cellUniverse; + cells (92 93 94 95);} + + SQBR { + id 1800; + type cellUniverse; + cells (96 97 98 99);} + + + latCore { + id 9999; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.50364 21.50364 0.0); + shape (17 17 0); + padMat Water; + map ( + 1001 1001 1001 1001 1800 5224 5224 5224 5224 5224 5224 5224 1700 1001 1001 1001 1001 + 1001 1001 1800 5224 5229 24310 7031120 24310 7031120 24310 7031120 24310 5228 5224 1700 1001 1001 + 1001 1800 5229 24310 14310 26310 14160 30310 14160 30310 14160 26310 14310 24310 5228 1700 1001 + 1001 5222 24310 2531110 26240 14160 26240 14160 26240 14160 26240 14160 26240 25311 24310 5223 1001 + 1800 5229 14310 26240 14240 26240 24160 22240 14160 22240 24160 26240 14240 26240 14310 5228 1700 + 5222 24310 26310 14160 26240 24160 22240 24160 22240 24160 22240 24160 26240 14160 26310 24310 5223 + 5222 703190 14160 26240 24160 22240 14160 22240 14160 22240 14160 22240 24160 26240 14160 703130 5223 + 5222 24310 30310 14160 22240 24160 22240 24160 26240 24160 22240 24160 22240 14160 30310 24310 5223 + 5222 703190 14160 26240 14160 22240 14160 26240 14160 26240 14160 22240 14160 26240 14160 703130 5223 + 5222 24310 30310 14160 22240 24160 22240 24160 26240 24160 22240 24160 22240 14160 30310 24310 5223 + 5222 703190 14160 26240 24160 22240 14160 22240 14160 22240 14160 22240 24160 26240 14160 703130 5223 + 5222 24310 26310 14160 26240 24160 22240 24160 22240 24160 22240 24160 26240 14160 26310 24310 5223 + 1600 5227 14310 26240 14240 26240 24160 22240 14160 22240 24160 26240 14240 26240 14310 5226 1500 + 1001 5222 24310 253170 26240 14160 26240 14160 26240 14160 26240 14160 26240 253150 24310 5223 1001 + 1001 1600 5227 24310 14310 26310 14160 30310 14160 30310 14160 26310 14310 24310 5226 1500 1001 + 1001 1001 1600 5225 5227 24310 703160 24310 703160 24310 703160 24310 5226 5225 1500 1001 1001 + 1001 1001 1001 1001 1600 5225 5225 5225 5225 5225 5225 5225 1500 1001 1001 1001 1001 ); } + + + coreAndStructures { + id 8888; + type cellUniverse; + cells (7 8 9 10 11 12 13 14 15 16 17);} + + + + } +} + + +viz { + bmpZ { + type bmp; + output imgZ; + what material; + centre (0.0 0.0 232.0); + //width (400.0 400.0); + axis z; + res (4000 4000); + } +} + + +nuclearData { + handles { + ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE; ures 0; } + } + + materials { + + // Note that commented nuclide densities are included in the specification + // but are not available in the JEFF-3.11 data library + + Air { + temp 566; + composition { + 18036.06 7.8730E-09; + 18038.06 1.4844E-09; + 18040.06 2.3506E-06; + 6012.06 6.7539E-08; + //6013.06 7.5658E-10; + 7014.06 1.9680E-04; + 7015.06 7.2354E-07; + 8016.06 5.2866E-05; + 8017.06 2.0084E-08; + //8018.06 1.0601E-07; + } + } + + SS304 { + temp 566; + composition { + 24050.06 7.6778E-04; + 24052.06 1.4806E-02; + 24053.06 1.6789E-03; + 24054.06 4.1791E-04; + 26054.06 3.4620E-03; + 26056.06 5.4345E-02; + 26057.06 1.2551E-03; + 26058.06 1.6703E-04; + 25055.06 1.7604E-03; + 28058.06 5.6089E-03; + 28060.06 2.1605E-03; + 28061.06 9.3917E-05; + 28062.06 2.9945E-04; + 28064.06 7.6261E-05; + 14028.06 9.5281E-04; + 14029.06 4.8381E-05; + 14030.06 3.1893E-05; } + } + + Helium { + temp 566; + composition { + 2003.06 4.8089E-10; + 2004.06 2.4044E-04; } + } + + BorosilicateGlass { + temp 566; + composition { + 13027.06 1.7352E-03; + 5010.06 9.6506E-04; + 5011.06 3.9189E-03; + 8016.06 4.6514E-02; + 8017.06 1.7671E-05; + //8018.06 9.3268E-05; + 14028.06 1.6926E-02; + 14029.06 8.5944E-04; + 14030.06 5.6654E-04; } + } + + Water { + temp 566; + moder {1001.06 lwj3.11; } + composition { + 5010.06 7.9714E-06; + 5011.06 3.2247E-05; + 1001.06 4.9456E-02; + 1002.06 7.7035E-06; + 8016.06 2.4673E-02; + 8017.06 9.3734E-06; + //8018.06 4.9474E-05; + } + } + + Zircaloy { + temp 566; + composition { + 24050.06 3.2962E-06; + 24052.06 6.3564E-05; + 24053.06 7.2076E-06; + 24054.06 1.7941E-06; + 26054.06 8.6698E-06; + 26056.06 1.3610E-04; + 26057.06 3.1431E-06; + 26058.06 4.1829E-07; + 8016.06 3.0744E-04; + 8017.06 1.1680E-07; + //8018.06 6.1648E-07; + 50112.06 4.6735E-06; + 50114.06 3.1799E-06; + 50115.06 1.6381E-06; + 50116.06 7.0055E-05; + 50117.06 3.7003E-05; + 50118.06 1.1669E-04; + 50119.06 4.1387E-05; + 50120.06 1.5697E-04; + 50122.06 2.2308E-05; + 50124.06 2.7897E-05; + 40090.06 2.1828E-02; + 40091.06 4.7601E-03; + 40092.06 7.2759E-03; + 40094.06 7.3734E-03; + 40096.06 1.1879E-03; } + } + + Inconel{ + temp 566; + composition { + 24050.06 7.8239E-04; + 24052.06 1.5088E-02; + 24053.06 1.7108E-03; + 24054.06 4.2586E-04; + 26054.06 1.4797E-03; + 26056.06 2.3229E-02; + 26057.06 5.3645E-04; + 26058.06 7.1392E-05; + 25055.06 7.8201E-04; + 28058.06 2.9320E-02; + 28060.06 1.1294E-02; + 28061.06 4.9094E-04; + 28062.06 1.5653E-03; + 28064.06 3.9864E-04; + 14028.06 5.6757E-04; + 14029.06 2.8820E-05; + 14030.06 1.8998E-05; } + } + + B4C{ + temp 566; + composition { + 5010.06 1.5206E-02; + 5011.06 6.1514E-02; + 6012.06 1.8972E-02; + //6013.06 2.1252E-04; + } + } + + Ag-In-Cd{ + temp 566; + composition { + 47107.06 2.3523E-02; + 47109.06 2.1854E-02; + 48106.06 3.3882E-05; + 48108.06 2.4166E-05; + 48110.06 3.3936E-04; + 48111.06 3.4821E-04; + 48112.06 6.5611E-04; + 48113.06 3.3275E-04; + 48114.06 7.8252E-04; + 48116.06 2.0443E-04; + 49113.06 3.4219E-04; + 49115.06 7.6511E-03; } + } + + //mox fuel used + UO2-16 { + temp 566; + composition { + 8016.06 4.5897E-02; + 8017.06 1.7436E-05; + //8018.06 9.2032E-05; + 92234.06 3.0131E-06; + 92235.06 3.7503E-04; + 92238.06 2.2625E-02;} + } + + UO2-24 { + temp 566; + composition { + 8016.06 4.5830E-02; + 8017.06 1.7411E-05; + //8018.06 9.1898E-05; + 92234.06 4.4842E-06; + 92235.06 5.5814E-04; + 92238.06 2.2407E-02;} + } + + UO2-31 { + temp 566; + composition { + 8016.06 4.5853E-02; + 8017.06 1.7420E-05; + //8018.06 9.1942E-05; + 92234.06 5.7987E-06; + 92235.06 7.2175E-04; + 92238.06 2.2253E-02;} + } + + UO2-32 { + temp 566; + composition { + 8016.06 4.6029E-02; + 8017.06 1.7487E-05; + //8018.06 9.2296E-05; + 92234.06 5.9959E-06; + 92235.06 7.4630E-04; + 92238.06 2.2317E-02; + } + } + + UO2-34 { + temp 566; + composition { + 8016.06 4.6110E-02; + 8017.06 1.7517E-05; + //8018.06 9.2459E-05; + 92234.06 6.4018E-06; + 92235.06 7.9681E-04; + 92238.06 2.2307E-02;} + } + + // vanadium51 was stated twice in carbonsteel below + // in the beavrs pdf - typo? + CarbonSteel { + temp 566; + composition { + 13027.06 4.3523E-05; + 5010.06 2.5833E-06; + 5011.06 1.0450E-05; + 6012.06 1.0442E-03; + //6013.06 1.1697E-05 ; + 20040.06 1.7043E-05; + 20042.06 1.1375E-07; + 20043.06 2.3734E-08; + 20044.06 3.6673E-07; + 20046.06 7.0322E-10; + 20048.06 3.2875E-08; + 24050.06 1.3738E-05; + 24052.06 2.6493E-04; + 24053.06 3.0041E-05; + 24054.06 7.4778E-06; + 29063.06 1.0223E-04; + 29065.06 4.5608E-05; + 26054.06 4.7437E-03; + 26056.06 7.4465E-02; + 26057.06 1.7197E-03; + 26058.06 2.2886E-04; + 25055.06 6.4126E-04; + 42100.06 2.9814E-05; + 42092.06 4.4822E-05; + 42094.06 2.8110E-05; + 42095.06 4.8567E-05; + 42096.06 5.1015E-05; + 42097.06 2.9319E-05; + 42098.06 7.4327E-05; + 41093.06 5.0559E-06; + 28058.06 4.0862E-04; + 28060.06 1.5740E-04; + 28061.06 6.8420E-06; + 28062.06 2.1815E-05; + 28064.06 5.5557E-06; + 15031.06 3.7913E-05; + 16032.06 3.4808E-05; + 16033.06 2.7420E-07; + 16034.06 1.5368E-06; + 16036.06 5.3398E-09; + 14028.06 6.1702E-04; + 14029.06 3.1330E-05; + 14030.06 2.0653E-05; + 22046.06 1.2144E-06; + 22047.06 1.0952E-06; + 22048.06 1.0851E-05; + 22049.06 7.9634E-07; + 22050.06 7.6249E-07; + //23050.06 1.1526E-07; + 23051.06 4.5989E-05; + } + } + + SupportPlateSS { + temp 566; + composition { + 24050.06 3.5223E-04; + 24052.06 6.7924E-03; + 24053.06 7.7020E-04; + 24054.06 1.9172E-04; + 26054.06 1.5882E-03; + 26056.06 2.4931E-02; + 26057.06 5.7578E-04; + 26058.06 7.6625E-05; + 25055.06 8.0762E-04; + 28058.06 2.5731E-03; + 28060.06 9.9117E-04; + 28061.06 4.3085E-05; + 28062.06 1.3738E-04; + 28064.06 3.4985E-05; + 14028.06 4.3711E-04; + 14029.06 2.2195E-05; + 14030.06 1.4631E-05;} + } + + SupportPlateBW { + temp 566; + moder {1001.06 lwj3.11; } + composition { + 5010.06 1.0559E-05; + 5011.06 4.2716E-05; + 1001.06 6.5512E-02; + 1002.06 1.0204E-05; + 8016.06 3.2683E-02; + 8017.06 1.2416E-05; + //8018.06 6.5535E-05; + } + } + + +} +} diff --git a/InputFiles/Benchmarks/BEAVRS/BEAVRS2D b/InputFiles/Benchmarks/BEAVRS/BEAVRS2D new file mode 100644 index 000000000..5a9bac1d1 --- /dev/null +++ b/InputFiles/Benchmarks/BEAVRS/BEAVRS2D @@ -0,0 +1,1581 @@ +!! +!! A 2D slice of the BEAVRS benchmark +!! +type eigenPhysicsPackage; + +pop 1000000; +active 100; +inactive 200; +XSdata ce; +dataType ce; + +// Specify output format default asciiMATLAB +//outputFormat asciiJSON; + +collisionOperator { neutronCE {type neutronCEstd;}} + +transportOperator { + type transportOperatorHT; cache 1; + } + +inactiveTally { + shannon { + type shannonEntropyClerk; + map {type multiMap; + maps (xax yax); + xax { type spaceMap; grid lin; min -161.2773; max 161.2773; N 15; axis x;} + yax { type spaceMap; grid lin; min -161.2773; max 161.2773; N 15; axis y;} + } + cycles 200; + } +} + +activeTally { + pinFissionRate { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax); + xax {type spaceMap; axis x; grid lin; N 255; min -161.2773; max 161.2773; } + yax {type spaceMap; axis y; grid lin; N 255; min -161.2773; max 161.2773; } + } + } + assemblyFissionRate { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax); + xax {type spaceMap; axis x; grid lin; N 15; min -161.2773; max 161.2773; } + yax {type spaceMap; axis y; grid lin; N 15; min -161.2773; max 161.2773; } + } + } + +} + +geometry { + type geometryStd; + boundary ( 0 0 0 0 0 0); + graph {type shrunk;} + + surfaces { + + // bounding widths for baffle on various sides + // right & left refers to the side of the reactor that it is on + // close/away refers to its location in relation to the LATTICE it is a part of + // (NOT the reactor itself) + rightClose { id 50; type plane; coeffs (1.0 0.0 0.0 8.36662);} + rightAway { id 51; type plane; coeffs (1.0 0.0 0.0 10.58912);} + + leftClose { id 60; type plane; coeffs (-1.0 0.0 0.0 8.36662);} + leftAway { id 61; type plane; coeffs (-1.0 0.0 0.0 10.58912);} + + bottomClose { id 70; type plane; coeffs (0.0 -1.0 0.0 8.36662);} + bottomAway { id 71; type plane; coeffs (0.0 -1.0 0.0 10.58912);} + + topClose { id 80; type plane; coeffs (0.0 1.0 0.0 8.36662);} + topAway { id 81; type plane; coeffs (0.0 1.0 0.0 10.58912);} + + + + // thickness specifications for RPV and RPV liner + outerRPV { id 1; type zCylinder; radius 241.3; origin (0.0 0.0 0.0); } + innerRPV { id 2; type zCylinder; radius 219.710; origin (0.0 0.0 0.0); } + innerRPVLiner { id 3; type zCylinder; radius 219.150; origin (0.0 0.0 0.0); } + + + + // thickness specifications for neutron shield + outerBoundNS { id 4; type zCylinder; radius 201.630; origin (0.0 0.0 0.0); } + innerBoundNS { id 5; type zCylinder; radius 194.84; origin (0.0 0.0 0.0); } + + + + //thickness specifications for core barrel + outerCoreBarrel { id 6; type zCylinder; radius 193.675; origin (0.0 0.0 0.0); } + innerCoreBarrel { id 7; type zCylinder; radius 187.96; origin (0.0 0.0 0.0); } + + + + //thickness specifications for grid with thickness of 0.0198 + pinThickGridInner { id 90; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.61015 0.61015 0.0); } + pinThickGridOuter { id 91; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.62992 0.62992 0.0); } + + + + //thickness specifications for grid with thickness of 0.0194 + pinThinGridInner { id 92; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.61015 0.61015 0.0); } + pinThinGridOuter { id 93; type zSquareCylinder; origin (0.0 0.0 0.0); halfwidth (0.62992 0.62992 0.0); } + + + // four planes that intersect to bound the Neutron sheild panel + P1 { id 8; type plane; coeffs (-0.48480962025 0.87461970714 0.0 0.0);} + P2 { id 9; type plane; coeffs (-0.87461970714 0.48480962025 0.0 0.0);} + P3 { id 10; type plane; coeffs (-0.87461970714 -0.48480962025 0.0 0.0);} + P4 { id 11; type plane; coeffs (-0.48480962025 -0.87461970714 0.0 0.0);} + + } + + cells { + + thickGrid {type simpleCell; id 55; surfaces (90 -91); filltype mat; material Inconel;} + thinGrid {type simpleCell; id 56; surfaces (-92 93); filltype mat; material Inconel;} + + pressureVessel { type simpleCell; id 7; surfaces (-1 2); filltype mat; material CarbonSteel;} + RPVLiner { type simpleCell; id 8; surfaces (-2 3); filltype mat; material SS304;} + outerWater1 {type simpleCell; id 9; surfaces (-3 4 ); filltype mat; material Water;} + + NS1{ type simpleCell; id 10; surfaces (-4 5 -8 9); filltype mat; material SS304;} + NS2{ type simpleCell; id 11; surfaces (-4 5 8 -9); filltype mat; material SS304;} + NS3{ type simpleCell; id 12; surfaces (-4 5 -10 11); filltype mat; material SS304;} + NS4{ type simpleCell; id 13; surfaces (-4 5 10 -11); filltype mat; material SS304;} + outerWaterSeg1 {type simpleCell; id 14; surfaces (-4 5 ); filltype mat; material Water;} + + outerWater2 {type simpleCell; id 15; surfaces (-5 6 ); filltype mat; material Water;} + + coreBarrel { type simpleCell; id 16; surfaces (-6 7); filltype mat; material SS304;} + + ! Choose whether to include a grid by commenting/uncommenting + !coreWithGrid {type simpleCell; id 17; surfaces (-5); filltype uni; universe 9999;} + coreWithoutGrid {type simpleCell; id 17; surfaces (-5); filltype uni; universe 10000;} + + + grid1 {type simpleCell; id 124; surfaces (-90); filltype uni; universe 24;} + grid2 {type simpleCell; id 112; surfaces (-90); filltype uni; universe 12;} + grid3 {type simpleCell; id 110; surfaces (-90); filltype uni; universe 10;} + grid4 {type simpleCell; id 131; surfaces (-90); filltype uni; universe 31;} + grid5 {type simpleCell; id 116; surfaces (-90); filltype uni; universe 16;} + grid6 {type simpleCell; id 114; surfaces (-90); filltype uni; universe 14;} + + + outsideLeftBaffle { type simpleCell; id 52; surfaces (-50); filltype mat; material Water;} + leftBaffle { type simpleCell; id 53; surfaces (50 -51); filltype mat; material SS304;} + insideLeftBaffle { type simpleCell; id 54; surfaces (51); filltype mat; material Water;} + + + outsideRightBaffle { type simpleCell; id 62; surfaces (-60); filltype mat; material Water;} + RightBaffle { type simpleCell; id 63; surfaces (60 -61); filltype mat; material SS304;} + insideRightBaffle { type simpleCell; id 64; surfaces (61); filltype mat; material Water;} + + + outsideTopBaffle { type simpleCell; id 72; surfaces (-70); filltype mat; material Water;} + TopBaffle { type simpleCell; id 73; surfaces (70 -71); filltype mat; material SS304;} + insideTopBaffle { type simpleCell; id 74; surfaces (71); filltype mat; material Water;} + + + outsideBottomBaffle { type simpleCell; id 82; surfaces (-80); filltype mat; material Water;} + BottomBaffle { type simpleCell; id 83; surfaces (80 -81); filltype mat; material SS304;} + insideBottomBaffle { type simpleCell; id 84; surfaces (81); filltype mat; material Water;} + + + topLeftCornerBaffle1 { type simpleCell; id 201; surfaces (60 -61 -81); filltype mat; material SS304;} + topLeftCornerBaffle2 { type simpleCell; id 202; surfaces (80 -81 -60); filltype mat; material SS304;} + topLeftCornerGap1 { type simpleCell; id 203; surfaces (81); filltype mat; material Water;} + topLeftCornerGap2 { type simpleCell; id 204; surfaces (61); filltype mat; material Water;} + topLeftMajorGap { type simpleCell; id 205; surfaces (-80 -60); filltype mat; material Water;} + + + topRightCornerBaffle1 { type simpleCell; id 301; surfaces (-81 50 -51); filltype mat; material SS304;} + topRightCornerBaffle2 { type simpleCell; id 302; surfaces (-50 80 -81); filltype mat; material SS304;} + topRightCornerGap1 { type simpleCell; id 303; surfaces (81); filltype mat; material Water;} + topRightCornerGap2 { type simpleCell; id 304; surfaces (51); filltype mat; material Water;} + topRightMajorGap { type simpleCell; id 305; surfaces (-80 -50); filltype mat; material Water;} + + + bottomLeftCornerBaffle1 { type simpleCell; id 401; surfaces (-71 60 -61); filltype mat; material SS304;} + bottomLeftCornerBaffle2 { type simpleCell; id 402; surfaces (-71 70 -60); filltype mat; material SS304;} + bottomLeftCornerGap1 { type simpleCell; id 403; surfaces (71); filltype mat; material Water;} + bottomLeftCornerGap2 { type simpleCell; id 404; surfaces (61); filltype mat; material Water;} + bottomLeftMajorGap { type simpleCell; id 405; surfaces (-70 -60); filltype mat; material Water;} + + + bottomRightCornerBaffle1 { type simpleCell; id 501; surfaces (-51 50 -71); filltype mat; material SS304;} + bottomRightCornerBaffle2 { type simpleCell; id 502; surfaces (-71 70 -50); filltype mat; material SS304;} + bottomRightCornerGap1 { type simpleCell; id 503; surfaces (51); filltype mat; material Water;} + bottomRightCornerGap2 { type simpleCell; id 504; surfaces (71); filltype mat; material Water;} + bottomRightMajorGap { type simpleCell; id 505; surfaces (-50 -70); filltype mat; material Water;} + + + TLSG1 { type simpleCell; id 601; surfaces (-80 -60); filltype mat; material Water;} + TLSG2 { type simpleCell; id 602; surfaces (-80 60); filltype mat; material Water;} + TLSG3 { type simpleCell; id 603; surfaces (80 -60); filltype mat; material Water;} + + topLeftSquare { type simpleCell; id 604; surfaces (80 60); filltype mat; material SS304;} + + + TRSG1 { type simpleCell; id 701; surfaces (-80 50); filltype mat; material Water;} + TRSG2 { type simpleCell; id 702; surfaces (-80 -50); filltype mat; material Water;} + TRSG3 { type simpleCell; id 703; surfaces (80 -50); filltype mat; material Water;} + + topRightSquare { type simpleCell; id 704; surfaces (80 50); filltype mat; material SS304;} + + + BLSG1 { type simpleCell; id 801; surfaces (70 -60); filltype mat; material Water;} + BLSG2 { type simpleCell; id 802; surfaces (-70 60); filltype mat; material Water;} + BLSG3 { type simpleCell; id 803; surfaces (-70 -60); filltype mat; material Water;} + + bottomLeftSquare { type simpleCell; id 804; surfaces (70 60); filltype mat; material SS304;} + + + BRSG1 { type simpleCell; id 901; surfaces (-70 50); filltype mat; material Water;} + BRSG2 { type simpleCell; id 902; surfaces (70 -50); filltype mat; material Water;} + BRSG3 { type simpleCell; id 903; surfaces (-70 -50); filltype mat; material Water;} + + bottomRightSquare { type simpleCell; id 904; surfaces (70 50); filltype mat; material SS304;} + } + + universes { + root { id 1; type rootUniverse; border 1; fill u<8888>; } + + // Pin universes + + //BP + pin10 { id 10; type pinUniverse; radii (0.21400 0.23051 0.24130 0.42672 0.43688 0.48387 0.56134 0.60198 0.0); + fills (Air SS304 Helium BorosilicateGlass Helium SS304 Water Zircaloy Water);} + + //GT + pin41 { id 12; type pinUniverse; radii (0.56134 0.60198 0.0 ); + fills (Water Zircaloy Water);} + + //INST Tube + pin51 { id 14; type pinUniverse; radii (0.43688 0.48387 .56134 0.60198 0.0 ); + fills (Air Zircaloy Water Zircaloy Water);} + + // pins + pin16 { id 16; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-16 Helium Zircaloy Water);} + + pin24 { id 24; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-24 Helium Zircaloy Water);} + + pin31 { id 31; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-31 Helium Zircaloy Water);} + + pin32 { id 32; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-32 Helium Zircaloy Water);} + + pin34 { id 34; type pinUniverse; radii (0.39218 0.40005 0.45720 0.0); + fills (UO2-34 Helium Zircaloy Water);} + + pinWater { id 1001; type pinUniverse; radii ( 0.0); fills (Water);} + pinSteel { id 1002; type pinUniverse; radii ( 0.0); fills (SS304);} + + // pin w/ grid universes + +// thickness of 0.0198 + GridPinOne { + id 110; + type cellUniverse; + cells (110 55);} + + GridPinTwo { + id 112; + type cellUniverse; + cells (112 55);} + + GridPinThree { + id 114; + type cellUniverse; + cells (114 55);} + + GridPinfour { + id 116; + type cellUniverse; + cells (116 55);} + + GridPinFive { + id 124; + type cellUniverse; + cells (124 55);} + + GridPinSix { + id 131; + type cellUniverse; + cells (131 55);} + +// thickness of 0.0194 + GridPinSeven { + id 9110; + type cellUniverse; + cells (110 56);} + + GridPinEight { + id 9112; + type cellUniverse; + cells (112 56);} + + GridPinNine { + id 9114; + type cellUniverse; + cells (114 56);} + + GridPinTen { + id 9216; + type cellUniverse; + cells (116 56);} + + GridPinEleven { + id 9224; + type cellUniverse; + cells (124 56);} + + GridPinTwelve { + id 9231; + type cellUniverse; + cells (131 56);} + + + + // Lattices w/ grid + A14E124 { + id 14124; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 112 124 124 112 124 124 112 124 124 124 124 124 + 124 124 124 112 124 124 124 124 124 124 124 124 124 112 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 112 124 124 112 124 124 112 124 124 112 124 124 112 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 112 124 124 112 124 124 114 124 124 112 124 124 112 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 112 124 124 112 124 124 112 124 124 112 124 124 112 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 112 124 124 124 124 124 124 124 124 124 112 124 124 124 + 124 124 124 124 124 112 124 124 112 124 124 112 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 ); } + + A14E116 { + id 14116; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 116 116 112 116 116 112 116 116 112 116 116 116 116 116 + 116 116 116 112 116 116 116 116 116 116 116 116 116 112 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 112 116 116 112 116 116 112 116 116 112 116 116 112 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 112 116 116 112 116 116 114 116 116 112 116 116 112 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 112 116 116 112 116 116 112 116 116 112 116 116 112 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 112 116 116 116 116 116 116 116 116 116 112 116 116 116 + 116 116 116 116 116 112 116 116 112 116 116 112 116 116 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 + 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116 116); } + + A14E131 { + id 14131; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 114 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + A60E131B { + id 6013116; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 112 131 131 110 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 114 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + A60E131T { + id 6013112; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 114 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 110 131 131 112 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + A60E131R { + id 601313; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 114 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 110 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + A60E131L { + id 601319; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 110 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 114 131 131 112 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + A15E131BR { + id 151315; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 110 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 114 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 110 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + + A15E131BL { + id 151317; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 110 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 114 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 110 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + A15E131TR { + id 151311; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 110 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 114 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 110 131 131 110 131 131 112 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + A15E131TL { + id 1513111; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 112 131 131 112 131 131 112 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 112 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 110 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 114 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 112 131 131 110 131 131 110 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 112 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + A116E131 { + id 116131; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 114 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 112 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + A20E131 { + id 20131; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 112 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 112 131 131 114 131 131 112 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 110 131 131 110 131 131 112 131 131 110 131 131 110 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 110 131 131 131 131 131 131 131 131 131 110 131 131 131 + 131 131 131 131 131 110 131 131 110 131 131 110 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 + 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 131 ); } + + + A12E124 { + id 12124; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 110 124 124 112 124 124 110 124 124 124 124 124 + 124 124 124 110 124 124 124 124 124 124 124 124 124 110 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 110 124 124 112 124 124 112 124 124 112 124 124 110 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 112 124 124 112 124 124 114 124 124 112 124 124 112 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 110 124 124 112 124 124 112 124 124 112 124 124 110 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 110 124 124 124 124 124 124 124 124 124 110 124 124 124 + 124 124 124 124 124 110 124 124 112 124 124 110 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 ); } + + A116E124 { + id 116124; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 110 124 124 110 124 124 110 124 124 124 124 124 + 124 124 124 110 124 124 124 124 124 124 124 124 124 110 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 110 124 124 112 124 124 112 124 124 112 124 124 110 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 110 124 124 112 124 124 114 124 124 112 124 124 110 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 110 124 124 112 124 124 112 124 124 112 124 124 110 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 110 124 124 124 124 124 124 124 124 124 110 124 124 124 + 124 124 124 124 124 110 124 124 110 124 124 110 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 + 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 124 ); } + + + // Lattices w/o grid + A14E24 { + id 1424; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 12 24 24 12 24 24 12 24 24 24 24 24 + 24 24 24 12 24 24 24 24 24 24 24 24 24 12 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 12 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 14 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 12 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 12 24 24 24 24 24 24 24 24 24 12 24 24 24 + 24 24 24 24 24 12 24 24 12 24 24 12 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A14E16 { + id 1416; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 12 16 16 12 16 16 12 16 16 16 16 16 + 16 16 16 12 16 16 16 16 16 16 16 16 16 12 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 12 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 14 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 12 16 16 12 16 16 12 16 16 12 16 16 12 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 12 16 16 16 16 16 16 16 16 16 12 16 16 16 + 16 16 16 16 16 12 16 16 12 16 16 12 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16); } + + A14E31 { + id 1431; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A60E31B { + id 60316; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A60E31T { + id 603112; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A60E31R { + id 60313; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 10 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A60E31L { + id 60319; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 14 31 31 12 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15E31BR { + id 15315; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + + A15E31BL { + id 15317; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15E31TR { + id 15311; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 14 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 10 31 31 10 31 31 12 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A15E31TL { + id 153111; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 12 31 31 12 31 31 12 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 12 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 14 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 12 31 31 10 31 31 10 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 12 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + A16E31 { + id 1631; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 14 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 12 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A20E31 { + id 2031; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 12 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 12 31 31 14 31 31 12 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 10 31 31 10 31 31 12 31 31 10 31 31 10 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 10 31 31 31 31 31 31 31 31 31 10 31 31 31 + 31 31 31 31 31 10 31 31 10 31 31 10 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 + 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 ); } + + + A12E24 { + id 1224; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 12 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 12 24 24 12 24 24 14 24 24 12 24 24 12 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 12 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + A16E24 { + id 1624; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat Water; + map ( + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 14 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 10 24 24 12 24 24 12 24 24 12 24 24 10 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 10 24 24 24 24 24 24 24 24 24 10 24 24 24 + 24 24 24 24 24 10 24 24 10 24 24 10 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 + 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 ); } + + + + leftBaffleUni { + id 2222; + type cellUniverse; + cells (52 53 54);} + + + rightBaffleUni { + id 2223; + type cellUniverse; + cells (62 63 64);} + + topBaffleUni { + id 2224; + type cellUniverse; + cells (72 73 74);} + + bottomBaffleUni { + id 2225; + type cellUniverse; + cells (84 83 82);} + + + topLeft { + id 2226; + type cellUniverse; + cells (201 202 203 204 205);} + + topRight { + id 2227; + type cellUniverse; + cells ( 301 302 303 304 305);} + + BottomLeft { + id 2228; + type cellUniverse; + cells ( 401 402 403 404 405);} + + BottomRight { + id 2229; + type cellUniverse; + cells ( 501 502 503 504 505);} + + + SQTL { + id 1005; + type cellUniverse; + cells (601 602 603 604);} + + + SQTR { + id 1006; + type cellUniverse; + cells (701 702 703 704);} + + SQBL { + id 1007; + type cellUniverse; + cells (801 802 803 804);} + + SQBR { + id 1008; + type cellUniverse; + cells (901 902 903 904);} + + + latCoreGrid { + id 9999; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.50364 21.50364 0.0); + shape (17 17 0); + padMat Water; + map ( + 1001 1001 1001 1001 1008 2224 2224 2224 2224 2224 2224 2224 1007 1001 1001 1001 1001 + 1001 1001 1008 2224 2229 14131 6013112 14131 6013112 14131 6013112 14131 2228 2224 1007 1001 1001 + 1001 1008 2229 14131 14131 116131 14116 20131 14116 20131 14116 116131 14131 14131 2228 1007 1001 + 1001 2222 14131 1513111 116124 14116 116124 14116 116124 14116 116124 14116 116124 151311 14131 2223 1001 + 1008 2229 14131 116124 14124 116124 14116 12124 14116 12124 14116 116124 14124 116124 14131 2228 1007 + 2222 14131 116131 14116 116124 14116 12124 14116 12124 14116 12124 14116 116124 14116 116131 14131 2223 + 2222 601319 14116 116124 14116 12124 14116 12124 14116 12124 14116 12124 14116 116124 14116 601313 2223 + 2222 14131 20131 14116 12124 14116 12124 14116 12124 14116 12124 14116 12124 14116 20131 14131 2223 + 2222 601319 14116 116124 14116 12124 14116 12124 14116 12124 14116 12124 14116 116124 14116 601313 2223 + 2222 14131 20131 14116 12124 14116 12124 14116 12124 14116 12124 14116 12124 14116 20131 14131 2223 + 2222 601319 14116 116124 14116 12124 14116 12124 14116 12124 14116 12124 14116 116124 14116 601313 2223 + 2222 14131 116131 14116 116124 14116 12124 14116 12124 14116 12124 14116 116124 14116 116131 14131 2223 + 1006 2227 14131 116124 14124 116124 14116 12124 14116 12124 14116 116124 14124 116124 14131 2226 1005 + 1001 2222 14131 151317 116124 14116 116124 14116 116124 14116 116124 14116 116124 151315 14131 2223 1001 + 1001 1006 2227 14131 14131 116131 14116 20131 14116 20131 14116 116131 14131 14131 2226 1005 1001 + 1001 1001 1006 2225 2227 14131 6013116 14131 6013116 14131 6013116 14131 2226 2225 1005 1001 1001 + 1001 1001 1001 1001 1006 2225 2225 2225 2225 2225 2225 2225 1005 1001 1001 1001 1001 ); } + + latCore { + id 10000; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.50364 21.50364 0.0); + shape (17 17 0); + padMat Water; + map ( + 1001 1001 1001 1001 1008 2224 2224 2224 2224 2224 2224 2224 1007 1001 1001 1001 1001 + 1001 1001 1008 2224 2229 1431 603112 1431 603112 1431 603112 1431 2228 2224 1007 1001 1001 + 1001 1008 2229 1431 1431 1631 1416 2031 1416 2031 1416 1631 1431 1431 2228 1007 1001 + 1001 2222 1431 153111 1624 1416 1624 1416 1624 1416 1624 1416 1624 15311 1431 2223 1001 + 1008 2229 1431 1624 1424 1624 1416 1224 1416 1224 1416 1624 1424 1624 1431 2228 1007 + 2222 1431 1631 1416 1624 1416 1224 1416 1224 1416 1224 1416 1624 1416 1631 1431 2223 + 2222 60319 1416 1624 1416 1224 1416 1224 1416 1224 1416 1224 1416 1624 1416 60313 2223 + 2222 1431 2031 1416 1224 1416 1224 1416 1224 1416 1224 1416 1224 1416 2031 1431 2223 + 2222 60319 1416 1624 1416 1224 1416 1224 1416 1224 1416 1224 1416 1624 1416 60313 2223 + 2222 1431 2031 1416 1224 1416 1224 1416 1224 1416 1224 1416 1224 1416 2031 1431 2223 + 2222 60319 1416 1624 1416 1224 1416 1224 1416 1224 1416 1224 1416 1624 1416 60313 2223 + 2222 1431 1631 1416 1624 1416 1224 1416 1224 1416 1224 1416 1624 1416 1631 1431 2223 + 1006 2227 1431 1624 1424 1624 1416 1224 1416 1224 1416 1624 1424 1624 1431 2226 1005 + 1001 2222 1431 15317 1624 1416 1624 1416 1624 1416 1624 1416 1624 15315 1431 2223 1001 + 1001 1006 2227 1431 1431 1631 1416 2031 1416 2031 1416 1631 1431 1431 2226 1005 1001 + 1001 1001 1006 2225 2227 1431 60316 1431 60316 1431 60316 1431 2226 2225 1005 1001 1001 + 1001 1001 1001 1001 1006 2225 2225 2225 2225 2225 2225 2225 1005 1001 1001 1001 1001 ); } + + coreAndStructures { + id 8888; + type cellUniverse; + cells (7 8 9 10 11 12 13 14 15 16 17);} + + + + } +} + + +viz { + bmp { + type bmp; + output img; + what material; + centre (0.0 0.0 0.0); + //width (25.0 25.0); + axis z; + res (5000 5000); + } +} + + +nuclearData { + handles { + ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE; ures 0;} + } + materials { + + ! Note that temperatures should be modified. + ! Reactor is isothermal and coolant temperature should be 566K. + ! This data is not directly available and we do not yet use + ! stochastic mixing or OTF Doppler. + ! Some libraries may not contain all isotopes present here. + ! These are commented out. + + Air { + temp 566; + composition { + 18036.06 7.8730E-09; + 18038.06 1.4844E-09; + 18040.06 2.3506E-06; + 6012.06 6.7539E-08; + //6013.06 7.5658E-10; + 7014.06 1.9680E-04; + 7015.06 7.2354E-07; + 8016.06 5.2866E-05; + 8017.06 2.0084E-08; + //8018.06 1.0601E-07; + } + } + + SS304 { + temp 566; + composition { + 24050.06 7.6778E-04; + 24052.06 1.4806E-02; + 24053.06 1.6789E-03; + 24054.06 4.1791E-04; + 26054.06 3.4620E-03; + 26056.06 5.4345E-02; + 26057.06 1.2551E-03; + 26058.06 1.6703E-04; + 25055.06 1.7604E-03; + 28058.06 5.6089E-03; + 28060.06 2.1605E-03; + 28061.06 9.3917E-05; + 28062.06 2.9945E-04; + 28064.06 7.6261E-05; + 14028.06 9.5281E-04; + 14029.06 4.8381E-05; + 14030.06 3.1893E-05; } + } + + Helium { + temp 566; + composition { + 2003.06 4.8089E-10; + 2004.06 2.4044E-04; } + } + + BorosilicateGlass { + temp 566; + composition { + 13027.06 1.7352E-03; + 5010.06 9.6506E-04; + 5011.06 3.9189E-03; + 8016.06 4.6514E-02; + 8017.06 1.7671E-05; + //8018.06 9.3268E-05; + 14028.06 1.6926E-02; + 14029.06 8.5944E-04; + 14030.06 5.6654E-04; } + } + + Water { + temp 566; + moder {1001.06 lwj3.11; } + composition { + 5010.06 7.9714E-06; + 5011.06 3.2247E-05; + 1001.06 4.9456E-02; + 1002.06 7.7035E-06; + 8016.06 2.4673E-02; + 8017.06 9.3734E-06; + //8018.06 4.9474E-05; + } + } + + Zircaloy { + temp 566; + composition { + 24050.06 3.2962E-06; + 24052.06 6.3564E-05; + 24053.06 7.2076E-06; + 24054.06 1.7941E-06; + 26054.06 8.6698E-06; + 26056.06 1.3610E-04; + 26057.06 3.1431E-06; + 26058.06 4.1829E-07; + 8016.06 3.0744E-04; + 8017.06 1.1680E-07; + //8018.06 6.1648E-07; + 50112.06 4.6735E-06; + 50114.06 3.1799E-06; + 50115.06 1.6381E-06; + 50116.06 7.0055E-05; + 50117.06 3.7003E-05; + 50118.06 1.1669E-04; + 50119.06 4.1387E-05; + 50120.06 1.5697E-04; + 50122.06 2.2308E-05; + 50124.06 2.7897E-05; + 40090.06 2.1828E-02; + 40091.06 4.7601E-03; + 40092.06 7.2759E-03; + 40094.06 7.3734E-03; + 40096.06 1.1879E-03; } + } + + Inconel{ + temp 566; + composition { + 24050.06 7.8239E-04; + 24052.06 1.5088E-02; + 24053.06 1.7108E-03; + 24054.06 4.2586E-04; + 26054.06 1.4797E-03; + 26056.06 2.3229E-02; + 26057.06 5.3645E-04; + 26058.06 7.1392E-05; + 25055.06 7.8201E-04; + 28058.06 2.9320E-02; + 28060.06 1.1294E-02; + 28061.06 4.9094E-04; + 28062.06 1.5653E-03; + 28064.06 3.9864E-04; + 14028.06 5.6757E-04; + 14029.06 2.8820E-05; + 14030.06 1.8998E-05; } + } + + B4C{ + temp 566; + composition { + 5010.06 1.5206E-02; + 5011.06 6.1514E-02; + 6012.06 1.8972E-02; + //6013.06 2.1252E-04; + } + } + + Ag-In-Cd{ + temp 566; + composition { + 47107.06 2.3523E-02; + 47109.06 2.1854E-02; + 48106.06 3.3882E-05; + 48108.06 2.4166E-05; + 48110.06 3.3936E-04; + 48111.06 3.4821E-04; + 48112.06 6.5611E-04; + 48113.06 3.3275E-04; + 48114.06 7.8252E-04; + 48116.06 2.0443E-04; + 49113.06 3.4219E-04; + 49115.06 7.6511E-03; } + } + + //mox fuel used + UO2-16 { + temp 566; + composition { + 8016.06 4.5897E-02; + 8017.06 1.7436E-05; + //8018.06 9.2032E-05; + 92234.06 3.0131E-06; + 92235.06 3.7503E-04; + 92238.06 2.2625E-02;} + } + + UO2-24 { + temp 566; + composition { + 8016.06 4.5830E-02; + 8017.06 1.7411E-05; + //8018.06 9.1898E-05; + 92234.06 4.4842E-06; + 92235.06 5.5814E-04; + 92238.06 2.2407E-02;} + } + + UO2-31 { + temp 566; + composition { + 8016.06 4.5853E-02; + 8017.06 1.7420E-05; + //8018.06 9.1942E-05; + 92234.06 5.7987E-06; + 92235.06 7.2175E-04; + 92238.06 2.2253E-02;} + } + + UO2-32 { + temp 566; + composition { + 8016.06 4.6029E-02; + 8017.06 1.7487E-05; + //8018.06 9.2296E-05; + 92234.06 5.9959E-06; + 92235.06 7.4630E-04; + 92238.06 2.2317E-02; + } + } + + UO2-34 { + temp 566; + composition { + 8016.06 4.6110E-02; + 8017.06 1.7517E-05; + //8018.06 9.2459E-05; + 92234.06 6.4018E-06; + 92235.06 7.9681E-04; + 92238.06 2.2307E-02;} + } + + // vanadium51 was stated twice in carbonsteel below + // in the beavrs pdf - typo? + CarbonSteel { + temp 566; + composition { + 13027.06 4.3523E-05; + 5010.06 2.5833E-06; + 5011.06 1.0450E-05; + 6012.06 1.0442E-03; + //6013.06 1.1697E-05 ; + 20040.06 1.7043E-05; + 20042.06 1.1375E-07; + 20043.06 2.3734E-08; + 20044.06 3.6673E-07; + 20046.06 7.0322E-10; + 20048.06 3.2875E-08; + 24050.06 1.3738E-05; + 24052.06 2.6493E-04; + 24053.06 3.0041E-05; + 24054.06 7.4778E-06; + 29063.06 1.0223E-04; + 29065.06 4.5608E-05; + 26054.06 4.7437E-03; + 26056.06 7.4465E-02; + 26057.06 1.7197E-03; + 26058.06 2.2886E-04; + 25055.06 6.4126E-04; + 42100.06 2.9814E-05; + 42092.06 4.4822E-05; + 42094.06 2.8110E-05; + 42095.06 4.8567E-05; + 42096.06 5.1015E-05; + 42097.06 2.9319E-05; + 42098.06 7.4327E-05; + 41093.06 5.0559E-06; + 28058.06 4.0862E-04; + 28060.06 1.5740E-04; + 28061.06 6.8420E-06; + 28062.06 2.1815E-05; + 28064.06 5.5557E-06; + 15031.06 3.7913E-05; + 16032.06 3.4808E-05; + 16033.06 2.7420E-07; + 16034.06 1.5368E-06; + 16036.06 5.3398E-09; + 14028.06 6.1702E-04; + 14029.06 3.1330E-05; + 14030.06 2.0653E-05; + 22046.06 1.2144E-06; + 22047.06 1.0952E-06; + 22048.06 1.0851E-05; + 22049.06 7.9634E-07; + 22050.06 7.6249E-07; + //23050.06 1.1526E-07; + 23051.06 4.5989E-05; + } + } + + SupportPlateSS { + temp 566; + composition { + 24050.06 3.5223E-04; + 24052.06 6.7924E-03; + 24053.06 7.7020E-04; + 24054.06 1.9172E-04; + 26054.06 1.5882E-03; + 26056.06 2.4931E-02; + 26057.06 5.7578E-04; + 26058.06 7.6625E-05; + 25055.06 8.0762E-04; + 28058.06 2.5731E-03; + 28060.06 9.9117E-04; + 28061.06 4.3085E-05; + 28062.06 1.3738E-04; + 28064.06 3.4985E-05; + 14028.06 4.3711E-04; + 14029.06 2.2195E-05; + 14030.06 1.4631E-05;} + } + + SupportPlateBW { + temp 566; + moder {1001.06 lwj3.11; } + composition { + 5010.06 1.0559E-05; + 5011.06 4.2716E-05; + 1001.06 6.5512E-02; + 1002.06 1.0204E-05; + 8016.06 3.2683E-02; + 8017.06 1.2416E-05; + //8018.06 6.5535E-05; + } + } + + +} +} diff --git a/InputFiles/Benchmarks/SourceConvergence/checkerboard b/InputFiles/Benchmarks/SourceConvergence/checkerboard index 06efea5ac..cc01927e3 100644 --- a/InputFiles/Benchmarks/SourceConvergence/checkerboard +++ b/InputFiles/Benchmarks/SourceConvergence/checkerboard @@ -1,3 +1,11 @@ +!! +!! OECD-NEA source convergence challenge problem 1. +!! Spent fuel pool with a checkerboard layout of assemblies, +!! separated by water, surrounded by both water and concrete. +!! Requires ~2500 unaccelerated inactive cycles to converge. +!! Has a keff ~0.889. The vast majority of fissions will take +!! place in the top left assembly bordered by concrete. +!! type eigenPhysicsPackage; pop 100000; @@ -173,7 +181,7 @@ viz { nuclearData { handles { - ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE;} + ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE; } } materials { From 4d1ef0a685e01e476827c9b7e1127e87cdb08f7e Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Fri, 5 Apr 2024 23:20:39 +0100 Subject: [PATCH 105/133] Add C5G7 to benchmarks --- InputFiles/Benchmarks/Multigroup/C5G7 | 192 ++++++++++++++++++ InputFiles/Benchmarks/Multigroup/XS_C5G7/CR | 31 +++ InputFiles/Benchmarks/Multigroup/XS_C5G7/FC | 34 ++++ InputFiles/Benchmarks/Multigroup/XS_C5G7/GT | 31 +++ .../Benchmarks/Multigroup/XS_C5G7/MOX43 | 36 ++++ InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX7 | 36 ++++ .../Benchmarks/Multigroup/XS_C5G7/MOX87 | 34 ++++ InputFiles/Benchmarks/Multigroup/XS_C5G7/UO2 | 34 ++++ .../Benchmarks/Multigroup/XS_C5G7/moder | 31 +++ 9 files changed, 459 insertions(+) create mode 100644 InputFiles/Benchmarks/Multigroup/C5G7 create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/CR create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/FC create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/GT create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX43 create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX7 create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX87 create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/UO2 create mode 100644 InputFiles/Benchmarks/Multigroup/XS_C5G7/moder diff --git a/InputFiles/Benchmarks/Multigroup/C5G7 b/InputFiles/Benchmarks/Multigroup/C5G7 new file mode 100644 index 000000000..c99ad7d7d --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/C5G7 @@ -0,0 +1,192 @@ +type eigenPhysicsPackage; +pop 80000; +active 1040; +inactive 50; +XSdata mg; +dataType mg; +outputFile C5G7 ; + +collisionOperator { neutronMG {type neutronMGstd; } } +transportOperator { type transportOperatorHT; cache 1;} + +inactiveTally {} +activeTally { + fissionMap {type collisionClerk; + map {type multiMap; + maps (xax yax); + xax { type spaceMap; axis x; grid lin; min -32.13; max 10.71; N 34;} + yax { type spaceMap; axis y; grid lin; min -10.71; max 32.13; N 34;} + } + response (fiss); + fiss { type macroResponse; MT -6; } + } +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 0 1 1 1); + graph {type extended;} + + surfaces { + Domain { id 3; type box; origin (0.0 0.0 0.0); halfwidth (32.13 32.13 32.13);} + } + + cells {} + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { id 1; type pinUniverse; radii (0.5400 0.0 ); fills (UO2 water);} + pin2 { id 2; type pinUniverse; radii (0.5400 0.0 ); fills (GT water);} + pin3 { id 3; type pinUniverse; radii (0.5400 0.0 ); fills (mox43 water);} + pin4 { id 4; type pinUniverse; radii (0.5400 0.0 ); fills (mox7 water);} + pin5 { id 5; type pinUniverse; radii (0.5400 0.0 ); fills (mox87 water);} + pin6 { id 6; type pinUniverse; radii (0.5400 0.0 ); fills (FC water);} + + // Infinite moderator + pin30 { id 30; type pinUniverse; radii (0.0); fills (water);} + +// Lattices +latUO2{ + id 10; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat water; + map ( + + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 + 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 2 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 6 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 2 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 + 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +); +} + +latMOX{ + id 20; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat water; + map ( + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 + 3 4 4 4 4 2 4 4 2 4 4 2 4 4 4 4 3 + 3 4 4 2 4 5 5 5 5 5 5 5 4 2 4 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 2 5 5 2 5 5 2 5 5 2 5 5 2 4 3 + 3 4 4 5 5 5 5 5 5 5 5 5 5 5 4 4 3 + 3 4 4 5 5 5 5 5 5 5 5 5 5 5 4 4 3 + 3 4 2 5 5 2 5 5 6 5 5 2 5 5 2 4 3 + 3 4 4 5 5 5 5 5 5 5 5 5 5 5 4 4 3 + 3 4 4 5 5 5 5 5 5 5 5 5 5 5 4 4 3 + 3 4 2 5 5 2 5 5 2 5 5 2 5 5 2 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 4 2 4 5 5 5 5 5 5 5 4 2 4 4 3 + 3 4 4 4 4 2 4 4 2 4 4 2 4 4 4 4 3 + 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +); +} + +latCore +{ + id 100; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.42 21.42 0.0); + shape (3 3 0); + padMat water; + map ( +10 20 30 +20 10 30 +30 30 30 +); +} + +} + +} + +viz { + bmp1 { + type bmp; + output C5G7_xy; + what material; + centre (0.0 0.0 10.0); + axis z; + res (1000 1000); } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + mox43 { + temp 300; + xsFile ./XS_C5G7/MOX43; + composition { } + } + + mox7 { + temp 300; + xsFile ./XS_C5G7/MOX7; + composition { } + } + + mox87 { + temp 300; + xsFile ./XS_C5G7/MOX87; + composition { } + } + + UO2 { + temp 300; + xsFile ./XS_C5G7/UO2; + composition { } + } + + // Fission chamber + FC { + temp 300; + xsFile ./XS_C5G7/FC; + composition { } + } + + // Guide tube + GT { + temp 300; + xsFile ./XS_C5G7/GT; + composition { } + } + + water { + temp 300; + xsFile ./XS_C5G7/moder; + composition { } + } + +} +} + + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/CR b/InputFiles/Benchmarks/Multigroup/XS_C5G7/CR new file mode 100644 index 000000000..e4dbeae5b --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/CR @@ -0,0 +1,31 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (1.7049E-03 8.36224E-03 8.37901E-02 3.97797E-01 6.98763E-01 9.29508E-01 1.17836); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +1.70563E-01 4.44012E-02 9.83670E-05 1.27786E-07 0.0 0.000000E+00 0.000000E+00 +0.000000E+00 4.71050E-01 6.85480E-04 3.91395E-10 0.0 0.0 0.0 +0.000000E+00 0.000000E+00 8.01859E-01 7.20132E-04 0.0 0.0 0.0 +0.000000E+00 0.000000E+00 0.000000E+00 5.70752E-01 1.46015E-03 0.0 0.0 +0.000000E+00 0.000000E+00 0.000000E+00 6.55562E-05 2.07838E-01 3.81486E-03 3.69760E-9 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 1.02427E-03 2.02465E-01 4.75290E-3 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 3.53043E-03 6.58597E-01 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/FC b/InputFiles/Benchmarks/Multigroup/XS_C5G7/FC new file mode 100644 index 000000000..441cd9895 --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/FC @@ -0,0 +1,34 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (5.113152100E-04 7.580717436E-05 3.159662810E-04 1.162255940E-03 3.397554610E-03 9.187885028E-03 2.324191959E-02); +fission (4.790020000E-09 5.825640000E-09 4.637190000E-07 5.244060000E-06 1.453900000E-07 7.149720000E-07 2.080410000E-06); +nu ( 2.762829800E+00 2.462390398E+00 2.433799348E+00 2.433799384E+00 2.433800124E+00 2.433800205E+00 2.433800068E+00); +chi ( 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +6.616590000E-02 5.907000000E-02 2.833400000E-04 1.462200000E-06 2.064200000E-08 0.000000000E+00 0.000000000E+00 +0.000000000E+00 2.403770000E-01 5.243500000E-02 2.499000000E-04 1.923900000E-05 2.987500000E-06 4.214000000E-07 +0.000000000E+00 0.000000000E+00 1.834250000E-01 9.228800000E-02 6.936500000E-03 1.079000000E-03 2.054300000E-04 +0.000000000E+00 0.000000000E+00 0.000000000E+00 7.907690000E-02 1.699900000E-01 2.586000000E-02 4.925600000E-03 +0.000000000E+00 0.000000000E+00 0.000000000E+00 3.734000000E-05 9.975700000E-02 2.067900000E-01 2.447800000E-02 +0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00 9.174200000E-04 3.167740000E-01 2.387600000E-01 +0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00 4.979300000E-02 1.099100000E+00 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/GT b/InputFiles/Benchmarks/Multigroup/XS_C5G7/GT new file mode 100644 index 000000000..77ed9f30f --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/GT @@ -0,0 +1,31 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (5.113200E-04 7.580100E-05 3.157200E-04 1.158200E-03 3.397500E-03 9.187800E-03 2.324200E-02); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +6.616590E-02 5.907000E-02 2.833400E-04 1.462200E-06 2.064200E-08 0.000000E+00 0.000000E+00 +0.000000E+00 2.403770E-01 5.243500E-02 2.499000E-04 1.923900E-05 2.987500E-06 4.214000E-07 +0.000000E+00 0.000000E+00 1.832970E-01 9.239700E-02 6.944600E-03 1.080300E-03 2.056700E-04 +0.000000E+00 0.000000E+00 0.000000E+00 7.885110E-02 1.701400E-01 2.588100E-02 4.929700E-03 +0.000000E+00 0.000000E+00 0.000000E+00 3.733300E-05 9.973720E-02 2.067900E-01 2.447800E-02 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 9.172600E-04 3.167650E-01 2.387700E-01 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 4.979200E-02 1.099120E+00 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX43 b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX43 new file mode 100644 index 000000000..46054ba02 --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX43 @@ -0,0 +1,36 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (8.0686000E-04 2.8808020E-03 2.2271650E-02 8.1322800E-02 1.2917650E-01 1.7642300E-01 1.6038200E-01); + +fission ( 7.627040E-03 8.768980E-04 5.698350E-03 2.288720E-02 1.076350E-02 2.327570E-01 2.489680E-01); + +nu (2.852089E+00 2.890990E+00 2.854860E+00 2.860730E+00 2.854470E+00 2.864150E+00 2.867800E+00); +chi ( 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +1.288760E-01 4.141300E-02 8.229000E-06 5.040500E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 3.254520E-01 1.639500E-03 1.598200E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 4.531880E-01 2.614200E-03 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 4.571730E-01 5.539400E-03 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 1.604600E-04 2.768140E-01 9.312700E-03 9.165600E-09 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 2.005100E-03 2.529620E-01 1.485000E-02 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 8.494800E-03 2.650070E-01 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX7 b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX7 new file mode 100644 index 000000000..3db4c6cb1 --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX7 @@ -0,0 +1,36 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (8.112400E-04 2.971050E-03 2.445944E-02 8.915700E-02 1.670164E-01 2.446660E-01 2.224070E-01); +fission (8.254460E-03 1.325650E-03 8.421560E-03 3.287300E-02 1.596360E-02 3.237940E-01 3.628030E-01); +nu ( 2.884980E+00 2.910790E+00 2.865740E+00 2.870630E+00 2.867140E+00 2.866580E+00 2.875390E+00); +chi ( 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00); + + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + + +P0 ( +1.304570E-01 4.179200E-02 8.510500E-06 5.132900E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 3.284280E-01 1.643600E-03 2.201700E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 4.583710E-01 2.533100E-03 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 4.637090E-01 5.476600E-03 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 1.761900E-04 2.823130E-01 8.728900E-03 9.001600E-09 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 2.276000E-03 2.497510E-01 1.311400E-02 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 8.864500E-03 2.595290E-01 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX87 b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX87 new file mode 100644 index 000000000..6d47c4a11 --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/MOX87 @@ -0,0 +1,34 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (8.141100E-04 3.031340E-03 2.596840E-02 9.367530E-02 1.891424E-01 2.838120E-01 2.595710E-01); +fission (8.672090E-03 1.624260E-03 1.027160E-02 3.904470E-02 1.925760E-02 3.748880E-01 4.305990E-01); +nu ( 2.904260E+00 2.917950E+00 2.869860E+00 2.874910E+00 2.871750E+00 2.867520E+00 2.878079E+00); +chi ( 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +1.315040E-01 4.204600E-02 8.697200E-06 5.193800E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 3.304030E-01 1.646300E-03 2.600600E-09 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 4.617920E-01 2.474900E-03 0.000000E+00 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 4.680210E-01 5.433000E-03 0.000000E+00 0.000000E+00 +0.000000E+00 0.000000E+00 0.000000E+00 1.859700E-04 2.857710E-01 8.397300E-03 8.928000E-09 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 2.391600E-03 2.476140E-01 1.232200E-02 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 8.968100E-03 2.560930E-01 +); + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/UO2 b/InputFiles/Benchmarks/Multigroup/XS_C5G7/UO2 new file mode 100644 index 000000000..ffb187b5d --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/UO2 @@ -0,0 +1,34 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; +capture ( 8.1274000E-04 2.8980990E-03 2.0315800E-02 7.7671200E-02 1.2211600E-02 2.8225200E-02 6.6776000E-02); +fission ( 7.212060E-3 8.193010E-4 6.453200E-3 1.856480E-2 1.780840E-2 8.303480E-2 2.160040E-1); +nu ( 2.7814494E+00 2.4744300E+00 2.4338297E+00 2.4338000E+00 2.43380E+00 2.43380E+00 2.43380E+00); +chi ( 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +1.2753700E-01 4.2378000E-02 9.4374000E-06 5.5163000E-09 0.0000000E+00 0.0000000E+00 0.0000000E+00 +0.0000000E+00 3.2445600E-01 1.6314000E-03 3.1427000E-09 0.0000000E+00 0.0000000E+00 0.0000000E+00 +0.0000000E+00 0.0000000E+00 4.5094000E-01 2.6792000E-03 0.0000000E+00 0.0000000E+00 0.0000000E+00 +0.0000000E+00 0.0000000E+00 0.0000000E+00 4.5256500E-01 5.5664000E-03 0.0000000E+00 0.0000000E+00 +0.0000000E+00 0.0000000E+00 0.0000000E+00 1.2525000E-04 2.7140100E-01 1.0255000E-02 1.0021000E-08 +0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 1.2968000E-03 2.6580200E-01 1.6809000E-02 +0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 8.5458000E-03 2.7308000E-01 +); + + diff --git a/InputFiles/Benchmarks/Multigroup/XS_C5G7/moder b/InputFiles/Benchmarks/Multigroup/XS_C5G7/moder new file mode 100644 index 000000000..029b934f1 --- /dev/null +++ b/InputFiles/Benchmarks/Multigroup/XS_C5G7/moder @@ -0,0 +1,31 @@ +// This XSS are from the C5G7 Benchamrk Problem +// Source: OECD-NEA +// ‘Benchmark specification for deterministic 2D/3D MOX +// fuel assembly transport calculations without spatial +// homogenisation (C5G7 MOX)’ +// + +numberOfGroups 7; + +capture (6.010500E-04 1.579300E-05 3.371600E-04 1.940600E-03 5.741600E-03 1.500100E-02 3.723900E-02); + +scatteringMultiplicity ( +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +1.0 1.0 1.0 1.0 1.0 1.0 1.0 +); + +P0 ( +4.447770E-02 1.134000E-01 7.234700E-04 3.749900E-06 5.318400E-08 0.000000E+00 0.000000E+00 +0.000000E+00 2.823340E-01 1.299400E-01 6.234000E-04 4.800200E-05 7.448600E-06 1.045500E-06 +0.000000E+00 0.000000E+00 3.452560E-01 2.245700E-01 1.699900E-02 2.644300E-03 5.034400E-04 +0.000000E+00 0.000000E+00 0.000000E+00 9.102840E-02 4.155100E-01 6.373200E-02 1.213900E-02 +0.000000E+00 0.000000E+00 0.000000E+00 7.143700E-05 1.391380E-01 5.118200E-01 6.122900E-02 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 2.215700E-03 6.999130E-01 5.373200E-01 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 1.324400E-01 2.480700E+00 +); + From 00f888d5a5c0c8535f6447c468227ccf41e608df Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Mon, 8 Apr 2024 13:44:06 +0100 Subject: [PATCH 106/133] Fixes normSize subroutine in dungeon Previously inserted uninitialised neutrons in the dungeon when population declines steeply. --- ParticleObjects/particleDungeon_class.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index 4d77538dd..ef7d75841 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -434,7 +434,7 @@ subroutine normSize(self, N, rand) ! Copy all particle maximum possible number of times do i = 1, n_copies - self % prisoners(N * i + 1 : N * (i + 1)) = self % prisoners(1:N) + self % prisoners(self % pop * i + 1 : self % pop * (i + 1)) = self % prisoners(1:self % pop) end do ! Choose the remainder particles to duplicate without replacement @@ -445,6 +445,7 @@ subroutine normSize(self, N, rand) duplicates(idx) = i end if end do + self % pop = self % pop * (n_copies + 1) ! Copy the duplicated particles at the end do i = 1, n_duplicates From 8679aa7348b453a787106472b8113a39c212356e Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:20:18 +0100 Subject: [PATCH 107/133] Typo in nuclearDatabase_inter.f90 --- NuclearData/nuclearDatabase_inter.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index ae89b4f56..dea78836f 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -21,7 +21,7 @@ module nuclearDatabase_inter !! subclasses of this type. !! !! Interface: - !! getTrackingXS -> returns XS used to sample track lenght + !! getTrackingXS -> returns XS used to sample track length !! getTotalMatXS -> returns total Material XS given a particle !! getMajorantXS -> returns majorant XS given particle and list of active materials !! matNamesMap -> returns pointer to map of material names to matIdx From 4f7383c0bbb958276981fe18c5fd94d627c79b9d Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Tue, 9 Apr 2024 14:29:12 +0100 Subject: [PATCH 108/133] Added Hoogenboom-Martin core --- InputFiles/Benchmarks/HoogenboomMartin/HMcore | 575 ++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 InputFiles/Benchmarks/HoogenboomMartin/HMcore diff --git a/InputFiles/Benchmarks/HoogenboomMartin/HMcore b/InputFiles/Benchmarks/HoogenboomMartin/HMcore new file mode 100644 index 000000000..f4f53f30e --- /dev/null +++ b/InputFiles/Benchmarks/HoogenboomMartin/HMcore @@ -0,0 +1,575 @@ +!! +!! Hoogenboom-Martin PWR core with specified tallies +!! +type eigenPhysicsPackage; + +pop 5000000; +active 150; +inactive 200; +XSdata ce; +dataType ce; + + +// Specify output format default asciiMATLAB +//outputFormat asciiJSON; + +collisionOperator { neutronCE {type neutronCEstd;} } + +transportOperator { + type transportOperatorHT; + } + +inactiveTally { + shannon { + type shannonEntropyClerk; + map {type multiMap; + maps (xax yax zax); + xax { type spaceMap; grid lin; min -182.07; max 182.07; N 21; axis x;} + yax { type spaceMap; grid lin; min -182.07; max 182.07; N 21; axis y;} + zax { type spaceMap; grid lin; min -183; max 183; N 20; axis z;} + } + cycles 200; + } +} + +activeTally { + + pinFiss { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax zax); + xax {type spaceMap; axis x; grid lin; N 289; min -182.07; max 182.07; } + yax {type spaceMap; axis y; grid lin; N 289; min -182.07; max 182.07; } + zax {type spaceMap; axis y; grid lin; N 100; min -183; max 183; } + } + } + assemblyFissRadial { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} + map {type multiMap; maps (xax yax); + xax {type spaceMap; axis x; grid lin; N 17; min -182.07; max 182.07; } + yax {type spaceMap; axis y; grid lin; N 17; min -182.07; max 182.07; } + } + } + +} + +! Uniform fission site map +uniformFissionSites { + type uniFissSitesField; + map {type multiMap; maps (xax yax zax); + xax {type spaceMap; axis x; grid lin; N 17; min -182.07; max 182.07; } + yax {type spaceMap; axis y; grid lin; N 17; min -182.07; max 182.07; } + zax {type spaceMap; axis y; grid lin; N 17; min -183; max 183; } + } +} + +geometry { + type geometryStd; + boundary (0 0 0 0 0 0); + graph {type shrunk;} + +surfaces { + + boundingSurface { id 80; type zTruncCylinder; origin (0.0 0.0 -3.0); halfwidth 226.0; radius 249.0; } + + surf5 { id 5; type zCylinder; origin (0.0 0.0 0.0); radius 187.6;} + surf6 { id 6; type zCylinder; origin (0.0 0.0 0.0); radius 209.0;} + surf7 { id 7; type zCylinder; origin (0.0 0.0 0.0); radius 229.0;} + + !lowerPlateBottom { id 31; type zPlane; z0 -229.0;} + lowerNozzleBottom { id 32; type zPlane; z0 -199.0;} + rodPlugBottom { id 33; type zPlane; z0 -193.0;} + FAbottom { id 34; type zPlane; z0 -183.0;} + centre { id 35; type zPlane; z0 0.0;} + FAtop { id 36; type zPlane; z0 183.0;} + upperPlenumTop { id 37; type zPlane; z0 203.0;} + upperNozzleTop { id 38; type zPlane; z0 215.0;} + !upperCorePlateTop { id 39; type zPlane; z0 223.0;} + } + + + cells { + lowercoreplate { id 103; type simpleCell; surfaces (-7 -32); filltype mat; material coreplate; } + bottomnozzle { id 104; type simpleCell; surfaces (-5 32 -33); filltype mat; material nozzlebottom; } + belowFA { id 105; type simpleCell; surfaces (-5 33 -34); filltype mat; material FAbottom; } + aboveFA { id 106; type simpleCell; surfaces (-5 36 -37); filltype mat; material FAtop; } + topnozzle { id 107; type simpleCell; surfaces (-5 37 -38); filltype mat; material nozzletop; } + upperplate { id 108; type simpleCell; surfaces (-7 38); filltype mat; material reflectortop; } + downcomer { id 109; type simpleCell; surfaces (6 -7 32 -38); filltype mat; material coldwater; } + reactorvessel { id 110; type simpleCell; surfaces (7); filltype mat; material reactorvessel; } + bottomreflector { id 111; type simpleCell; surfaces (5 -6 32 -34); filltype mat; material reflectorbottom; } + topreflector { id 112; type simpleCell; surfaces (5 -6 36 -38); filltype mat; material reflectortop; } + + corelower { id 210; type simpleCell; surfaces (-6 34 -35); filltype uni; universe 10; } + coreupper { id 220; type simpleCell; surfaces (-6 35 -36); filltype uni; universe 20; } + } + + + +universes { + root { id 1000; type rootUniverse; border 80; fill u<100>; } + uni_cellcore { id 100; type cellUniverse; cells (103 104 105 106 107 108 109 110 111 112 210 220); } + + //Pin universes + UO2bottom { id 1; type pinUniverse; radii ( 0.41 0.475 0.0 ); fills (UOXfuel Zrcladding coldwater);} + GTbottom { id 2; type pinUniverse; radii (0.56 0.62 0.0 ); fills (coldwater Zrcladding coldwater);} + UO2top { id 3; type pinUniverse; radii ( 0.41 0.475 0.0 ); fills (UOXfuel Zrcladding hotwater);} + GTtop { id 4; type pinUniverse; radii (0.56 0.62 0.0 ); fills (hotwater Zrcladding hotwater);} + + bottomReflPin { id 5; type pinUniverse; radii (0.0 ); fills (reflectorbottom);} + topReflPin { id 7; type pinUniverse; radii (0.0 ); fills (reflectortop);} + + + + + // Fuel Assembly Lattice (Lower half) + bottomAssembly { + id 6; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat coldwater; + map ( + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 + 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 2 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 2 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 2 1 1 2 1 1 2 1 1 2 1 1 2 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 1 1 + 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ); } + + // Fuel Assembly Lattice (Upper half) + topAssembly { + id 8; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat hotwater; + map ( + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 + 3 3 3 4 3 3 3 3 3 3 3 3 3 4 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 4 3 3 4 3 3 4 3 3 4 3 3 4 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 4 3 3 3 3 3 3 3 3 3 4 3 3 3 + 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ); } + + + // Core Lattice (Lower Half) + lowerCore { + id 10; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.42 21.42 0.0); + shape (21 21 0); + padMat coldwater; + map ( + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 + 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 5 5 5 5 5 + 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 5 + 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 + 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 + 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 + 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 + 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 5 + 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 5 5 5 5 5 + 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5); } + + // Core Lattice (Upper Half) + upperCore { + id 20; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (21.42 21.42 0.0); + shape (21 21 0); + padMat hotwater; + map ( + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 + 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 + 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 7 + 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 + 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 + 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 + 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 + 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 + 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 + 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 7 + 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7); } + + + } + + +} + + +viz { + + bmpz { + type bmp; + output radial; + what material; + centre (0.0 0.0 0.0); + axis z; + res (1000 1000); + } + + bmpx { + type bmp; + output axial; + what material; + centre (0.0 0.0 0.0); + width (500.0 500.0); + axis x; + res (1000 1000); + } + + assembly { + type bmp; + output assembly; + what material; + centre (21.42 21.42 0.0); + width (21.42 21.42); + axis z; + res (1000 1000); + } + + +} + + + +nuclearData { + handles { + ce {type aceNeutronDatabase; aceLibrary $SCONE_ACE;} + } + +materials { + + +UOXfuel { + temp 16486; + composition { + 92234.03 4.9476e-6; + 92235.03 4.8218e-4; + 92236.03 9.0402e-5; + 92238.03 2.1504e-2; + 93237.03 7.3733e-6; + 94238.03 1.5148e-6; + 94239.03 1.3955e-4; + 94240.03 3.4405e-5; + 94241.03 2.1439e-5; + 94242.03 3.7422e-6; + 95241.03 4.5041e-7; + 95242.03 9.2301e-9; + 95243.03 4.7878e-7; + 96242.03 1.0485e-7; + 96243.03 1.4268e-9; + 96244.03 8.8756e-8; + 96245.03 3.5285e-9; + 42095.03 2.6497e-5; + 43099.03 3.2772e-5; + 44101.03 3.0742e-5; + 44103.03 2.3505e-6; + 47109.03 2.0009e-6; + 54135.03 1.0801e-8; + 55133.03 3.4612e-5; + 60143.03 2.6078e-5; + 60145.03 1.9898e-5; + 62147.03 1.6128e-6; + 62149.03 1.1627e-7; + 62150.03 7.1727e-6; + 62151.03 5.4947e-7; + 62152.03 3.0221e-6; + 63153.03 2.6209e-6; + 64155.03 1.5369e-9; + 8016.03 4.5737e-2;} +} + +Zrcladding { + temp 31628; + composition { + 40090.03 0.019578; + 40091.03 0.0042689; + 40092.03 0.00652638; + 40094.03 0.00661301; + 40096.03 0.00106413;} + } + +coldwater { + temp 45286; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 0.04938; + 8016.03 0.02469; + 5010.03 1.60238E-05; + 5011.03 6.63914E-05;} +} + + + +hotwater { + temp 46865; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 0.04404; + 8016.03 0.02202; + 5010.03 1.4291E-05; + 5011.03 5.92118E-05;} +} + + + + +reactorvessel { + temp 51694; + composition { + 26054.03 4.79006E-03; + 26056.03 7.5184E-02; + 26057.03 1.7361E-03; + 26058.03 2.314E-04; + 28058.03 5.5118E-04; + 28060.03 2.1231E-04; + 28061.03 9.226E-06; + 28062.03 2.943E-05; + 28064.03 7.493E-06; + 25055.03 8.6498E-04; + 42092.03 4.3902E-05; + 42094.03 2.7421E-05; + 42095.03 4.7263E-05; + 42096.03 4.9566E-05; + 42097.03 2.8427E-05; + 42098.03 7.1914E-05; + 42100.03 2.8744E-05; + 14028.03 6.2434E-04; + 14029.03 3.172E-05; + 14030.03 2.093E-05; + 24050.03 9.929E-06; + 24052.03 1.9144E-04; + 24053.03 2.1709E-05; + 24054.03 5.403E-06; + 6012.03 9.9112E-04; + 29063.03 1.03424E-04; + 29065.03 4.6139E-05; + } +} + + +reflectorbottom { + temp 56982; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 2.4886E-02; + 8016.03 1.2343E-02; + 5010.03 8.0233E-06; + 5011.03 3.3228E-05; + 26054.03 1.7161E-03; + 26056.03 2.69351E-02; + 26057.03 6.22E-04; + 26058.03 8.291E-05; + 28058.03 2.4803E-03; + 28060.03 9.554E-04; + 28061.03 4.152E-05; + 28062.03 1.324E-04; + 28064.03 3.372E-05; + 25055.03 8.65E-04; + 14028.03 7.8043E-04; + 14029.03 3.965E-05; + 14030.03 2.617E-05; + 24050.03 3.773E-04; + 24052.03 7.2746E-03; + 24053.03 8.249E-04; + 24054.03 2.053E-04; + } +} + + +reflectortop { + temp 54357; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 2.2196E-02; + 8016.03 1.1008E-02; + 5010.03 7.156E-06; + 5011.03 2.964E-05; + 26054.03 1.716E-03; + 26056.03 2.6935E-02; + 26057.03 6.2196E-04; + 26058.03 8.291E-05; + 28058.03 2.4803E-03; + 28060.03 9.554E-04; + 28061.03 4.152E-05; + 28062.03 1.3242E-04; + 28064.03 3.372E-05; + 25055.03 8.6498E-04; + 14028.03 7.8043E-04; + 14029.03 3.965E-05; + 14030.03 2.617E-05; + 24050.03 3.7729E-04; + 24052.03 7.27459E-03; + 24053.03 8.2494E-04; + 24054.03 2.053E-04; + } +} + + +coreplate { + temp 54687; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 4.9773E-03; + 8016.03 2.4685E-03; + 5010.03 1.605E-06; + 5011.03 6.646E-06; + 26054.03 3.08892E-03; + 26056.03 4.8483E-02; + 26057.03 1.1195E-03; + 26058.03 1.492E-04; + 28058.03 4.4646E-03; + 28060.03 1.71968E-03; + 28061.03 7.473E-05; + 28062.03 2.38356E-04; + 28064.03 6.0692E-05; + 25055.03 1.55696E-03; + 14028.03 1.4048E-03; + 14029.03 7.1371E-05; + 14030.03 4.7098E-05; + 24050.03 6.7912E-04; + 24052.03 1.3094E-02; + 24053.03 1.48489E-03; + 24054.03 3.69545E-04; + } +} + +nozzlebottom { + temp 87648; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 3.733E-2; + 8016.03 1.851E-2; + 5010.03 1.203E-5; + 5011.03 4.984E-5; + 26054.03 8.580E-4; + 26056.03 1.347E-02; + 26057.03 3.110E-04; + 26058.03 4.146E-05; + 28058.03 1.240E-03; + 28060.03 4.777E-04; + 28061.03 2.076E-05; + 28062.03 6.621E-05; + 28064.03 1.686E-05; + 25055.03 4.325E-04; + 14028.03 3.902E-04; + 14029.03 1.983E-05; + 14030.03 1.308E-05; + 24050.03 1.886E-04; + 24052.03 3.637E-03; + 24053.03 4.125E-04; + 24054.03 1.027E-04; + } +} + + +nozzletop { + temp 87064; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 3.7733E-2; + 8016.03 1.8714E-2; + 5010.03 1.2165E-5; + 5011.03 5.0381E-5; + 26054.03 5.1482E-4; + 26056.03 8.0805E-3; + 26057.03 1.8659E-4; + 26058.03 2.4874E-5; + 28058.03 7.441E-4; + 28060.03 2.8661E-4; + 28061.03 1.2455E-5; + 28062.03 3.9726E-05; + 28064.03 1.0115E-05; + 25055.03 2.5949E-04; + 14028.03 2.3413E-04; + 14029.03 1.1895E-05; + 14030.03 7.8496E-6; + 24050.03 1.1319E-04; + 24052.03 2.1824E-03; + 24053.03 2.4748E-04; + 24054.03 6.1591E-05; + } +} + +FAbottom { + temp 45034; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 2.986E-02; + 8016.03 1.481E-02; + 5010.03 9.628E-06; + 5011.03 3.987E-05; + 40090.03 8.822E-03; + 40091.03 1.924E-03; + 40092.03 2.941E-03; + 40094.03 2.980E-03; + 40096.03 4.795E-04; + } +} + +FAtop { + temp 43053; + moder { 1001.03 lwj3.00; } + composition { + 1001.03 3.107E-02; + 8016.03 1.541E-02; + 5010.03 1.002E-05; + 5011.03 4.149E-05; + 40090.03 4.411E-03; + 40091.03 9.618E-04; + 40092.03 1.470E-03; + 40094.03 1.490E-03; + 40096.03 2.398E-04; + } +} + + +} +} From 822ceeb3046198372f40acc2b3947b0a4c72fc04 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 10 Apr 2024 12:30:08 +0100 Subject: [PATCH 109/133] Fixed a tally typo in HM core --- InputFiles/Benchmarks/HoogenboomMartin/HMcore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InputFiles/Benchmarks/HoogenboomMartin/HMcore b/InputFiles/Benchmarks/HoogenboomMartin/HMcore index f4f53f30e..063a240b7 100644 --- a/InputFiles/Benchmarks/HoogenboomMartin/HMcore +++ b/InputFiles/Benchmarks/HoogenboomMartin/HMcore @@ -38,7 +38,7 @@ activeTally { map {type multiMap; maps (xax yax zax); xax {type spaceMap; axis x; grid lin; N 289; min -182.07; max 182.07; } yax {type spaceMap; axis y; grid lin; N 289; min -182.07; max 182.07; } - zax {type spaceMap; axis y; grid lin; N 100; min -183; max 183; } + zax {type spaceMap; axis z; grid lin; N 100; min -183; max 183; } } } assemblyFissRadial { type collisionClerk; response (fission); fission { type macroResponse; MT -6;} From 4491e68d86073ba206080125cfc47e980eb0e61f Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 10 Apr 2024 14:09:43 +0100 Subject: [PATCH 110/133] Made UFS not default to uniform fissile volumes --- Geometry/Fields/VectorFields/uniFissSitesField_class.f90 | 5 +++-- docs/User Manual.rst | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 b/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 index 12aa7fb4b..501e2adf2 100644 --- a/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 +++ b/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 @@ -66,7 +66,7 @@ module uniFissSitesField_class private class(tallyMap), allocatable :: map integer(shortInt) :: N = 0 - logical(defBool) :: uniformVolMap + logical(defBool) :: uniformVolMap = .false. integer(shortInt) :: pop real(defReal), dimension(:), allocatable :: volFraction real(defReal), dimension(:), allocatable :: sourceFraction @@ -104,7 +104,7 @@ subroutine init(self, dict) self % buildSource = ZERO ! Settings for volume calculation - call dict % getOrDefault(self % uniformVolMap,'uniformVolMap', .true.) + call dict % getOrDefault(self % uniformVolMap,'uniformVolMap', .false.) if (.not. self % uniformVolMap) call dict % getOrDefault(self % pop,'popVolumes', 1000000) end subroutine init @@ -121,6 +121,7 @@ elemental subroutine kill(self) deallocate(self % buildSource) self % N = 0 + self % uniformVolMap = .false. end subroutine kill diff --git a/docs/User Manual.rst b/docs/User Manual.rst index b772dab77..0a3dcb714 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -379,7 +379,7 @@ keyword ``UFS`` is set to 1. Then, in the input file, one needs to add: :: In the input above, ``map`` is the geometrical map used for UFS. The map has to contain fissile material for the method to make sense. Other keywords are: -* uniformVolMap (*optional*, default = 1): 1 for true; 0 for false; flag that states +* uniformVolMap (*optional*, default = 0): 1 for true; 0 for false; flag that states whether the bins of the map contain equal volumes of fissile material or not * popVolumes (*optional*, default = 1.0e7): if ``uniformVolMap`` is false, a Monte Carlo calculation is run to estimate the fissile material volumes in each map bin. This entry From b9ff07eed30ccd0969bbfc8f38b7ff522dd0fbb7 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 10 Apr 2024 14:15:47 +0100 Subject: [PATCH 111/133] Fixed UFS test --- Geometry/Fields/VectorFields/Tests/uniFissSitesField_test.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Geometry/Fields/VectorFields/Tests/uniFissSitesField_test.f90 b/Geometry/Fields/VectorFields/Tests/uniFissSitesField_test.f90 index c6ef4c87b..04c2da05d 100644 --- a/Geometry/Fields/VectorFields/Tests/uniFissSitesField_test.f90 +++ b/Geometry/Fields/VectorFields/Tests/uniFissSitesField_test.f90 @@ -46,7 +46,7 @@ subroutine setUp(this) ! Build material map definition call dict % store('type', 'uniFissSitesField') - call dict % store('uniformMap', 1) + call dict % store('uniformVolMap', 1) call dict % store('map', dictMap) call this % ufsField % init(dict) From 0a64f29ded8d6765a5ed970776d068610668be7b Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 10 Apr 2024 19:19:58 +0100 Subject: [PATCH 112/133] Changed settings on HM Also increased the number of allowable rejections in the UFS volume sampling calculation - the previous was slightly conservative. --- Geometry/Fields/VectorFields/uniFissSitesField_class.f90 | 2 +- InputFiles/Benchmarks/HoogenboomMartin/HMcore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 b/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 index 501e2adf2..0bb8425e3 100644 --- a/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 +++ b/Geometry/Fields/VectorFields/uniFissSitesField_class.f90 @@ -177,7 +177,7 @@ subroutine estimateVol(self, geom, rand, type) rejection : do ! Protect against infinite loop j = j +1 - if ( j > 200) then + if ( j > 1000) then call fatalError(Here, 'Infinite loop in sampling of fission sites. Please check that& & defined volume contains fissile material.') end if diff --git a/InputFiles/Benchmarks/HoogenboomMartin/HMcore b/InputFiles/Benchmarks/HoogenboomMartin/HMcore index 063a240b7..b57d995ca 100644 --- a/InputFiles/Benchmarks/HoogenboomMartin/HMcore +++ b/InputFiles/Benchmarks/HoogenboomMartin/HMcore @@ -53,6 +53,7 @@ activeTally { ! Uniform fission site map uniformFissionSites { type uniFissSitesField; + popVolumes 10000000; map {type multiMap; maps (xax yax zax); xax {type spaceMap; axis x; grid lin; N 17; min -182.07; max 182.07; } yax {type spaceMap; axis y; grid lin; N 17; min -182.07; max 182.07; } From faec96612c692409fc5cd1c09fea7683c7974269 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Mon, 15 Apr 2024 19:27:32 +0100 Subject: [PATCH 113/133] Tidying the 1D tally maps, adding 1D radial and angular maps --- Tallies/TallyMaps/CMakeLists.txt | 50 ++-- .../{ => Maps1D}/Tests/cellMap_test.f90 | 0 .../{ => Maps1D}/Tests/collNumMap_test.f90 | 0 .../Maps1D/Tests/cylindricalRadMap_test.f90 | 202 ++++++++++++++ .../Maps1D/Tests/directionMap_test.f90 | 153 +++++++++++ .../{ => Maps1D}/Tests/energyMap_test.f90 | 0 .../{ => Maps1D}/Tests/homogMatMap_test.f90 | 0 .../{ => Maps1D}/Tests/materialMap_test.f90 | 0 .../{ => Maps1D}/Tests/spaceMap_test.f90 | 0 .../Tests/sphericalRadMap_test.f90} | 88 +++--- .../{ => Maps1D}/Tests/testMap_test.f90 | 0 .../{ => Maps1D}/Tests/weightMap_test.f90 | 0 .../TallyMaps/{ => Maps1D}/cellMap_class.f90 | 1 + .../{ => Maps1D}/collNumMap_class.f90 | 0 .../Maps1D/cylindricalRadMap_class.f90 | 260 ++++++++++++++++++ .../TallyMaps/Maps1D/directionMap_class.f90 | 194 +++++++++++++ .../{ => Maps1D}/energyMap_class.f90 | 0 .../{ => Maps1D}/homogMatMap_class.f90 | 2 +- .../{ => Maps1D}/materialMap_class.f90 | 0 .../TallyMaps/{ => Maps1D}/spaceMap_class.f90 | 0 .../sphericalRadMap_class.f90} | 70 ++--- .../{ => Maps1D}/tallyMap1DFactory_func.f90 | 49 ++-- .../{ => Maps1D}/tallyMap1D_inter.f90 | 0 .../TallyMaps/{ => Maps1D}/testMap_class.f90 | 0 .../{ => Maps1D}/weightMap_class.f90 | 0 .../TallyMaps/Tests/cylindricalMap_test.f90 | 2 +- Tallies/TallyMaps/cylindricalMap_class.f90 | 2 +- Tallies/TallyMaps/matXsMapOLD_class.f90 | 186 ------------- Tallies/TallyMaps/tallyMapFactory_func.f90 | 5 - Tallies/TallyMaps/tallyMapSlot_class.f90 | 163 ----------- 30 files changed, 939 insertions(+), 488 deletions(-) rename Tallies/TallyMaps/{ => Maps1D}/Tests/cellMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/collNumMap_test.f90 (100%) create mode 100644 Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 create mode 100644 Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 rename Tallies/TallyMaps/{ => Maps1D}/Tests/energyMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/homogMatMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/materialMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/spaceMap_test.f90 (100%) rename Tallies/TallyMaps/{Tests/sphericalMap_test.f90 => Maps1D/Tests/sphericalRadMap_test.f90} (62%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/testMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/Tests/weightMap_test.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/cellMap_class.f90 (99%) rename Tallies/TallyMaps/{ => Maps1D}/collNumMap_class.f90 (100%) create mode 100644 Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 create mode 100644 Tallies/TallyMaps/Maps1D/directionMap_class.f90 rename Tallies/TallyMaps/{ => Maps1D}/energyMap_class.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/homogMatMap_class.f90 (98%) rename Tallies/TallyMaps/{ => Maps1D}/materialMap_class.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/spaceMap_class.f90 (100%) rename Tallies/TallyMaps/{sphericalMap_class.f90 => Maps1D/sphericalRadMap_class.f90} (78%) rename Tallies/TallyMaps/{ => Maps1D}/tallyMap1DFactory_func.f90 (79%) rename Tallies/TallyMaps/{ => Maps1D}/tallyMap1D_inter.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/testMap_class.f90 (100%) rename Tallies/TallyMaps/{ => Maps1D}/weightMap_class.f90 (100%) delete mode 100644 Tallies/TallyMaps/matXsMapOLD_class.f90 delete mode 100644 Tallies/TallyMaps/tallyMapSlot_class.f90 diff --git a/Tallies/TallyMaps/CMakeLists.txt b/Tallies/TallyMaps/CMakeLists.txt index 35383328a..bea5c9e58 100644 --- a/Tallies/TallyMaps/CMakeLists.txt +++ b/Tallies/TallyMaps/CMakeLists.txt @@ -1,31 +1,33 @@ # Add Source Files to the global list add_sources(./tallyMap_inter.f90 - ./tallyMap1D_inter.f90 - ./tallyMap1DFactory_func.f90 ./tallyMapFactory_func.f90 - ./tallyMapSlot_class.f90 - ./testMap_class.f90 - ./energyMap_class.f90 - ./spaceMap_class.f90 - ./materialMap_class.f90 - ./homogMatMap_class.f90 ./multiMap_class.f90 - ./weightMap_class.f90 - ./sphericalMap_class.f90 - ./cellMap_class.f90 - ./cylindricalMap_class.f90 - ./collNumMap_class.f90 - # ./matXsMap_class.f90 + ./cylindricalMap_class.f90 + ./Maps1D/tallyMap1D_inter.f90 + ./Maps1D/tallyMap1DFactory_func.f90 + ./Maps1D/testMap_class.f90 + ./Maps1D/energyMap_class.f90 + ./Maps1D/spaceMap_class.f90 + ./Maps1D/materialMap_class.f90 + ./Maps1D/homogMatMap_class.f90 + ./Maps1D/weightMap_class.f90 + ./Maps1D/sphericalRadMap_class.f90 + ./Maps1D/cellMap_class.f90 + ./Maps1D/cylindricalRadMap_class.f90 + ./Maps1D/collNumMap_class.f90 + ./Maps1D/directionMap_class.f90 ) -add_unit_tests(./Tests/materialMap_test.f90 - ./Tests/energyMap_test.f90 - ./Tests/weightMap_test.f90 - ./Tests/spaceMap_test.f90 - ./Tests/testMap_test.f90 - ./Tests/multiMap_test.f90 - ./Tests/homogMatMap_test.f90 - ./Tests/sphericalMap_test.f90 - ./Tests/cellMap_test.f90 +add_unit_tests(./Tests/multiMap_test.f90 ./Tests/cylindricalMap_test.f90 - ./Tests/collNumMap_test.f90) + ./Maps1D/Tests/materialMap_test.f90 + ./Maps1D/Tests/energyMap_test.f90 + ./Maps1D/Tests/weightMap_test.f90 + ./Maps1D/Tests/spaceMap_test.f90 + ./Maps1D/Tests/testMap_test.f90 + ./Maps1D/Tests/homogMatMap_test.f90 + ./Maps1D/Tests/sphericalRadMap_test.f90 + ./Maps1D/Tests/cylindricalRadMap_test.f90 + ./Maps1D/Tests/cellMap_test.f90 + ./Maps1D/Tests/collNumMap_test.f90 + ./Maps1D/Tests/directionMap_test.f90) diff --git a/Tallies/TallyMaps/Tests/cellMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/cellMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/cellMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/cellMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/collNumMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/collNumMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/collNumMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/collNumMap_test.f90 diff --git a/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 new file mode 100644 index 000000000..63d6c824a --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 @@ -0,0 +1,202 @@ +module cylindricalRadMap_test + use numPrecision + use pFUnit_mod + use particle_class, only : particleState + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + + use cylindricalRadMap_class, only : cylindricalRadMap + + implicit none + + +@testCase + type, extends(TestCase) :: test_cylindricalRadMap + private + type(cylindricalRadMap) :: map_radial + type(cylindricalRadMap) :: map_unstruct + type(cylindricalRadMap) :: map_equivol + + contains + procedure :: setUp + procedure :: tearDown + end type test_cylindricalRadMap + +contains + + !! + !! Sets up test_cylindricalRadMap object we can use in a number of tests + !! + subroutine setUp(this) + class(test_cylindricalRadMap), intent(inout) :: this + type(dictionary) :: tempDict + + ! Build radial map with different orientation & minimum radius + call tempDict % init(5) + call tempDict % store('orientation','x') + call tempDict % store('rGrid','equivolume') + call tempDict % store('Rmin', 2.0_defReal) + call tempDict % store('Rmax', 10.0_defReal) + call tempDict % store('rN', 5) + + call this % map_radial % init(tempDict) + call tempDict % kill() + + ! Build map with different origin & unstruct bins + call tempDict % init(3) + call tempDict % store('origin',[ONE, ONE]) + call tempDict % store('rGrid','unstruct') + call tempDict % store('bins', [1.5_defReal, 2.3_defReal, 3.8_defReal, 8.0_defReal]) + + call this % map_unstruct % init(tempDict) + call tempDict % kill() + + ! Build map with equivolume bins + call tempDict % init(3) + call tempDict % store('rGrid','equivolume') + call tempDict % store('Rmax', 8.0_defReal) + call tempDict % store('rN', 4) + + call this % map_equivol % init(tempDict) + call tempDict % kill() + + end subroutine setUp + + !! + !! Kills test_cylindricalRadMap object we can use in a number of tests + !! + subroutine tearDown(this) + class(test_cylindricalRadMap), intent(inout) :: this + + call this % map_radial % kill() + call this % map_unstruct % kill() + call this % map_equivol % kill() + + end subroutine tearDown + +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +!! PROPER TESTS BEGIN HERE +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> + + !! + !! Test radial map with different orientation & minimum radius + !! +@Test + subroutine testRadial(this) + class(test_cylindricalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [0.4_defReal, 5.38_defReal, 8.9_defReal, 9.1_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4),parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 2, 4, 5] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = z + states(:) % r(2) = r * cos(phi) + states(:) % r(3) = r * sin(phi) + + idx = this % map_radial % map(states) + + @assertEqual(RES_IDX, idx) + + end subroutine testRadial + + !! + !! Test map with different origin & unstruct bins + !! +@Test + subroutine testUnstruct(this) + class(test_cylindricalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.52_defReal, 5.5_defReal, 8.9_defReal, 2.88_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 3, 0, 2] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) + states(:) % r(2) = r * sin(phi) + states(:) % r(3) = z + + ! Shift the origin + states(:) % r(1) = states(:) % r(1) + ONE + states(:) % r(2) = states(:) % r(2) + ONE + states(:) % r(3) = states(:) % r(3) + + idx = this % map_unstruct % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testUnstruct + + !! + !! Test map with equivolume bins + !! +@Test + subroutine testEquivol(this) + class(test_cylindricalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.82_defReal, 4.68_defReal, 7.9_defReal, 17.01_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 2, 4, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) + states(:) % r(2) = r * sin(phi) + states(:) % r(3) = z + + idx = this % map_equivol % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testEquivol + + !! + !! Test bin number retrival + !! +@Test + subroutine testBinNumber(this) + class(test_cylindricalRadMap), intent(inout) :: this + + ! Test that map is 1D + @assertEqual(5, this % map_radial % bins(0),'All bins') + @assertEqual(5, this % map_radial % bins(1),'1st dimension') + @assertEqual(0, this % map_radial % bins(2),'2nd dimension') + @assertEqual(3, this % map_unstruct % bins(1),'1st dimension') + @assertEqual(4, this % map_equivol % bins(1),'1st dimension') + + ! Get dimensionality + @assertEqual(1, this % map_radial % dimensions()) + @assertEqual(1, this % map_unstruct % dimensions()) + + end subroutine testBinNumber + + !! + !! Test correctness of print subroutine + !! Does not checks that values are correct, but that calls sequence is without errors + !! +@Test + subroutine testPrint(this) + class(test_cylindricalRadMap), intent(inout) :: this + type(outputFile) :: out + + call out % init('dummyPrinter', fatalErrors = .false.) + + call this % map_radial % print(out) + @assertTrue(out % isValid(),'Radial map case') + call out % reset() + + call this % map_unstruct % print(out) + @assertTrue(out % isValid(),'Unstruct map case') + call out % reset() + + call this % map_equivol % print(out) + @assertTrue(out % isValid(),'Unstruct map case') + call out % reset() + + end subroutine testPrint + + +end module cylindricalRadMap_test diff --git a/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 new file mode 100644 index 000000000..ff5c3e508 --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 @@ -0,0 +1,153 @@ +module directionMap_test + use numPrecision + use pFUnit_mod + use particle_class, only : particleState + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + + use directionMap_class, only : directionMap + + implicit none + + +@testCase + type, extends(TestCase) :: test_directionMap + private + type(directionMap) :: map1 + type(directionMap) :: map2 + + contains + procedure :: setUp + procedure :: tearDown + + end type test_directionMap + +contains + + !! + !! Sets up test_directionMap object + !! + subroutine setUp(this) + class(test_directionMap), intent(inout) :: this + type(dictionary) :: tempDict + + ! Build map with yz plane + call tempDict % init(2) + call tempDict % store('plane','yz') + call tempDict % store('N', 4) + + call this % map1 % init(tempDict) + call tempDict % kill() + + ! Build map with default plane + call tempDict % init(1) + call tempDict % store('N', 8) + + call this % map2 % init(tempDict) + call tempDict % kill() + + end subroutine setUp + + !! + !! Kills test_directionMap objects + !! + subroutine tearDown(this) + class(test_directionMap), intent(inout) :: this + + call this % map1 % kill() + call this % map2 % kill() + + end subroutine tearDown + +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +!! PROPER TESTS BEGIN HERE +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> + + !! + !! Test first map + !! +@Test + subroutine testMap1(this) + class(test_directionMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: x = [0.44_defReal, 15.8_defReal, 83.2_defReal, 999.1_defReal] + real(defReal),dimension(4),parameter :: phi = [-0.1_defReal, 0.84_defReal, 0.33_defReal, 0.64_defReal]*PI + integer(shortInt),dimension(4),parameter :: RES_IDX = [2, 4, 3, 4] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % dir(1) = x + states(:) % dir(2) = cos(phi) + states(:) % dir(3) = sin(phi) + + idx = this % map1 % map(states) + + @assertEqual(RES_IDX, idx) + + end subroutine testMap1 + + !! + !! Test second + !! +@Test + subroutine testMap2(this) + class(test_directionMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: x = [0.9999_defReal, 0.87_defReal, -0.3_defReal, 0.18_defReal] + real(defReal),dimension(4),parameter :: y = [0.45_defReal, 0.88_defReal, 0.51_defReal, -0.92_defReal] + real(defReal),dimension(4),parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [5, 6, 7, 3] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % dir(1) = x + states(:) % dir(2) = y + states(:) % dir(3) = z + + idx = this % map2 % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testMap2 + + !! + !! Test bin number retrival + !! +@Test + subroutine testBinNumber(this) + class(test_directionMap), intent(inout) :: this + + ! Test that map is 1D + @assertEqual(4, this % map1 % bins(0),'All bins') + @assertEqual(4, this % map1 % bins(1),'1st dimension') + @assertEqual(0, this % map2 % bins(2),'2nd dimension') + @assertEqual(8, this % map2 % bins(1),'1st dimension') + + ! Get dimensionality + @assertEqual(1, this % map1 % dimensions()) + @assertEqual(1, this % map2 % dimensions()) + + end subroutine testBinNumber + + !! + !! Test correctness of print subroutine + !! Does not checks that values are correct, but that calls sequence is without errors + !! +@Test + subroutine testPrint(this) + class(test_directionMap), intent(inout) :: this + type(outputFile) :: out + + call out % init('dummyPrinter', fatalErrors = .false.) + + call this % map2 % print(out) + @assertTrue(out % isValid(),'Radial map case') + call out % reset() + + call this % map1 % print(out) + @assertTrue(out % isValid(),'Unstruct map case') + call out % reset() + + end subroutine testPrint + + +end module directionMap_test diff --git a/Tallies/TallyMaps/Tests/energyMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/energyMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/energyMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/energyMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/homogMatMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/homogMatMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/homogMatMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/homogMatMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/materialMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/materialMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/materialMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/materialMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/spaceMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/spaceMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/spaceMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/spaceMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/sphericalMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 similarity index 62% rename from Tallies/TallyMaps/Tests/sphericalMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 index 22daeaa5a..e0e9fb651 100644 --- a/Tallies/TallyMaps/Tests/sphericalMap_test.f90 +++ b/Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 @@ -1,35 +1,35 @@ -module sphericalMap_test +module sphericalRadMap_test use numPrecision use pFUnit_mod use particle_class, only : particleState use dictionary_class, only : dictionary use outputFile_class, only : outputFile - use sphericalMap_class, only : sphericalMap + use sphericalRadMap_class, only : sphericalRadMap implicit none @testCase - type, extends(TestCase) :: test_sphericalMap + type, extends(TestCase) :: test_sphericalRadMap private - type(sphericalMap) :: map_lin_from_zero - type(sphericalMap) :: map_lin_from_min - type(sphericalMap) :: map_unstruct - type(sphericalMap) :: map_equivol + type(sphericalRadMap) :: map_lin_from_zero + type(sphericalRadMap) :: map_lin_from_min + type(sphericalRadMap) :: map_unstruct + type(sphericalRadMap) :: map_equivol contains procedure :: setUp procedure :: tearDown - end type test_sphericalMap + end type test_sphericalRadMap contains !! - !! Sets up test_sphericalMap object we can use in a number of tests + !! Sets up test_sphericalRadMap object we can use in a number of tests !! subroutine setUp(this) - class(test_sphericalMap), intent(inout) :: this + class(test_sphericalRadMap), intent(inout) :: this type(dictionary) :: tempDict ! Build map with default origin & minimum radius @@ -73,10 +73,10 @@ subroutine setUp(this) end subroutine setUp !! - !! Kills test_sphericalMap object we can use in a number of tests + !! Kills test_sphericalRadMap object we can use in a number of tests !! subroutine tearDown(this) - class(test_sphericalMap), intent(inout) :: this + class(test_sphericalRadMap), intent(inout) :: this call this % map_lin_from_zero % kill() call this % map_lin_from_min % kill() @@ -94,13 +94,13 @@ end subroutine tearDown !! @Test subroutine testFromOrigin(this) - class(test_sphericalMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [0.4_defReal, 3.58_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 8, 18, 0] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states + class(test_sphericalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [0.4_defReal, 3.58_defReal, 8.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 8, 18, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states ! Initialise states states(:) % r(1) = r * cos(phi) * sin(tht) @@ -117,13 +117,13 @@ end subroutine testFromOrigin !! @Test subroutine testFromMin(this) - class(test_sphericalMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 4, 0] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states + class(test_sphericalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 8.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 4, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states ! Initialise states states(:) % r(1) = r * cos(phi) * sin(tht) @@ -145,13 +145,13 @@ end subroutine testFromMin !! @Test subroutine testUnstruct(this) - class(test_sphericalMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [4.5_defReal, 15.5_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 0, 3, 4] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states + class(test_sphericalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [4.5_defReal, 15.5_defReal, 8.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 0, 3, 4] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states ! Initialise states states(:) % r(1) = r * cos(phi) * sin(tht) @@ -168,13 +168,13 @@ end subroutine testUnstruct !! @Test subroutine testEquiVol(this) - class(test_sphericalMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 18.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 7, 2] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states + class(test_sphericalRadMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 18.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 7, 2] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states ! Initialise states states(:) % r(1) = r * cos(phi) * sin(tht) @@ -191,7 +191,7 @@ end subroutine testEquiVol !! @Test subroutine testBinNumber(this) - class(test_sphericalMap), intent(inout) :: this + class(test_sphericalRadMap), intent(inout) :: this @assertEqual(20, this % map_lin_from_zero % bins(1),'1st Dimension') @assertEqual(4, this % map_unstruct % bins(1),'1st Dimension') @@ -209,8 +209,8 @@ end subroutine testBinNumber !! @Test subroutine testPrint(this) - class(test_sphericalMap), intent(inout) :: this - type(outputFile) :: out + class(test_sphericalRadMap), intent(inout) :: this + type(outputFile) :: out call out % init('dummyPrinter', fatalErrors = .false.) @@ -233,4 +233,4 @@ subroutine testPrint(this) end subroutine testPrint -end module sphericalMap_test +end module sphericalRadMap_test diff --git a/Tallies/TallyMaps/Tests/testMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/testMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/testMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/testMap_test.f90 diff --git a/Tallies/TallyMaps/Tests/weightMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/weightMap_test.f90 similarity index 100% rename from Tallies/TallyMaps/Tests/weightMap_test.f90 rename to Tallies/TallyMaps/Maps1D/Tests/weightMap_test.f90 diff --git a/Tallies/TallyMaps/cellMap_class.f90 b/Tallies/TallyMaps/Maps1D/cellMap_class.f90 similarity index 99% rename from Tallies/TallyMaps/cellMap_class.f90 rename to Tallies/TallyMaps/Maps1D/cellMap_class.f90 index 293f5a8e7..d8934bdff 100644 --- a/Tallies/TallyMaps/cellMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/cellMap_class.f90 @@ -7,6 +7,7 @@ module cellMap_class use particle_class, only : particleState use outputFile_class, only : outputFile use tallyMap1D_inter, only : tallyMap1D, kill_super => kill + ! Geometry use geometryStd_class, only : geometryStd, geometryStd_CptrCast use geometry_inter, only : geometry diff --git a/Tallies/TallyMaps/collNumMap_class.f90 b/Tallies/TallyMaps/Maps1D/collNumMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/collNumMap_class.f90 rename to Tallies/TallyMaps/Maps1D/collNumMap_class.f90 diff --git a/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 b/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 new file mode 100644 index 000000000..436c32eb5 --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 @@ -0,0 +1,260 @@ +module cylindricalRadMap_class + + use numPrecision + use universalVariables, only : valueOutsideArray, X_AXIS, Y_AXIS, Z_AXIS + use genericProcedures, only : fatalError, dotProduct, numToChar + use dictionary_class, only : dictionary + use grid_class, only : grid + use particle_class, only : particleState + use outputFile_class, only : outputFile + use tallyMap1D_inter, only : tallyMap1D, kill_super => kill + + implicit none + private + + !! + !! Divides space into a radial mesh in cylindrical co-ordinates + !! + !! Interface: + !! tallyMap1D interface + !! + !! NOTE: + !! Behaviour of points exactly at the boundary of bins is undefined. + !! particle can end-up in either of the two + !! + !! Sample Dictionary Input: + !! cylindricalRadMap { + !! type cylindricalRadMap; + !! #orientation x;# // Optional. Default z + !! #origin (1.0 0.0);# // Optional. Default (0 0). Order is xy, xz or yz. + !! rGrid lin; + !! #Rmin 2.0;# // Optional. Default 0.0 + !! Rmax 10.0; + !! rN 10; + !! } + !! + type, public, extends (tallyMap1D) :: cylindricalRadMap + private + real(defReal), dimension(2) :: origin = ZERO + type(grid) :: rBounds + integer(shortInt) :: rN = 0 + integer(shortInt) :: DIM1 = 0 + integer(shortInt) :: DIM2 = 0 + + contains + ! Superclass + procedure :: init + procedure :: bins + procedure :: getAxisName + procedure :: map + procedure :: print + procedure :: kill + + end type cylindricalRadMap + +contains + + !! + !! Initialise tallyMap from a dictionary + !! + !! See tallyMap for specification. + !! + subroutine init(self, dict) + class(cylindricalRadMap), intent(inout) :: self + class(dictionary), intent(in) :: dict + real(defReal), dimension(:), allocatable :: temp, grid + character(nameLen) :: type + real(defReal) :: Rmin, Rmax, vol + integer(shortInt) :: i + character(100), parameter :: Here = 'init (cylindricalRadMap_class.f90)' + + ! Check & load origin + call dict % getOrDefault(temp, 'origin', [ZERO, ZERO]) + + if (size(temp) /= 2) then + call fatalError(Here, 'Expected 2 values for origin. Got: ' // numToChar(size(temp))) + end if + self % origin = temp + + ! Check orientation of the cylinder + if (dict % isPresent('orientation')) then + call dict % get(type, 'orientation') + else + type = 'z' + end if + + select case(type) + case('x') + self % DIM1 = Y_AXIS + self % DIM2 = Z_AXIS + + case('y') + self % DIM1 = X_AXIS + self % DIM2 = Z_AXIS + + case('z') + self % DIM1 = X_AXIS + self % DIM2 = Y_AXIS + + case default + call fatalError(Here, 'Keyword orientation must be x, y or z. It is: '//type) + + end select + + ! Load radial grid information + if (.not. dict % isPresent('rGrid')) call fatalError(Here, 'Keyword rGrid must be present') + call dict % get(type, 'rGrid') + + ! Check type of radial grid bins + select case(type) + case('lin') + call dict % getOrDefault(Rmin, 'Rmin', ZERO) + call dict % get(Rmax, 'Rmax') + call dict % get(self % rN, 'rN') + + ! Check that minimum radius is OK + if (Rmin < ZERO) then + call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(Rmin)) + end if + + ! Build grid + call self % rBounds % init(Rmin, Rmax, self % rN, type) + + case('unstruct') + + call dict % get(grid,'bins') + + ! Initialise + self % rN = size(grid) - 1 + call self % rBounds % init(grid) + + case('equivolume') + + call dict % getOrDefault(Rmin, 'Rmin', ZERO) + call dict % get(Rmax, 'Rmax') + call dict % get(self % rN, 'rN') + + ! Check that minimum radius is OK + if (Rmin < ZERO) then + call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(Rmin)) + end if + + ! Calculate volume + vol = (Rmax**2 - Rmin**2) /self % rN + + allocate(grid(self % rN + 1)) + ! Calculate grid boundaries + grid(1) = Rmin + grid(self % rN + 1) = Rmax + do i = 2,self % rN + grid(i) = sqrt(vol + grid(i-1)**2) + end do + + call self % rBounds % init(grid) + + case default + call fatalError(Here, "'rGrid' can take only values of: lin, unstruct, equivolume") + + end select + + end subroutine init + + !! + !! Return total number of bins in this division along Dimension D + !! + !! See tallyMap for specification. + !! + elemental function bins(self, D) result(N) + class(cylindricalRadMap), intent(in) :: self + integer(shortInt), intent(in) :: D + integer(shortInt) :: N + + if (D == 1 .or. D == 0) then + N = self % rN + else + N = 0 + end if + + end function bins + + !! + !! Return string that describes variable used to divide event space + !! + !! See tallyMap for specification + !! + function getAxisName(self) result(name) + class(cylindricalRadMap), intent(in) :: self + character(nameLen) :: name + + name = 'cylindricalRadMap' + + end function getAxisName + + !! + !! Map particle to a single bin. Return 0 for particle out of division + !! + !! See tallyMap for specification. + !! + elemental function map(self, state) result(idx) + class(cylindricalRadMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + real(defReal) :: r + + ! Calculate the distance from the origin + r = norm2(state % r([self % DIM1, self % DIM2]) - self % origin) + + ! Search and return 0 if r is out-of-bounds + idx = self % rBounds % search(r) + + if (idx == valueOutsideArray) then + idx = 0 + return + end if + + end function map + + !! + !! Add information about division axis to the output file + !! + !! See tallyMap for specification. + !! + subroutine print(self,out) + class(cylindricalRadMap), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen) :: name + integer(shortInt) :: i + + ! Name the array + name = trim(self % getAxisName()) //'RadialBounds' + + call out % startArray(name, [2,self % rN]) + do i = 1, self % rN + ! Print lower bin boundary + call out % addValue(self % rBounds % bin(i)) + + ! Print upper bin boundar + call out % addValue(self % rBounds % bin(i + 1)) + + end do + call out % endArray() + + end subroutine print + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(cylindricalRadMap), intent(inout) :: self + + call kill_super(self) + + self % origin = ZERO + call self % rBounds % kill() + self % rN = 0 + self % DIM1 = 0 + self % DIM2 = 0 + + end subroutine kill + +end module cylindricalRadMap_class diff --git a/Tallies/TallyMaps/Maps1D/directionMap_class.f90 b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 new file mode 100644 index 000000000..73172e383 --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 @@ -0,0 +1,194 @@ +module directionMap_class + + use numPrecision + use universalVariables, only : valueOutsideArray, X_AXIS, Y_AXIS, Z_AXIS + use genericProcedures, only : fatalError, dotProduct, numToChar + use dictionary_class, only : dictionary + use grid_class, only : grid + use particle_class, only : particleState + use outputFile_class, only : outputFile + use tallyMap1D_inter, only : tallyMap1D, kill_super => kill + + implicit none + private + + !! + !! Maps the particle direction in linear bins in the range 0-360 degrees + !! + !! Interface: + !! tallyMap1D interface + !! + !! NOTE: + !! Behaviour of points exactly at the boundary of bins is undefined. + !! particle can end-up in either of the two + !! + !! Sample Dictionary Input: + !! directionMap { + !! type directionMap; + !! #plane xz;# // Optional. Default xy + !! N 10; + !! } + !! + type, public, extends (tallyMap1D) :: directionMap + private + type(grid) :: bounds + integer(shortInt) :: N = 0 + integer(shortInt) :: DIM1 = 0 + integer(shortInt) :: DIM2 = 0 + + contains + ! Superclass + procedure :: init + procedure :: bins + procedure :: getAxisName + procedure :: map + procedure :: print + procedure :: kill + + end type directionMap + +contains + + !! + !! Initialise tallyMap from a dictionary + !! + !! See tallyMap for specification. + !! + subroutine init(self, dict) + class(directionMap), intent(inout) :: self + class(dictionary), intent(in) :: dict + character(nameLen) :: type + character(100), parameter :: Here = 'init (directionMap_class.f90)' + + ! Check orientation of the cylinder + if (dict % isPresent('plane')) then + call dict % get(type, 'plane') + else + type = 'xy' + end if + + select case(type) + case('yz') + self % DIM1 = Y_AXIS + self % DIM2 = Z_AXIS + + case('xz') + self % DIM1 = X_AXIS + self % DIM2 = Z_AXIS + + case('xy') + self % DIM1 = X_AXIS + self % DIM2 = Y_AXIS + + case default + call fatalError(Here, 'Keyword orientation must be x, y or z. It is: '//type) + + end select + + ! Build grid + call dict % get(self % N, 'N') + call self % bounds % init(-PI, PI, self % N, 'lin') + + end subroutine init + + !! + !! Return total number of bins in this division along Dimension D + !! + !! See tallyMap for specification. + !! + elemental function bins(self, D) result(N) + class(directionMap), intent(in) :: self + integer(shortInt), intent(in) :: D + integer(shortInt) :: N + + if (D == 1 .or. D == 0) then + N = self % N + else + N = 0 + end if + + end function bins + + !! + !! Return string that describes variable used to divide event space + !! + !! See tallyMap for specification + !! + function getAxisName(self) result(name) + class(directionMap), intent(in) :: self + character(nameLen) :: name + + name = 'directionMap' + + end function getAxisName + + !! + !! Map particle to a single bin. Return 0 for particle out of division + !! + !! See tallyMap for specification. + !! + elemental function map(self, state) result(idx) + class(directionMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + real(defReal) :: x, y, theta + + x = state % dir(self % DIM1) + y = state % dir(self % DIM2) + + theta = atan2(y,x) + ! Search along the azimuthal dimension and return 0 if index is out-of-bounds + idx = self % bounds % search(theta) + + ! Should never happen + if (idx == valueOutsideArray) then + idx = 0 + return + end if + + end function map + + !! + !! Add information about division axis to the output file + !! + !! See tallyMap for specification. + !! + subroutine print(self,out) + class(directionMap), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen) :: name + integer(shortInt) :: i + + ! Print grid bins + name = trim(self % getAxisName()) //'AngularBounds' + + call out % startArray(name, [2,self % N]) + + do i = 1, self % N + ! Print lower bin boundary + call out % addValue(self % bounds % bin(i) + PI) + + ! Print upper bin boundar + call out % addValue(self % bounds % bin(i + 1) + PI) + end do + + call out % endArray() + + end subroutine print + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(directionMap), intent(inout) :: self + + call kill_super(self) + + call self % bounds % kill() + self % N = 0 + self % DIM1 = 0 + self % DIM2 = 0 + + end subroutine kill + +end module directionMap_class diff --git a/Tallies/TallyMaps/energyMap_class.f90 b/Tallies/TallyMaps/Maps1D/energyMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/energyMap_class.f90 rename to Tallies/TallyMaps/Maps1D/energyMap_class.f90 diff --git a/Tallies/TallyMaps/homogMatMap_class.f90 b/Tallies/TallyMaps/Maps1D/homogMatMap_class.f90 similarity index 98% rename from Tallies/TallyMaps/homogMatMap_class.f90 rename to Tallies/TallyMaps/Maps1D/homogMatMap_class.f90 index d6eb97fa4..b0476d8f0 100644 --- a/Tallies/TallyMaps/homogMatMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/homogMatMap_class.f90 @@ -193,7 +193,7 @@ elemental function map(self,state) result(idx) integer(shortInt) :: idx, isThere do idx = 1,size(self % binMap) - isThere = self % binMap(idx) % getOrDefault( state % matIdx, self % default) + isThere = self % binMap(idx) % getOrDefault(state % matIdx, self % default) if (isThere == 1) return end do diff --git a/Tallies/TallyMaps/materialMap_class.f90 b/Tallies/TallyMaps/Maps1D/materialMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/materialMap_class.f90 rename to Tallies/TallyMaps/Maps1D/materialMap_class.f90 diff --git a/Tallies/TallyMaps/spaceMap_class.f90 b/Tallies/TallyMaps/Maps1D/spaceMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/spaceMap_class.f90 rename to Tallies/TallyMaps/Maps1D/spaceMap_class.f90 diff --git a/Tallies/TallyMaps/sphericalMap_class.f90 b/Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 similarity index 78% rename from Tallies/TallyMaps/sphericalMap_class.f90 rename to Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 index 8a6d9dfff..4781bf33a 100644 --- a/Tallies/TallyMaps/sphericalMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 @@ -1,4 +1,4 @@ -module sphericalMap_class +module sphericalRadMap_class use numPrecision use universalVariables, only : valueOutsideArray @@ -7,28 +7,24 @@ module sphericalMap_class use grid_class, only : grid use particle_class, only : particleState use outputFile_class, only : outputFile - use tallyMap_inter, only : tallyMap, kill_super => kill + use tallyMap1D_inter, only : tallyMap1D, kill_super => kill implicit none private - !! !! Divides space into a mesh in spherical co-ordinates !! - !! TODO: - !! Implement polar & azimuthal subdivision - !! !! Interface: - !! tallyMap interface + !! tallyMap1D interface !! !! NOTE: !! Behaviour of points exactly at the boundary of bins is undefined. !! particle can end-up in either of the two !! !! Sample Dictionary Input: - !! sphericalMap { - !! type sphericalMap; + !! sphericalRadMap { + !! type sphericalRadMap; !! #origin (1.0 0.0 0.0);# // Optional. Default (0 0 0) !! grid lin; !! #Rmin 2.0;# // Optional. Default 0.0 @@ -37,21 +33,22 @@ module sphericalMap_class !! } !! !! - type, public, extends (tallyMap) :: sphericalMap + type, public, extends (tallyMap1D) :: sphericalRadMap private real(defReal), dimension(3) :: origin = ZERO type(grid) :: rBounds integer(shortInt) :: N = 0 + contains ! Superclass procedure :: init procedure :: bins - procedure :: dimensions procedure :: getAxisName procedure :: map procedure :: print procedure :: kill - end type sphericalMap + + end type sphericalRadMap contains @@ -61,13 +58,13 @@ module sphericalMap_class !! See tallyMap for specification. !! subroutine init(self, dict) - class(sphericalMap), intent(inout) :: self + class(sphericalRadMap), intent(inout) :: self class(dictionary), intent(in) :: dict real(defReal), dimension(:), allocatable :: temp, grid character(nameLen) :: type real(defReal) :: Rmin, Rmax, vol integer(shortInt) :: i - character(100), parameter :: Here = 'init (sphericalmap_class.f90)' + character(100), parameter :: Here = 'init (sphericalRadMap_class.f90)' ! Check & load origin call dict % getOrDefault(temp, 'origin', [ZERO, ZERO, ZERO]) @@ -140,9 +137,9 @@ end subroutine init !! See tallyMap for specification. !! elemental function bins(self, D) result(N) - class(sphericalMap), intent(in) :: self - integer(shortInt), intent(in) :: D - integer(shortInt) :: N + class(sphericalRadMap), intent(in) :: self + integer(shortInt), intent(in) :: D + integer(shortInt) :: N if (D == 1 .or. D == 0) then N = self % N @@ -152,29 +149,16 @@ elemental function bins(self, D) result(N) end function bins - !! - !! Return number of dimensions - !! - !! See tallyMap for specification. - !! - elemental function dimensions(self) result(D) - class(sphericalMap), intent(in) :: self - integer(shortInt) :: D - - D = 1 - - end function dimensions - !! !! Return string that describes variable used to divide event space !! !! See tallyMap for specification !! function getAxisName(self) result(name) - class(sphericalMap), intent(in) :: self - character(nameLen) :: name + class(sphericalRadMap), intent(in) :: self + character(nameLen) :: name - name ='sphericalMap' + name ='sphericalRadMap' end function getAxisName @@ -184,10 +168,10 @@ end function getAxisName !! See tallyMap for specification. !! elemental function map(self, state) result(idx) - class(sphericalMap), intent(in) :: self - class(particleState), intent(in) :: state - integer(shortInt) :: idx - real(defReal) :: r + class(sphericalRadMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + real(defReal) :: r ! Calculate the distance from the origin r = norm2(state % r - self % origin) @@ -204,10 +188,10 @@ end function map !! See tallyMap for specification. !! subroutine print(self,out) - class(sphericalMap), intent(in) :: self - class(outputFile), intent(inout) :: out - character(nameLen) :: name - integer(shortInt) :: i + class(sphericalRadMap), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen) :: name + integer(shortInt) :: i ! Name the array name = trim(self % getAxisName()) //'Bounds' @@ -229,7 +213,7 @@ end subroutine print !! Return to uninitialised state !! elemental subroutine kill(self) - class(sphericalMap), intent(inout) :: self + class(sphericalRadMap), intent(inout) :: self call kill_super(self) @@ -239,4 +223,4 @@ elemental subroutine kill(self) end subroutine kill -end module sphericalMap_class +end module sphericalRadMap_class diff --git a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 similarity index 79% rename from Tallies/TallyMaps/tallyMap1DFactory_func.f90 rename to Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 index aab438ea3..fa67068cd 100644 --- a/Tallies/TallyMaps/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 @@ -25,15 +25,16 @@ module tallyMap1DFactory_func use tallyMap1D_inter, only : tallyMap1D ! TallyMap implementations - use energyMap_class, only : energyMap - use spaceMap_class, only : spaceMap - use materialMap_class, only : materialMap - use homogMatMap_class, only : homogMatMap - use weightMap_class, only : weightMap - use cellMap_class, only : cellMap - use testMap_class, only : testMap - use collNumMap_class, only : collNumMap -! use matXsMap_class, only : matXsMap + use energyMap_class, only : energyMap + use spaceMap_class, only : spaceMap + use materialMap_class, only : materialMap + use homogMatMap_class, only : homogMatMap + use weightMap_class, only : weightMap + use cellMap_class, only : cellMap + use testMap_class, only : testMap + use collNumMap_class, only : collNumMap + use sphericalRadMap_class, only : sphericalRadMap + use directionMap_class, only : directionMap implicit none private @@ -45,14 +46,16 @@ module tallyMap1DFactory_func ! It is printed if type was unrecognised ! NOTE: ! For now it is necessary to adjust trailing blanks so all enteries have the same length - character(nameLen),dimension(*),parameter, public :: AVALIBLE_tallyMaps1D = [ 'energyMap ',& - 'spaceMap ',& - 'materialMap',& - 'homogMatMap',& - 'weightMap ',& - 'cellMap ',& - 'testMap ',& - 'collNumMap '] + character(nameLen),dimension(*),parameter, public :: AVALIBLE_tallyMaps1D = [ 'energyMap ',& + 'spaceMap ',& + 'materialMap ',& + 'homogMatMap ',& + 'weightMap ',& + 'cellMap ',& + 'collNumMap ',& + 'sphericalRadMap',& + 'directionMap ',& + 'testMap '] contains @@ -100,12 +103,18 @@ subroutine new_tallyMap1D(new, dict) case('cellMap') allocate(cellMap :: new) - case('testMap') - allocate(testMap :: new) - case('collNumMap') allocate(collNumMap :: new) + case('sphericalRadMap') + allocate(sphericalRadMap :: new) + + case('directionMap') + allocate(directionMap :: new) + + case('testMap') + allocate(testMap :: new) + case default print *, AVALIBLE_tallyMaps1D call fatalError(Here,'Unrecognised type of tallyMap1D : ' // trim(type)) diff --git a/Tallies/TallyMaps/tallyMap1D_inter.f90 b/Tallies/TallyMaps/Maps1D/tallyMap1D_inter.f90 similarity index 100% rename from Tallies/TallyMaps/tallyMap1D_inter.f90 rename to Tallies/TallyMaps/Maps1D/tallyMap1D_inter.f90 diff --git a/Tallies/TallyMaps/testMap_class.f90 b/Tallies/TallyMaps/Maps1D/testMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/testMap_class.f90 rename to Tallies/TallyMaps/Maps1D/testMap_class.f90 diff --git a/Tallies/TallyMaps/weightMap_class.f90 b/Tallies/TallyMaps/Maps1D/weightMap_class.f90 similarity index 100% rename from Tallies/TallyMaps/weightMap_class.f90 rename to Tallies/TallyMaps/Maps1D/weightMap_class.f90 diff --git a/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 b/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 index 2de328219..71aafb283 100644 --- a/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 +++ b/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 @@ -179,7 +179,7 @@ end subroutine testBinNumber !! !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequance is without errors + !! Does not checks that values are correct, but that calls sequence is without errors !! @Test subroutine testPrint(this) diff --git a/Tallies/TallyMaps/cylindricalMap_class.f90 b/Tallies/TallyMaps/cylindricalMap_class.f90 index b8d8eb757..0a6eb7352 100644 --- a/Tallies/TallyMaps/cylindricalMap_class.f90 +++ b/Tallies/TallyMaps/cylindricalMap_class.f90 @@ -51,7 +51,7 @@ module cylindricalMap_class type(grid) :: rBounds type(grid) :: axBounds type(grid) :: azBounds - integer(shortInt) :: rN = 0 + integer(shortInt) :: rN = 0 integer(shortInt) :: axN = 0 integer(shortInt) :: azN = 0 integer(shortInt) :: DIM1 = 0 diff --git a/Tallies/TallyMaps/matXsMapOLD_class.f90 b/Tallies/TallyMaps/matXsMapOLD_class.f90 deleted file mode 100644 index 990977fbc..000000000 --- a/Tallies/TallyMaps/matXsMapOLD_class.f90 +++ /dev/null @@ -1,186 +0,0 @@ -module matXsMap_class - - use numPrecision - use universalVariables - use genericProcedures, only : fatalError - use dictionary_class, only : dictionary - use grid_class, only : grid - use particle_class, only : particle - use outputFile_class, only : outputFile - use tallyMap_inter, only : tallyMap - - use nuclearDataRegistry_mod, only : getMatIdx - use nuclearData_inter, only : nuclearData - use transportNuclearData_inter, only : transportNuclearData - - implicit none - private - - !! - !! Constructor - !! - interface matXsMap - module procedure matXsMap_fromDict - end interface - - !! - !! Very weird map that creates bins depending on value of total XS in a specific material - !! Unfortunatly cannot detect upper and lower bound. Need to be provided manually. - !! I wander if there is any practical use for it. - !! - type, public,extends(tallyMap) :: matXsMap - private - type(grid) :: binBounds ! Bin grid - integer(shortInt) :: N ! Number of Bins - integer(shortInt) :: matIdx ! Material Index of querry material - - contains - ! Superclass interface implementaction - procedure :: bins ! Return number of bins - procedure :: map ! Map particle to a bin - procedure :: getAxisName ! Return character describing variable of devision - procedure :: print ! Print values associated with bins to outputfile - - ! Class specific procedures - procedure :: init - end type matXsMap - -contains - - !! - !! Initialise from min and max value, number of bins and extrapolation - !! - subroutine init(self, mini, maxi, N, type, matName) - class(matXsMap), intent(inout) :: self - real(defReal), intent(in) :: mini - real(defReal), intent(in) :: maxi - integer(shortInt),intent(in) :: N - character(nameLen), intent(in) :: type - character(nameLen), intent(in) :: matName - - self % N = N - call self % binBounds % init(mini, maxi, N, type) - - self % matIdx = getMatIdx(matName) - - end subroutine init - - - !! - !! Return total number of bins in this division - !! - pure function bins(self) result(N) - class(matXsMap), intent(in) :: self - integer(shortInt) :: N - - N = self % N - - end function bins - - !! - !! Map particle to a single bin. Return 0 for particle out of division - !! - function map(self,p) result(idx) - class(matXsMap), intent(in) :: self - class(particle), intent(in) :: p - integer(shortInt) :: idx - real(defReal) :: SigmaTot - character(100),parameter :: Here = 'map (matXsMap_class.f90)' - - ! Obtain XS - associate (xsData => p % xsData) - select type(xsData) - class is (transportNuclearData) - SigmaTot = xsData % getTotalMatXS(p, self % matIdx) - - class default - call fatalError(Here,'Dynamic type of XS data attached to particle is not transportNuclearData') - - end select - end associate - - idx = self % binBounds % search(SigmaTot) - if (idx == valueOutsideArray) idx = 0 - - end function map - - !! - !! Return string that describes variable used to divide event space - !! - function getAxisName(self) result(name) - class(matXsMap), intent(in) :: self - character(nameLen) :: name - - name = 'matXs' - - end function getAxisName - - !! - !! Add information about division axis to the output file - !! - subroutine print(self,out) - class(matXsMap), intent(in) :: self - class(outputFile), intent(inout) :: out - character(nameLen) :: name - integer(shortInt) :: i - - ! Name the array - name = trim(self % getAxisName()) //'Bounds' - - call out % startArray(name,[self % N,2]) - do i=1,self % N - ! Print lower bin boundary - call out % addValue(self % binBounds % bin(i)) - end do - - do i=1,self % N - ! Print upper bin boundar - call out % addValue(self % binBounds % bin(i+1)) - end do - - call out % endArray() - - end subroutine print - - !! - !! Return instance of matXsMap from dictionary - !! - function matXsMap_fromDict(dict) result(new) - class(dictionary), intent(in) :: dict - type(matXsMap) :: new - character(nameLen) :: str, matName - real(defReal) :: mini, maxi - real(defReal),dimension(:),allocatable :: bins - integer(shortInt) :: N - character(100), parameter :: Here = 'matXsMap_fromDict (matXsMap_class.f90)' - - if(.not.dict % isPresent('grid')) call fatalError(Here,"Keyword 'grid' must be present") - if(.not.dict % isPresent('mat')) call fatalError(Here,"Keyword 'mat' must be present") - - ! Read material name - call dict % get(matName,'mat') - - - - ! Read grid definition keyword - call dict % get(str,'grid') - - ! Choose approperiate definition - select case(str) - case('lin','log') - ! Read settings - call dict % get(mini,'min') - call dict % get(maxi,'max') - call dict % get(N,'N') - - ! Initialise - call new % init(mini, maxi, N, str, matName) - - case default - call fatalError(Here,"'grid' keyword must be: lin or log") - - end select - - end function matXsMap_fromDict - -end module matXsMap_class diff --git a/Tallies/TallyMaps/tallyMapFactory_func.f90 b/Tallies/TallyMaps/tallyMapFactory_func.f90 index 5eb67f6f2..33d5108fb 100644 --- a/Tallies/TallyMaps/tallyMapFactory_func.f90 +++ b/Tallies/TallyMaps/tallyMapFactory_func.f90 @@ -20,7 +20,6 @@ module tallyMapFactory_func ! TallyMap implementations use multiMap_class, only : multiMap - use sphericalMap_class, only : sphericalMap use cylindricalMap_class, only : cylindricalMap implicit none @@ -33,7 +32,6 @@ module tallyMapFactory_func ! NOTE: ! For now it is necessary to adjust trailing blanks so all enteries have the same length character(nameLen),dimension(*),parameter :: AVALIBLE_tallyMaps = [ 'multiMap ', & - 'sphericalMap ', & 'cylindricalMap'] @@ -72,9 +70,6 @@ subroutine new_tallyMap(new, dict) case('multiMap') allocate( multiMap :: new) - case('sphericalMap') - allocate( sphericalMap :: new) - case('cylindricalMap') allocate( cylindricalMap :: new) diff --git a/Tallies/TallyMaps/tallyMapSlot_class.f90 b/Tallies/TallyMaps/tallyMapSlot_class.f90 deleted file mode 100644 index 3c3910bf8..000000000 --- a/Tallies/TallyMaps/tallyMapSlot_class.f90 +++ /dev/null @@ -1,163 +0,0 @@ -module tallyMapSlot_class - - use numPrecision - use particle_class, only : particleState - use outputFile_class, only : outputFile - use dictionary_class, only : dictionary - use tallyMap_inter, only : tallyMap, kill_super => kill - use tallyMapFactory_func, only : new_tallyMap - - implicit none - private - - !! - !! Container for polymorphic instances of tallyMaps - !! - !! tallyMapSlot is itself a tallyMap. Init functions uses tallyMapFactory - !! to build any type of tallyMap as specified in the provided dictionary - !! - !! Private Members: - !! slot -> allocatable tallyMap content - !! - !! Interface: - !! tallyMap interface - !! moveAllocFrom -> moves allocation of allocatable class(tallyMap) into the slot - !! - type, public,extends(tallyMap) :: tallyMapSlot - private - class(tallyMap),allocatable :: slot - contains - ! Superclass interface implementaction - procedure :: init - procedure :: dimensions - procedure :: bins - procedure :: map - procedure :: getAxisName - procedure :: print - procedure :: kill - - ! Class specific procedures - procedure :: moveAllocFrom - - end type tallyMapSlot - -contains - - !! - !! Shortcut to factory. - !! Builds object in a factory from a dictionary and stores it in a slot - !! - !! See tallyMap for specification - !! - subroutine init(self, dict) - class(tallyMapSlot), intent(inout) :: self - class(dictionary), intent(in) :: dict - - call self % kill() - call new_tallyMap(self % slot, dict) - - end subroutine init - - !! - !! Return total number of bins in this division - !! - !! See tallyMap for specification - !! - elemental function bins(self, D) result(N) - class(tallyMapSlot), intent(in) :: self - integer(shortInt),intent(in) :: D - integer(shortInt) :: N - - N = self % slot % bins(D) - - end function bins - - !! - !! Return number of dimensions - !! - !! See tallyMap for specification - !! - elemental function dimensions(self) result(D) - class(tallyMapSlot), intent(in) :: self - integer(shortInt) :: D - - D = self % slot % dimensions() - - end function dimensions - - - !! - !! Map particle to a single bin. Return 0 for particle out of division - !! - !! See tallyMap for specification - !! - elemental function map(self,state) result(idx) - class(tallyMapSlot), intent(in) :: self - class(particleState), intent(in) :: state - integer(shortInt) :: idx - - idx = self % slot % map(state) - - end function map - - !! - !! Return string that describes variable used to divide event space - !! - !! See tallyMap for specification - !! - function getAxisName(self) result(name) - class(tallyMapSlot), intent(in) :: self - character(nameLen) :: name - - name = self % slot % getAxisName() - - end function getAxisName - - !! - !! Add information about division axis to the output file - !! - !! See tallyMap for specification - !! - subroutine print(self,out) - class(tallyMapSlot), intent(in) :: self - class(outpuTFile), intent(inout) :: out - - call self % slot % print(out) - - end subroutine print - - !! - !! Move allocation from allocatable RHS into slot - !! - !! Args: - !! RHS [inout] -> allocatable tallyMap to load into the slot - !! - !! Errors: - !! None - !! - !! NOTE: - !! RHS is deallocated on exit - !! - subroutine moveAllocFrom(LHS,RHS) - class(tallyMapSlot), intent(inout) :: LHS - class(tallyMap), allocatable, intent(inout) :: RHS - - call LHS % kill() - call move_alloc(RHS, LHS % slot) - - end subroutine moveAllocFrom - - !! - !! Deallocate content of the slot - !! - elemental subroutine kill(self) - class(tallyMapSlot), intent(inout) :: self - - call kill_super(self) - - if(allocated(self % slot)) deallocate(self % slot) - - end subroutine kill - - -end module tallyMapSlot_class From 98ec4dff85ab9d32f3dad613db34b5c075114bac Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Tue, 16 Apr 2024 13:03:32 +0100 Subject: [PATCH 114/133] Merge cyl and sph radial maps into one radialMap --- Tallies/TallyMaps/CMakeLists.txt | 8 +- .../Maps1D/Tests/cylindricalRadMap_test.f90 | 202 ----------- .../TallyMaps/Maps1D/Tests/radialMap_test.f90 | 331 ++++++++++++++++++ .../Maps1D/Tests/sphericalRadMap_test.f90 | 236 ------------- .../Maps1D/cylindricalRadMap_class.f90 | 260 -------------- .../TallyMaps/Maps1D/directionMap_class.f90 | 4 +- Tallies/TallyMaps/Maps1D/radialMap_class.f90 | 267 ++++++++++++++ .../Maps1D/sphericalRadMap_class.f90 | 226 ------------ .../Maps1D/tallyMap1DFactory_func.f90 | 44 +-- Tallies/TallyMaps/cylindricalMap_class.f90 | 4 +- 10 files changed, 627 insertions(+), 955 deletions(-) delete mode 100644 Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 create mode 100644 Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 delete mode 100644 Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 delete mode 100644 Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 create mode 100644 Tallies/TallyMaps/Maps1D/radialMap_class.f90 delete mode 100644 Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 diff --git a/Tallies/TallyMaps/CMakeLists.txt b/Tallies/TallyMaps/CMakeLists.txt index bea5c9e58..0ac9ee1d0 100644 --- a/Tallies/TallyMaps/CMakeLists.txt +++ b/Tallies/TallyMaps/CMakeLists.txt @@ -11,9 +11,8 @@ add_sources(./tallyMap_inter.f90 ./Maps1D/materialMap_class.f90 ./Maps1D/homogMatMap_class.f90 ./Maps1D/weightMap_class.f90 - ./Maps1D/sphericalRadMap_class.f90 ./Maps1D/cellMap_class.f90 - ./Maps1D/cylindricalRadMap_class.f90 + ./Maps1D/radialMap_class.f90 ./Maps1D/collNumMap_class.f90 ./Maps1D/directionMap_class.f90 ) @@ -26,8 +25,7 @@ add_unit_tests(./Tests/multiMap_test.f90 ./Maps1D/Tests/spaceMap_test.f90 ./Maps1D/Tests/testMap_test.f90 ./Maps1D/Tests/homogMatMap_test.f90 - ./Maps1D/Tests/sphericalRadMap_test.f90 - ./Maps1D/Tests/cylindricalRadMap_test.f90 + ./Maps1D/Tests/radialMap_test.f90 ./Maps1D/Tests/cellMap_test.f90 ./Maps1D/Tests/collNumMap_test.f90 - ./Maps1D/Tests/directionMap_test.f90) + ./Maps1D/Tests/directionMap_test.f90) diff --git a/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 deleted file mode 100644 index 63d6c824a..000000000 --- a/Tallies/TallyMaps/Maps1D/Tests/cylindricalRadMap_test.f90 +++ /dev/null @@ -1,202 +0,0 @@ -module cylindricalRadMap_test - use numPrecision - use pFUnit_mod - use particle_class, only : particleState - use dictionary_class, only : dictionary - use outputFile_class, only : outputFile - - use cylindricalRadMap_class, only : cylindricalRadMap - - implicit none - - -@testCase - type, extends(TestCase) :: test_cylindricalRadMap - private - type(cylindricalRadMap) :: map_radial - type(cylindricalRadMap) :: map_unstruct - type(cylindricalRadMap) :: map_equivol - - contains - procedure :: setUp - procedure :: tearDown - end type test_cylindricalRadMap - -contains - - !! - !! Sets up test_cylindricalRadMap object we can use in a number of tests - !! - subroutine setUp(this) - class(test_cylindricalRadMap), intent(inout) :: this - type(dictionary) :: tempDict - - ! Build radial map with different orientation & minimum radius - call tempDict % init(5) - call tempDict % store('orientation','x') - call tempDict % store('rGrid','equivolume') - call tempDict % store('Rmin', 2.0_defReal) - call tempDict % store('Rmax', 10.0_defReal) - call tempDict % store('rN', 5) - - call this % map_radial % init(tempDict) - call tempDict % kill() - - ! Build map with different origin & unstruct bins - call tempDict % init(3) - call tempDict % store('origin',[ONE, ONE]) - call tempDict % store('rGrid','unstruct') - call tempDict % store('bins', [1.5_defReal, 2.3_defReal, 3.8_defReal, 8.0_defReal]) - - call this % map_unstruct % init(tempDict) - call tempDict % kill() - - ! Build map with equivolume bins - call tempDict % init(3) - call tempDict % store('rGrid','equivolume') - call tempDict % store('Rmax', 8.0_defReal) - call tempDict % store('rN', 4) - - call this % map_equivol % init(tempDict) - call tempDict % kill() - - end subroutine setUp - - !! - !! Kills test_cylindricalRadMap object we can use in a number of tests - !! - subroutine tearDown(this) - class(test_cylindricalRadMap), intent(inout) :: this - - call this % map_radial % kill() - call this % map_unstruct % kill() - call this % map_equivol % kill() - - end subroutine tearDown - -!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> -!! PROPER TESTS BEGIN HERE -!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> - - !! - !! Test radial map with different orientation & minimum radius - !! -@Test - subroutine testRadial(this) - class(test_cylindricalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [0.4_defReal, 5.38_defReal, 8.9_defReal, 9.1_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4),parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] - integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 2, 4, 5] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = z - states(:) % r(2) = r * cos(phi) - states(:) % r(3) = r * sin(phi) - - idx = this % map_radial % map(states) - - @assertEqual(RES_IDX, idx) - - end subroutine testRadial - - !! - !! Test map with different origin & unstruct bins - !! -@Test - subroutine testUnstruct(this) - class(test_cylindricalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.52_defReal, 5.5_defReal, 8.9_defReal, 2.88_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 3, 0, 2] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) - states(:) % r(2) = r * sin(phi) - states(:) % r(3) = z - - ! Shift the origin - states(:) % r(1) = states(:) % r(1) + ONE - states(:) % r(2) = states(:) % r(2) + ONE - states(:) % r(3) = states(:) % r(3) - - idx = this % map_unstruct % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testUnstruct - - !! - !! Test map with equivolume bins - !! -@Test - subroutine testEquivol(this) - class(test_cylindricalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.82_defReal, 4.68_defReal, 7.9_defReal, 17.01_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 2, 4, 0] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) - states(:) % r(2) = r * sin(phi) - states(:) % r(3) = z - - idx = this % map_equivol % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testEquivol - - !! - !! Test bin number retrival - !! -@Test - subroutine testBinNumber(this) - class(test_cylindricalRadMap), intent(inout) :: this - - ! Test that map is 1D - @assertEqual(5, this % map_radial % bins(0),'All bins') - @assertEqual(5, this % map_radial % bins(1),'1st dimension') - @assertEqual(0, this % map_radial % bins(2),'2nd dimension') - @assertEqual(3, this % map_unstruct % bins(1),'1st dimension') - @assertEqual(4, this % map_equivol % bins(1),'1st dimension') - - ! Get dimensionality - @assertEqual(1, this % map_radial % dimensions()) - @assertEqual(1, this % map_unstruct % dimensions()) - - end subroutine testBinNumber - - !! - !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequence is without errors - !! -@Test - subroutine testPrint(this) - class(test_cylindricalRadMap), intent(inout) :: this - type(outputFile) :: out - - call out % init('dummyPrinter', fatalErrors = .false.) - - call this % map_radial % print(out) - @assertTrue(out % isValid(),'Radial map case') - call out % reset() - - call this % map_unstruct % print(out) - @assertTrue(out % isValid(),'Unstruct map case') - call out % reset() - - call this % map_equivol % print(out) - @assertTrue(out % isValid(),'Unstruct map case') - call out % reset() - - end subroutine testPrint - - -end module cylindricalRadMap_test diff --git a/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 new file mode 100644 index 000000000..eea303f19 --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 @@ -0,0 +1,331 @@ +module radialMap_test + + use numPrecision + use pFUnit_mod + use particle_class, only : particleState + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + + use radialMap_class, only : radialMap + + implicit none + + +@testCase + type, extends(TestCase) :: test_radialMap + private + type(radialMap) :: map_cyl_linear + type(radialMap) :: map_cyl_equivol + type(radialMap) :: map_cyl_unstruct + type(radialMap) :: map_sph_from_zero + type(radialMap) :: map_sph_from_min + type(radialMap) :: map_sph_equivol + + contains + procedure :: setUp + procedure :: tearDown + end type test_radialMap + +contains + + !! + !! Sets up test_radialMap object we can use in a number of tests + !! + subroutine setUp(this) + class(test_radialMap), intent(inout) :: this + type(dictionary) :: tempDict + + ! Build cylindrical map with linear bins + call tempDict % init(4) + call tempDict % store('axis','x') + call tempDict % store('grid','lin') + call tempDict % store('max', 8.0_defReal) + call tempDict % store('N', 4) + + call this % map_cyl_linear % init(tempDict) + call tempDict % kill() + + ! Build cylindrical map with different orientation & minimum radius + call tempDict % init(5) + call tempDict % store('axis','z') + call tempDict % store('grid','equivolume') + call tempDict % store('min', 2.0_defReal) + call tempDict % store('max', 10.0_defReal) + call tempDict % store('N', 5) + + call this % map_cyl_equivol % init(tempDict) + call tempDict % kill() + + ! Build cylindrical map with different origin & unstruct bins + call tempDict % init(4) + call tempDict % store('axis','z') + call tempDict % store('origin',[ONE, ONE]) + call tempDict % store('grid','unstruct') + call tempDict % store('bins', [1.5_defReal, 2.3_defReal, 3.8_defReal, 8.0_defReal]) + + call this % map_cyl_unstruct % init(tempDict) + call tempDict % kill() + + ! Build spherical map with default origin & minimum radius + call tempDict % init(3) + call tempDict % store('grid','lin') + call tempDict % store('max', 10.0_defReal) + call tempDict % store('N', 20) + + call this % map_sph_from_zero % init(tempDict) + call tempDict % kill() + + ! Build spherical map with diffrent origin & minimum radius + call tempDict % init(5) + call tempDict % store('origin', [ONE, ONE, ONE]) + call tempDict % store('grid', 'lin') + call tempDict % store('min', 5.0_defReal) + call tempDict % store('max', 10.0_defReal) + call tempDict % store('N', 5) + + call this % map_sph_from_min % init(tempDict) + call tempDict % kill() + + ! Build spherical map with equivolume bins + call tempDict % init(4) + call tempDict % store('grid', 'equivolume') + call tempDict % store('min', 2.0_defReal) + call tempDict % store('max', 20.0_defReal) + call tempDict % store('N', 8) + + call this % map_sph_equivol % init(tempDict) + call tempDict % kill() + + end subroutine setUp + + !! + !! Kills test_radialMap object we can use in a number of tests + !! + subroutine tearDown(this) + class(test_radialMap), intent(inout) :: this + + call this % map_cyl_linear % kill() + call this % map_cyl_equivol % kill() + call this % map_cyl_unstruct % kill() + call this % map_sph_from_zero % kill() + call this % map_sph_from_min % kill() + call this % map_sph_equivol % kill() + + end subroutine tearDown + +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +!! PROPER TESTS BEGIN HERE +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> + + !! + !! Test cylindrical map with different orientation & minimum radius + !! +@Test + subroutine testCylLinear(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [0.4_defReal, 5.38_defReal, 7.9_defReal, 9.1_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4),parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 3, 4, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = z + states(:) % r(2) = r * cos(phi) + states(:) % r(3) = r * sin(phi) + + idx = this % map_cyl_linear % map(states) + + @assertEqual(RES_IDX, idx) + + end subroutine testCylLinear + + !! + !! Test cylindrical map with equivolume bins + !! +@Test + subroutine testCylEquivol(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.82_defReal, 4.68_defReal, 7.9_defReal, 9.01_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 4, 5] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) + states(:) % r(2) = r * sin(phi) + states(:) % r(3) = z + + idx = this % map_cyl_equivol % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testCylEquivol + + !! + !! Test cylindrical map with different origin & unstruct bins + !! +@Test + subroutine testCylUnstruct(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.52_defReal, 5.5_defReal, 8.9_defReal, 2.88_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.0_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 3, 0, 2] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) + states(:) % r(2) = r * sin(phi) + states(:) % r(3) = z + + ! Shift the origin + states(:) % r(1) = states(:) % r(1) + ONE + states(:) % r(2) = states(:) % r(2) + ONE + states(:) % r(3) = states(:) % r(3) + + idx = this % map_cyl_unstruct % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testCylUnstruct + + !! + !! Test spherical map with default-initialised grid + !! +@Test + subroutine testSphFromOrigin(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [0.4_defReal, 3.58_defReal, 8.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 8, 18, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) * sin(tht) + states(:) % r(2) = r * sin(phi) * sin(tht) + states(:) % r(3) = r * cos(tht) + + idx = this % map_sph_from_zero % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testSphFromOrigin + + !! + !! Test spherical map with grid with shifted origin & minimum radius + !! +@Test + subroutine testSphFromMin(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 8.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 4, 0] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) * sin(tht) + states(:) % r(2) = r * sin(phi) * sin(tht) + states(:) % r(3) = r * cos(tht) + + ! Shift the origin + states(:) % r(1) = states(:) % r(1) + ONE + states(:) % r(2) = states(:) % r(2) + ONE + states(:) % r(3) = states(:) % r(3) + ONE + + idx = this % map_sph_from_min % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testSphFromMin + + !! + !! Test spherical map with grid with equivolume bins + !! +@Test + subroutine testSphEquivol(this) + class(test_radialMap), intent(inout) :: this + real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 18.9_defReal, 11.0_defReal] + real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] + real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] + integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 7, 2] + integer(shortInt),dimension(4) :: idx + type(particleState),dimension(4) :: states + + ! Initialise states + states(:) % r(1) = r * cos(phi) * sin(tht) + states(:) % r(2) = r * sin(phi) * sin(tht) + states(:) % r(3) = r * cos(tht) + + idx = this % map_sph_equivol % map(states) + @assertEqual(RES_IDX, idx) + + end subroutine testSphEquivol + + !! + !! Test bin number retrival + !! +@Test + subroutine testBinNumber(this) + class(test_radialMap), intent(inout) :: this + + ! Test that map is 1D + @assertEqual(4, this % map_cyl_linear % bins(0),'All bins') + @assertEqual(4, this % map_cyl_linear % bins(1),'1st dimension') + @assertEqual(0, this % map_cyl_linear % bins(2),'2nd dimension') + @assertEqual(3, this % map_cyl_unstruct % bins(1),'1st dimension') + @assertEqual(5, this % map_cyl_equivol % bins(1),'1st dimension') + @assertEqual(20, this % map_sph_from_zero % bins(1),'1st Dimension') + @assertEqual(20, this % map_sph_from_zero % bins(0),'All bins') + @assertEqual(0, this % map_sph_from_min % bins(2),'Invalid Dimension') + + ! Get dimensionality + @assertEqual(1, this % map_cyl_linear % dimensions()) + @assertEqual(1, this % map_cyl_unstruct % dimensions()) + @assertEqual(1, this % map_sph_from_min % dimensions()) + + end subroutine testBinNumber + + !! + !! Test correctness of print subroutine + !! Does not checks that values are correct, but that calls sequence is without errors + !! +@Test + subroutine testPrint(this) + class(test_radialMap), intent(inout) :: this + type(outputFile) :: out + + call out % init('dummyPrinter', fatalErrors = .false.) + + call this % map_cyl_linear % print(out) + @assertTrue(out % isValid(),'Linear map case (cylindrical)') + call out % reset() + + call this % map_cyl_equivol % print(out) + @assertTrue(out % isValid(),'Equivolume map case (cylindrical)') + call out % reset() + + call this % map_cyl_unstruct % print(out) + @assertTrue(out % isValid(),'Unstruct map case (cylindrical)') + call out % reset() + + call this % map_sph_from_zero % print(out) + @assertTrue(out % isValid(),'Linear map case from zero (spherical)') + call out % reset() + + call this % map_sph_from_min % print(out) + @assertTrue(out % isValid(),'Linear map case from minimum radius (spherical)') + call out % reset() + + call this % map_sph_equivol % print(out) + @assertTrue(out % isValid(),'Equivolume map case (spherical)') + call out % reset() + + end subroutine testPrint + + +end module radialMap_test diff --git a/Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 deleted file mode 100644 index e0e9fb651..000000000 --- a/Tallies/TallyMaps/Maps1D/Tests/sphericalRadMap_test.f90 +++ /dev/null @@ -1,236 +0,0 @@ -module sphericalRadMap_test - use numPrecision - use pFUnit_mod - use particle_class, only : particleState - use dictionary_class, only : dictionary - use outputFile_class, only : outputFile - - use sphericalRadMap_class, only : sphericalRadMap - - implicit none - - -@testCase - type, extends(TestCase) :: test_sphericalRadMap - private - type(sphericalRadMap) :: map_lin_from_zero - type(sphericalRadMap) :: map_lin_from_min - type(sphericalRadMap) :: map_unstruct - type(sphericalRadMap) :: map_equivol - - contains - procedure :: setUp - procedure :: tearDown - end type test_sphericalRadMap - -contains - - !! - !! Sets up test_sphericalRadMap object we can use in a number of tests - !! - subroutine setUp(this) - class(test_sphericalRadMap), intent(inout) :: this - type(dictionary) :: tempDict - - ! Build map with default origin & minimum radius - call tempDict % init(4) - call tempDict % store('grid','lin') - call tempDict % store('Rmax', 10.0_defReal) - call tempDict % store('N', 20) - - call this % map_lin_from_zero % init(tempDict) - call tempDict % kill() - - ! Build map with diffrent origin & minimum radius - call tempDict % init(5) - call tempDict % store('origin', [ONE, ONE, ONE]) - call tempDict % store('grid', 'lin') - call tempDict % store('Rmin', 5.0_defReal) - call tempDict % store('Rmax', 10.0_defReal) - call tempDict % store('N', 5) - - call this % map_lin_from_min % init(tempDict) - call tempDict % kill() - - ! Build map with unstruct bins - call tempDict % init(2) - call tempDict % store('grid', 'unstruct') - call tempDict % store('bins', [4.0_defReal, 5.8_defReal, 7.3_defReal, 10.5_defReal, 15.0_defReal]) - - call this % map_unstruct % init(tempDict) - call tempDict % kill() - - ! Build map with equivolume bins - call tempDict % init(4) - call tempDict % store('grid', 'equivolume') - call tempDict % store('Rmin', 2.0_defReal) - call tempDict % store('Rmax', 20.0_defReal) - call tempDict % store('N', 8) - - call this % map_equivol % init(tempDict) - call tempDict % kill() - - end subroutine setUp - - !! - !! Kills test_sphericalRadMap object we can use in a number of tests - !! - subroutine tearDown(this) - class(test_sphericalRadMap), intent(inout) :: this - - call this % map_lin_from_zero % kill() - call this % map_lin_from_min % kill() - call this % map_unstruct % kill() - call this % map_equivol % kill() - - end subroutine tearDown - -!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> -!! PROPER TESTS BEGIN HERE -!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> - - !! - !! Test default-initialised grid - !! -@Test - subroutine testFromOrigin(this) - class(test_sphericalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [0.4_defReal, 3.58_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 8, 18, 0] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) * sin(tht) - states(:) % r(2) = r * sin(phi) * sin(tht) - states(:) % r(3) = r * cos(tht) - - idx = this % map_lin_from_zero % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testFromOrigin - - !! - !! Test grid with shifted origin & minimum radius - !! -@Test - subroutine testFromMin(this) - class(test_sphericalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 4, 0] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) * sin(tht) - states(:) % r(2) = r * sin(phi) * sin(tht) - states(:) % r(3) = r * cos(tht) - - ! Shift the origin - states(:) % r(1) = states(:) % r(1) + ONE - states(:) % r(2) = states(:) % r(2) + ONE - states(:) % r(3) = states(:) % r(3) + ONE - - idx = this % map_lin_from_min % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testFromMin - - !! - !! Test grid with unstruct bins - !! -@Test - subroutine testUnstruct(this) - class(test_sphericalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [4.5_defReal, 15.5_defReal, 8.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [1, 0, 3, 4] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) * sin(tht) - states(:) % r(2) = r * sin(phi) * sin(tht) - states(:) % r(3) = r * cos(tht) - - idx = this % map_unstruct % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testUnstruct - - !! - !! Test grid with equivolume bins - !! -@Test - subroutine testEquiVol(this) - class(test_sphericalRadMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: r = [1.5_defReal, 5.5_defReal, 18.9_defReal, 11.0_defReal] - real(defReal), dimension(4),parameter :: phi = [1.4_defReal, 3.98_defReal, 0.5_defReal, PI/2] - real(defReal), dimension(4), parameter :: tht = [ZERO, PI/2, PI/4, -PI/2] - integer(shortInt),dimension(4),parameter :: RES_IDX = [0, 1, 7, 2] - integer(shortInt),dimension(4) :: idx - type(particleState),dimension(4) :: states - - ! Initialise states - states(:) % r(1) = r * cos(phi) * sin(tht) - states(:) % r(2) = r * sin(phi) * sin(tht) - states(:) % r(3) = r * cos(tht) - - idx = this % map_equivol % map(states) - @assertEqual(RES_IDX, idx) - - end subroutine testEquiVol - - !! - !! Test bin number retrival - !! -@Test - subroutine testBinNumber(this) - class(test_sphericalRadMap), intent(inout) :: this - - @assertEqual(20, this % map_lin_from_zero % bins(1),'1st Dimension') - @assertEqual(4, this % map_unstruct % bins(1),'1st Dimension') - @assertEqual(20, this % map_lin_from_zero % bins(0),'All bins') - @assertEqual(0, this % map_lin_from_zero % bins(-3),'Invalid Dimension') - - ! Get dimensionality - @assertEqual(1, this % map_lin_from_zero % dimensions()) - - end subroutine testBinNumber - - !! - !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequance is without errors - !! -@Test - subroutine testPrint(this) - class(test_sphericalRadMap), intent(inout) :: this - type(outputFile) :: out - - call out % init('dummyPrinter', fatalErrors = .false.) - - call this % map_lin_from_zero % print(out) - @assertTrue(out % isValid(),'Default-initialised map case') - call out % reset() - - call this % map_lin_from_min % print(out) - @assertTrue(out % isValid(),'Map with minimum R') - call out % reset() - - call this % map_unstruct % print(out) - @assertTrue(out % isValid(),'Map with unstruct bins') - call out % reset() - - call this % map_equivol % print(out) - @assertTrue(out % isValid(),'Map with equivolume bins') - call out % reset() - - end subroutine testPrint - - -end module sphericalRadMap_test diff --git a/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 b/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 deleted file mode 100644 index 436c32eb5..000000000 --- a/Tallies/TallyMaps/Maps1D/cylindricalRadMap_class.f90 +++ /dev/null @@ -1,260 +0,0 @@ -module cylindricalRadMap_class - - use numPrecision - use universalVariables, only : valueOutsideArray, X_AXIS, Y_AXIS, Z_AXIS - use genericProcedures, only : fatalError, dotProduct, numToChar - use dictionary_class, only : dictionary - use grid_class, only : grid - use particle_class, only : particleState - use outputFile_class, only : outputFile - use tallyMap1D_inter, only : tallyMap1D, kill_super => kill - - implicit none - private - - !! - !! Divides space into a radial mesh in cylindrical co-ordinates - !! - !! Interface: - !! tallyMap1D interface - !! - !! NOTE: - !! Behaviour of points exactly at the boundary of bins is undefined. - !! particle can end-up in either of the two - !! - !! Sample Dictionary Input: - !! cylindricalRadMap { - !! type cylindricalRadMap; - !! #orientation x;# // Optional. Default z - !! #origin (1.0 0.0);# // Optional. Default (0 0). Order is xy, xz or yz. - !! rGrid lin; - !! #Rmin 2.0;# // Optional. Default 0.0 - !! Rmax 10.0; - !! rN 10; - !! } - !! - type, public, extends (tallyMap1D) :: cylindricalRadMap - private - real(defReal), dimension(2) :: origin = ZERO - type(grid) :: rBounds - integer(shortInt) :: rN = 0 - integer(shortInt) :: DIM1 = 0 - integer(shortInt) :: DIM2 = 0 - - contains - ! Superclass - procedure :: init - procedure :: bins - procedure :: getAxisName - procedure :: map - procedure :: print - procedure :: kill - - end type cylindricalRadMap - -contains - - !! - !! Initialise tallyMap from a dictionary - !! - !! See tallyMap for specification. - !! - subroutine init(self, dict) - class(cylindricalRadMap), intent(inout) :: self - class(dictionary), intent(in) :: dict - real(defReal), dimension(:), allocatable :: temp, grid - character(nameLen) :: type - real(defReal) :: Rmin, Rmax, vol - integer(shortInt) :: i - character(100), parameter :: Here = 'init (cylindricalRadMap_class.f90)' - - ! Check & load origin - call dict % getOrDefault(temp, 'origin', [ZERO, ZERO]) - - if (size(temp) /= 2) then - call fatalError(Here, 'Expected 2 values for origin. Got: ' // numToChar(size(temp))) - end if - self % origin = temp - - ! Check orientation of the cylinder - if (dict % isPresent('orientation')) then - call dict % get(type, 'orientation') - else - type = 'z' - end if - - select case(type) - case('x') - self % DIM1 = Y_AXIS - self % DIM2 = Z_AXIS - - case('y') - self % DIM1 = X_AXIS - self % DIM2 = Z_AXIS - - case('z') - self % DIM1 = X_AXIS - self % DIM2 = Y_AXIS - - case default - call fatalError(Here, 'Keyword orientation must be x, y or z. It is: '//type) - - end select - - ! Load radial grid information - if (.not. dict % isPresent('rGrid')) call fatalError(Here, 'Keyword rGrid must be present') - call dict % get(type, 'rGrid') - - ! Check type of radial grid bins - select case(type) - case('lin') - call dict % getOrDefault(Rmin, 'Rmin', ZERO) - call dict % get(Rmax, 'Rmax') - call dict % get(self % rN, 'rN') - - ! Check that minimum radius is OK - if (Rmin < ZERO) then - call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(Rmin)) - end if - - ! Build grid - call self % rBounds % init(Rmin, Rmax, self % rN, type) - - case('unstruct') - - call dict % get(grid,'bins') - - ! Initialise - self % rN = size(grid) - 1 - call self % rBounds % init(grid) - - case('equivolume') - - call dict % getOrDefault(Rmin, 'Rmin', ZERO) - call dict % get(Rmax, 'Rmax') - call dict % get(self % rN, 'rN') - - ! Check that minimum radius is OK - if (Rmin < ZERO) then - call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(Rmin)) - end if - - ! Calculate volume - vol = (Rmax**2 - Rmin**2) /self % rN - - allocate(grid(self % rN + 1)) - ! Calculate grid boundaries - grid(1) = Rmin - grid(self % rN + 1) = Rmax - do i = 2,self % rN - grid(i) = sqrt(vol + grid(i-1)**2) - end do - - call self % rBounds % init(grid) - - case default - call fatalError(Here, "'rGrid' can take only values of: lin, unstruct, equivolume") - - end select - - end subroutine init - - !! - !! Return total number of bins in this division along Dimension D - !! - !! See tallyMap for specification. - !! - elemental function bins(self, D) result(N) - class(cylindricalRadMap), intent(in) :: self - integer(shortInt), intent(in) :: D - integer(shortInt) :: N - - if (D == 1 .or. D == 0) then - N = self % rN - else - N = 0 - end if - - end function bins - - !! - !! Return string that describes variable used to divide event space - !! - !! See tallyMap for specification - !! - function getAxisName(self) result(name) - class(cylindricalRadMap), intent(in) :: self - character(nameLen) :: name - - name = 'cylindricalRadMap' - - end function getAxisName - - !! - !! Map particle to a single bin. Return 0 for particle out of division - !! - !! See tallyMap for specification. - !! - elemental function map(self, state) result(idx) - class(cylindricalRadMap), intent(in) :: self - class(particleState), intent(in) :: state - integer(shortInt) :: idx - real(defReal) :: r - - ! Calculate the distance from the origin - r = norm2(state % r([self % DIM1, self % DIM2]) - self % origin) - - ! Search and return 0 if r is out-of-bounds - idx = self % rBounds % search(r) - - if (idx == valueOutsideArray) then - idx = 0 - return - end if - - end function map - - !! - !! Add information about division axis to the output file - !! - !! See tallyMap for specification. - !! - subroutine print(self,out) - class(cylindricalRadMap), intent(in) :: self - class(outputFile), intent(inout) :: out - character(nameLen) :: name - integer(shortInt) :: i - - ! Name the array - name = trim(self % getAxisName()) //'RadialBounds' - - call out % startArray(name, [2,self % rN]) - do i = 1, self % rN - ! Print lower bin boundary - call out % addValue(self % rBounds % bin(i)) - - ! Print upper bin boundar - call out % addValue(self % rBounds % bin(i + 1)) - - end do - call out % endArray() - - end subroutine print - - !! - !! Return to uninitialised state - !! - elemental subroutine kill(self) - class(cylindricalRadMap), intent(inout) :: self - - call kill_super(self) - - self % origin = ZERO - call self % rBounds % kill() - self % rN = 0 - self % DIM1 = 0 - self % DIM2 = 0 - - end subroutine kill - -end module cylindricalRadMap_class diff --git a/Tallies/TallyMaps/Maps1D/directionMap_class.f90 b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 index 73172e383..c6d345b37 100644 --- a/Tallies/TallyMaps/Maps1D/directionMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 @@ -166,10 +166,10 @@ subroutine print(self,out) do i = 1, self % N ! Print lower bin boundary - call out % addValue(self % bounds % bin(i) + PI) + call out % addValue(self % bounds % bin(i)) ! Print upper bin boundar - call out % addValue(self % bounds % bin(i + 1) + PI) + call out % addValue(self % bounds % bin(i + 1)) end do call out % endArray() diff --git a/Tallies/TallyMaps/Maps1D/radialMap_class.f90 b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 new file mode 100644 index 000000000..710b6fd50 --- /dev/null +++ b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 @@ -0,0 +1,267 @@ +module radialMap_class + + use numPrecision + use universalVariables, only : valueOutsideArray, X_AXIS, Y_AXIS, Z_AXIS + use genericProcedures, only : fatalError, dotProduct, numToChar + use dictionary_class, only : dictionary + use grid_class, only : grid + use particle_class, only : particleState + use outputFile_class, only : outputFile + use tallyMap1D_inter, only : tallyMap1D, kill_super => kill + + implicit none + private + + !! + !! Divides space into a radial mesh in cylindrical or spherical co-ordinates + !! + !! Interface: + !! tallyMap1D interface + !! + !! NOTE: + !! Behaviour of points exactly at the boundary of bins is undefined. + !! particle can end-up in either of the two + !! + !! Sample Dictionary Input: + !! radialMap { + !! type radialMap; + !! axis x; // Optional. Default is spherical map + !! #origin (1.0 0.0 0.0);# // Optional. Default (0.0 0.0 0.0) + !! grid lin; + !! #min 2.0;# // Optional. Default 0.0 + !! max 10.0; + !! N 10; + !! } + !! + type, public, extends (tallyMap1D) :: radialMap + private + real(defReal), dimension(:), allocatable :: origin + integer(shortInt), dimension(:), allocatable :: axis + type(grid) :: bounds + integer(shortInt) :: N = 0 + + contains + ! Superclass + procedure :: init + procedure :: bins + procedure :: getAxisName + procedure :: map + procedure :: print + procedure :: kill + + end type radialMap + +contains + + !! + !! Initialise tallyMap from a dictionary + !! + !! See tallyMap for specification. + !! + subroutine init(self, dict) + class(radialMap), intent(inout) :: self + class(dictionary), intent(in) :: dict + real(defReal), dimension(:), allocatable :: grid + character(nameLen) :: type + real(defReal) :: min, max, vol, exp + integer(shortInt) :: i + logical(defBool) :: spherical + character(100), parameter :: Here = 'init (radialMap_class.f90)' + + ! Check if the map is cylindrical or spherical, and orientation of the cylinder + call dict % getOrDefault(type, 'axis', 'xyz') + spherical = .false. + + select case(type) + case('x') + allocate(self % axis(2), self % origin(2)) + self % axis = [Y_AXIS, Z_AXIS] + + case('y') + allocate(self % axis(2), self % origin(2)) + self % axis = [X_AXIS, Z_AXIS] + + case('z') + allocate(self % axis(2), self % origin(2)) + self % axis = [X_AXIS, Y_AXIS] + + case('xyz') + allocate(self % axis(3), self % origin(3)) + self % axis = [X_AXIS, Y_AXIS, Z_AXIS] + spherical = .true. + + case default + call fatalError(Here, 'Keyword orientation must be x, y, z or nothing for spherical. It is: '//type) + + end select + + ! Check & load origin + if (spherical) then + call dict % getOrDefault(self % origin, 'origin', [ZERO, ZERO, ZERO]) + else + call dict % getOrDefault(self % origin, 'origin', [ZERO, ZERO]) + end if + + ! Load radial grid information + if (.not. dict % isPresent('grid')) call fatalError(Here, 'Keyword grid must be present') + call dict % get(type, 'grid') + + ! Check type of radial grid bins + select case(type) + + case('lin') + + call dict % getOrDefault(min, 'min', ZERO) + call dict % get(max, 'max') + call dict % get(self % N, 'N') + + ! Check that minimum radius is ok + if (min < ZERO) then + call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(min)) + end if + + ! Build grid + call self % bounds % init(min, max, self % N, type) + + case('unstruct') + + call dict % get(grid,'bins') + + ! Initialise + self % N = size(grid) - 1 + call self % bounds % init(grid) + + case('equivolume') + + call dict % getOrDefault(min, 'min', ZERO) + call dict % get(max, 'max') + call dict % get(self % N, 'N') + + ! Check that minimum radius is OK + if (min < ZERO) then + call fatalError(Here, 'Minumum radius must be +ve. It is: '//numToChar(min)) + end if + + ! Get exponent for spherical or cylindrical mesh + if (spherical) then + exp = 3.0_defReal + else + exp = 2.0_defReal + end if + + ! Allocate grid and initialise grid boundaries + allocate(grid(self % N + 1)) + grid(1) = min + grid(self % N + 1) = max + + ! Calculate volume + vol = (max**exp - min**exp)/self % N + + ! Calculate grid boundaries + do i = 2,self % N + grid(i) = (vol + grid(i-1)**exp)**(ONE/exp) + end do + + call self % bounds % init(grid) + + case default + call fatalError(Here, "'grid' can take only values of: lin, unstruct, equivolume") + + end select + + end subroutine init + + !! + !! Return total number of bins in this division along dimension D + !! + !! See tallyMap for specification. + !! + elemental function bins(self, D) result(N) + class(radialMap), intent(in) :: self + integer(shortInt), intent(in) :: D + integer(shortInt) :: N + + if (D == 1 .or. D == 0) then + N = self % N + else + N = 0 + end if + + end function bins + + !! + !! Return string that describes variable used to divide event space + !! + !! See tallyMap for specification + !! + function getAxisName(self) result(name) + class(radialMap), intent(in) :: self + character(nameLen) :: name + + name = 'radialMap' + + end function getAxisName + + !! + !! Map particle to a single bin. Return 0 for particle out of division + !! + !! See tallyMap for specification. + !! + elemental function map(self, state) result(idx) + class(radialMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + real(defReal) :: r + + ! Calculate the distance from the origin + r = norm2(state % r(self % axis) - self % origin) + + ! Search and return 0 if r is out-of-bounds + idx = self % bounds % search(r) + if (idx == valueOutsideArray) idx = 0 + + end function map + + !! + !! Add information about division axis to the output file + !! + !! See tallyMap for specification. + !! + subroutine print(self,out) + class(radialMap), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen) :: name + integer(shortInt) :: i + + ! Name the array + name = trim(self % getAxisName()) //'RadialBounds' + + call out % startArray(name, [2,self % N]) + do i = 1, self % N + ! Print lower bin boundary + call out % addValue(self % bounds % bin(i)) + + ! Print upper bin boundar + call out % addValue(self % bounds % bin(i + 1)) + + end do + call out % endArray() + + end subroutine print + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(radialMap), intent(inout) :: self + + call kill_super(self) + + call self % bounds % kill() + self % origin = ZERO + self % axis = 0 + self % N = 0 + + end subroutine kill + +end module radialMap_class diff --git a/Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 b/Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 deleted file mode 100644 index 4781bf33a..000000000 --- a/Tallies/TallyMaps/Maps1D/sphericalRadMap_class.f90 +++ /dev/null @@ -1,226 +0,0 @@ -module sphericalRadMap_class - - use numPrecision - use universalVariables, only : valueOutsideArray - use genericProcedures, only : fatalError, dotProduct, numToChar - use dictionary_class, only : dictionary - use grid_class, only : grid - use particle_class, only : particleState - use outputFile_class, only : outputFile - use tallyMap1D_inter, only : tallyMap1D, kill_super => kill - - implicit none - private - - !! - !! Divides space into a mesh in spherical co-ordinates - !! - !! Interface: - !! tallyMap1D interface - !! - !! NOTE: - !! Behaviour of points exactly at the boundary of bins is undefined. - !! particle can end-up in either of the two - !! - !! Sample Dictionary Input: - !! sphericalRadMap { - !! type sphericalRadMap; - !! #origin (1.0 0.0 0.0);# // Optional. Default (0 0 0) - !! grid lin; - !! #Rmin 2.0;# // Optional. Default 0.0 - !! Rmax 10.0; - !! N 10; - !! } - !! - !! - type, public, extends (tallyMap1D) :: sphericalRadMap - private - real(defReal), dimension(3) :: origin = ZERO - type(grid) :: rBounds - integer(shortInt) :: N = 0 - - contains - ! Superclass - procedure :: init - procedure :: bins - procedure :: getAxisName - procedure :: map - procedure :: print - procedure :: kill - - end type sphericalRadMap - -contains - - !! - !! Initialise tallyMap from a dictionary - !! - !! See tallyMap for specification. - !! - subroutine init(self, dict) - class(sphericalRadMap), intent(inout) :: self - class(dictionary), intent(in) :: dict - real(defReal), dimension(:), allocatable :: temp, grid - character(nameLen) :: type - real(defReal) :: Rmin, Rmax, vol - integer(shortInt) :: i - character(100), parameter :: Here = 'init (sphericalRadMap_class.f90)' - - ! Check & load origin - call dict % getOrDefault(temp, 'origin', [ZERO, ZERO, ZERO]) - - if (size(temp) /= 3) then - call fatalError(Here, 'Expected 3 values for origin. Got: ' // numToChar(size(temp))) - end if - self % origin = temp - - ! Load grid information - if (.not.dict % isPresent('grid')) call fatalError(Here, 'Keyword grid must be present') - call dict % get(type, 'grid') - - select case(type) - case('lin') - call dict % getOrDefault(Rmin, 'Rmin', ZERO) - call dict % get(Rmax, 'Rmax') - call dict % get(self % N, 'N') - - ! Check that minimum radius is OK - if (Rmin < ZERO) then - call fatalError(Here, 'Minumum radius must be +ve is:'//numToChar(Rmin)) - end if - - ! Build grid - call self % rBounds % init(Rmin, Rmax, self % N, type) - - case('unstruct') - - call dict % get(grid,'bins') - - ! Initialise - self % N = size(grid) - 1 - call self % rBounds % init(grid) - - case('equivolume') - - call dict % getOrDefault(Rmin, 'Rmin', ZERO) - call dict % get(Rmax, 'Rmax') - call dict % get(self % N, 'N') - - ! Check that minimum radius is OK - if (Rmin < ZERO) then - call fatalError(Here, 'Minumum radius must be +ve is:'//numToChar(Rmin)) - end if - - ! Calculate volume - vol = (Rmax**3 - Rmin**3) /self % N - - allocate(grid(self % N + 1)) - ! Calculate grid boundaries - grid(1) = Rmin - grid(self % N + 1) = Rmax - do i = 2,self % N - grid(i) = (vol + grid(i-1)**3)**(ONE/3.0_defReal) - end do - - call self % rBounds % init(grid) - - case default - call fatalError(Here, "'grid' can take only values of: lin, unstruct and equivolume") - - end select - - end subroutine init - - !! - !! Return total number of bins in this division along Dimension D - !! - !! See tallyMap for specification. - !! - elemental function bins(self, D) result(N) - class(sphericalRadMap), intent(in) :: self - integer(shortInt), intent(in) :: D - integer(shortInt) :: N - - if (D == 1 .or. D == 0) then - N = self % N - else - N = 0 - end if - - end function bins - - !! - !! Return string that describes variable used to divide event space - !! - !! See tallyMap for specification - !! - function getAxisName(self) result(name) - class(sphericalRadMap), intent(in) :: self - character(nameLen) :: name - - name ='sphericalRadMap' - - end function getAxisName - - !! - !! Map particle to a single bin. Return 0 for particle out of division - !! - !! See tallyMap for specification. - !! - elemental function map(self, state) result(idx) - class(sphericalRadMap), intent(in) :: self - class(particleState), intent(in) :: state - integer(shortInt) :: idx - real(defReal) :: r - - ! Calculate the distance from the origin - r = norm2(state % r - self % origin) - - ! Search and return 0 if r is out-of-bounds - idx = self % rBounds % search(r) - if (idx == valueOutsideArray) idx = 0 - - end function map - - !! - !! Add information about division axis to the output file - !! - !! See tallyMap for specification. - !! - subroutine print(self,out) - class(sphericalRadMap), intent(in) :: self - class(outputFile), intent(inout) :: out - character(nameLen) :: name - integer(shortInt) :: i - - ! Name the array - name = trim(self % getAxisName()) //'Bounds' - - call out % startArray(name, [2,self % N]) - do i = 1, self % N - ! Print lower bin boundary - call out % addValue(self % rBounds % bin(i)) - - ! Print upper bin boundar - call out % addValue(self % rBounds % bin(i + 1)) - - end do - call out % endArray() - - end subroutine print - - !! - !! Return to uninitialised state - !! - elemental subroutine kill(self) - class(sphericalRadMap), intent(inout) :: self - - call kill_super(self) - - self % origin = ZERO - call self % rBounds % kill() - self % N = 0 - - end subroutine kill - -end module sphericalRadMap_class diff --git a/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 b/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 index fa67068cd..c64ae1209 100644 --- a/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 +++ b/Tallies/TallyMaps/Maps1D/tallyMap1DFactory_func.f90 @@ -25,16 +25,16 @@ module tallyMap1DFactory_func use tallyMap1D_inter, only : tallyMap1D ! TallyMap implementations - use energyMap_class, only : energyMap - use spaceMap_class, only : spaceMap - use materialMap_class, only : materialMap - use homogMatMap_class, only : homogMatMap - use weightMap_class, only : weightMap - use cellMap_class, only : cellMap - use testMap_class, only : testMap - use collNumMap_class, only : collNumMap - use sphericalRadMap_class, only : sphericalRadMap - use directionMap_class, only : directionMap + use energyMap_class, only : energyMap + use spaceMap_class, only : spaceMap + use materialMap_class, only : materialMap + use homogMatMap_class, only : homogMatMap + use weightMap_class, only : weightMap + use cellMap_class, only : cellMap + use testMap_class, only : testMap + use collNumMap_class, only : collNumMap + use radialMap_class, only : radialMap + use directionMap_class, only : directionMap implicit none private @@ -46,16 +46,16 @@ module tallyMap1DFactory_func ! It is printed if type was unrecognised ! NOTE: ! For now it is necessary to adjust trailing blanks so all enteries have the same length - character(nameLen),dimension(*),parameter, public :: AVALIBLE_tallyMaps1D = [ 'energyMap ',& - 'spaceMap ',& - 'materialMap ',& - 'homogMatMap ',& - 'weightMap ',& - 'cellMap ',& - 'collNumMap ',& - 'sphericalRadMap',& - 'directionMap ',& - 'testMap '] + character(nameLen),dimension(*),parameter, public :: AVALIBLE_tallyMaps1D = [ 'energyMap ',& + 'spaceMap ',& + 'materialMap ',& + 'homogMatMap ',& + 'weightMap ',& + 'cellMap ',& + 'collNumMap ',& + 'radialMap ',& + 'directionMap',& + 'testMap '] contains @@ -106,8 +106,8 @@ subroutine new_tallyMap1D(new, dict) case('collNumMap') allocate(collNumMap :: new) - case('sphericalRadMap') - allocate(sphericalRadMap :: new) + case('radialMap') + allocate(radialMap :: new) case('directionMap') allocate(directionMap :: new) diff --git a/Tallies/TallyMaps/cylindricalMap_class.f90 b/Tallies/TallyMaps/cylindricalMap_class.f90 index 0a6eb7352..f55d1e33f 100644 --- a/Tallies/TallyMaps/cylindricalMap_class.f90 +++ b/Tallies/TallyMaps/cylindricalMap_class.f90 @@ -376,10 +376,10 @@ subroutine print(self,out) call out % startArray(name, [2,self % azN]) do i = 1, self % azN ! Print lower bin boundary - call out % addValue(self % azBounds % bin(i) + PI) + call out % addValue(self % azBounds % bin(i)) ! Print upper bin boundar - call out % addValue(self % azBounds % bin(i + 1) + PI) + call out % addValue(self % azBounds % bin(i + 1)) end do call out % endArray() From 6989dfb62e2ac226df3c5387d2beac70e6bae966 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Sun, 5 May 2024 17:21:40 +0100 Subject: [PATCH 115/133] Updating the directionMap to degrees, and updating the docs --- .../Maps1D/Tests/directionMap_test.f90 | 26 +++-- .../TallyMaps/Maps1D/Tests/radialMap_test.f90 | 4 +- .../TallyMaps/Maps1D/directionMap_class.f90 | 56 +++++++--- Tallies/TallyMaps/Maps1D/radialMap_class.f90 | 24 ++-- .../TallyMaps/Tests/cylindricalMap_test.f90 | 4 +- Tallies/TallyMaps/cylindricalMap_class.f90 | 20 ++-- docs/User Manual.rst | 104 ++++++++++-------- 7 files changed, 143 insertions(+), 95 deletions(-) diff --git a/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 index ff5c3e508..f09c43e9d 100644 --- a/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 +++ b/Tallies/TallyMaps/Maps1D/Tests/directionMap_test.f90 @@ -40,8 +40,10 @@ subroutine setUp(this) call tempDict % kill() ! Build map with default plane - call tempDict % init(1) - call tempDict % store('N', 8) + call tempDict % init(3) + call tempDict % store('N', 9) + call tempDict % store('min', 90) + call tempDict % store('max', 180) call this % map2 % init(tempDict) call tempDict % kill() @@ -70,8 +72,8 @@ end subroutine tearDown subroutine testMap1(this) class(test_directionMap), intent(inout) :: this real(defReal),dimension(4),parameter :: x = [0.44_defReal, 15.8_defReal, 83.2_defReal, 999.1_defReal] - real(defReal),dimension(4),parameter :: phi = [-0.1_defReal, 0.84_defReal, 0.33_defReal, 0.64_defReal]*PI - integer(shortInt),dimension(4),parameter :: RES_IDX = [2, 4, 3, 4] + real(defReal),dimension(4),parameter :: phi = [100.1_defReal, 20.84_defReal, 333.9_defReal, 264.8_defReal]*PI/180.0_defReal + integer(shortInt),dimension(4),parameter :: RES_IDX = [4, 3, 2, 1] integer(shortInt),dimension(4) :: idx type(particleState),dimension(4) :: states @@ -92,19 +94,19 @@ end subroutine testMap1 @Test subroutine testMap2(this) class(test_directionMap), intent(inout) :: this - real(defReal),dimension(4),parameter :: x = [0.9999_defReal, 0.87_defReal, -0.3_defReal, 0.18_defReal] - real(defReal),dimension(4),parameter :: y = [0.45_defReal, 0.88_defReal, 0.51_defReal, -0.92_defReal] - real(defReal),dimension(4),parameter :: z = [1.0_defReal, 39.8_defReal, 0.05_defReal, -12.2_defReal] - integer(shortInt),dimension(4),parameter :: RES_IDX = [5, 6, 7, 3] + real(defReal),dimension(4),parameter :: z = [0.44_defReal, 15.8_defReal, 83.2_defReal, 999.1_defReal] + real(defReal),dimension(4),parameter :: phi = [170.1_defReal, 90.84_defReal, 133.9_defReal, 264.8_defReal]*PI/180.0_defReal + integer(shortInt),dimension(4),parameter :: RES_IDX = [9, 1, 5, 0] integer(shortInt),dimension(4) :: idx type(particleState),dimension(4) :: states ! Initialise states - states(:) % dir(1) = x - states(:) % dir(2) = y + states(:) % dir(1) = cos(phi) + states(:) % dir(2) = sin(phi) states(:) % dir(3) = z idx = this % map2 % map(states) + @assertEqual(RES_IDX, idx) end subroutine testMap2 @@ -120,7 +122,7 @@ subroutine testBinNumber(this) @assertEqual(4, this % map1 % bins(0),'All bins') @assertEqual(4, this % map1 % bins(1),'1st dimension') @assertEqual(0, this % map2 % bins(2),'2nd dimension') - @assertEqual(8, this % map2 % bins(1),'1st dimension') + @assertEqual(9, this % map2 % bins(1),'1st dimension') ! Get dimensionality @assertEqual(1, this % map1 % dimensions()) @@ -130,7 +132,7 @@ end subroutine testBinNumber !! !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequence is without errors + !! Does not check that values are correct, but that call sequence is without errors !! @Test subroutine testPrint(this) diff --git a/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 b/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 index eea303f19..dedd16637 100644 --- a/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 +++ b/Tallies/TallyMaps/Maps1D/Tests/radialMap_test.f90 @@ -59,7 +59,7 @@ subroutine setUp(this) ! Build cylindrical map with different origin & unstruct bins call tempDict % init(4) call tempDict % store('axis','z') - call tempDict % store('origin',[ONE, ONE]) + call tempDict % store('origin',[ONE, ONE, ZERO]) call tempDict % store('grid','unstruct') call tempDict % store('bins', [1.5_defReal, 2.3_defReal, 3.8_defReal, 8.0_defReal]) @@ -292,7 +292,7 @@ end subroutine testBinNumber !! !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequence is without errors + !! Does not check that values are correct, but that call sequence is without errors !! @Test subroutine testPrint(this) diff --git a/Tallies/TallyMaps/Maps1D/directionMap_class.f90 b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 index c6d345b37..a1ce82ed9 100644 --- a/Tallies/TallyMaps/Maps1D/directionMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/directionMap_class.f90 @@ -13,20 +13,29 @@ module directionMap_class private !! - !! Maps the particle direction in linear bins in the range 0-360 degrees + !! Maps the particle direction in linear bins in the range -180 -> 180 degrees (default) + !! or boundaries defined by the user + !! + !! The angle is calculated using as a reference the positive direction of the + !! axis x in the 'xy' and 'xz' cases, or y in the 'yz' case + !! + !! NOTE: the map is built in radians for convenience when using the function atan2, but + !! the user input and the results are in degrees for easy of interpretation !! !! Interface: !! tallyMap1D interface !! !! NOTE: !! Behaviour of points exactly at the boundary of bins is undefined. - !! particle can end-up in either of the two + !! Particle can end-up in either of the two !! !! Sample Dictionary Input: !! directionMap { !! type directionMap; - !! #plane xz;# // Optional. Default xy + !! #plane xz;# // Optional. Default xy !! N 10; + !! #min 60;# // Optional. Default -180 + !! #max 120;# // Optional. Default 180 !! } !! type, public, extends (tallyMap1D) :: directionMap @@ -55,9 +64,10 @@ module directionMap_class !! See tallyMap for specification. !! subroutine init(self, dict) - class(directionMap), intent(inout) :: self - class(dictionary), intent(in) :: dict - character(nameLen) :: type + class(directionMap), intent(inout) :: self + class(dictionary), intent(in) :: dict + character(nameLen) :: type + real(defReal) :: min, max character(100), parameter :: Here = 'init (directionMap_class.f90)' ! Check orientation of the cylinder @@ -81,13 +91,28 @@ subroutine init(self, dict) self % DIM2 = Y_AXIS case default - call fatalError(Here, 'Keyword orientation must be x, y or z. It is: '//type) + call fatalError(Here, 'Keyword orientation must be xy, yz or xz. It is: '//type) end select - ! Build grid + ! Get grid details call dict % get(self % N, 'N') - call self % bounds % init(-PI, PI, self % N, 'lin') + call dict % getOrDefault(min, 'min', -180.0_defReal) + call dict % getOrDefault(max, 'max', 180.0_defReal) + + ! Check boundaries + if (min < -180.0_defReal .or. min > 180.0_defReal) then + call fatalError(Here, 'Minimum angle must be between -180 and 180 degrees. It is: '//type) + end if + + if (max < -180.0_defReal .or. max > 180.0_defReal) then + call fatalError(Here, 'Maximum angle must be between -180 and 180 degrees. It is: '//type) + end if + + ! Build map in radians + min = min*PI/180.0_defReal + max = max*PI/180.0_defReal + call self % bounds % init(min, max, self % N, 'lin') end subroutine init @@ -133,11 +158,14 @@ elemental function map(self, state) result(idx) integer(shortInt) :: idx real(defReal) :: x, y, theta + ! Map the angle x = state % dir(self % DIM1) y = state % dir(self % DIM2) + ! Returns angle in radians in the range -PI to PI theta = atan2(y,x) - ! Search along the azimuthal dimension and return 0 if index is out-of-bounds + + ! Search in the grid return 0 if index is out-of-bounds idx = self % bounds % search(theta) ! Should never happen @@ -165,11 +193,11 @@ subroutine print(self,out) call out % startArray(name, [2,self % N]) do i = 1, self % N - ! Print lower bin boundary - call out % addValue(self % bounds % bin(i)) + ! Print lower bin boundary in degrees + call out % addValue(self % bounds % bin(i)/PI*180.0_defReal) - ! Print upper bin boundar - call out % addValue(self % bounds % bin(i + 1)) + ! Print upper bin boundary in degrees + call out % addValue(self % bounds % bin(i + 1)/PI*180.0_defReal) end do call out % endArray() diff --git a/Tallies/TallyMaps/Maps1D/radialMap_class.f90 b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 index 710b6fd50..52aa5f122 100644 --- a/Tallies/TallyMaps/Maps1D/radialMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 @@ -25,7 +25,7 @@ module radialMap_class !! Sample Dictionary Input: !! radialMap { !! type radialMap; - !! axis x; // Optional. Default is spherical map + !! axis x; // Optional. Default is 'xyz' (spherical map) !! #origin (1.0 0.0 0.0);# // Optional. Default (0.0 0.0 0.0) !! grid lin; !! #min 2.0;# // Optional. Default 0.0 @@ -61,7 +61,7 @@ module radialMap_class subroutine init(self, dict) class(radialMap), intent(inout) :: self class(dictionary), intent(in) :: dict - real(defReal), dimension(:), allocatable :: grid + real(defReal), dimension(:), allocatable :: temp, grid character(nameLen) :: type real(defReal) :: min, max, vol, exp integer(shortInt) :: i @@ -91,17 +91,19 @@ subroutine init(self, dict) spherical = .true. case default - call fatalError(Here, 'Keyword orientation must be x, y, z or nothing for spherical. It is: '//type) + call fatalError(Here, 'Keyword orientation must be x, y, z or xyz for spherical. It is: '//type) end select ! Check & load origin - if (spherical) then - call dict % getOrDefault(self % origin, 'origin', [ZERO, ZERO, ZERO]) - else - call dict % getOrDefault(self % origin, 'origin', [ZERO, ZERO]) + call dict % getOrDefault(temp, 'origin', [ZERO, ZERO, ZERO]) + + if (size(temp) /= 3) then + call fatalError(Here, 'Expected 3 values for origin. Got: ' // numToChar(size(temp))) end if + self % origin = temp(self % axis) + ! Load radial grid information if (.not. dict % isPresent('grid')) call fatalError(Here, 'Keyword grid must be present') call dict % get(type, 'grid') @@ -208,10 +210,10 @@ end function getAxisName !! See tallyMap for specification. !! elemental function map(self, state) result(idx) - class(radialMap), intent(in) :: self - class(particleState), intent(in) :: state - integer(shortInt) :: idx - real(defReal) :: r + class(radialMap), intent(in) :: self + class(particleState), intent(in) :: state + integer(shortInt) :: idx + real(defReal) :: r ! Calculate the distance from the origin r = norm2(state % r(self % axis) - self % origin) diff --git a/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 b/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 index 71aafb283..d73ec4dd4 100644 --- a/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 +++ b/Tallies/TallyMaps/Tests/cylindricalMap_test.f90 @@ -44,7 +44,7 @@ subroutine setUp(this) ! Build map with different origin & unstruct bins call tempDict % init(3) - call tempDict % store('origin',[ONE, ONE]) + call tempDict % store('origin',[ONE, ONE, TWO]) call tempDict % store('rGrid','unstruct') call tempDict % store('bins', [1.5_defReal, 2.3_defReal, 3.8_defReal, 8.0_defReal]) @@ -179,7 +179,7 @@ end subroutine testBinNumber !! !! Test correctness of print subroutine - !! Does not checks that values are correct, but that calls sequence is without errors + !! Does not check that values are correct, but that call sequence is without errors !! @Test subroutine testPrint(this) diff --git a/Tallies/TallyMaps/cylindricalMap_class.f90 b/Tallies/TallyMaps/cylindricalMap_class.f90 index f55d1e33f..7d326b64d 100644 --- a/Tallies/TallyMaps/cylindricalMap_class.f90 +++ b/Tallies/TallyMaps/cylindricalMap_class.f90 @@ -27,7 +27,7 @@ module cylindricalMap_class !! cylindricalMap { !! type cylindricalMap; !! #orientation x;# // Optional. Defeult z - !! #origin (1.0 0.0);# // Optional. Default (0 0). Order is xy, xz or yz. + !! #origin (1.0 0.0 0.0);# // Optional. Default (0 0 0) !! rGrid lin; !! #Rmin 2.0;# // Optional. Default 0.0 !! Rmax 10.0; @@ -66,6 +66,7 @@ module cylindricalMap_class procedure :: map procedure :: print procedure :: kill + end type cylindricalMap contains @@ -84,14 +85,6 @@ subroutine init(self, dict) integer(shortInt) :: i character(100), parameter :: Here = 'init (cylindricalMap_class.f90)' - ! Check & load origin - call dict % getOrDefault(temp, 'origin', [ZERO, ZERO]) - - if (size(temp) /= 2) then - call fatalError(Here, 'Expected 2 values for origin. Got: ' // numToChar(size(temp))) - end if - self % origin = temp - ! Check orientation of the cylinder if (dict % isPresent('orientation')) then call dict % get(type, 'orientation') @@ -120,6 +113,15 @@ subroutine init(self, dict) end select + ! Check & load origin + call dict % getOrDefault(temp, 'origin', [ZERO, ZERO, ZERO]) + + if (size(temp) /= 3) then + call fatalError(Here, 'Expected 3 values for origin. Got: ' // numToChar(size(temp))) + end if + + self % origin = temp([self % DIM1, self % DIM2]) + ! Load radial grid information if (.not. dict % isPresent('rGrid')) call fatalError(Here, 'Keyword rGrid must be present') call dict % get(type, 'rGrid') diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ac7575ed0..fba5d5a6f 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1123,6 +1123,27 @@ Example: :: map { type cellMap; cells (1 5 3 2 4 100); undefBin T; } +* collNumMap (1D map), filters the particles tallied over number of collisions they underwent + + - collNumbers: list of collision numbers (integers) to be used as map bins + +Examples: :: + + map1 { type collNumMap; collNumbers ( 0 1 2 3 4 5 10 20); } + +* directionMap (1D map), angular map for the particle's direction with a linear grid + + - axis (*optional*, default = ``xy``): ``xy``, ``yz``, ``xz`` define the plane + of the direction to map + - N: number of bins + - min (*optional*, default = -180): grid lower limit [degrees] + - max (*optional*, default = 180): grid upper limit [degrees] + +Examples: :: + + map1 { type directionMap; axis xz; min 0.0; max 90.0; N 6; } + map2 { type directionMap; N 36; } + * energyMap (1D map), defines an energy group structure - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins @@ -1177,23 +1198,33 @@ Example: :: map { type materialMap; materials (fuel water cladding reflector fuelGd); undefBin T; } -* multiMap, ensemble of multiple 1D maps +* radialMap, spherical or cylindrical radial map - - maps: list of the names of the maps that will compose the ``multiMap``. This - is followed by dictionaries that define the requested maps + - axis (*optional*, default = ``xyz``): ``x``, ``y``, ``z``, is the normal of + the cylindrical plane, or ``xyz`` to indicate spherical coordinates + - origin (*optional*, default = (0.0 0.0 0.0)): (x y z) vector with the origin + of the radial map. If the map is cylindrical, only the two coordinates perpendicular + to the cylinder's normal matter + - grid: ``lin`` for linearly spaced bins or ``equivolume`` -Example: :: + + min (*optional*, default = 0.0): minimum radius [cm] + + max: maximum radius [cm] + + N: number of radial bins - map { type multiMap; maps (map1 map2 map10); - map1 { <1D map definition> } - map2 { <1D map definition> } - map10 { <1D map definition> } - } + - grid: ``unstruct`` for unstructured grids, to be manually defined + + + bins: array with the explicit definition of the spherical bin boundaries + to be used + +Examples: :: + + map1 { type radialMap; axis xyz; origin (2.0 1.0 0.0); grid lin; min 3.0; max 10.0; N 14; } + map2 { type radialMap; axis z; grid equivolume; max 20.0; N 10; } + map3 { type radialMap; grid unstruct; bins (1.0 2.0 2.5 3.0 5.0); } * spaceMap (1D map), geometric cartesian map - axis: ``x``, ``y`` or ``z`` - - grid: ``lin`` for linearly spaced bins + min: bottom coordinate [cm] @@ -1209,27 +1240,23 @@ Examples: :: map1 { type spaceMap; axis x; grid lin; min -50.0; max 50.0; N 100; } map2 { type spaceMap; axis z; grid unstruct; bins (0.0 0.2 0.3 0.5 0.7 0.8 1.0); } -* sphericalMap, geometric spherical map - - - origin (*optional*, default = (0.0 0.0 .0.)): (x y z) vector with the origin - of the spherical map +* weightMap (1D map), divides weight into number of discrete bins - - grid: ``lin`` for linearly spaced bins or ``equivolume`` for spherical shells + - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins - + Rmin (*optional*, default = 0.0): minimum radius [cm] - + Rmax: maximum radius [cm] - + N: number of radial bins + + min: bottom weight + + max: top weight + + N: number of bins - grid: ``unstruct`` for unstructured grids, to be manually defined - + bins: array with the explicit definition of the spherical bin boundaries - to be used + + bins: array with the explicit definition of the weight bin boundaries to be used Examples: :: - map1 { type sphericalMap; origin (2.0 1.0 0.0); grid lin; Rmin 3.0; Rmax 10.0; N 14; } - map2 { type sphericalMap; grid equivolume; Rmax 20.0; N 10; } - map3 { type sphericalMap; grid unstruct; bins (1.0 2.0 2.5 3.0 5.0); } + map1 { type weightMap; grid log; min 1.0e-3; max 100.0; N 100; } + map2 { type weightMap; grid lin; min 0.1; max 2.0; N 20; } + map3 { type weightMap; bins (0.0 0.2 0.4 0.6 0.8 1.0 2.0 5.0 10.0); } * cylindricalMap, geometric cylindrical map; other than the radial discretisation, one could add axial and azimuthal discretisation @@ -1261,31 +1288,18 @@ Example: :: map1 { type cylindricalMap; orientation y; origin (7.0 0.0); rGrid lin; Rmax 5.0; rN 10; } map2 { type cylindricalMap; rGrid unstruct; bins (2.0 3.0 4.5 5.0); axGrid lin; axMin 0.0; axMax 6.0 axN 24; azimuthalN 8; } -* collNumMap (1D map), filters the particles tallied over number of collisions they underwent - - - collNumbers: list of collision numbers (integers) to be used as map bins - -Examples: :: - - map1 { type collNumMap; collNumbers ( 0 1 2 3 4 5 10 20); } - -* weightMap (1D map), divides weight into number of discrete bins - - - grid: ``log`` for logarithmically spaced bins or ``lin`` for linearly spaced bins - - + min: bottom weight - + max: top weight - + N: number of bins - - - grid: ``unstruct`` for unstructured grids, to be manually defined +* multiMap, ensemble of multiple 1D maps - + bins: array with the explicit definition of the weight bin boundaries to be used + - maps: list of the names of the maps that will compose the ``multiMap``. This + is followed by dictionaries that define the requested maps -Examples: :: +Example: :: - map1 { type weightMap; grid log; min 1.0e-3; max 100.0; N 100; } - map2 { type weightMap; grid lin; min 0.1; max 2.0; N 20; } - map3 { type weightMap; bins (0.0 0.2 0.4 0.6 0.8 1.0 2.0 5.0 10.0); } + map { type multiMap; maps (map1 map2 map10); + map1 { <1D map definition> } + map2 { <1D map definition> } + map10 { <1D map definition> } + } Tally Filters ############# From 64a09b918cfbec6e6300c6fd957e0bf06145746f Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Sun, 5 May 2024 17:29:22 +0100 Subject: [PATCH 116/133] Making the origin 3D in all cases --- Tallies/TallyMaps/Maps1D/radialMap_class.f90 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Tallies/TallyMaps/Maps1D/radialMap_class.f90 b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 index 52aa5f122..5477f67bb 100644 --- a/Tallies/TallyMaps/Maps1D/radialMap_class.f90 +++ b/Tallies/TallyMaps/Maps1D/radialMap_class.f90 @@ -35,10 +35,10 @@ module radialMap_class !! type, public, extends (tallyMap1D) :: radialMap private - real(defReal), dimension(:), allocatable :: origin integer(shortInt), dimension(:), allocatable :: axis - type(grid) :: bounds - integer(shortInt) :: N = 0 + real(defReal), dimension(3) :: origin + type(grid) :: bounds + integer(shortInt) :: N = 0 contains ! Superclass @@ -74,19 +74,19 @@ subroutine init(self, dict) select case(type) case('x') - allocate(self % axis(2), self % origin(2)) + allocate(self % axis(2)) self % axis = [Y_AXIS, Z_AXIS] case('y') - allocate(self % axis(2), self % origin(2)) + allocate(self % axis(2)) self % axis = [X_AXIS, Z_AXIS] case('z') - allocate(self % axis(2), self % origin(2)) + allocate(self % axis(2)) self % axis = [X_AXIS, Y_AXIS] case('xyz') - allocate(self % axis(3), self % origin(3)) + allocate(self % axis(3)) self % axis = [X_AXIS, Y_AXIS, Z_AXIS] spherical = .true. @@ -102,7 +102,7 @@ subroutine init(self, dict) call fatalError(Here, 'Expected 3 values for origin. Got: ' // numToChar(size(temp))) end if - self % origin = temp(self % axis) + self % origin = temp ! Load radial grid information if (.not. dict % isPresent('grid')) call fatalError(Here, 'Keyword grid must be present') @@ -216,7 +216,7 @@ elemental function map(self, state) result(idx) real(defReal) :: r ! Calculate the distance from the origin - r = norm2(state % r(self % axis) - self % origin) + r = norm2(state % r(self % axis) - self % origin(self % axis)) ! Search and return 0 if r is out-of-bounds idx = self % bounds % search(r) From b7429b34e630edf28d416039d06e81fedd49157e Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 9 May 2024 14:45:18 +0100 Subject: [PATCH 117/133] Adding particle density response --- SharedModules/universalVariables.f90 | 2 +- Tallies/TallyResponses/CMakeLists.txt | 4 +- .../Tests/densityResponse_test.f90 | 66 +++++++++++++++++ .../Tests/fluxResponse_test.f90 | 2 +- .../TallyResponses/densityResponse_class.f90 | 74 +++++++++++++++++++ .../tallyResponseFactory_func.f90 | 13 +++- 6 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 Tallies/TallyResponses/Tests/densityResponse_test.f90 create mode 100644 Tallies/TallyResponses/densityResponse_class.f90 diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index 81250f3f5..08a2a76ac 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -75,7 +75,7 @@ module universalVariables TRACKING_XS = 3 ! Physical constants - real(defReal), parameter :: neutronMass = 939.5654133_defReal, & ! Neutron mass in MeV/c^2 + real(defReal), parameter :: neutronMass = 939.5654133_defReal, & ! Neutron mass in MeV (m*c^2) lightSpeed = 2.99792458e10_defReal, & ! Light speed in cm/s energyPerFission = 200.0_defReal ! MeV diff --git a/Tallies/TallyResponses/CMakeLists.txt b/Tallies/TallyResponses/CMakeLists.txt index 67985b802..438502ab1 100644 --- a/Tallies/TallyResponses/CMakeLists.txt +++ b/Tallies/TallyResponses/CMakeLists.txt @@ -6,6 +6,7 @@ add_sources(./tallyResponse_inter.f90 ./macroResponse_class.f90 ./microResponse_class.f90 ./weightResponse_class.f90 + ./densityResponse_class.f90 ./testResponse_class.f90 ) @@ -15,4 +16,5 @@ add_unit_tests(./Tests/fluxResponse_test.f90 ./Tests/macroResponse_test.f90 ./Tests/microResponse_test.f90 ./Tests/weightResponse_test.f90 - ) \ No newline at end of file + ./Tests/densityResponse_test.f90 + ) \ No newline at end of file diff --git a/Tallies/TallyResponses/Tests/densityResponse_test.f90 b/Tallies/TallyResponses/Tests/densityResponse_test.f90 new file mode 100644 index 000000000..8e39cc2d6 --- /dev/null +++ b/Tallies/TallyResponses/Tests/densityResponse_test.f90 @@ -0,0 +1,66 @@ +module densityResponse_test + + use numPrecision + use densityResponse_class, only : densityResponse + use particle_class, only : particle + use dictionary_class, only : dictionary + use nuclearDatabase_inter, only : nuclearDatabase + use pFUnit_mod + + implicit none + +@testCase + type, extends(TestCase) :: test_densityResponse + private + type(densityResponse) :: response + contains + procedure :: setUp + procedure :: tearDown + end type test_densityResponse + + +contains + + !! + !! Sets up test_densityResponse object we can use in a number of tests + !! + subroutine setUp(this) + class(test_densityResponse), intent(inout) :: this + type(dictionary) :: tempDict + + end subroutine setUp + + !! + !! Kills test_densityResponse object we can use in a number of tests + !! + subroutine tearDown(this) + class(test_densityResponse), intent(inout) :: this + + end subroutine tearDown + +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +!! PROPER TESTS BEGIN HERE +!!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> + + !! + !! Test correct behaviour of the response + !! +@Test + subroutine densityResponseing(this) + class(test_densityResponse), intent(inout) :: this + type(particle) :: p + class(nuclearDatabase),pointer :: xsData + real(defReal) :: res + + ! Test with different particle energies + p % E = ONE + res = 1.3831592645e+09_defReal + @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) + + p % E = 1.6e-06_defReal + res = 1.7495734571e+06_defReal + @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) + + end subroutine densityResponseing + +end module densityResponse_test diff --git a/Tallies/TallyResponses/Tests/fluxResponse_test.f90 b/Tallies/TallyResponses/Tests/fluxResponse_test.f90 index 7c6a61636..2f1533a73 100644 --- a/Tallies/TallyResponses/Tests/fluxResponse_test.f90 +++ b/Tallies/TallyResponses/Tests/fluxResponse_test.f90 @@ -43,7 +43,7 @@ end subroutine tearDown !!<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! - !! Test correct behaviour of the filter + !! Test correct behaviour of the response !! @Test subroutine fluxResponseing(this) diff --git a/Tallies/TallyResponses/densityResponse_class.f90 b/Tallies/TallyResponses/densityResponse_class.f90 new file mode 100644 index 000000000..b92138fa9 --- /dev/null +++ b/Tallies/TallyResponses/densityResponse_class.f90 @@ -0,0 +1,74 @@ +module densityResponse_class + + use numPrecision + use universalVariables, only : neutronMass, lightSpeed + use dictionary_class, only : dictionary + use particle_class, only : particle + use tallyResponse_inter, only : tallyResponse + + ! Nuclear Data interface + use nuclearDatabase_inter, only : nuclearDatabase + + implicit none + private + + !! + !! tallyResponse to score particle density contribution + !! + !! Returns the velocity of the particle, calculated from its energy + !! + !! Interface: + !! tallyResponse Interface + !! + type, public,extends(tallyResponse) :: densityResponse + private + contains + procedure :: init + procedure :: get + procedure :: kill + end type densityResponse + +contains + + !! + !! Initialise Response from dictionary + !! + !! See tallyResponse_inter for details + !! + subroutine init(self, dict) + class(densityResponse), intent(inout) :: self + class(dictionary), intent(in) :: dict + + ! Do nothing + + end subroutine init + + !! + !! Get the particle velocity (Response to score particle density) + !! + !! See tallyResponse_inter for details + !! + function get(self, p, xsData) result(val) + class(densityResponse), intent(in) :: self + class(particle), intent(in) :: p + class(nuclearDatabase), intent(inout) :: xsData + real(defReal) :: val + + ! Calculate the velocity in [cm/s] + ! neutronMass: [MeV/c^2] + ! lightSpeed: [cm/s] + val = sqrt(TWO * p % E / neutronMass) * lightSpeed + + end function get + + !! + !! Return to uninitialised State + !! + elemental subroutine kill(self) + class(densityResponse), intent(inout) :: self + + ! Do nothing for nothing can be done + + end subroutine kill + +end module densityResponse_class diff --git a/Tallies/TallyResponses/tallyResponseFactory_func.f90 b/Tallies/TallyResponses/tallyResponseFactory_func.f90 index 117b4c29b..1168fee88 100644 --- a/Tallies/TallyResponses/tallyResponseFactory_func.f90 +++ b/Tallies/TallyResponses/tallyResponseFactory_func.f90 @@ -12,6 +12,7 @@ module tallyResponseFactory_func use macroResponse_class, only : macroResponse use microResponse_class, only : microResponse use weightResponse_class, only : weightResponse + use densityResponse_class, only : densityResponse use testResponse_class, only : testResponse implicit none @@ -23,10 +24,11 @@ module tallyResponseFactory_func ! It is printed if type was unrecognised ! NOTE: ! For now it is necessary to adjust trailing blanks so all enteries have the same length - character(nameLen),dimension(*),parameter :: AVALIBLE_tallyResponses = ['fluxResponse ',& - 'macroResponse ',& - 'microResponse ',& - 'weightResponse'] + character(nameLen),dimension(*),parameter :: AVALIBLE_tallyResponses = ['fluxResponse ',& + 'macroResponse ',& + 'microResponse ',& + 'weightResponse ',& + 'densityResponse'] contains @@ -61,6 +63,9 @@ subroutine new_tallyResponse(new,dict) case('weightResponse') allocate(weightResponse :: new) + case('densityResponse') + allocate(densityResponse :: new) + case('testResponse') allocate(testResponse :: new) From 14f9f3f896bfa83f1f6b12b438a515c4bdcbf93e Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 9 May 2024 14:49:43 +0100 Subject: [PATCH 118/133] Updating the docs --- Tallies/TallyResponses/densityResponse_class.f90 | 4 ++-- docs/User Manual.rst | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Tallies/TallyResponses/densityResponse_class.f90 b/Tallies/TallyResponses/densityResponse_class.f90 index b92138fa9..23d1528c7 100644 --- a/Tallies/TallyResponses/densityResponse_class.f90 +++ b/Tallies/TallyResponses/densityResponse_class.f90 @@ -15,7 +15,7 @@ module densityResponse_class !! !! tallyResponse to score particle density contribution !! - !! Returns the velocity of the particle, calculated from its energy + !! Returns the velocity of the particle in [cm/s], calculated from its energy !! !! Interface: !! tallyResponse Interface @@ -55,7 +55,7 @@ function get(self, p, xsData) result(val) real(defReal) :: val ! Calculate the velocity in [cm/s] - ! neutronMass: [MeV/c^2] + ! neutronMass: [MeV] ! lightSpeed: [cm/s] val = sqrt(TWO * p % E / neutronMass) * lightSpeed diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ac7575ed0..5433e74e2 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1058,6 +1058,15 @@ Example: :: collision_estimator { type collisionClerk; response (flux); flux { type fluxResponse; } } } +* densityResponse: used to calculate the particle desnsity, i.e., the response function is + the particle velocity in [cm/s] + +Example: :: + + tally { + collision_estimator { type collisionClerk; response (dens); dens { type densityResponse; } } + } + * macroResponse: used to score macroscopic reaction rates - MT: MT number of the desired reaction. The options are: -1 total, -2 capture, From 374913fee33a0f53dd9ab4a5c237ee3bfc104bcb Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 9 May 2024 14:55:14 +0100 Subject: [PATCH 119/133] Returns inverse of velocity --- Tallies/TallyResponses/Tests/densityResponse_test.f90 | 4 ++-- Tallies/TallyResponses/densityResponse_class.f90 | 8 +++++--- docs/User Manual.rst | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Tallies/TallyResponses/Tests/densityResponse_test.f90 b/Tallies/TallyResponses/Tests/densityResponse_test.f90 index 8e39cc2d6..d9a8301a6 100644 --- a/Tallies/TallyResponses/Tests/densityResponse_test.f90 +++ b/Tallies/TallyResponses/Tests/densityResponse_test.f90 @@ -54,11 +54,11 @@ subroutine densityResponseing(this) ! Test with different particle energies p % E = ONE - res = 1.3831592645e+09_defReal + res = ONE/1.3831592645e+09_defReal @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) p % E = 1.6e-06_defReal - res = 1.7495734571e+06_defReal + res = ONE/1.7495734571e+06_defReal @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) end subroutine densityResponseing diff --git a/Tallies/TallyResponses/densityResponse_class.f90 b/Tallies/TallyResponses/densityResponse_class.f90 index 23d1528c7..d06f7e10c 100644 --- a/Tallies/TallyResponses/densityResponse_class.f90 +++ b/Tallies/TallyResponses/densityResponse_class.f90 @@ -15,7 +15,7 @@ module densityResponse_class !! !! tallyResponse to score particle density contribution !! - !! Returns the velocity of the particle in [cm/s], calculated from its energy + !! Returns the inverse of the particle velocity in [cm/s], calculated from its energy !! !! Interface: !! tallyResponse Interface @@ -44,7 +44,7 @@ subroutine init(self, dict) end subroutine init !! - !! Get the particle velocity (Response to score particle density) + !! Calculate the particle velocity and return the inverse (response to score particle density) !! !! See tallyResponse_inter for details !! @@ -53,11 +53,13 @@ function get(self, p, xsData) result(val) class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData real(defReal) :: val + real(defReal) :: velocity ! Calculate the velocity in [cm/s] ! neutronMass: [MeV] ! lightSpeed: [cm/s] - val = sqrt(TWO * p % E / neutronMass) * lightSpeed + velocity = sqrt(TWO * p % E / neutronMass) * lightSpeed + val = ONE / velocity end function get diff --git a/docs/User Manual.rst b/docs/User Manual.rst index 5433e74e2..fb549b3e0 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -1059,7 +1059,7 @@ Example: :: } * densityResponse: used to calculate the particle desnsity, i.e., the response function is - the particle velocity in [cm/s] + the inverse of the particle velocity in [cm/s] Example: :: From 9b57315c8a7b8f075d58432209c476983e3b4e7d Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Thu, 9 May 2024 15:09:06 +0100 Subject: [PATCH 120/133] Adding photons in densityResponse --- .../Tests/densityResponse_test.f90 | 16 +++++++-- .../TallyResponses/densityResponse_class.f90 | 34 +++++++++++++++---- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/Tallies/TallyResponses/Tests/densityResponse_test.f90 b/Tallies/TallyResponses/Tests/densityResponse_test.f90 index d9a8301a6..42b5173ee 100644 --- a/Tallies/TallyResponses/Tests/densityResponse_test.f90 +++ b/Tallies/TallyResponses/Tests/densityResponse_test.f90 @@ -1,8 +1,9 @@ module densityResponse_test use numPrecision + use universalVariables, only : lightSpeed use densityResponse_class, only : densityResponse - use particle_class, only : particle + use particle_class, only : particle, P_NEUTRON, P_PHOTON use dictionary_class, only : dictionary use nuclearDatabase_inter, only : nuclearDatabase use pFUnit_mod @@ -52,7 +53,8 @@ subroutine densityResponseing(this) class(nuclearDatabase),pointer :: xsData real(defReal) :: res - ! Test with different particle energies + ! Test neutron density with different particle energies + p % type = P_NEUTRON p % E = ONE res = ONE/1.3831592645e+09_defReal @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) @@ -61,6 +63,16 @@ subroutine densityResponseing(this) res = ONE/1.7495734571e+06_defReal @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) + ! Test photon density + p % type = P_PHOTON + res = ONE/lightSpeed + @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) + + ! Test response for unknown particle type + p % type = 345 + res = ZERO + @assertEqual(res, this % response % get(p, xsData)) + end subroutine densityResponseing end module densityResponse_test diff --git a/Tallies/TallyResponses/densityResponse_class.f90 b/Tallies/TallyResponses/densityResponse_class.f90 index d06f7e10c..5fd74d091 100644 --- a/Tallies/TallyResponses/densityResponse_class.f90 +++ b/Tallies/TallyResponses/densityResponse_class.f90 @@ -3,7 +3,7 @@ module densityResponse_class use numPrecision use universalVariables, only : neutronMass, lightSpeed use dictionary_class, only : dictionary - use particle_class, only : particle + use particle_class, only : particle, P_NEUTRON, P_PHOTON use tallyResponse_inter, only : tallyResponse ! Nuclear Data interface @@ -15,7 +15,10 @@ module densityResponse_class !! !! tallyResponse to score particle density contribution !! - !! Returns the inverse of the particle velocity in [cm/s], calculated from its energy + !! Returns the inverse of the particle velocity in [cm/s] + !! + !! The velocity is calculated from the particle energy for neutrons, and it is + !! the speed of light for photons !! !! Interface: !! tallyResponse Interface @@ -44,7 +47,12 @@ subroutine init(self, dict) end subroutine init !! - !! Calculate the particle velocity and return the inverse (response to score particle density) + !! Calculates the particle velocity for neutron and photons + !! NOTE: neutronMass: [MeV] + !! lightSpeed: [cm/s] + !! + !! The function returns the inverse of the velocity (response to score particle density) + !! if the particle type is neutron or photon, and zero otherwise !! !! See tallyResponse_inter for details !! @@ -55,10 +63,22 @@ function get(self, p, xsData) result(val) real(defReal) :: val real(defReal) :: velocity - ! Calculate the velocity in [cm/s] - ! neutronMass: [MeV] - ! lightSpeed: [cm/s] - velocity = sqrt(TWO * p % E / neutronMass) * lightSpeed + ! Initialise response + val = ZERO + + ! Calculates the velocity for the relevant particle [cm/s] + if (p % type == P_NEUTRON) then + velocity = sqrt(TWO * p % E / neutronMass) * lightSpeed + + elseif (p % type == P_PHOTON) then + velocity = lightSpeed + + else + return + + end if + + ! Returns the inverse of the velocity val = ONE / velocity end function get From 5333d9cd627c20e391d85f778d1fe3dbe9b5f74d Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 24 Jan 2024 16:46:46 +0100 Subject: [PATCH 121/133] Add id to track the source particle index --- ParticleObjects/particle_class.f90 | 31 ++++--------------- PhysicsPackages/eigenPhysicsPackage_class.f90 | 2 ++ .../fixedSourcePhysicsPackage_class.f90 | 1 + 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 69021c389..d992a2f47 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -56,6 +56,7 @@ module particle_class integer(shortInt) :: cellIdx = -1 ! Cell idx at the lowest coord level integer(shortInt) :: uniqueID = -1 ! Unique id at the lowest coord level integer(shortInt) :: collisionN = 0 ! Number of collisions + integer(shortInt) :: showerID = 0 ! ID of the shower (source particle number) contains generic :: assignment(=) => fromParticle generic :: operator(.eq.) => equal_particleState @@ -111,6 +112,7 @@ module particle_class integer(shortInt) :: fate = 0 ! Neutron's fate after being subjected to an operator integer(shortInt) :: type ! Particle type integer(shortInt) :: collisionN = 0 ! Index of the number of collisions the particle went through + integer(shortInt) :: showerID = 0 ! ID of the shower (source particle number) ! Particle processing information class(RNG), pointer :: pRNG => null() ! Pointer to RNG associated with the particle @@ -275,6 +277,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % time = RHS % time LHS % collisionN = RHS % collisionN LHS % splitCount = 0 ! Reinitialise counter for number of splits + LHS % showerID = RHS % showerID end subroutine particle_fromParticleState @@ -618,6 +621,7 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() LHS % collisionN = RHS % collisionN + LHS % showerID = RHS % showerID end subroutine particleState_fromParticle @@ -641,6 +645,7 @@ function equal_particleState(LHS,RHS) result(isEqual) isEqual = isEqual .and. LHS % cellIdx == RHS % cellIdx isEqual = isEqual .and. LHS % uniqueID == RHS % uniqueID isEqual = isEqual .and. LHS % collisionN == RHS % collisionN + isEqual = isEqual .and. LHS % showerID == RHS % showerID if( LHS % isMG ) then isEqual = isEqual .and. LHS % G == RHS % G @@ -649,31 +654,6 @@ function equal_particleState(LHS,RHS) result(isEqual) end if end function equal_particleState -! !! -! !! Copy particle state into archive object -! !! -! subroutine particleState_fromParticle(LHS,RHS) -! class(particleState), intent(out) :: LHS -! class(particle), intent(in) :: RHS -! -! ! Call superclass procedure -! call phaseCoord_fromParticle(LHS,RHS) -! -! end subroutine particleState_fromParticle - -! !! -! !! Extend equality definition to particle state -! !! -! function equal_particleState(LHS,RHS) result(isEqual) -! class(particleState), intent(in) :: LHS -! type(particleState), intent(in) :: RHS -! logical(defBool) :: isEqual -! -! ! Call superclass procedure -! isEqual = equal_phaseCoord(LHS,RHS) -! -! end function equal_particleState - !! !! Prints state of the phaseCoord !! @@ -708,6 +688,7 @@ elemental subroutine kill_particleState(self) self % cellIdx = -1 self % uniqueID = -1 self % collisionN = 0 + self % showerID = 0 end subroutine kill_particleState diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index d67603e8a..10f814cbc 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -195,6 +195,8 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Obtain particle current cycle dungeon call self % thisCycle % copy(neutron, n) + neutron % showerID = n + bufferLoop: do call self % geom % placeCoord(neutron % coords) diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index b1dbb4e86..2b608c7e5 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -181,6 +181,7 @@ subroutine cycles(self, tally, N_cycles) ! Obtain particle from dungeon call self % thisCycle % copy(p, n) + p % showerID = n bufferLoop: do From b87c57aae3b74074b637f1ec8b4475ea34fc4b54 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Wed, 24 Jan 2024 19:06:00 +0100 Subject: [PATCH 122/133] Initial implementation of the dungeon sort --- ParticleObjects/particleDungeon_class.f90 | 75 +++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index ef7d75841..527dfb59e 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -91,6 +91,7 @@ module particleDungeon_class procedure :: popWeight procedure :: setSize procedure :: printToFile + procedure :: sortByShowerID ! Private procedures procedure, private :: detain_particle @@ -99,6 +100,7 @@ module particleDungeon_class procedure, private :: detainCritical_particleState procedure, private :: replace_particle procedure, private :: replace_particleState + end type particleDungeon contains @@ -413,6 +415,8 @@ subroutine normSize(self, N, rand) call fatalError(Here,'Requested size: '//numToChar(N) //' is not +ve') end if + call self % sortByShowerID(N) + ! Calculate excess particles to be removed excessP = self % pop - N @@ -457,6 +461,66 @@ subroutine normSize(self, N, rand) end subroutine normSize + !! + !! Reorder the dungeon so the shower ID is in the ascending order + !! + !! Args: + !! k [in] -> Maximum shower ID + !! + subroutine sortByShowerID(self, k) + class(particleDungeon), intent(inout) :: self + integer(shortInt), intent(in) :: k + integer(shortInt), dimension(k) :: count + integer(shortInt) :: i, id, loc, c + integer(shortInt), dimension(:), allocatable :: perm + type(particleState) :: tmp + character(100), parameter :: Here = 'sortByShowerID (particleDungeon_class.f90)' + + ! Count number of particles with each shower ID + count = 0 + do i = 1, self % pop + id = self % prisoners(i) % showerID + count(id) = count(id) + 1 + end do + + ! Convert to starting index + loc = 1 + do i = 1, k + c = count(i) + count(i) = loc + loc = loc + c + end do + + ! Create the permutation array + allocate(perm(self % pop)) + do i = 1, self % pop + id = self % prisoners(i) % showerID + loc = count(id) + count(id) = count(id) + 1 + perm(loc) = i + end do + + ! Permute particles + do i = 1, self % pop + loc = perm(i) + + ! If the element was already swapped follow it to its location + do while (loc < i) + loc = perm(loc) + end do + + ! Swap elements + if (loc /= i) then + tmp = self % prisoners(i) + self % prisoners(i) = self % prisoners(loc) + self % prisoners(loc) = tmp + end if + + end do + + end subroutine sortByShowerID + + !! !! Kill or particles in the dungeon !! @@ -542,10 +606,13 @@ subroutine printToFile(self, name) ! Print out each particle co-ordinate do i = 1, self % pop - write(10,'(8A)') numToChar(self % prisoners(i) % r), & - numToChar(self % prisoners(i) % dir), & - numToChar(self % prisoners(i) % E), & - numToChar(self % prisoners(i) % G) + ! write(10,'(8A)') numToChar(self % prisoners(i) % r), & + ! numToChar(self % prisoners(i) % dir), & + ! numToChar(self % prisoners(i) % E), & + ! numToChar(self % prisoners(i) % G) + write(10, *) self % prisoners(i) % r, self % prisoners(i) % dir, & + self % prisoners(i) % E, self % prisoners(i) % G, & + self % prisoners(i) % showerID end do ! Close the file From 1ef0048ef5ead28ffc8d298367c1826e8268bc0a Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 27 Jan 2024 14:50:22 +0100 Subject: [PATCH 123/133] Make source OpenMP reproducable --- ParticleObjects/Source/source_inter.f90 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ParticleObjects/Source/source_inter.f90 b/ParticleObjects/Source/source_inter.f90 index 141cc3558..5e3c141f3 100644 --- a/ParticleObjects/Source/source_inter.f90 +++ b/ParticleObjects/Source/source_inter.f90 @@ -110,15 +110,13 @@ subroutine generate(self, dungeon, n, rand) ! Generate n particles to populate dungeon ! TODO: advance the rand after source generation! ! This should prevent reusing RNs during transport - !$omp parallel - pRand = rand - !$omp do + !$omp parallel do do i = 1, n + pRand = rand call pRand % stride(i) call dungeon % replace(self % sampleParticle(pRand), i) end do - !$omp end do - !$omp end parallel + !$omp end parallel do end subroutine generate From c4e3fa452883d72b2bd7a3766a21b11fa1048eaa Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 27 Jan 2024 16:49:02 +0100 Subject: [PATCH 124/133] Add range checks to the sorting of particleDungeon Determine the maximum value of the key without implicit assumptions. --- ParticleObjects/particleDungeon_class.f90 | 9 +++++++-- PhysicsPackages/eigenPhysicsPackage_class.f90 | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index 527dfb59e..ad29aae2d 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -403,7 +403,7 @@ subroutine normSize(self, N, rand) integer(shortInt), intent(in) :: N class(RNG), intent(inout) :: rand integer(shortInt) :: excessP, n_copies, n_duplicates - integer(shortInt) :: i, idx + integer(shortInt) :: i, idx, maxShowerID integer(shortInt), dimension(:), allocatable :: duplicates character(100), parameter :: Here =' normSize (particleDungeon_class.f90)' @@ -415,7 +415,9 @@ subroutine normSize(self, N, rand) call fatalError(Here,'Requested size: '//numToChar(N) //' is not +ve') end if - call self % sortByShowerID(N) + ! Determine the maximum shower ID and sort the dungeon + maxShowerID = maxval(self % prisoners(1:self % pop) % showerID) + call self % sortByShowerID(maxShowerID) ! Calculate excess particles to be removed excessP = self % pop - N @@ -480,6 +482,9 @@ subroutine sortByShowerID(self, k) count = 0 do i = 1, self % pop id = self % prisoners(i) % showerID + + if (id < 1 .or. id > k) call fatalError(Here, 'Shower ID out of range: '//numToChar(id)) + count(id) = count(id) + 1 end do diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index 10f814cbc..66ac502d6 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -206,7 +206,7 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Save state call neutron % savePreHistory() - ! Transport particle untill its death + ! Transport particle until its death history: do call transOp % transport(neutron, tally, buffer, self % nextCycle) if(neutron % isDead) exit history @@ -241,7 +241,7 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) end if ! Normalise population - call self % nextCycle % normSize(self % pop, pRNG) + call self % nextCycle % normSize(self % pop, self % pRNG) if(self % printSource == 1) then call self % nextCycle % printToFile(trim(self % outputFile)//'_source'//numToChar(i)) @@ -310,7 +310,7 @@ subroutine generateInitialState(self) call self % thisCycle % init(3 * self % pop) call self % nextCycle % init(3 * self % pop) - ! Generate initial surce + ! Generate initial source print *, "GENERATING INITIAL FISSION SOURCE" call self % initSource % generate(self % thisCycle, self % pop, self % pRNG) print *, "DONE!" @@ -409,7 +409,7 @@ subroutine init(self, dict) call dict % getOrDefault(self % outputFile,'outputFile','./output') ! Get output format and verify - ! Initialise output file before calculation (so mistake in format will be cought early) + ! Initialise output file before calculation (so mistake in format will be caught early) call dict % getOrDefault(self % outputFormat, 'outputFormat', 'asciiMATLAB') call test_out % init(self % outputFormat) From 76f9ae107d74edcef210b4ba6e55c45deb7db129 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 27 Jan 2024 17:07:18 +0100 Subject: [PATCH 125/133] Add missing particleDungeon tests of sorting --- .../Tests/particleDungeon_test.f90 | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/ParticleObjects/Tests/particleDungeon_test.f90 b/ParticleObjects/Tests/particleDungeon_test.f90 index a110df0e0..f76736382 100644 --- a/ParticleObjects/Tests/particleDungeon_test.f90 +++ b/ParticleObjects/Tests/particleDungeon_test.f90 @@ -217,6 +217,7 @@ subroutine testNormPopDown() ! Store some particles with non-uniform weight do i = 1,10 p % w = 0.5_defReal + i * 0.1_defReal + p % showerID = 1 ! Avoid triggering error on sort by showerID call dungeon % detain(p) end do @@ -254,6 +255,7 @@ subroutine testNormPopUp() ! Store some particles with non-uniform weight do i = 1,10 p % w = 0.5_defReal + i * 0.1_defReal + p % showerID = 1 ! Avoid triggering error on sort by showerID call dungeon % detain(p) end do @@ -271,5 +273,75 @@ subroutine testNormPopUp() end subroutine testNormPopUp + !! + !! Test sorting of the population by shower ID without duplicates + !! +@Test + subroutine testSortingByShowerID() + type(particleDungeon) :: dungeon + type(particle) :: p + integer(shortInt) :: i + real(defReal), parameter :: TOL = 1.0E-9 + + ! Initialise + call dungeon % init(10) + + ! Store some particles with shower ID in reverse order + do i = 1,10 + p % showerID = 10 - i + 1 + call dungeon % detain(p) + end do + + ! Sort by shower ID + call dungeon % sortByShowerId(10) + + ! Verify order + do i = 1,10 + call dungeon % copy(p, i) + @assertEqual(i, p % showerID) + end do + + end subroutine testSortingByShowerID + + + !! + !! Test sorting of the population by shower ID with duplicates + !! + @Test + subroutine testSortingByShowerID_withDuplicates() + type(particleDungeon) :: dungeon + type(particle) :: p + integer(shortInt) :: i, j + integer(shortInt), parameter :: N_duplicates = 7 + real(defReal), parameter :: TOL = 1.0E-9 + + ! Initialise + call dungeon % init(10 * N_duplicates) + + ! Store some particles with shower ID in reverse order + ! Use the group number to distinguish duplicates and make sure + ! that the insertion order is preserved (for particles with the same shower ID) + do j = 1,N_duplicates + do i = 1,10 + p % showerID = 10 - i + 1 + p % G = j + call dungeon % detain(p) + end do + end do + + ! Sort by shower ID + call dungeon % sortByShowerId(10) + + ! Verify order + do i = 1,10 + do j = 1, N_duplicates + call dungeon % copy(p, j + (i-1) * N_duplicates) + @assertEqual(i, p % showerID) + @assertEqual(j, p % G) + end do + end do + + end subroutine testSortingByShowerID_withDuplicates + end module particleDungeon_test From 2a2be13515a2b1ba55a94a58e41bec9168a791a1 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 17 Feb 2024 15:01:17 +0100 Subject: [PATCH 126/133] Rename showerID to broodID --- .../Tests/particleDungeon_test.f90 | 24 ++++++++--------- ParticleObjects/particleDungeon_class.f90 | 20 +++++++------- ParticleObjects/particle_class.f90 | 27 +++++++------------ PhysicsPackages/eigenPhysicsPackage_class.f90 | 2 +- .../fixedSourcePhysicsPackage_class.f90 | 2 +- 5 files changed, 33 insertions(+), 42 deletions(-) diff --git a/ParticleObjects/Tests/particleDungeon_test.f90 b/ParticleObjects/Tests/particleDungeon_test.f90 index f76736382..4e3b0ce4e 100644 --- a/ParticleObjects/Tests/particleDungeon_test.f90 +++ b/ParticleObjects/Tests/particleDungeon_test.f90 @@ -217,7 +217,7 @@ subroutine testNormPopDown() ! Store some particles with non-uniform weight do i = 1,10 p % w = 0.5_defReal + i * 0.1_defReal - p % showerID = 1 ! Avoid triggering error on sort by showerID + p % broodID = 1 ! Avoid triggering error on sort by broodID call dungeon % detain(p) end do @@ -255,7 +255,7 @@ subroutine testNormPopUp() ! Store some particles with non-uniform weight do i = 1,10 p % w = 0.5_defReal + i * 0.1_defReal - p % showerID = 1 ! Avoid triggering error on sort by showerID + p % broodID = 1 ! Avoid triggering error on sort by broodID call dungeon % detain(p) end do @@ -277,7 +277,7 @@ end subroutine testNormPopUp !! Test sorting of the population by shower ID without duplicates !! @Test - subroutine testSortingByShowerID() + subroutine testSortingByBroodID() type(particleDungeon) :: dungeon type(particle) :: p integer(shortInt) :: i @@ -288,27 +288,27 @@ subroutine testSortingByShowerID() ! Store some particles with shower ID in reverse order do i = 1,10 - p % showerID = 10 - i + 1 + p % broodID = 10 - i + 1 call dungeon % detain(p) end do ! Sort by shower ID - call dungeon % sortByShowerId(10) + call dungeon % sortByBroodID(10) ! Verify order do i = 1,10 call dungeon % copy(p, i) - @assertEqual(i, p % showerID) + @assertEqual(i, p % broodID) end do - end subroutine testSortingByShowerID + end subroutine testSortingByBroodID !! !! Test sorting of the population by shower ID with duplicates !! @Test - subroutine testSortingByShowerID_withDuplicates() + subroutine testSortingByBroodID_withDuplicates() type(particleDungeon) :: dungeon type(particle) :: p integer(shortInt) :: i, j @@ -323,25 +323,25 @@ subroutine testSortingByShowerID_withDuplicates() ! that the insertion order is preserved (for particles with the same shower ID) do j = 1,N_duplicates do i = 1,10 - p % showerID = 10 - i + 1 + p % broodID = 10 - i + 1 p % G = j call dungeon % detain(p) end do end do ! Sort by shower ID - call dungeon % sortByShowerId(10) + call dungeon % sortByBroodID(10) ! Verify order do i = 1,10 do j = 1, N_duplicates call dungeon % copy(p, j + (i-1) * N_duplicates) - @assertEqual(i, p % showerID) + @assertEqual(i, p % broodID) @assertEqual(j, p % G) end do end do - end subroutine testSortingByShowerID_withDuplicates + end subroutine testSortingByBroodID_withDuplicates end module particleDungeon_test diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index ad29aae2d..b25052432 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -91,7 +91,7 @@ module particleDungeon_class procedure :: popWeight procedure :: setSize procedure :: printToFile - procedure :: sortByShowerID + procedure :: sortByBroodID ! Private procedures procedure, private :: detain_particle @@ -403,7 +403,7 @@ subroutine normSize(self, N, rand) integer(shortInt), intent(in) :: N class(RNG), intent(inout) :: rand integer(shortInt) :: excessP, n_copies, n_duplicates - integer(shortInt) :: i, idx, maxShowerID + integer(shortInt) :: i, idx, maxBroodID integer(shortInt), dimension(:), allocatable :: duplicates character(100), parameter :: Here =' normSize (particleDungeon_class.f90)' @@ -416,8 +416,8 @@ subroutine normSize(self, N, rand) end if ! Determine the maximum shower ID and sort the dungeon - maxShowerID = maxval(self % prisoners(1:self % pop) % showerID) - call self % sortByShowerID(maxShowerID) + maxBroodID = maxval(self % prisoners(1:self % pop) % broodID) + call self % sortByBroodID(maxbroodID) ! Calculate excess particles to be removed excessP = self % pop - N @@ -469,19 +469,19 @@ end subroutine normSize !! Args: !! k [in] -> Maximum shower ID !! - subroutine sortByShowerID(self, k) + subroutine sortByBroodID(self, k) class(particleDungeon), intent(inout) :: self integer(shortInt), intent(in) :: k integer(shortInt), dimension(k) :: count integer(shortInt) :: i, id, loc, c integer(shortInt), dimension(:), allocatable :: perm type(particleState) :: tmp - character(100), parameter :: Here = 'sortByShowerID (particleDungeon_class.f90)' + character(100), parameter :: Here = 'sortBybroodID (particleDungeon_class.f90)' ! Count number of particles with each shower ID count = 0 do i = 1, self % pop - id = self % prisoners(i) % showerID + id = self % prisoners(i) % broodID if (id < 1 .or. id > k) call fatalError(Here, 'Shower ID out of range: '//numToChar(id)) @@ -499,7 +499,7 @@ subroutine sortByShowerID(self, k) ! Create the permutation array allocate(perm(self % pop)) do i = 1, self % pop - id = self % prisoners(i) % showerID + id = self % prisoners(i) % broodID loc = count(id) count(id) = count(id) + 1 perm(loc) = i @@ -523,7 +523,7 @@ subroutine sortByShowerID(self, k) end do - end subroutine sortByShowerID + end subroutine sortByBroodID !! @@ -617,7 +617,7 @@ subroutine printToFile(self, name) ! numToChar(self % prisoners(i) % G) write(10, *) self % prisoners(i) % r, self % prisoners(i) % dir, & self % prisoners(i) % E, self % prisoners(i) % G, & - self % prisoners(i) % showerID + self % prisoners(i) % broodID end do ! Close the file diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index d992a2f47..e8f493f2c 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -37,6 +37,9 @@ module particle_class !! cellIdx -> Cell Index at the lowest level in which particle is present !! uniqueID -> Unique ID of the cell at the lowest level in which particle is present !! collisionN -> Number of collisions the particle went through + !! broodID -> ID of the source particle. It is used to indicate the primogenitor of the particles + !! in the particleDungeon so they can be sorted, which is necessary for reproducibility + !! with OpenMP !! !! Interface: !! assignemnt(=) -> Build particleState from particle @@ -56,7 +59,7 @@ module particle_class integer(shortInt) :: cellIdx = -1 ! Cell idx at the lowest coord level integer(shortInt) :: uniqueID = -1 ! Unique id at the lowest coord level integer(shortInt) :: collisionN = 0 ! Number of collisions - integer(shortInt) :: showerID = 0 ! ID of the shower (source particle number) + integer(shortInt) :: broodID = 0 ! ID of the source particle contains generic :: assignment(=) => fromParticle generic :: operator(.eq.) => equal_particleState @@ -68,18 +71,6 @@ module particle_class procedure,private :: equal_particleState end type particleState -! !! -! !! Archived state of the particle used for tallying transitions, fission matrixes etc. -! !! -! type, public,extends(phaseCoord) :: -! contains -! generic :: operator(.eq.) => equal_particleState -! procedure :: fromParticle => particleState_fromParticle -! -! ! Private procedures -! procedure,private :: equal_particleState -! end type - !! !! This type represents particle !! @@ -112,7 +103,7 @@ module particle_class integer(shortInt) :: fate = 0 ! Neutron's fate after being subjected to an operator integer(shortInt) :: type ! Particle type integer(shortInt) :: collisionN = 0 ! Index of the number of collisions the particle went through - integer(shortInt) :: showerID = 0 ! ID of the shower (source particle number) + integer(shortInt) :: broodID = 0 ! ID of the shower (source particle number) ! Particle processing information class(RNG), pointer :: pRNG => null() ! Pointer to RNG associated with the particle @@ -277,7 +268,7 @@ pure subroutine particle_fromParticleState(LHS,RHS) LHS % time = RHS % time LHS % collisionN = RHS % collisionN LHS % splitCount = 0 ! Reinitialise counter for number of splits - LHS % showerID = RHS % showerID + LHS % broodID = RHS % broodID end subroutine particle_fromParticleState @@ -621,7 +612,7 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() LHS % collisionN = RHS % collisionN - LHS % showerID = RHS % showerID + LHS % broodID = RHS % broodID end subroutine particleState_fromParticle @@ -645,7 +636,7 @@ function equal_particleState(LHS,RHS) result(isEqual) isEqual = isEqual .and. LHS % cellIdx == RHS % cellIdx isEqual = isEqual .and. LHS % uniqueID == RHS % uniqueID isEqual = isEqual .and. LHS % collisionN == RHS % collisionN - isEqual = isEqual .and. LHS % showerID == RHS % showerID + isEqual = isEqual .and. LHS % broodID == RHS % broodID if( LHS % isMG ) then isEqual = isEqual .and. LHS % G == RHS % G @@ -688,7 +679,7 @@ elemental subroutine kill_particleState(self) self % cellIdx = -1 self % uniqueID = -1 self % collisionN = 0 - self % showerID = 0 + self % broodID = 0 end subroutine kill_particleState diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index 66ac502d6..5eedbb931 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -195,7 +195,7 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Obtain particle current cycle dungeon call self % thisCycle % copy(neutron, n) - neutron % showerID = n + neutron % broodID = n bufferLoop: do call self % geom % placeCoord(neutron % coords) diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 2b608c7e5..4e7da1caf 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -181,7 +181,7 @@ subroutine cycles(self, tally, N_cycles) ! Obtain particle from dungeon call self % thisCycle % copy(p, n) - p % showerID = n + p % broodID = n bufferLoop: do From b1ff411e81db43cc6a3cc6343bfb7f72b8c7fc06 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 17 Feb 2024 15:13:05 +0100 Subject: [PATCH 127/133] Apply PR comments --- .../Tests/particleDungeon_test.f90 | 8 ++++---- ParticleObjects/particleDungeon_class.f90 | 19 ++++++++++++------- PhysicsPackages/eigenPhysicsPackage_class.f90 | 2 -- .../fixedSourcePhysicsPackage_class.f90 | 1 - 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ParticleObjects/Tests/particleDungeon_test.f90 b/ParticleObjects/Tests/particleDungeon_test.f90 index 4e3b0ce4e..c6bb978b8 100644 --- a/ParticleObjects/Tests/particleDungeon_test.f90 +++ b/ParticleObjects/Tests/particleDungeon_test.f90 @@ -279,7 +279,7 @@ end subroutine testNormPopUp @Test subroutine testSortingByBroodID() type(particleDungeon) :: dungeon - type(particle) :: p + type(particleState) :: p integer(shortInt) :: i real(defReal), parameter :: TOL = 1.0E-9 @@ -297,7 +297,7 @@ subroutine testSortingByBroodID() ! Verify order do i = 1,10 - call dungeon % copy(p, i) + p = dungeon % get(i) @assertEqual(i, p % broodID) end do @@ -310,7 +310,7 @@ end subroutine testSortingByBroodID @Test subroutine testSortingByBroodID_withDuplicates() type(particleDungeon) :: dungeon - type(particle) :: p + type(particleState) :: p integer(shortInt) :: i, j integer(shortInt), parameter :: N_duplicates = 7 real(defReal), parameter :: TOL = 1.0E-9 @@ -335,7 +335,7 @@ subroutine testSortingByBroodID_withDuplicates() ! Verify order do i = 1,10 do j = 1, N_duplicates - call dungeon % copy(p, j + (i-1) * N_duplicates) + p = dungeon % get(j + (i-1) * N_duplicates) @assertEqual(i, p % broodID) @assertEqual(j, p % G) end do diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index b25052432..b63e08a0d 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -326,8 +326,16 @@ end subroutine replace_particleState !! !! Copy particle from a location inside the dungeon - !! Makes particle alive at exit - !! Gives fatalError if requested index is 0, -ve or above current population + !! + !! Makes particle alive at exit. Also sets the broodID of the particle + !! making it ready to be transported. + !! + !! Args: + !! p [inout] -> Particle to be filled with data + !! idx [in] -> Index of the particle to be copied + !! + !! Errors: + !! fatalError if requested index is 0, -ve or above current population !! subroutine copy(self, p, idx) class(particleDungeon), intent(in) :: self @@ -337,13 +345,14 @@ subroutine copy(self, p, idx) ! Protect against out-of-bounds access if( idx <= 0 .or. idx > self % pop ) then - call fatalError(Here,'Out of bounds acces with idx: '// numToChar(idx)// & + call fatalError(Here,'Out of bounds access with idx: '// numToChar(idx)// & ' with particle population of: '// numToChar(self % pop)) end if ! Load data into the particle p = self % prisoners(idx) p % isDead = .false. + p % broodID = idx end subroutine copy @@ -611,10 +620,6 @@ subroutine printToFile(self, name) ! Print out each particle co-ordinate do i = 1, self % pop - ! write(10,'(8A)') numToChar(self % prisoners(i) % r), & - ! numToChar(self % prisoners(i) % dir), & - ! numToChar(self % prisoners(i) % E), & - ! numToChar(self % prisoners(i) % G) write(10, *) self % prisoners(i) % r, self % prisoners(i) % dir, & self % prisoners(i) % E, self % prisoners(i) % G, & self % prisoners(i) % broodID diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index 5eedbb931..4ede0e8f4 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -195,8 +195,6 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Obtain particle current cycle dungeon call self % thisCycle % copy(neutron, n) - neutron % broodID = n - bufferLoop: do call self % geom % placeCoord(neutron % coords) diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 4e7da1caf..b1dbb4e86 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -181,7 +181,6 @@ subroutine cycles(self, tally, N_cycles) ! Obtain particle from dungeon call self % thisCycle % copy(p, n) - p % broodID = n bufferLoop: do From 97d692bc393c6684c059140803eb702506d2ab4c Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski Date: Sat, 17 Feb 2024 15:33:10 +0100 Subject: [PATCH 128/133] Uprade docs to indicate when reproducibility fails --- docs/User Manual.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/User Manual.rst b/docs/User Manual.rst index ac7575ed0..241ff9bbe 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -86,6 +86,10 @@ fixedSourcePhysicsPackage, used for fixed source calculations stored in a thread-private buffer, after which particles are shifted to the common buffer +.. note:: + If the common buffer is used, the calculation will not be reproducible if it + is performed in parallel. This issue may be addressed in the future. + Example: :: type fixedSourcePhysicsPackage; From 65c2896f87ec045bfb73af476c1b7d07dfb5e4d8 Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> Date: Fri, 10 May 2024 14:03:39 +0200 Subject: [PATCH 129/133] Remove 'showerID' from comments Co-authored-by: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> --- ParticleObjects/Tests/particleDungeon_test.f90 | 18 +++++++++--------- ParticleObjects/particleDungeon_class.f90 | 10 +++++----- ParticleObjects/particle_class.f90 | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ParticleObjects/Tests/particleDungeon_test.f90 b/ParticleObjects/Tests/particleDungeon_test.f90 index c6bb978b8..088de1ec9 100644 --- a/ParticleObjects/Tests/particleDungeon_test.f90 +++ b/ParticleObjects/Tests/particleDungeon_test.f90 @@ -274,7 +274,7 @@ subroutine testNormPopUp() end subroutine testNormPopUp !! - !! Test sorting of the population by shower ID without duplicates + !! Test sorting of the population by brood ID without duplicates !! @Test subroutine testSortingByBroodID() @@ -286,13 +286,13 @@ subroutine testSortingByBroodID() ! Initialise call dungeon % init(10) - ! Store some particles with shower ID in reverse order + ! Store some particles with brood ID in reverse order do i = 1,10 p % broodID = 10 - i + 1 call dungeon % detain(p) end do - ! Sort by shower ID + ! Sort by brood ID call dungeon % sortByBroodID(10) ! Verify order @@ -305,7 +305,7 @@ end subroutine testSortingByBroodID !! - !! Test sorting of the population by shower ID with duplicates + !! Test sorting of the population by brood ID with duplicates !! @Test subroutine testSortingByBroodID_withDuplicates() @@ -318,18 +318,18 @@ subroutine testSortingByBroodID_withDuplicates() ! Initialise call dungeon % init(10 * N_duplicates) - ! Store some particles with shower ID in reverse order + ! Store some particles with brood ID in reverse order ! Use the group number to distinguish duplicates and make sure - ! that the insertion order is preserved (for particles with the same shower ID) - do j = 1,N_duplicates - do i = 1,10 + ! that the insertion order is preserved (for particles with the same brood ID) + do j = 1, N_duplicates + do i = 1, 10 p % broodID = 10 - i + 1 p % G = j call dungeon % detain(p) end do end do - ! Sort by shower ID + ! Sort by brood ID call dungeon % sortByBroodID(10) ! Verify order diff --git a/ParticleObjects/particleDungeon_class.f90 b/ParticleObjects/particleDungeon_class.f90 index b63e08a0d..62d6d45ba 100644 --- a/ParticleObjects/particleDungeon_class.f90 +++ b/ParticleObjects/particleDungeon_class.f90 @@ -424,7 +424,7 @@ subroutine normSize(self, N, rand) call fatalError(Here,'Requested size: '//numToChar(N) //' is not +ve') end if - ! Determine the maximum shower ID and sort the dungeon + ! Determine the maximum brood ID and sort the dungeon maxBroodID = maxval(self % prisoners(1:self % pop) % broodID) call self % sortByBroodID(maxbroodID) @@ -473,10 +473,10 @@ subroutine normSize(self, N, rand) end subroutine normSize !! - !! Reorder the dungeon so the shower ID is in the ascending order + !! Reorder the dungeon so the brood ID is in the ascending order !! !! Args: - !! k [in] -> Maximum shower ID + !! k [in] -> Maximum brood ID !! subroutine sortByBroodID(self, k) class(particleDungeon), intent(inout) :: self @@ -487,12 +487,12 @@ subroutine sortByBroodID(self, k) type(particleState) :: tmp character(100), parameter :: Here = 'sortBybroodID (particleDungeon_class.f90)' - ! Count number of particles with each shower ID + ! Count number of particles with each brood ID count = 0 do i = 1, self % pop id = self % prisoners(i) % broodID - if (id < 1 .or. id > k) call fatalError(Here, 'Shower ID out of range: '//numToChar(id)) + if (id < 1 .or. id > k) call fatalError(Here, 'Brood ID out of range: '//numToChar(id)) count(id) = count(id) + 1 end do diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index e8f493f2c..cbc5c9d62 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -103,7 +103,7 @@ module particle_class integer(shortInt) :: fate = 0 ! Neutron's fate after being subjected to an operator integer(shortInt) :: type ! Particle type integer(shortInt) :: collisionN = 0 ! Index of the number of collisions the particle went through - integer(shortInt) :: broodID = 0 ! ID of the shower (source particle number) + integer(shortInt) :: broodID = 0 ! ID of the brood (source particle number) ! Particle processing information class(RNG), pointer :: pRNG => null() ! Pointer to RNG associated with the particle From 8fba0159c562ae1eda94025ce21b72f5a96f68b2 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi(vr339)" Date: Sat, 11 May 2024 00:36:07 +0100 Subject: [PATCH 130/133] Moving calculating velocity to the particle --- ParticleObjects/Tests/particle_test.f90 | 5 ++ ParticleObjects/particle_class.f90 | 64 ++++++++++++++++--- SharedModules/genericProcedures.f90 | 2 +- SharedModules/universalVariables.f90 | 3 +- .../Tests/densityResponse_test.f90 | 12 ++-- .../TallyResponses/densityResponse_class.f90 | 33 ++-------- 6 files changed, 74 insertions(+), 45 deletions(-) diff --git a/ParticleObjects/Tests/particle_test.f90 b/ParticleObjects/Tests/particle_test.f90 index 0042082b6..8bbc19a4c 100644 --- a/ParticleObjects/Tests/particle_test.f90 +++ b/ParticleObjects/Tests/particle_test.f90 @@ -1,5 +1,6 @@ module particle_test use numPrecision + use universalVariables use particle_class, only : particle, particleState, P_NEUTRON, P_PHOTON, verifyType use pFUnit_mod @@ -247,6 +248,9 @@ subroutine testMiscAccess(this) @assertEqual(3, cellIdx, 'Cell Index. Level 1.') @assertEqual(1, uniIdx, 'Universe Index. Level 1.') + ! Verify getting velocity + @assertEqual(lightSpeed, this % p_CE % getVelocity()) + end subroutine testMiscAccess !! @@ -306,6 +310,7 @@ subroutine testMovementProcedures(this) @assertEqual(r0_lvl1, r_lvl1, 'Global position after global teleport') @assertTrue(this % p_CE % coords % isAbove(), 'Particle is above geometry') + end subroutine testMovementProcedures !! diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index 69021c389..f2f009f8e 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -5,6 +5,7 @@ module particle_class use genericProcedures use coord_class, only : coordList use RNG_class, only : RNG + use errors_mod, only : fatalError implicit none private @@ -12,7 +13,7 @@ module particle_class !! !! Particle types paramethers !! - integer(shortInt), parameter,public :: P_NEUTRON = 1,& + integer(shortInt), parameter,public :: P_NEUTRON = 1, & P_PHOTON = 2 !! @@ -129,7 +130,7 @@ module particle_class generic :: build => buildCE, buildMG generic :: assignment(=) => particle_fromParticleState - ! Inquiry about coordinates + ! Enquiry about coordinates procedure :: rLocal procedure :: rGlobal procedure :: dirLocal @@ -140,14 +141,17 @@ module particle_class procedure :: matIdx procedure, non_overridable :: getType + ! Enquiry about physical state + procedure :: getVelocity + ! Operations on coordinates - procedure :: moveGlobal - procedure :: moveLocal - procedure :: rotate - procedure :: teleport - procedure :: point - procedure :: takeAboveGeom - procedure :: setMatIdx + procedure :: moveGlobal + procedure :: moveLocal + procedure :: rotate + procedure :: teleport + procedure :: point + procedure :: takeAboveGeom + procedure :: setMatIdx ! Save particle state information procedure, non_overridable :: savePreHistory @@ -427,6 +431,48 @@ pure function getType(self) result(type) end function getType + !! + !! Return the particle velocity in [cm/s] + !! neutronMass: [MeV] + !! lightSpeed: [cm/s] + !! + !! NOTE: + !! The velocities are computed from non-relativistic formula for massive particles. + !! A small error might appear in MeV range (e.g. for fusion applications) + !! + !! Args: + !! None + !! + !! Result: + !! Particle velocity + !! + !! Errors: + !! fatalError if the particle type is neither P_NEUTRON nor P_PHOTON + !! fatalError if the particle is MG + !! + function getVelocity(self) result(velocity) + class(particle), intent(in) :: self + real(defReal) :: velocity + character(100), parameter :: Here = 'getVelocity (particle_class.f90)' + + ! Verify the particle is not MG + if (self % isMG) call fatalError(Here, 'Velocity cannot be calculated for MG particle') + + ! Calculates the velocity for the relevant particle [cm/s] + if (self % type == P_NEUTRON) then + velocity = sqrt(TWO * self % E / neutronMass) * lightSpeed + + elseif (self % type == P_PHOTON) then + velocity = lightSpeed + + else + call fatalError(Here, 'Particle type requested is neither neutron (1) nor photon (2). It is: ' & + & //numToChar(self % type)) + + end if + + end function getVelocity + !!<><><><><><><>><><><><><><><><><><><>><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> !! Particle operations on coordinates procedures !!<><><><><><><>><><><><><><><><><><><>><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> diff --git a/SharedModules/genericProcedures.f90 b/SharedModules/genericProcedures.f90 index 2cbb9d280..04646b2d2 100644 --- a/SharedModules/genericProcedures.f90 +++ b/SharedModules/genericProcedures.f90 @@ -4,7 +4,7 @@ module genericProcedures use numPrecision use openmp_func, only : ompGetMaxThreads - use errors_mod, only: fatalError + use errors_mod, only : fatalError use endfConstants use universalVariables diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index 08a2a76ac..b6ee050d5 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -75,7 +75,8 @@ module universalVariables TRACKING_XS = 3 ! Physical constants - real(defReal), parameter :: neutronMass = 939.5654133_defReal, & ! Neutron mass in MeV (m*c^2) + ! Neutron mass and speed of light in vacuum from from https://physics.nist.gov/cuu/Constants/index.html + real(defReal), parameter :: neutronMass = 939.56542194_defReal, & ! Neutron mass in MeV (m*c^2) lightSpeed = 2.99792458e10_defReal, & ! Light speed in cm/s energyPerFission = 200.0_defReal ! MeV diff --git a/Tallies/TallyResponses/Tests/densityResponse_test.f90 b/Tallies/TallyResponses/Tests/densityResponse_test.f90 index 42b5173ee..a93d0cab2 100644 --- a/Tallies/TallyResponses/Tests/densityResponse_test.f90 +++ b/Tallies/TallyResponses/Tests/densityResponse_test.f90 @@ -1,7 +1,7 @@ module densityResponse_test use numPrecision - use universalVariables, only : lightSpeed + use universalVariables, only : neutronMass, lightSpeed use densityResponse_class, only : densityResponse use particle_class, only : particle, P_NEUTRON, P_PHOTON use dictionary_class, only : dictionary @@ -55,12 +55,13 @@ subroutine densityResponseing(this) ! Test neutron density with different particle energies p % type = P_NEUTRON + p % isMG = .false. p % E = ONE - res = ONE/1.3831592645e+09_defReal + res = ONE / lightSpeed / sqrt(TWO * p % E / neutronMass) @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) p % E = 1.6e-06_defReal - res = ONE/1.7495734571e+06_defReal + res = ONE / lightSpeed / sqrt(TWO * p % E / neutronMass) @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) ! Test photon density @@ -68,11 +69,6 @@ subroutine densityResponseing(this) res = ONE/lightSpeed @assertEqual(res, this % response % get(p, xsData), res*1.0E-9_defReal) - ! Test response for unknown particle type - p % type = 345 - res = ZERO - @assertEqual(res, this % response % get(p, xsData)) - end subroutine densityResponseing end module densityResponse_test diff --git a/Tallies/TallyResponses/densityResponse_class.f90 b/Tallies/TallyResponses/densityResponse_class.f90 index 5fd74d091..be9a33499 100644 --- a/Tallies/TallyResponses/densityResponse_class.f90 +++ b/Tallies/TallyResponses/densityResponse_class.f90 @@ -17,8 +17,9 @@ module densityResponse_class !! !! Returns the inverse of the particle velocity in [cm/s] !! - !! The velocity is calculated from the particle energy for neutrons, and it is - !! the speed of light for photons + !! NOTE: + !! The velocities are computed from non-relativistic formula for massive particles. + !! The small error might appear in MeV range (e.g. for fusion applications) !! !! Interface: !! tallyResponse Interface @@ -29,6 +30,7 @@ module densityResponse_class procedure :: init procedure :: get procedure :: kill + end type densityResponse contains @@ -47,12 +49,7 @@ subroutine init(self, dict) end subroutine init !! - !! Calculates the particle velocity for neutron and photons - !! NOTE: neutronMass: [MeV] - !! lightSpeed: [cm/s] - !! - !! The function returns the inverse of the velocity (response to score particle density) - !! if the particle type is neutron or photon, and zero otherwise + !! Returns the inverse of the particle velocity (response to score particle density) !! !! See tallyResponse_inter for details !! @@ -61,25 +58,9 @@ function get(self, p, xsData) result(val) class(particle), intent(in) :: p class(nuclearDatabase), intent(inout) :: xsData real(defReal) :: val - real(defReal) :: velocity - - ! Initialise response - val = ZERO - - ! Calculates the velocity for the relevant particle [cm/s] - if (p % type == P_NEUTRON) then - velocity = sqrt(TWO * p % E / neutronMass) * lightSpeed - - elseif (p % type == P_PHOTON) then - velocity = lightSpeed - - else - return - - end if - ! Returns the inverse of the velocity - val = ONE / velocity + ! Gets the particle velocity from the particle + val = ONE / p % getVelocity() end function get From 85aa16da043137983210989db5628215ef2ce5ba Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi" Date: Fri, 26 Jul 2024 12:54:17 +0100 Subject: [PATCH 131/133] Implement TMS --- .../collisionProcessor_inter.f90 | 29 +- .../neutronCEimp_class.f90 | 75 ++- .../neutronCEstd_class.f90 | 91 +-- CollisionOperator/scatteringKernels_func.f90 | 86 ++- InputFiles/Benchmarks/BEAVRS/BEAVRS | 382 ++++++------ InputFiles/Benchmarks/BEAVRS/BEAVRS2D | 382 ++++++------ InputFiles/Benchmarks/HoogenboomMartin/HMcore | 12 - InputFiles/Benchmarks/MCNP/BIGTEN | 4 +- InputFiles/Benchmarks/MCNP/Falstaff | 6 +- InputFiles/Benchmarks/MCNP/IEUMF04 | 16 +- InputFiles/Benchmarks/MCNP/Jezebel | 2 +- InputFiles/Benchmarks/MCNP/Jezebel233 | 2 +- InputFiles/Benchmarks/MCNP/Jezebel240 | 2 +- InputFiles/Benchmarks/MCNP/LEUST02 | 4 +- InputFiles/Benchmarks/MCNP/ORNL10 | 4 +- InputFiles/Benchmarks/MCNP/ORNL11 | 4 +- InputFiles/Benchmarks/MCNP/PNL2 | 2 +- InputFiles/Benchmarks/MCNP/PUMF11 | 4 +- InputFiles/Benchmarks/MCNP/SB212 | 8 +- InputFiles/Benchmarks/MCNP/Tinkertoy2 | 10 +- InputFiles/Benchmarks/MCNP/U233MF05 | 4 +- .../Benchmarks/SourceConvergence/checkerboard | 7 +- .../Tests/aceNeutronDatabase_iTest.f90 | 7 +- .../Tests/thermalScatteringData_iTest.f90 | 7 +- .../Tests/urrProbabilityTables_iTest.f90 | 7 +- .../aceDatabase/aceNeutronDatabase_class.f90 | 564 +++++++++++++----- .../aceDatabase/aceNeutronNuclide_class.f90 | 129 +++- .../ceNeutronData/ceNeutronCache_mod.f90 | 47 +- .../ceNeutronData/ceNeutronDatabase_inter.f90 | 116 +++- .../ceNeutronData/ceNeutronMaterial_class.f90 | 350 ++++++++--- .../ceNeutronData/ceNeutronNuclide_inter.f90 | 44 +- NuclearData/materialMenu_mod.f90 | 21 +- .../baseMgNeutronDatabase_class.f90 | 24 +- NuclearData/nuclearDatabase_inter.f90 | 34 +- .../testNeutronDatabase_class.f90 | 18 +- ParticleObjects/particle_class.f90 | 7 +- SharedModules/numPrecision.f90 | 7 +- SharedModules/universalVariables.f90 | 8 +- .../TallyClerks/Tests/collisionClerk_test.f90 | 4 +- .../Tests/keffImplicitClerk_test.f90 | 1 + Tallies/TallyClerks/Tests/mgXsClerk_test.f90 | 2 +- Tallies/TallyClerks/collisionClerk_class.f90 | 47 +- .../collisionProbabilityClerk_class.f90 | 7 +- .../TallyClerks/keffImplicitClerk_class.f90 | 33 +- Tallies/TallyClerks/mgXsClerk_class.f90 | 92 +-- Tallies/TallyClerks/simpleFMClerk_class.f90 | 61 +- .../TallyResponses/macroResponse_class.f90 | 8 +- .../TallyResponses/microResponse_class.f90 | 9 +- .../transportOperatorDT_class.f90 | 3 +- .../transportOperatorHT_class.f90 | 7 +- TransportOperator/transportOperator_inter.f90 | 2 +- docs/User Manual.rst | 55 +- 52 files changed, 1890 insertions(+), 967 deletions(-) diff --git a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 index 466951106..f14c3da75 100644 --- a/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 +++ b/CollisionOperator/CollisionProcessors/collisionProcessor_inter.f90 @@ -26,6 +26,7 @@ module collisionProcessor_inter real(defReal) :: muL = ONE !! Cosine of deflection angle in LAB-frame real(defReal) :: A = ZERO !! Target Mass [Neutron Mass] real(defReal) :: kT = ZERO !! Target temperature [MeV] + real(defReal) :: E = ZERO !! Collision energy (could be relative to target) [MeV] end type @@ -113,25 +114,35 @@ subroutine collide(self, p, tally, thisCycle, nextCycle) class(particleDungeon),intent(inout) :: thisCycle class(particleDungeon),intent(inout) :: nextCycle type(collisionData) :: collDat - character(100),parameter :: Here = ' collide (collisionProcessor.f90)' + logical(defBool) :: virtual + integer(shortInt) :: addCollision + character(100),parameter :: Here = 'collide (collisionProcessor.f90)' ! Load material index into data package collDat % matIdx = p % matIdx() + ! Choose collision nuclide and general type (Scatter, Capture or Fission) + call self % sampleCollision(p, tally, collDat, thisCycle, nextCycle) + + ! In case of a TMS rejection, set collision as virtual + if (collDat % MT == noInteraction) then + virtual = .true. + addCollision = 0 + else + virtual = .false. + addCollision = 1 + end if + ! Report in-collision & save pre-collison state ! Note: the ordering must not be changed between feeding the particle to the tally ! and updating the particle's preCollision state, otherwise this may cause certain ! tallies (e.g., collisionProbability) to return dubious results - - call tally % reportInColl(p, .false.) + call tally % reportInColl(p, virtual) call p % savePreCollision() - ! Choose collision nuclide and general type (Scatter, Capture or Fission) - call self % sampleCollision(p, tally, collDat, thisCycle, nextCycle) - ! Perform implicit treatment - call self % implicit(p, tally, collDat, thisCycle, nextCycle) + if (collDat % MT /= noInteraction) call self % implicit(p, tally, collDat, thisCycle, nextCycle) ! Select physics to be processed based on MT number select case(collDat % MT) @@ -159,13 +170,13 @@ subroutine collide(self, p, tally, thisCycle, nextCycle) call self % cutoffs(p, tally, collDat, thisCycle, nextCycle) ! Update particle collision counter - p % collisionN = p % collisionN + 1 + p % collisionN = p % collisionN + addCollision ! Report out-of-collision call tally % reportOutColl(p, collDat % MT, collDat % muL) ! Report end-of-history if particle was killed - if( p % isDead) then + if (p % isDead) then p % fate = ABS_FATE call tally % reportHist(p) end if diff --git a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 index 89d5a09d7..416d36a2c 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEimp_class.f90 @@ -2,7 +2,7 @@ module neutronCEimp_class use numPrecision use endfConstants - use universalVariables, only : nameUFS, nameWW + use universalVariables, only : nameUFS, nameWW, REJECTED use genericProcedures, only : fatalError, rotateVector, numToChar use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -63,11 +63,11 @@ module neutronCEimp_class !! impGen -> are fission sites generated implicitly? (on by default) !! UFS -> uniform fission sites variance reduction !! maxSplit -> maximum number of splits allowed per particle (default = 1000) - !! thresh_E -> Energy threshold for explicit treatment of target nuclide movement [-]. - !! Target movment is sampled if neutron energy E < kT * thresh_E where + !! threshE -> Energy threshold for explicit treatment of target nuclide movement [-]. + !! Target movement is sampled if neutron energy E < kT * threshE where !! kT is target material temperature in [MeV]. (default = 400.0) - !! thresh_A -> Mass threshold for explicit tratment of target nuclide movement [Mn]. - !! Target movment is sampled if target mass A < thresh_A. (default = 1.0) + !! threshA -> Mass threshold for explicit treatment of target nuclide movement [Mn]. + !! Target movment is sampled if target mass A < threshA. (default = 1.0) !! DBRCeMin -> Minimum energy to which DBRC is applied !! DBRCeMax -> Maximum energy to which DBRC is applied !! splitting -> splits particles above certain weight (on by default) @@ -107,8 +107,8 @@ module neutronCEimp_class real(defReal) :: minWgt real(defReal) :: maxWgt real(defReal) :: avWgt - real(defReal) :: thresh_E - real(defReal) :: thresh_A + real(defReal) :: threshE + real(defReal) :: threshA real(defReal) :: DBRCeMin real(defReal) :: DBRCeMax integer(shortInt) :: maxSplit @@ -121,6 +121,7 @@ module neutronCEimp_class logical(defBool) :: implicitSites ! Generates fission sites on every fissile collision logical(defBool) :: uniFissSites + ! Variance reduction requirements type(weightWindowsField), pointer :: weightWindowsMap contains @@ -166,8 +167,8 @@ subroutine init(self, dict) call dict % getOrDefault(self % maxE,'maxEnergy',20.0_defReal) ! Thermal scattering kernel thresholds - call dict % getOrDefault(self % thresh_E, 'energyThreshold', 400.0_defReal) - call dict % getOrDefault(self % thresh_A, 'massThreshold', 1.0_defReal) + call dict % getOrDefault(self % threshE, 'energyThreshold', 400.0_defReal) + call dict % getOrDefault(self % threshA, 'massThreshold', 1.0_defReal) ! Obtain settings for variance reduction call dict % getOrDefault(self % weightWindows,'weightWindows', .false.) @@ -185,8 +186,8 @@ subroutine init(self, dict) if( self % minE < ZERO ) call fatalError(Here,'-ve minEnergy') if( self % maxE < ZERO ) call fatalError(Here,'-ve maxEnergy') if( self % minE >= self % maxE) call fatalError(Here,'minEnergy >= maxEnergy') - if( self % thresh_E < 0) call fatalError(Here,' -ve energyThreshold') - if( self % thresh_A < 0) call fatalError(Here,' -ve massThreshold') + if( self % threshE < 0) call fatalError(Here,' -ve energyThreshold') + if( self % threshA < 0) call fatalError(Here,' -ve massThreshold') ! DBRC energy limits call dict % getOrDefault(self % DBRCeMin,'DBRCeMin', (1.0E-8_defReal)) @@ -246,13 +247,19 @@ subroutine sampleCollision(self, p, tally, collDat, thisCycle, nextCycle) if(.not.associated(self % mat)) call fatalError(Here, 'Material is not ceNeutronMaterial') ! Select collision nuclide - collDat % nucIdx = self % mat % sampleNuclide(p % E, p % pRNG) + call self % mat % sampleNuclide(p % E, p % pRNG, collDat % nucIdx, collDat % E) + + ! If nuclide was rejected in TMS loop return to tracking + if (collDat % nucIdx == REJECTED) then + collDat % MT = noInteraction + return + end if self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + if (.not.associated(self % mat)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Select Main reaction channel - call self % nuc % getMicroXSs(microXss, p % E, p % pRNG) + call self % nuc % getMicroXSs(microXss, collDat % E, p % pRNG) r = p % pRNG % get() collDat % MT = microXss % invert(r) @@ -281,13 +288,17 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) ! Generate fission sites if nuclide is fissile fiss_and_implicit = self % nuc % isFissile() .and. self % implicitSites + if (fiss_and_implicit) then + ! Obtain required data wgt = p % w ! Current weight k_eff = p % k_eff ! k_eff for normalisation rand1 = p % pRNG % get() ! Random number to sample sites - call self % nuc % getMicroXSs(microXSs, p % E, p % pRNG) + ! Retrieve cross section at the energy used for reaction sampling + call self % nuc % getMicroXSs(microXSs, collDat % E, p % pRNG) + sig_nufiss = microXSs % nuFission sig_tot = microXSs % total @@ -339,19 +350,23 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) ! Perform implicit absorption if (self % implicitAbsorption) then - if(.not.fiss_and_implicit) then - call self % nuc % getMicroXSs(microXSs, p % E, p % pRNG) + + if (.not.fiss_and_implicit) then + call self % nuc % getMicroXSs(microXSs, collDat % E, p % pRNG) end if + sig_scatter = microXSs % elasticScatter + microXSs % inelasticScatter sig_tot = microXSs % total p % w = p % w * sig_scatter/sig_tot ! Sample between elastic and inelastic totalElastic = microXSs % elasticScatter + microXSs % inelasticScatter + if (p % pRNG % get() < microXSs % elasticScatter/totalElastic) then collDat % MT = N_N_elastic else collDat % MT = N_N_inelastic end if + end if end subroutine implicit @@ -391,12 +406,15 @@ subroutine fission(self, p, tally, collDat, thisCycle, nextCycle) character(100),parameter :: Here = 'fission (neutronCEimp_class.f90)' if (.not.self % implicitSites) then + ! Obtain required data wgt = p % w ! Current weight k_eff = p % k_eff ! k_eff for normalisation rand1 = p % pRNG % get() ! Random number to sample sites - call self % nuc % getMicroXSs(microXSs, p % E, p % pRNG) + ! Retrieve cross section at the energy used for reaction sampling + call self % nuc % getMicroXSs(microXSs, collDat % E, p % pRNG) + sig_nufiss = microXSs % nuFission sig_fiss = microXSs % fission @@ -467,19 +485,28 @@ subroutine elastic(self, p, tally, collDat, thisCycle, nextCycle) logical(defBool) :: isFixed, hasDBRC character(100),parameter :: Here = 'elastic (neutronCEimp_class.f90)' + ! Assess if thermal scattering data is needed or not + if (self % nuc % needsSabEl(p % E)) collDat % MT = N_N_ThermEL + ! Get reaction reac => uncorrelatedReactionCE_CptrCast( self % xsData % getReaction(collDat % MT, collDat % nucIdx)) if(.not.associated(reac)) call fatalError(Here,'Failed to get elastic neutron scatter') ! Scatter particle collDat % A = self % nuc % getMass() - collDat % kT = self % nuc % getkT() + + ! Retrieve kT from either material or nuclide + if (self % mat % useTMS(p % E)) then + collDat % kT = self % mat % kT + else + collDat % kT = self % nuc % getkT() + end if ! Check is DBRC is on hasDBRC = self % nuc % hasDBRC() - isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & - & .and. (collDat % A > self % thresh_A) + isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % threshE) & + & .and. (collDat % A > self % threshA) ! Apply criterion for Free-Gas vs Fixed Target scattering if (.not. reac % inCMFrame()) then @@ -506,7 +533,7 @@ subroutine inelastic(self, p, tally, collDat, thisCycle, nextCycle) character(100),parameter :: Here =' inelastic (neutronCEimp_class.f90)' ! Invert inelastic scattering and Get reaction - collDat % MT = self % nuc % invertInelastic(p % E, p % pRNG) + collDat % MT = self % nuc % invertInelastic(collDat % E, p % pRNG) reac => uncorrelatedReactionCE_CptrCast( self % xsData % getReaction(collDat % MT, collDat % nucIdx)) if(.not.associated(reac)) call fatalError(Here, "Failed to get scattering reaction") @@ -680,7 +707,7 @@ subroutine scatterFromFixed(self, p, collDat, reac) ! Save incident energy E_out = p % E - if( MT == N_N_elastic) then + if (MT == N_N_elastic) then call asymptoticScatter(E_out, mu, collDat % A) else @@ -739,7 +766,7 @@ subroutine scatterFromMoving(self, p, collDat, reac) ! Assign pointer for the 0K nuclide ceNuc0K => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(nucIdx)) - if(.not.associated(ceNuc0K)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + if (.not.associated(ceNuc0K)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Get elastic scattering 0K majorant maj = self % xsData % getScattMicroMajXS(p % E, kT, A, nucIdx) diff --git a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 index e2ddf2f44..e3544b64e 100644 --- a/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 +++ b/CollisionOperator/CollisionProcessors/neutronCEstd_class.f90 @@ -2,6 +2,7 @@ module neutronCEstd_class use numPrecision use endfConstants + use universalVariables, only : REJECTED use genericProcedures, only : fatalError, rotateVector, numToChar use dictionary_class, only : dictionary use RNG_class, only : RNG @@ -31,7 +32,8 @@ module neutronCEstd_class ! Scattering procedures use scatteringKernels_func, only : asymptoticScatter, targetVelocity_constXS, & - asymptoticInelasticScatter, targetVelocity_DBRCXS + asymptoticInelasticScatter, targetVelocity_DBRCXS, & + relativeEnergy_constXS ! Tally interfaces use tallyAdmin_class, only : tallyAdmin @@ -50,11 +52,11 @@ module neutronCEstd_class !! minE -> minimum energy cut-off [MeV] (default = 1.0E-11) !! maxE -> maximum energy. Higher energies are set to maximum (not re-rolled) [MeV] !! (default = 20.0) - !! thresh_E -> Energy threshold for explicit treatment of target nuclide movement [-]. - !! Target movment is sampled if neutron energy E < kT * thresh_E where - !! kT is target material temperature in [MeV]. (default = 400.0) - !! thresh_A -> Mass threshold for explicit tratment of target nuclide movement [Mn]. - !! Target movment is sampled if target mass A < thresh_A. (default = 1.0) + !! threshE -> Energy threshold for explicit treatment of target nuclide movement [-]. + !! Target movement is sampled if neutron energy E < kT * threshE where + !! kT is target material temperature in [MeV]. (default = 400.0) + !! threshA -> Mass threshold for explicit treatment of target nuclide movement [Mn]. + !! Target movement is sampled if target mass A < threshA. (default = 1.0) !! DBRCeMin -> Minimum energy to which DBRC is applied !! DBRCeMax -> Maximum energy to which DBRC is applied !! @@ -77,8 +79,8 @@ module neutronCEstd_class !! Settings - private real(defReal) :: minE real(defReal) :: maxE - real(defReal) :: thresh_E - real(defReal) :: thresh_A + real(defReal) :: threshE + real(defReal) :: threshA real(defReal) :: DBRCeMin real(defReal) :: DBRCeMax @@ -99,6 +101,7 @@ module neutronCEstd_class procedure,private :: scatterFromFixed procedure,private :: scatterFromMoving procedure,private :: scatterInLAB + end type neutronCEstd contains @@ -120,15 +123,15 @@ subroutine init(self, dict) call dict % getOrDefault(self % maxE,'maxEnergy',20.0_defReal) ! Thermal scattering kernel thresholds - call dict % getOrDefault(self % thresh_E, 'energyThreshold', 400.0_defReal) - call dict % getOrDefault(self % thresh_A, 'massThreshold', 1.0_defReal) + call dict % getOrDefault(self % threshE, 'energyThreshold', 400.0_defReal) + call dict % getOrDefault(self % threshA, 'massThreshold', 1.0_defReal) ! Verify settings - if( self % minE < ZERO ) call fatalError(Here,'-ve minEnergy') - if( self % maxE < ZERO ) call fatalError(Here,'-ve maxEnergy') - if( self % minE >= self % maxE) call fatalError(Here,'minEnergy >= maxEnergy') - if( self % thresh_E < 0) call fatalError(Here,' -ve energyThreshold') - if( self % thresh_A < 0) call fatalError(Here,' -ve massThreshold') + if (self % minE < ZERO) call fatalError(Here,'-ve minEnergy') + if (self % maxE < ZERO) call fatalError(Here,'-ve maxEnergy') + if (self % minE >= self % maxE) call fatalError(Here,'minEnergy >= maxEnergy') + if (self % threshE < 0) call fatalError(Here,' -ve energyThreshold') + if (self % threshA < 0) call fatalError(Here,' -ve massThreshold') ! DBRC energy limits call dict % getOrDefault(self % DBRCeMin,'DBRCeMin', (1.0E-8_defReal)) @@ -151,26 +154,32 @@ subroutine sampleCollision(self, p, tally, collDat, thisCycle, nextCycle) character(100),parameter :: Here = 'sampleCollision (neutronCEstd_class.f90)' ! Verify that particle is CE neutron - if(p % isMG .or. p % type /= P_NEUTRON) then + if (p % isMG .or. p % type /= P_NEUTRON) then call fatalError(Here, 'Supports only CE Neutron. Was given MG '//printType(p % type)) end if ! Verify and load nuclear data pointer self % xsData => ndReg_getNeutronCE() - if(.not.associated(self % xsData)) call fatalError(Here, 'There is no active Neutron CE data!') + if (.not.associated(self % xsData)) call fatalError(Here, 'There is no active Neutron CE data!') ! Verify and load material pointer - self % mat => ceNeutronMaterial_CptrCast( self % xsData % getMaterial( p % matIdx())) - if(.not.associated(self % mat)) call fatalError(Here, 'Material is not ceNeutronMaterial') + self % mat => ceNeutronMaterial_CptrCast(self % xsData % getMaterial(p % matIdx())) + if (.not.associated(self % mat)) call fatalError(Here, 'Material is not ceNeutronMaterial') ! Select collision nuclide - collDat % nucIdx = self % mat % sampleNuclide(p % E, p % pRNG) + call self % mat % sampleNuclide(p % E, p % pRNG, collDat % nucIdx, collDat % E) + + ! If nuclide was rejected in TMS loop return to tracking + if (collDat % nucIdx == REJECTED) then + collDat % MT = noInteraction + return + end if self % nuc => ceNeutronNuclide_CptrCast(self % xsData % getNuclide(collDat % nucIdx)) - if(.not.associated(self % mat)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + if (.not.associated(self % nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') ! Select Main reaction channel - call self % nuc % getMicroXSs(microXss, p % E, p % pRNG) + call self % nuc % getMicroXSs(microXss, collDat % E, p % pRNG) r = p % pRNG % get() collDat % MT = microXss % invert(r) @@ -196,14 +205,17 @@ subroutine implicit(self, p, tally, collDat, thisCycle, nextCycle) character(100),parameter :: Here = 'implicit (neutronCEstd_class.f90)' ! Generate fission sites if nuclide is fissile - if ( self % nuc % isFissile()) then + if (self % nuc % isFissile()) then + ! Obtain required data wgt = p % w ! Current weight w0 = p % preHistory % wgt ! Starting weight k_eff = p % k_eff ! k_eff for normalisation rand1 = p % pRNG % get() ! Random number to sample sites - call self % nuc % getMicroXSs(microXSs, p % E, p % pRNG) + ! Retrieve cross section at the energy used for reaction sampling + call self % nuc % getMicroXSs(microXSs, collDat % E, p % pRNG) + sig_nufiss = microXSs % nuFission sig_tot = microXSs % total @@ -294,19 +306,28 @@ subroutine elastic(self, p, tally, collDat, thisCycle, nextCycle) logical(defBool) :: isFixed, hasDBRC character(100),parameter :: Here = 'elastic (neutronCEstd_class.f90)' + ! Assess if thermal scattering data is needed or not + if (self % nuc % needsSabEl(p % E)) collDat % MT = N_N_ThermEL + ! Get reaction reac => uncorrelatedReactionCE_CptrCast( self % xsData % getReaction(collDat % MT, collDat % nucIdx)) - if(.not.associated(reac)) call fatalError(Here,'Failed to get elastic neutron scatter') + if (.not.associated(reac)) call fatalError(Here,'Failed to get elastic neutron scatter') ! Scatter particle collDat % A = self % nuc % getMass() - collDat % kT = self % nuc % getkT() + + ! Retrieve kT from either material or nuclide + if (self % mat % useTMS(p % E)) then + collDat % kT = self % mat % kT + else + collDat % kT = self % nuc % getkT() + end if ! Check is DBRC is on hasDBRC = self % nuc % hasDBRC() - isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % thresh_E) & - & .and. (collDat % A > self % thresh_A) + isFixed = (.not. hasDBRC) .and. (p % E > collDat % kT * self % threshE) & + & .and. (collDat % A > self % threshA) ! Apply criterion for Free-Gas vs Fixed Target scattering if (.not. reac % inCMFrame()) then @@ -332,10 +353,10 @@ subroutine inelastic(self, p, tally, collDat, thisCycle, nextCycle) class(uncorrelatedReactionCE), pointer :: reac character(100),parameter :: Here =' inelastic (neutronCEstd_class.f90)' - ! Invert inelastic scattering and Get reaction - collDat % MT = self % nuc % invertInelastic(p % E, p % pRNG) - reac => uncorrelatedReactionCE_CptrCast( self % xsData % getReaction(collDat % MT, collDat % nucIdx)) - if(.not.associated(reac)) call fatalError(Here, "Failed to get scattering reaction") + ! Invert inelastic scattering and get reaction + collDat % MT = self % nuc % invertInelastic(collDat % E, p % pRNG) + reac => uncorrelatedReactionCE_CptrCast(self % xsData % getReaction(collDat % MT, collDat % nucIdx)) + if (.not.associated(reac)) call fatalError(Here, "Failed to get scattering reaction") ! Scatter particle if (reac % inCMFrame()) then @@ -402,15 +423,15 @@ subroutine scatterFromFixed(self, p, collDat, reac) integer(shortInt) :: MT ! Read data - MT = collDat % MT + MT = collDat % MT - ! Sample mu , phi and outgoing energy + ! Sample mu, phi and outgoing energy call reac % sampleOut(mu, phi, E_outCM, p % E, p % pRNG) ! Save incident energy E_out = p % E - if( MT == N_N_elastic) then + if (MT == N_N_elastic) then call asymptoticScatter(E_out, mu, collDat % A) else call asymptoticInelasticScatter(E_out, mu, E_outCM, collDat % A) diff --git a/CollisionOperator/scatteringKernels_func.f90 b/CollisionOperator/scatteringKernels_func.f90 index 400424fbe..c80df4afb 100644 --- a/CollisionOperator/scatteringKernels_func.f90 +++ b/CollisionOperator/scatteringKernels_func.f90 @@ -12,9 +12,11 @@ module scatteringKernels_func private public :: asymptoticScatter + public :: asymptoticInelasticScatter public :: targetVelocity_constXS public :: targetVelocity_DBRCXS - public :: asymptoticInelasticScatter + public :: relativeEnergy_constXS + public :: dopplerCorrectionFactor private :: sample_x2expx2 private :: sample_x3expx2 @@ -113,7 +115,7 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) Y = sqrt(A*E/kT) ! Calculate threshold factor alpha - alpha = 2.0/(Y*sqrt(PI)+2.0) + alpha = TWO / (Y * SQRT_PI + TWO) rejectionLoop: do @@ -125,9 +127,9 @@ function targetVelocity_constXS(E,dir,A,kT,rand) result (V_t) end do rejectionLoop - ! Calculate azimithal angle for target and obtain target direction + ! Calculate azimuthal angle for target and obtain target direction r1 = rand % get() - phi = 2.0 *PI * r1 + phi = TWO * PI * r1 V_t = rotateVector(dir, mu, phi) @@ -164,7 +166,7 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) ! Calculate threshold factor alpha ! In MCNP, alpha is p1 - alpha = 2.0 / (Y * sqrt(PI) + 2.0) + alpha = TWO / (Y * SQRT_PI + TWO) rejectionLoop: do @@ -191,7 +193,7 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) end do rejectionLoop - ! Calculate azimithal angle for target and obtain target direction + ! Calculate azimuthal angle for target and obtain target direction r2 = rand % get() phi = 2.0 * PI * r2 @@ -202,6 +204,73 @@ function targetVelocity_DBRCXS(nuc, E, dir, A, kT, rand, tempMaj) result (V_t) end function targetVelocity_DBRCXS + !! + !! Function that returns a sample of target frame neutron energy using constant XS approximation + !! V_t is a vector. The velocity is scaled by a factor sqrt(Mn/2) where Mn is mass of a neutron + !! so that V_t*V_t=E_t with E_t beeing kinetic energy of a NEUTRON traveling with TARGET VELOCITY + !! (note that it is not a kinetic energy of the target). + !! + function relativeEnergy_constXS(E, A, kT, rand) result(relE) + real(defReal), intent(in) :: E + real(defReal), intent(in) :: A + real(defReal), intent(in) :: kT + class(RNG), intent(inout) :: rand + logical(defBool) :: accept + real(defReal) :: alpha, mu + real(defReal) :: X, Y + real(defReal) :: relV, relE + + ! Calculate neutron Y = beta *V_n + ! beta = sqrt(A*Mn/2kT). Note velocity scaling by sqrt(Mn/2). + Y = sqrt(A*E/kT) + + ! Calculate threshold factor alpha + alpha = TWO / (Y * SQRT_PI + TWO) + + rejectionLoop: do + + ! Sample velocity and calculate angle and acceptance probability + call sample_targetVelocity(X, accept, relV, mu, rand, Y, alpha) + + ! Accept or reject mu + if (accept) exit rejectionLoop + + end do rejectionLoop + + ! Relative energy + relE = (relV**2 * kT / A) + + end function relativeEnergy_constXS + + !! + !! Returns the Doppler Broadening low energy correction factor. When performing Doppler + !! broadening (e.g., TMS), this is multiplied to the cross sections at the base temperature + !! to give the effective cross section. + !! + !! Common notation for this constant is g_E(E, A, kT) or g(v, A, kT). + !! + !! The energy Limits are taken from Serpent 2.1.31 + !! + function dopplerCorrectionFactor(E, A, kT) result(g) + real(defReal), intent(in) :: E + real(defReal), intent(in) :: A + real(defReal), intent(in) :: kT + real(defReal) :: alpha, invAlph + real(defReal) :: g + + alpha = sqrt(A * E / kT) + + invAlph = ONE / alpha + + if (alpha > 250.0_defReal) then + g = ONE + else if (alpha > 2.568_defReal) then + g = ONE + HALF * invAlph * invAlph + else + g = (ONE + HALF * invAlph * invAlph) * erf(alpha) + exp(-alpha * alpha) * invAlph / SQRT_PI + end if + + end function dopplerCorrectionFactor !! !! Helper function to sample x^2 * exp( - x^2) probability distribution @@ -295,10 +364,10 @@ subroutine sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) end if ! Sample polar angle of target velocity wrt. neutron direction - mu = 2.0 * r2 - 1.0; + mu = TWO * r2 - ONE; ! Calculate relative velocity between neutron and target - rel_v = sqrt(Y * Y + X * X - 2.0 * X * Y * mu) + rel_v = sqrt(Y * Y + X * X - TWO * X * Y * mu) ! Calculate Acceptance Propability P_acc = rel_v / (Y + X) @@ -308,5 +377,4 @@ subroutine sample_targetVelocity(X, accept, rel_v, mu, rand, Y, alpha) end subroutine sample_targetVelocity - end module scatteringKernels_func diff --git a/InputFiles/Benchmarks/BEAVRS/BEAVRS b/InputFiles/Benchmarks/BEAVRS/BEAVRS index 3c7cb89de..54ac5f845 100644 --- a/InputFiles/Benchmarks/BEAVRS/BEAVRS +++ b/InputFiles/Benchmarks/BEAVRS/BEAVRS @@ -1954,7 +1954,7 @@ nuclearData { // but are not available in the JEFF-3.11 data library Air { - temp 566; + !temp 566; composition { 18036.06 7.8730E-09; 18038.06 1.4844E-09; @@ -1972,27 +1972,27 @@ nuclearData { SS304 { temp 566; composition { - 24050.06 7.6778E-04; - 24052.06 1.4806E-02; - 24053.06 1.6789E-03; - 24054.06 4.1791E-04; - 26054.06 3.4620E-03; - 26056.06 5.4345E-02; - 26057.06 1.2551E-03; - 26058.06 1.6703E-04; - 25055.06 1.7604E-03; - 28058.06 5.6089E-03; - 28060.06 2.1605E-03; - 28061.06 9.3917E-05; - 28062.06 2.9945E-04; - 28064.06 7.6261E-05; - 14028.06 9.5281E-04; - 14029.06 4.8381E-05; - 14030.06 3.1893E-05; } + 24050.03 7.6778E-04; + 24052.03 1.4806E-02; + 24053.03 1.6789E-03; + 24054.03 4.1791E-04; + 26054.03 3.4620E-03; + 26056.03 5.4345E-02; + 26057.03 1.2551E-03; + 26058.03 1.6703E-04; + 25055.03 1.7604E-03; + 28058.03 5.6089E-03; + 28060.03 2.1605E-03; + 28061.03 9.3917E-05; + 28062.03 2.9945E-04; + 28064.03 7.6261E-05; + 14028.03 9.5281E-04; + 14029.03 4.8381E-05; + 14030.03 3.1893E-05; } } Helium { - temp 566; + !temp 566; composition { 2003.06 4.8089E-10; 2004.06 2.4044E-04; } @@ -2001,20 +2001,20 @@ nuclearData { BorosilicateGlass { temp 566; composition { - 13027.06 1.7352E-03; - 5010.06 9.6506E-04; - 5011.06 3.9189E-03; - 8016.06 4.6514E-02; - 8017.06 1.7671E-05; - //8018.06 9.3268E-05; - 14028.06 1.6926E-02; - 14029.06 8.5944E-04; - 14030.06 5.6654E-04; } + 13027.03 1.7352E-03; + 5010.03 9.6506E-04; + 5011.03 3.9189E-03; + 8016.03 4.6514E-02; + 8017.03 1.7671E-05; + //8018.03 9.3268E-05; + 14028.03 1.6926E-02; + 14029.03 8.5944E-04; + 14030.03 5.6654E-04; } } Water { - temp 566; - moder {1001.06 lwj3.11; } + !temp 566; + moder {1001.03 lwj3.11; } composition { 5010.06 7.9714E-06; 5011.06 3.2247E-05; @@ -2029,58 +2029,58 @@ nuclearData { Zircaloy { temp 566; composition { - 24050.06 3.2962E-06; - 24052.06 6.3564E-05; - 24053.06 7.2076E-06; - 24054.06 1.7941E-06; - 26054.06 8.6698E-06; - 26056.06 1.3610E-04; - 26057.06 3.1431E-06; - 26058.06 4.1829E-07; - 8016.06 3.0744E-04; - 8017.06 1.1680E-07; - //8018.06 6.1648E-07; - 50112.06 4.6735E-06; - 50114.06 3.1799E-06; - 50115.06 1.6381E-06; - 50116.06 7.0055E-05; - 50117.06 3.7003E-05; - 50118.06 1.1669E-04; - 50119.06 4.1387E-05; - 50120.06 1.5697E-04; - 50122.06 2.2308E-05; - 50124.06 2.7897E-05; - 40090.06 2.1828E-02; - 40091.06 4.7601E-03; - 40092.06 7.2759E-03; - 40094.06 7.3734E-03; - 40096.06 1.1879E-03; } + 24050.03 3.2962E-06; + 24052.03 6.3564E-05; + 24053.03 7.2076E-06; + 24054.03 1.7941E-06; + 26054.03 8.6698E-06; + 26056.03 1.3610E-04; + 26057.03 3.1431E-06; + 26058.03 4.1829E-07; + 8016.03 3.0744E-04; + 8017.03 1.1680E-07; + //8018.03 6.1648E-07; + 50112.03 4.6735E-06; + 50114.03 3.1799E-06; + 50115.03 1.6381E-06; + 50116.03 7.0055E-05; + 50117.03 3.7003E-05; + 50118.03 1.1669E-04; + 50119.03 4.1387E-05; + 50120.03 1.5697E-04; + 50122.03 2.2308E-05; + 50124.03 2.7897E-05; + 40090.03 2.1828E-02; + 40091.03 4.7601E-03; + 40092.03 7.2759E-03; + 40094.03 7.3734E-03; + 40096.03 1.1879E-03; } } Inconel{ temp 566; composition { - 24050.06 7.8239E-04; - 24052.06 1.5088E-02; - 24053.06 1.7108E-03; - 24054.06 4.2586E-04; - 26054.06 1.4797E-03; - 26056.06 2.3229E-02; - 26057.06 5.3645E-04; - 26058.06 7.1392E-05; - 25055.06 7.8201E-04; - 28058.06 2.9320E-02; - 28060.06 1.1294E-02; - 28061.06 4.9094E-04; - 28062.06 1.5653E-03; - 28064.06 3.9864E-04; - 14028.06 5.6757E-04; - 14029.06 2.8820E-05; - 14030.06 1.8998E-05; } + 24050.03 7.8239E-04; + 24052.03 1.5088E-02; + 24053.03 1.7108E-03; + 24054.03 4.2586E-04; + 26054.03 1.4797E-03; + 26056.03 2.3229E-02; + 26057.03 5.3645E-04; + 26058.03 7.1392E-05; + 25055.03 7.8201E-04; + 28058.03 2.9320E-02; + 28060.03 1.1294E-02; + 28061.03 4.9094E-04; + 28062.03 1.5653E-03; + 28064.03 3.9864E-04; + 14028.03 5.6757E-04; + 14029.03 2.8820E-05; + 14030.03 1.8998E-05; } } B4C{ - temp 566; + !temp 566; composition { 5010.06 1.5206E-02; 5011.06 6.1514E-02; @@ -2092,75 +2092,75 @@ nuclearData { Ag-In-Cd{ temp 566; composition { - 47107.06 2.3523E-02; - 47109.06 2.1854E-02; - 48106.06 3.3882E-05; - 48108.06 2.4166E-05; - 48110.06 3.3936E-04; - 48111.06 3.4821E-04; - 48112.06 6.5611E-04; - 48113.06 3.3275E-04; - 48114.06 7.8252E-04; - 48116.06 2.0443E-04; - 49113.06 3.4219E-04; - 49115.06 7.6511E-03; } + 47107.03 2.3523E-02; + 47109.03 2.1854E-02; + 48106.03 3.3882E-05; + 48108.03 2.4166E-05; + 48110.03 3.3936E-04; + 48111.03 3.4821E-04; + 48112.03 6.5611E-04; + 48113.03 3.3275E-04; + 48114.03 7.8252E-04; + 48116.03 2.0443E-04; + 49113.03 3.4219E-04; + 49115.03 7.6511E-03; } } //mox fuel used UO2-16 { temp 566; composition { - 8016.06 4.5897E-02; - 8017.06 1.7436E-05; - //8018.06 9.2032E-05; - 92234.06 3.0131E-06; - 92235.06 3.7503E-04; - 92238.06 2.2625E-02;} + 8016.03 4.5897E-02; + 8017.03 1.7436E-05; + //8018.03 9.2032E-05; + 92234.03 3.0131E-06; + 92235.03 3.7503E-04; + 92238.03 2.2625E-02;} } UO2-24 { temp 566; composition { - 8016.06 4.5830E-02; - 8017.06 1.7411E-05; - //8018.06 9.1898E-05; - 92234.06 4.4842E-06; - 92235.06 5.5814E-04; - 92238.06 2.2407E-02;} + 8016.03 4.5830E-02; + 8017.03 1.7411E-05; + //8018.03 9.1898E-05; + 92234.03 4.4842E-06; + 92235.03 5.5814E-04; + 92238.03 2.2407E-02;} } UO2-31 { temp 566; composition { - 8016.06 4.5853E-02; - 8017.06 1.7420E-05; - //8018.06 9.1942E-05; - 92234.06 5.7987E-06; - 92235.06 7.2175E-04; - 92238.06 2.2253E-02;} + 8016.03 4.5853E-02; + 8017.03 1.7420E-05; + //8018.03 9.1942E-05; + 92234.03 5.7987E-06; + 92235.03 7.2175E-04; + 92238.03 2.2253E-02;} } UO2-32 { temp 566; composition { - 8016.06 4.6029E-02; - 8017.06 1.7487E-05; - //8018.06 9.2296E-05; - 92234.06 5.9959E-06; - 92235.06 7.4630E-04; - 92238.06 2.2317E-02; + 8016.03 4.6029E-02; + 8017.03 1.7487E-05; + //8018.03 9.2296E-05; + 92234.03 5.9959E-06; + 92235.03 7.4630E-04; + 92238.03 2.2317E-02; } } UO2-34 { temp 566; composition { - 8016.06 4.6110E-02; - 8017.06 1.7517E-05; - //8018.06 9.2459E-05; - 92234.06 6.4018E-06; - 92235.06 7.9681E-04; - 92238.06 2.2307E-02;} + 8016.03 4.6110E-02; + 8017.03 1.7517E-05; + //8018.03 9.2459E-05; + 92234.03 6.4018E-06; + 92235.03 7.9681E-04; + 92238.03 2.2307E-02;} } // vanadium51 was stated twice in carbonsteel below @@ -2168,92 +2168,92 @@ nuclearData { CarbonSteel { temp 566; composition { - 13027.06 4.3523E-05; - 5010.06 2.5833E-06; - 5011.06 1.0450E-05; - 6012.06 1.0442E-03; - //6013.06 1.1697E-05 ; - 20040.06 1.7043E-05; - 20042.06 1.1375E-07; - 20043.06 2.3734E-08; - 20044.06 3.6673E-07; - 20046.06 7.0322E-10; - 20048.06 3.2875E-08; - 24050.06 1.3738E-05; - 24052.06 2.6493E-04; - 24053.06 3.0041E-05; - 24054.06 7.4778E-06; - 29063.06 1.0223E-04; - 29065.06 4.5608E-05; - 26054.06 4.7437E-03; - 26056.06 7.4465E-02; - 26057.06 1.7197E-03; - 26058.06 2.2886E-04; - 25055.06 6.4126E-04; - 42100.06 2.9814E-05; - 42092.06 4.4822E-05; - 42094.06 2.8110E-05; - 42095.06 4.8567E-05; - 42096.06 5.1015E-05; - 42097.06 2.9319E-05; - 42098.06 7.4327E-05; - 41093.06 5.0559E-06; - 28058.06 4.0862E-04; - 28060.06 1.5740E-04; - 28061.06 6.8420E-06; - 28062.06 2.1815E-05; - 28064.06 5.5557E-06; - 15031.06 3.7913E-05; - 16032.06 3.4808E-05; - 16033.06 2.7420E-07; - 16034.06 1.5368E-06; - 16036.06 5.3398E-09; - 14028.06 6.1702E-04; - 14029.06 3.1330E-05; - 14030.06 2.0653E-05; - 22046.06 1.2144E-06; - 22047.06 1.0952E-06; - 22048.06 1.0851E-05; - 22049.06 7.9634E-07; - 22050.06 7.6249E-07; - //23050.06 1.1526E-07; - 23051.06 4.5989E-05; + 13027.03 4.3523E-05; + 5010.03 2.5833E-06; + 5011.03 1.0450E-05; + 6012.03 1.0442E-03; + //6013.03 1.1697E-05 ; + 20040.03 1.7043E-05; + 20042.03 1.1375E-07; + 20043.03 2.3734E-08; + 20044.03 3.6673E-07; + 20046.03 7.0322E-10; + 20048.03 3.2875E-08; + 24050.03 1.3738E-05; + 24052.03 2.6493E-04; + 24053.03 3.0041E-05; + 24054.03 7.4778E-06; + 29063.03 1.0223E-04; + 29065.03 4.5608E-05; + 26054.03 4.7437E-03; + 26056.03 7.4465E-02; + 26057.03 1.7197E-03; + 26058.03 2.2886E-04; + 25055.03 6.4126E-04; + 42100.03 2.9814E-05; + 42092.03 4.4822E-05; + 42094.03 2.8110E-05; + 42095.03 4.8567E-05; + 42096.03 5.1015E-05; + 42097.03 2.9319E-05; + 42098.03 7.4327E-05; + 41093.03 5.0559E-06; + 28058.03 4.0862E-04; + 28060.03 1.5740E-04; + 28061.03 6.8420E-06; + 28062.03 2.1815E-05; + 28064.03 5.5557E-06; + 15031.03 3.7913E-05; + 16032.03 3.4808E-05; + 16033.03 2.7420E-07; + 16034.03 1.5368E-06; + 16036.03 5.3398E-09; + 14028.03 6.1702E-04; + 14029.03 3.1330E-05; + 14030.03 2.0653E-05; + 22046.03 1.2144E-06; + 22047.03 1.0952E-06; + 22048.03 1.0851E-05; + 22049.03 7.9634E-07; + 22050.03 7.6249E-07; + //23050.03 1.1526E-07; + 23051.03 4.5989E-05; } } SupportPlateSS { temp 566; composition { - 24050.06 3.5223E-04; - 24052.06 6.7924E-03; - 24053.06 7.7020E-04; - 24054.06 1.9172E-04; - 26054.06 1.5882E-03; - 26056.06 2.4931E-02; - 26057.06 5.7578E-04; - 26058.06 7.6625E-05; - 25055.06 8.0762E-04; - 28058.06 2.5731E-03; - 28060.06 9.9117E-04; - 28061.06 4.3085E-05; - 28062.06 1.3738E-04; - 28064.06 3.4985E-05; - 14028.06 4.3711E-04; - 14029.06 2.2195E-05; - 14030.06 1.4631E-05;} + 24050.03 3.5223E-04; + 24052.03 6.7924E-03; + 24053.03 7.7020E-04; + 24054.03 1.9172E-04; + 26054.03 1.5882E-03; + 26056.03 2.4931E-02; + 26057.03 5.7578E-04; + 26058.03 7.6625E-05; + 25055.03 8.0762E-04; + 28058.03 2.5731E-03; + 28060.03 9.9117E-04; + 28061.03 4.3085E-05; + 28062.03 1.3738E-04; + 28064.03 3.4985E-05; + 14028.03 4.3711E-04; + 14029.03 2.2195E-05; + 14030.03 1.4631E-05;} } SupportPlateBW { temp 566; - moder {1001.06 lwj3.11; } + moder {1001.03 lwj3.11; } composition { - 5010.06 1.0559E-05; - 5011.06 4.2716E-05; - 1001.06 6.5512E-02; - 1002.06 1.0204E-05; - 8016.06 3.2683E-02; - 8017.06 1.2416E-05; - //8018.06 6.5535E-05; + 5010.03 1.0559E-05; + 5011.03 4.2716E-05; + 1001.03 6.5512E-02; + 1002.03 1.0204E-05; + 8016.03 3.2683E-02; + 8017.03 1.2416E-05; + //8018.03 6.5535E-05; } } diff --git a/InputFiles/Benchmarks/BEAVRS/BEAVRS2D b/InputFiles/Benchmarks/BEAVRS/BEAVRS2D index 5a9bac1d1..441d43e6d 100644 --- a/InputFiles/Benchmarks/BEAVRS/BEAVRS2D +++ b/InputFiles/Benchmarks/BEAVRS/BEAVRS2D @@ -1273,7 +1273,7 @@ nuclearData { ! These are commented out. Air { - temp 566; + !temp 566; composition { 18036.06 7.8730E-09; 18038.06 1.4844E-09; @@ -1291,27 +1291,27 @@ nuclearData { SS304 { temp 566; composition { - 24050.06 7.6778E-04; - 24052.06 1.4806E-02; - 24053.06 1.6789E-03; - 24054.06 4.1791E-04; - 26054.06 3.4620E-03; - 26056.06 5.4345E-02; - 26057.06 1.2551E-03; - 26058.06 1.6703E-04; - 25055.06 1.7604E-03; - 28058.06 5.6089E-03; - 28060.06 2.1605E-03; - 28061.06 9.3917E-05; - 28062.06 2.9945E-04; - 28064.06 7.6261E-05; - 14028.06 9.5281E-04; - 14029.06 4.8381E-05; - 14030.06 3.1893E-05; } + 24050.03 7.6778E-04; + 24052.03 1.4806E-02; + 24053.03 1.6789E-03; + 24054.03 4.1791E-04; + 26054.03 3.4620E-03; + 26056.03 5.4345E-02; + 26057.03 1.2551E-03; + 26058.03 1.6703E-04; + 25055.03 1.7604E-03; + 28058.03 5.6089E-03; + 28060.03 2.1605E-03; + 28061.03 9.3917E-05; + 28062.03 2.9945E-04; + 28064.03 7.6261E-05; + 14028.03 9.5281E-04; + 14029.03 4.8381E-05; + 14030.03 3.1893E-05; } } Helium { - temp 566; + !temp 566; composition { 2003.06 4.8089E-10; 2004.06 2.4044E-04; } @@ -1320,20 +1320,20 @@ nuclearData { BorosilicateGlass { temp 566; composition { - 13027.06 1.7352E-03; - 5010.06 9.6506E-04; - 5011.06 3.9189E-03; - 8016.06 4.6514E-02; - 8017.06 1.7671E-05; - //8018.06 9.3268E-05; - 14028.06 1.6926E-02; - 14029.06 8.5944E-04; - 14030.06 5.6654E-04; } + 13027.03 1.7352E-03; + 5010.03 9.6506E-04; + 5011.03 3.9189E-03; + 8016.03 4.6514E-02; + 8017.03 1.7671E-05; + //8018.03 9.3268E-05; + 14028.03 1.6926E-02; + 14029.03 8.5944E-04; + 14030.03 5.6654E-04; } } Water { - temp 566; - moder {1001.06 lwj3.11; } + !temp 566; + moder {1001.03 lwj3.11; } composition { 5010.06 7.9714E-06; 5011.06 3.2247E-05; @@ -1348,58 +1348,58 @@ nuclearData { Zircaloy { temp 566; composition { - 24050.06 3.2962E-06; - 24052.06 6.3564E-05; - 24053.06 7.2076E-06; - 24054.06 1.7941E-06; - 26054.06 8.6698E-06; - 26056.06 1.3610E-04; - 26057.06 3.1431E-06; - 26058.06 4.1829E-07; - 8016.06 3.0744E-04; - 8017.06 1.1680E-07; - //8018.06 6.1648E-07; - 50112.06 4.6735E-06; - 50114.06 3.1799E-06; - 50115.06 1.6381E-06; - 50116.06 7.0055E-05; - 50117.06 3.7003E-05; - 50118.06 1.1669E-04; - 50119.06 4.1387E-05; - 50120.06 1.5697E-04; - 50122.06 2.2308E-05; - 50124.06 2.7897E-05; - 40090.06 2.1828E-02; - 40091.06 4.7601E-03; - 40092.06 7.2759E-03; - 40094.06 7.3734E-03; - 40096.06 1.1879E-03; } + 24050.03 3.2962E-06; + 24052.03 6.3564E-05; + 24053.03 7.2076E-06; + 24054.03 1.7941E-06; + 26054.03 8.6698E-06; + 26056.03 1.3610E-04; + 26057.03 3.1431E-06; + 26058.03 4.1829E-07; + 8016.03 3.0744E-04; + 8017.03 1.1680E-07; + //8018.03 6.1648E-07; + 50112.03 4.6735E-06; + 50114.03 3.1799E-06; + 50115.03 1.6381E-06; + 50116.03 7.0055E-05; + 50117.03 3.7003E-05; + 50118.03 1.1669E-04; + 50119.03 4.1387E-05; + 50120.03 1.5697E-04; + 50122.03 2.2308E-05; + 50124.03 2.7897E-05; + 40090.03 2.1828E-02; + 40091.03 4.7601E-03; + 40092.03 7.2759E-03; + 40094.03 7.3734E-03; + 40096.03 1.1879E-03; } } Inconel{ temp 566; composition { - 24050.06 7.8239E-04; - 24052.06 1.5088E-02; - 24053.06 1.7108E-03; - 24054.06 4.2586E-04; - 26054.06 1.4797E-03; - 26056.06 2.3229E-02; - 26057.06 5.3645E-04; - 26058.06 7.1392E-05; - 25055.06 7.8201E-04; - 28058.06 2.9320E-02; - 28060.06 1.1294E-02; - 28061.06 4.9094E-04; - 28062.06 1.5653E-03; - 28064.06 3.9864E-04; - 14028.06 5.6757E-04; - 14029.06 2.8820E-05; - 14030.06 1.8998E-05; } + 24050.03 7.8239E-04; + 24052.03 1.5088E-02; + 24053.03 1.7108E-03; + 24054.03 4.2586E-04; + 26054.03 1.4797E-03; + 26056.03 2.3229E-02; + 26057.03 5.3645E-04; + 26058.03 7.1392E-05; + 25055.03 7.8201E-04; + 28058.03 2.9320E-02; + 28060.03 1.1294E-02; + 28061.03 4.9094E-04; + 28062.03 1.5653E-03; + 28064.03 3.9864E-04; + 14028.03 5.6757E-04; + 14029.03 2.8820E-05; + 14030.03 1.8998E-05; } } B4C{ - temp 566; + !temp 566; composition { 5010.06 1.5206E-02; 5011.06 6.1514E-02; @@ -1411,75 +1411,75 @@ nuclearData { Ag-In-Cd{ temp 566; composition { - 47107.06 2.3523E-02; - 47109.06 2.1854E-02; - 48106.06 3.3882E-05; - 48108.06 2.4166E-05; - 48110.06 3.3936E-04; - 48111.06 3.4821E-04; - 48112.06 6.5611E-04; - 48113.06 3.3275E-04; - 48114.06 7.8252E-04; - 48116.06 2.0443E-04; - 49113.06 3.4219E-04; - 49115.06 7.6511E-03; } + 47107.03 2.3523E-02; + 47109.03 2.1854E-02; + 48106.03 3.3882E-05; + 48108.03 2.4166E-05; + 48110.03 3.3936E-04; + 48111.03 3.4821E-04; + 48112.03 6.5611E-04; + 48113.03 3.3275E-04; + 48114.03 7.8252E-04; + 48116.03 2.0443E-04; + 49113.03 3.4219E-04; + 49115.03 7.6511E-03; } } //mox fuel used UO2-16 { temp 566; composition { - 8016.06 4.5897E-02; - 8017.06 1.7436E-05; - //8018.06 9.2032E-05; - 92234.06 3.0131E-06; - 92235.06 3.7503E-04; - 92238.06 2.2625E-02;} + 8016.03 4.5897E-02; + 8017.03 1.7436E-05; + //8018.03 9.2032E-05; + 92234.03 3.0131E-06; + 92235.03 3.7503E-04; + 92238.03 2.2625E-02;} } UO2-24 { temp 566; composition { - 8016.06 4.5830E-02; - 8017.06 1.7411E-05; - //8018.06 9.1898E-05; - 92234.06 4.4842E-06; - 92235.06 5.5814E-04; - 92238.06 2.2407E-02;} + 8016.03 4.5830E-02; + 8017.03 1.7411E-05; + //8018.03 9.1898E-05; + 92234.03 4.4842E-06; + 92235.03 5.5814E-04; + 92238.03 2.2407E-02;} } UO2-31 { temp 566; composition { - 8016.06 4.5853E-02; - 8017.06 1.7420E-05; - //8018.06 9.1942E-05; - 92234.06 5.7987E-06; - 92235.06 7.2175E-04; - 92238.06 2.2253E-02;} + 8016.03 4.5853E-02; + 8017.03 1.7420E-05; + //8018.03 9.1942E-05; + 92234.03 5.7987E-06; + 92235.03 7.2175E-04; + 92238.03 2.2253E-02;} } UO2-32 { temp 566; composition { - 8016.06 4.6029E-02; - 8017.06 1.7487E-05; - //8018.06 9.2296E-05; - 92234.06 5.9959E-06; - 92235.06 7.4630E-04; - 92238.06 2.2317E-02; + 8016.03 4.6029E-02; + 8017.03 1.7487E-05; + //8018.03 9.2296E-05; + 92234.03 5.9959E-06; + 92235.03 7.4630E-04; + 92238.03 2.2317E-02; } } UO2-34 { temp 566; composition { - 8016.06 4.6110E-02; - 8017.06 1.7517E-05; - //8018.06 9.2459E-05; - 92234.06 6.4018E-06; - 92235.06 7.9681E-04; - 92238.06 2.2307E-02;} + 8016.03 4.6110E-02; + 8017.03 1.7517E-05; + //8018.03 9.2459E-05; + 92234.03 6.4018E-06; + 92235.03 7.9681E-04; + 92238.03 2.2307E-02;} } // vanadium51 was stated twice in carbonsteel below @@ -1487,92 +1487,92 @@ nuclearData { CarbonSteel { temp 566; composition { - 13027.06 4.3523E-05; - 5010.06 2.5833E-06; - 5011.06 1.0450E-05; - 6012.06 1.0442E-03; - //6013.06 1.1697E-05 ; - 20040.06 1.7043E-05; - 20042.06 1.1375E-07; - 20043.06 2.3734E-08; - 20044.06 3.6673E-07; - 20046.06 7.0322E-10; - 20048.06 3.2875E-08; - 24050.06 1.3738E-05; - 24052.06 2.6493E-04; - 24053.06 3.0041E-05; - 24054.06 7.4778E-06; - 29063.06 1.0223E-04; - 29065.06 4.5608E-05; - 26054.06 4.7437E-03; - 26056.06 7.4465E-02; - 26057.06 1.7197E-03; - 26058.06 2.2886E-04; - 25055.06 6.4126E-04; - 42100.06 2.9814E-05; - 42092.06 4.4822E-05; - 42094.06 2.8110E-05; - 42095.06 4.8567E-05; - 42096.06 5.1015E-05; - 42097.06 2.9319E-05; - 42098.06 7.4327E-05; - 41093.06 5.0559E-06; - 28058.06 4.0862E-04; - 28060.06 1.5740E-04; - 28061.06 6.8420E-06; - 28062.06 2.1815E-05; - 28064.06 5.5557E-06; - 15031.06 3.7913E-05; - 16032.06 3.4808E-05; - 16033.06 2.7420E-07; - 16034.06 1.5368E-06; - 16036.06 5.3398E-09; - 14028.06 6.1702E-04; - 14029.06 3.1330E-05; - 14030.06 2.0653E-05; - 22046.06 1.2144E-06; - 22047.06 1.0952E-06; - 22048.06 1.0851E-05; - 22049.06 7.9634E-07; - 22050.06 7.6249E-07; - //23050.06 1.1526E-07; - 23051.06 4.5989E-05; + 13027.03 4.3523E-05; + 5010.03 2.5833E-06; + 5011.03 1.0450E-05; + 6012.03 1.0442E-03; + //6013.03 1.1697E-05 ; + 20040.03 1.7043E-05; + 20042.03 1.1375E-07; + 20043.03 2.3734E-08; + 20044.03 3.6673E-07; + 20046.03 7.0322E-10; + 20048.03 3.2875E-08; + 24050.03 1.3738E-05; + 24052.03 2.6493E-04; + 24053.03 3.0041E-05; + 24054.03 7.4778E-06; + 29063.03 1.0223E-04; + 29065.03 4.5608E-05; + 26054.03 4.7437E-03; + 26056.03 7.4465E-02; + 26057.03 1.7197E-03; + 26058.03 2.2886E-04; + 25055.03 6.4126E-04; + 42100.03 2.9814E-05; + 42092.03 4.4822E-05; + 42094.03 2.8110E-05; + 42095.03 4.8567E-05; + 42096.03 5.1015E-05; + 42097.03 2.9319E-05; + 42098.03 7.4327E-05; + 41093.03 5.0559E-06; + 28058.03 4.0862E-04; + 28060.03 1.5740E-04; + 28061.03 6.8420E-06; + 28062.03 2.1815E-05; + 28064.03 5.5557E-06; + 15031.03 3.7913E-05; + 16032.03 3.4808E-05; + 16033.03 2.7420E-07; + 16034.03 1.5368E-06; + 16036.03 5.3398E-09; + 14028.03 6.1702E-04; + 14029.03 3.1330E-05; + 14030.03 2.0653E-05; + 22046.03 1.2144E-06; + 22047.03 1.0952E-06; + 22048.03 1.0851E-05; + 22049.03 7.9634E-07; + 22050.03 7.6249E-07; + //23050.03 1.1526E-07; + 23051.03 4.5989E-05; } } SupportPlateSS { temp 566; composition { - 24050.06 3.5223E-04; - 24052.06 6.7924E-03; - 24053.06 7.7020E-04; - 24054.06 1.9172E-04; - 26054.06 1.5882E-03; - 26056.06 2.4931E-02; - 26057.06 5.7578E-04; - 26058.06 7.6625E-05; - 25055.06 8.0762E-04; - 28058.06 2.5731E-03; - 28060.06 9.9117E-04; - 28061.06 4.3085E-05; - 28062.06 1.3738E-04; - 28064.06 3.4985E-05; - 14028.06 4.3711E-04; - 14029.06 2.2195E-05; - 14030.06 1.4631E-05;} + 24050.03 3.5223E-04; + 24052.03 6.7924E-03; + 24053.03 7.7020E-04; + 24054.03 1.9172E-04; + 26054.03 1.5882E-03; + 26056.03 2.4931E-02; + 26057.03 5.7578E-04; + 26058.03 7.6625E-05; + 25055.03 8.0762E-04; + 28058.03 2.5731E-03; + 28060.03 9.9117E-04; + 28061.03 4.3085E-05; + 28062.03 1.3738E-04; + 28064.03 3.4985E-05; + 14028.03 4.3711E-04; + 14029.03 2.2195E-05; + 14030.03 1.4631E-05;} } SupportPlateBW { temp 566; - moder {1001.06 lwj3.11; } + moder {1001.03 lwj3.11; } composition { - 5010.06 1.0559E-05; - 5011.06 4.2716E-05; - 1001.06 6.5512E-02; - 1002.06 1.0204E-05; - 8016.06 3.2683E-02; - 8017.06 1.2416E-05; - //8018.06 6.5535E-05; + 5010.03 1.0559E-05; + 5011.03 4.2716E-05; + 1001.03 6.5512E-02; + 1002.03 1.0204E-05; + 8016.03 3.2683E-02; + 8017.03 1.2416E-05; + //8018.03 6.5535E-05; } } diff --git a/InputFiles/Benchmarks/HoogenboomMartin/HMcore b/InputFiles/Benchmarks/HoogenboomMartin/HMcore index b57d995ca..1ab1e93fd 100644 --- a/InputFiles/Benchmarks/HoogenboomMartin/HMcore +++ b/InputFiles/Benchmarks/HoogenboomMartin/HMcore @@ -289,7 +289,6 @@ materials { UOXfuel { - temp 16486; composition { 92234.03 4.9476e-6; 92235.03 4.8218e-4; @@ -328,7 +327,6 @@ UOXfuel { } Zrcladding { - temp 31628; composition { 40090.03 0.019578; 40091.03 0.0042689; @@ -338,7 +336,6 @@ Zrcladding { } coldwater { - temp 45286; moder { 1001.03 lwj3.00; } composition { 1001.03 0.04938; @@ -350,7 +347,6 @@ coldwater { hotwater { - temp 46865; moder { 1001.03 lwj3.00; } composition { 1001.03 0.04404; @@ -363,7 +359,6 @@ hotwater { reactorvessel { - temp 51694; composition { 26054.03 4.79006E-03; 26056.03 7.5184E-02; @@ -397,7 +392,6 @@ reactorvessel { reflectorbottom { - temp 56982; moder { 1001.03 lwj3.00; } composition { 1001.03 2.4886E-02; @@ -426,7 +420,6 @@ reflectorbottom { reflectortop { - temp 54357; moder { 1001.03 lwj3.00; } composition { 1001.03 2.2196E-02; @@ -455,7 +448,6 @@ reflectortop { coreplate { - temp 54687; moder { 1001.03 lwj3.00; } composition { 1001.03 4.9773E-03; @@ -483,7 +475,6 @@ coreplate { } nozzlebottom { - temp 87648; moder { 1001.03 lwj3.00; } composition { 1001.03 3.733E-2; @@ -512,7 +503,6 @@ nozzlebottom { nozzletop { - temp 87064; moder { 1001.03 lwj3.00; } composition { 1001.03 3.7733E-2; @@ -540,7 +530,6 @@ nozzletop { } FAbottom { - temp 45034; moder { 1001.03 lwj3.00; } composition { 1001.03 2.986E-02; @@ -556,7 +545,6 @@ FAbottom { } FAtop { - temp 43053; moder { 1001.03 lwj3.00; } composition { 1001.03 3.107E-02; diff --git a/InputFiles/Benchmarks/MCNP/BIGTEN b/InputFiles/Benchmarks/MCNP/BIGTEN index 777b15685..3f7aaba13 100644 --- a/InputFiles/Benchmarks/MCNP/BIGTEN +++ b/InputFiles/Benchmarks/MCNP/BIGTEN @@ -74,7 +74,7 @@ nuclearData { materials { core { - temp 293; + !temp 293; composition { 92234.03 4.8416E-5; 92235.03 4.8151E-3; @@ -83,7 +83,7 @@ nuclearData { } } refl { - temp 293; + !temp 293; composition { 92234.03 2.8672E-7; 92235.03 1.0058E-4; diff --git a/InputFiles/Benchmarks/MCNP/Falstaff b/InputFiles/Benchmarks/MCNP/Falstaff index bade833ed..b41a6f322 100644 --- a/InputFiles/Benchmarks/MCNP/Falstaff +++ b/InputFiles/Benchmarks/MCNP/Falstaff @@ -74,7 +74,7 @@ nuclearData { materials { solution { - temp 293; + !temp 293; composition { 92232.03 0.000000045608; 92233.03 0.0022379; @@ -88,7 +88,7 @@ materials { moder {01001.03 hh2o.04; } } steel { - temp 293; + !temp 293; composition { 26000.03 0.061248; 24000.03 0.016678; @@ -96,7 +96,7 @@ materials { } } reflector { - temp 293; + !temp 293; composition { 04009.03 0.12161; } diff --git a/InputFiles/Benchmarks/MCNP/IEUMF04 b/InputFiles/Benchmarks/MCNP/IEUMF04 index 554d27119..7f035fca6 100644 --- a/InputFiles/Benchmarks/MCNP/IEUMF04 +++ b/InputFiles/Benchmarks/MCNP/IEUMF04 @@ -88,7 +88,7 @@ nuclearData { layer1 { - temp 293; + !temp 293; composition { 92234.03 1.5926E-4; 92235.03 1.7443E-2; @@ -99,7 +99,7 @@ nuclearData { } } layer2 { - temp 293; + !temp 293; composition { 92234.03 1.5878E-4; 92235.03 1.7415E-2; @@ -110,7 +110,7 @@ nuclearData { } } layer3 { - temp 293; + !temp 293; composition { 92234.03 1.5803E-4; 92235.03 1.7418E-2; @@ -121,7 +121,7 @@ nuclearData { } } layer4 { - temp 293; + !temp 293; composition { 92234.03 1.3423E-4; 92235.03 1.7356E-2; @@ -132,7 +132,7 @@ nuclearData { } } layer5 { - temp 293; + !temp 293; composition { 92234.03 1.6281E-4; 92235.03 1.7417E-2; @@ -143,7 +143,7 @@ nuclearData { } } layer6 { - temp 293; + !temp 293; composition { 92234.03 1.7609E-4; 92235.03 1.7326E-2; @@ -154,7 +154,7 @@ nuclearData { } } layer7 { - temp 293; + !temp 293; composition { 92234.03 1.5156E-4; 92235.03 1.7266E-2; @@ -165,7 +165,7 @@ nuclearData { } } refl { - temp 293; + !temp 293; composition { 06012.03 7.7716E-2; } diff --git a/InputFiles/Benchmarks/MCNP/Jezebel b/InputFiles/Benchmarks/MCNP/Jezebel index 03ec450c0..bedf3ce60 100644 --- a/InputFiles/Benchmarks/MCNP/Jezebel +++ b/InputFiles/Benchmarks/MCNP/Jezebel @@ -76,7 +76,7 @@ materials { fuel { - temp 293; + !temp 293; composition { 94239.03 3.7047E-2; 94240.03 1.7512E-3; diff --git a/InputFiles/Benchmarks/MCNP/Jezebel233 b/InputFiles/Benchmarks/MCNP/Jezebel233 index aa990732a..d6b20c5d8 100644 --- a/InputFiles/Benchmarks/MCNP/Jezebel233 +++ b/InputFiles/Benchmarks/MCNP/Jezebel233 @@ -73,7 +73,7 @@ materials { fuel { - temp 293; + !temp 293; composition { 92233.03 0.046712; 92234.03 0.00059026; diff --git a/InputFiles/Benchmarks/MCNP/Jezebel240 b/InputFiles/Benchmarks/MCNP/Jezebel240 index 600e6761f..d3999f596 100644 --- a/InputFiles/Benchmarks/MCNP/Jezebel240 +++ b/InputFiles/Benchmarks/MCNP/Jezebel240 @@ -76,7 +76,7 @@ materials { fuel { - temp 293; + !temp 293; composition { 94239.03 2.9934E-2; 94240.03 7.8754E-3; diff --git a/InputFiles/Benchmarks/MCNP/LEUST02 b/InputFiles/Benchmarks/MCNP/LEUST02 index 66121dbfd..8ed86030b 100644 --- a/InputFiles/Benchmarks/MCNP/LEUST02 +++ b/InputFiles/Benchmarks/MCNP/LEUST02 @@ -72,7 +72,7 @@ nuclearData { solution { - temp 293; + !temp 293; composition { 92234.03 2.5304E-7; 92235.03 6.1604E-5; @@ -84,7 +84,7 @@ nuclearData { moder {1001.03 hh2o.04; } } aluminium { - temp 293; + !temp 293; composition { 13027.03 5.9699E-2; 14000.03 5.5202E-4; diff --git a/InputFiles/Benchmarks/MCNP/ORNL10 b/InputFiles/Benchmarks/MCNP/ORNL10 index 6a201802e..d4c396646 100644 --- a/InputFiles/Benchmarks/MCNP/ORNL10 +++ b/InputFiles/Benchmarks/MCNP/ORNL10 @@ -73,7 +73,7 @@ materials { solution { - temp 293; + !temp 293; composition { 92233.03 3.9124E-9; 92234.03 4.0905E-7; @@ -87,7 +87,7 @@ materials { moder {1001.03 hh2o.04; } } shell { - temp 293; + !temp 293; composition { 13027.03 5.9881E-2; 14000.03 2.1790E-4; diff --git a/InputFiles/Benchmarks/MCNP/ORNL11 b/InputFiles/Benchmarks/MCNP/ORNL11 index f6651c976..f594aca7f 100644 --- a/InputFiles/Benchmarks/MCNP/ORNL11 +++ b/InputFiles/Benchmarks/MCNP/ORNL11 @@ -73,7 +73,7 @@ materials { solution { - temp 293; + !temp 293; composition { 92233.03 3.3441E-5; 92234.03 5.2503E-7; @@ -87,7 +87,7 @@ materials { moder { 1001.03 hh2o.04; } } shell { - temp 293; + !temp 293; composition { 13027.03 5.9881E-2; 14000.03 2.1790E-4; diff --git a/InputFiles/Benchmarks/MCNP/PNL2 b/InputFiles/Benchmarks/MCNP/PNL2 index ccdb3cea9..3378a518e 100644 --- a/InputFiles/Benchmarks/MCNP/PNL2 +++ b/InputFiles/Benchmarks/MCNP/PNL2 @@ -75,7 +75,7 @@ materials { solution { - temp 293; + !temp 293; composition { 94238.03 2.6153E-8; 94239.03 4.1249E-4; diff --git a/InputFiles/Benchmarks/MCNP/PUMF11 b/InputFiles/Benchmarks/MCNP/PUMF11 index 1d62df2d6..c1d9caade 100644 --- a/InputFiles/Benchmarks/MCNP/PUMF11 +++ b/InputFiles/Benchmarks/MCNP/PUMF11 @@ -74,7 +74,7 @@ materials { fuel { - temp 293; + !temp 293; composition { 94239.03 4.6982E-2; 94240.03 2.5852E-3; @@ -83,7 +83,7 @@ materials { } } water { - temp 293; + !temp 293; composition { 1001.03 6.6766E-2; 08016.03 3.3383E-2; diff --git a/InputFiles/Benchmarks/MCNP/SB212 b/InputFiles/Benchmarks/MCNP/SB212 index ff4c944bc..2a59c5cee 100644 --- a/InputFiles/Benchmarks/MCNP/SB212 +++ b/InputFiles/Benchmarks/MCNP/SB212 @@ -166,7 +166,7 @@ materials { fuel { // 233UO2-ZrO2 - temp 293; + !temp 293; composition { 92233.03 3.9891E-3; 92234.03 6.3690E-5; @@ -177,7 +177,7 @@ materials { } blade { - temp 293; + !temp 293; composition { 26000.03 5.9259E-2; // Fe 24000.03 1.7428E-2; // Cr @@ -188,7 +188,7 @@ materials { } water { - temp 293; + !temp 293; composition { 08016.03 3.3368E-2; 1001.03 6.6735E-2; @@ -197,7 +197,7 @@ materials { } zirc { // Zircaloy - temp 293; + !temp 293; composition { 40000.03 4.2537E-2; // Zr 50000.03 4.9918E-4; // Sn diff --git a/InputFiles/Benchmarks/MCNP/Tinkertoy2 b/InputFiles/Benchmarks/MCNP/Tinkertoy2 index 31aec3479..b79e65c73 100644 --- a/InputFiles/Benchmarks/MCNP/Tinkertoy2 +++ b/InputFiles/Benchmarks/MCNP/Tinkertoy2 @@ -140,7 +140,7 @@ nuclearData { materials { fuel { - temp 293; + !temp 293; composition { 92234.03 4.8271E-4; 92235.03 4.4797E-2; @@ -150,7 +150,7 @@ materials { } steel { - temp 293; + !temp 293; composition { 06012.03 3.1691E-4; // C 25055.03 1.7321E-3; // Mn @@ -162,7 +162,7 @@ materials { } concrete { - temp 293; + !temp 293; composition { 01001.03 1.4868E-2; // H 06012.03 3.8144E-3; // C @@ -177,7 +177,7 @@ materials { } paraffin { - temp 293; + !temp 293; composition { 01001.03 8.2574E-2; // H 06012.03 3.9699E-2; // C @@ -186,7 +186,7 @@ materials { air { // No data for air given, this composition taken from: // https://www.researchgate.net/figure/contd-Atom-Densities-for-Basic-Materials-atom-barn-cm_tbl17_267562651 - temp 293; + !temp 293; composition { 07014.03 4.1985E-5; 08016.03 1.1263E-5; diff --git a/InputFiles/Benchmarks/MCNP/U233MF05 b/InputFiles/Benchmarks/MCNP/U233MF05 index 332a1270f..25d11c59d 100644 --- a/InputFiles/Benchmarks/MCNP/U233MF05 +++ b/InputFiles/Benchmarks/MCNP/U233MF05 @@ -73,7 +73,7 @@ materials { fuel { - temp 293; + !temp 293; composition { 92233.03 0.047312; 92234.03 0.00052770; @@ -81,7 +81,7 @@ materials { } } reflector { - temp 293; + !temp 293; composition { 04009.03 0.11984; 08016.03 0.0013776; diff --git a/InputFiles/Benchmarks/SourceConvergence/checkerboard b/InputFiles/Benchmarks/SourceConvergence/checkerboard index cc01927e3..f1c79c187 100644 --- a/InputFiles/Benchmarks/SourceConvergence/checkerboard +++ b/InputFiles/Benchmarks/SourceConvergence/checkerboard @@ -186,7 +186,6 @@ nuclearData { materials { water { - temp 75675; rgb (0 0 139); // Colour of water is dark blue moder { 1001.03 lwj3.00; } composition { @@ -196,21 +195,19 @@ nuclearData { } clad { - temp 12345; composition { 40000.03 4.291E-002; } } fuel { - temp 87476; composition { 92235.03 8.2213E-004; 92238.03 2.238E-002; 8016.03 4.6054E-002; } } + concrete { - temp 6786; composition { 1001.03 5.5437E-03; 6012.03 6.9793E-03; @@ -218,8 +215,8 @@ nuclearData { 20000.03 8.9591E-03; 8016.03 4.3383E-002;} } + steel { - temp 8765; composition { 26000.03 8.377E-02; } diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 index cd197bff7..9896f9418 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/aceNeutronDatabase_iTest.f90 @@ -24,13 +24,13 @@ module aceNeutronDatabase_iTest ! Material definitions character(*),parameter :: MAT_INPUT_STR = & - & "water { temp 273; & + & "water { & & composition { & & 1001.03 5.028E-02; & & 8016.03 2.505E-02; & & } & & } & - & uo2 { temp 1; & + & uo2 { & & composition { & & 92233.03 2.286E-02; & & 8016.03 4.572E-02; & @@ -91,7 +91,7 @@ subroutine test_aceNeutronDatabase() @assertNotAssociated( ceNeutronMaterial_TptrCast( data % getMaterial(3))) ! Get water - mat => ceNeutronMaterial_TptrCast( data % getMaterial(1)) + mat => ceNeutronMaterial_TptrCast(data % getMaterial(1)) @assertAssociated(mat) ! Make sure densities are present @@ -172,7 +172,6 @@ subroutine test_aceNeutronDatabase() name = 'uo2' @assertTrue( 0 /= matNames % getOrDefault(name, 0)) - !<><><><><><><><><><><><><><><><><><><><><><><><> ! Test getting nuclide XSs ! diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 index 61c75c77a..cbd3e2313 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/thermalScatteringData_iTest.f90 @@ -17,14 +17,14 @@ module thermalScatteringData_iTest ! Material definitions character(*),parameter :: MAT_INPUT_STR = & - & "water { temp 1; & + & "water { & & moder {1001.03 h-h2o.49; } & & composition { & & 1001.03 2.0E-3; & & 8016.03 1.0E-3; & & } & & } & - & graphite { temp 1; & + & graphite { & & moder {6012.06 grph30.46;} & & composition { & & 6012.06 2.0E-3; & @@ -126,9 +126,8 @@ subroutine test_thermalScatteringData() !<><><><><><><><><><><><><><><><><><><><><><><><> ! Test getting XSs ! H-1 - nuc => ceNeutronNuclide_CptrCast( data % getNuclide(2)) + nuc => ceNeutronNuclide_CptrCast(data % getNuclide(2)) nuclideCache(2) % E_tot = ONE - nuclideCache(2) % needsSabInel = .true. call nuc % getMicroXSs(microXSs, 1.8E-6_defReal, p % pRNG) diff --git a/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 b/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 index 6afb16e30..cba91b668 100644 --- a/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/Tests/urrProbabilityTables_iTest.f90 @@ -17,7 +17,7 @@ module urrProbabilityTables_iTest ! Material definitions character(*),parameter :: MAT_INPUT_STR = & - & " uo2 { temp 1; & + & " uo2 { & & composition { & & 92235.03 1.0E-3; & & 8016.03 2.0E-3; & @@ -26,7 +26,7 @@ module urrProbabilityTables_iTest ! CE Neutron Database specification character(*),parameter :: ACE_INPUT_STR = & - & "aceLibrary ./IntegrationTestFiles/testLib; ures 1 ;" + & "aceLibrary ./IntegrationTestFiles/testLib; ures 1 ; majorant 1; " contains @@ -98,10 +98,9 @@ subroutine test_urrProbabilityTables() ! U-235 nuc => ceNeutronNuclide_CptrCast( data % getNuclide(1)) - zaidCache(1) % E = 9.1E-3_defReal + zaidCache(1) % E = 9.1E-3_defReal zaidCache(1) % xi = 0.347_defReal nuclideCache(1) % E_tot = ONE - nuclideCache(1) % needsUrr = .true. call nuc % getMicroXSs(microXSs, 9.1E-3_defReal, p % pRNG) diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 index 19190e80f..b8e36a7b2 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronDatabase_class.f90 @@ -37,6 +37,9 @@ module aceNeutronDatabase_class cache_zaidCache => zaidCache, & cache_init => init + ! Scattering procedures + use scatteringKernels_func, only : relativeEnergy_constXS, dopplerCorrectionFactor + implicit none private @@ -61,7 +64,7 @@ module aceNeutronDatabase_class !! Public Members: !! nuclides -> array of aceNeutronNuclides with data !! materials -> array of ceNeutronMaterials with data - !! Ebounds -> array with bottom (1) and top (2) energy bound + !! eBounds -> array with bottom (1) and top (2) energy bound !! majorant -> unionised majorant cross section !! eGridUnion -> unionised energy grid !! activeMat -> array of materials present in the geometry @@ -79,7 +82,7 @@ module aceNeutronDatabase_class type(ceNeutronMaterial),dimension(:),pointer :: materials => null() real(defReal), dimension(:), allocatable :: majorant real(defReal), dimension(:), allocatable :: eGridUnion - real(defReal), dimension(2) :: Ebounds = ZERO + real(defReal), dimension(2) :: eBounds = ZERO integer(shortInt),dimension(:),allocatable :: activeMat ! Probability tables data @@ -101,22 +104,25 @@ module aceNeutronDatabase_class ! ceNeutronDatabase Procedures procedure :: energyBounds - procedure :: updateTotalMatXS procedure :: updateMajorantXS + procedure :: updateTrackMatXS + procedure :: updateTotalMatXS procedure :: updateMacroXSs procedure :: updateTotalNucXS procedure :: updateMicroXSs + procedure :: updateTotalTempNucXS procedure :: getScattMicroMajXS ! class Procedures procedure :: initUrr procedure :: initDBRC procedure :: initMajorant + procedure :: updateTotalTempMajXS + procedure :: updateRelEnMacroXSs end type aceNeutronDatabase - contains !! @@ -136,7 +142,7 @@ elemental subroutine kill(self) deallocate(self % materials) end if - self % EBounds = ZERO + self % eBounds = ZERO if(allocated(self % activeMat)) deallocate(self % activeMat) @@ -209,37 +215,40 @@ function getReaction(self, MT, idx) result(reac) ! MT < 0 -> material reaction ! MT = 0 -> does not exist ! MT = 1 -> N_total has no reaction object - if ( MT <= 1 ) then + if (MT <= 1) then reac => null() return end if ! Detect invalid indices - if( idx < 1 .or. idx > size(self % nuclides)) then + if (idx < 1 .or. idx > size(self % nuclides)) then reac => null() return end if ! Get nuclide reaction - if( MT == N_N_elastic) then - if (cache_nuclideCache(idx) % needsSabEl) then - reac => self % nuclides(idx) % thData % elasticOut - else - reac => self % nuclides(idx) % elasticScatter - end if - else if ( MT == N_fission) then + if (MT == N_N_elastic) then + reac => self % nuclides(idx) % elasticScatter + + else if (MT == N_N_ThermEL) then + reac => self % nuclides(idx) % thData % elasticOut + + else if (MT == N_fission) then reac => self % nuclides(idx) % fission + else if (MT == N_N_ThermINEL) then reac => self % nuclides(idx) % thData % inelasticOut + else ! Find index of MT reaction idxMT = self % nuclides(idx) % idxMT % getOrDefault(MT, 0) ! See if the MT is present or not - if(idxMT == 0) then + if (idxMT == 0) then reac => null() else reac => self % nuclides(idx) % MTdata(idxMT) % kinematics end if + end if end function getReaction @@ -256,23 +265,23 @@ function getScattMicroMajXS(self, E, kT, A, nucIdx) result(maj) real(defReal), intent(in) :: A integer(shortInt), intent(in) :: nucIdx real(defReal) :: maj - real(defReal) :: E_upper, E_lower, E_min, E_max + real(defReal) :: eUpper, eLower, eMin, eMax real(defReal) :: alpha ! Find energy limits to define majorant calculation range - alpha = 4 / (sqrt( E * A / kT )) - E_upper = E * (1 + alpha) * (1 + alpha) - E_lower = E * (1 - alpha) * (1 - alpha) + alpha = 3.0_defReal * sqrt( kT / (E * A) ) + eUpper = E * (ONE + alpha) * (ONE + alpha) + eLower = E * (ONE - alpha) * (ONE - alpha) ! Find system minimum and maximum energies - call self % energyBounds(E_min, E_max) + call self % energyBounds(eMin, eMax) ! Avoid energy limits being outside system range - if (E_lower < E_min) E_lower = E_min - if (E_upper > E_max) E_upper = E_max + if (eLower < eMin .or. ONE < alpha) eLower = eMin + if (eUpper > eMax) eUpper = eMax ! Find largest elastic scattering xs in energy range given by E_lower and E_upper - maj = self % nuclides(nucIdx) % elScatteringMaj(E_lower, E_upper) + maj = self % nuclides(nucIdx) % getMajXS(eLower, eUpper, N_N_ELASTIC) end function getScattMicroMajXS @@ -281,58 +290,19 @@ end function getScattMicroMajXS !! !! See ceNeutronDatabase for more details !! - subroutine energyBounds(self, E_min, E_max) + subroutine energyBounds(self, eMin, eMax) class(aceNeutronDatabase), intent(in) :: self - real(defReal), intent(out) :: E_min - real(defReal), intent(out) :: E_max + real(defReal), intent(out) :: eMin + real(defReal), intent(out) :: eMax - E_min = self % Ebounds(1) - E_max = self % Ebounds(2) + eMin = self % eBounds(1) + eMax = self % eBounds(2) end subroutine energyBounds !! - !! Make sure that totalXS of material with matIdx is at energy E - !! in ceNeutronChache - !! - !! See ceNeutronDatabase for more details - !! - subroutine updateTotalMatXS(self, E, matIdx, rand) - class(aceNeutronDatabase), intent(in) :: self - real(defReal), intent(in) :: E - integer(shortInt), intent(in) :: matIdx - class(RNG), optional, intent(inout) :: rand - integer(shortInt) :: i, nucIdx - real(defReal) :: dens - - associate (mat => cache_materialCache(matIdx)) - ! Set new energy - mat % E_tot = E - - ! Clean current total XS - mat % xss % total = ZERO - - ! Construct total macro XS - do i = 1, size(self % materials(matIdx) % nuclides) - dens = self % materials(matIdx) % dens(i) - nucIdx = self % materials(matIdx) % nuclides(i) - - ! Update if needed - if (cache_nuclideCache(nucIdx) % E_tot /= E) then - call self % updateTotalNucXS(E, nucIdx, rand) - end if - - ! Add microscopic XSs - mat % xss % total = mat % xss % total + dens * cache_nuclideCache(nucIdx) % xss % total - end do - - end associate - - end subroutine updateTotalMatXS - - !! - !! Make sure that the majorant of ALL Active materials is at energy E - !! in ceNeutronChache + !! Make sure that the majorant of ALL active materials is at energy E + !! in ceNeutronCache !! !! See ceNeutronDatabase for more details !! @@ -344,20 +314,20 @@ subroutine updateMajorantXS(self, E, rand) real(defReal) :: f character(100), parameter :: Here = 'updateMajorantXS (aceNeutronDatabase_class.f90)' - associate (maj => cache_majorantCache(1) ) + associate (maj => cache_majorantCache(1)) maj % E = E ! Get majorant via the precomputed unionised cross section if (self % hasMajorant) then idx = binarySearch(self % eGridUnion, E) - if(idx <= 0) then + if (idx <= 0) then call fatalError(Here,'Failed to find energy: '//numToChar(E)//& ' in unionised majorant grid') end if - associate(E_top => self % eGridUnion(idx + 1), E_low => self % eGridUnion(idx)) + associate (E_top => self % eGridUnion(idx + 1), E_low => self % eGridUnion(idx)) f = (E - E_low) / (E_top - E_low) end associate @@ -372,11 +342,11 @@ subroutine updateMajorantXS(self, E, rand) matIdx = self % activeMat(i) ! Update if needed - if( cache_materialCache(matIdx) % E_tot /= E) then - call self % updateTotalMatXS(E, matIdx, rand) + if (cache_materialCache(matIdx) % E_track /= E) then + call self % updateTrackMatXS(E, matIdx, rand) end if - maj % xs = max(maj % xs, cache_materialCache(matIdx) % xss % total) + maj % xs = max(maj % xs, cache_materialCache(matIdx) % trackXS) end do end if @@ -385,6 +355,132 @@ subroutine updateMajorantXS(self, E, rand) end subroutine updateMajorantXS + !! + !! Make sure that trackXS of material with matIdx is at energy E = E_track + !! in ceNeutronChache + !! + !! See ceNeutronDatabase for more details + !! + subroutine updateTrackMatXS(self, E, matIdx, rand) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + integer(shortInt), intent(in) :: matIdx + class(RNG), optional, intent(inout) :: rand + + associate (matCache => cache_materialCache(matIdx), & + mat => self % materials(matIdx)) + + ! Set new energy + matCache % E_track = E + + if (mat % useTMS(E)) then + ! The material tracking xs is the temperature majorant in the case of TMS + call self % updateTotalTempMajXS(E, matIdx) + + else + ! When TMS is not in use, the material tracking xs is equivalent to the total + call self % updateTotalMatXS(E, matIdx, rand) + matCache % trackXS = matCache % xss % total + + end if + + end associate + + end subroutine updateTrackMatXS + + !! + !! Subroutine to update the temperature majorant in a given material at given temperature + !! + !! The function finds the upper and lower limits of the energy range the nuclide majorant + !! is included into, then adds up the nuclide temperature majorant multiplied by the Doppler + !! correction factor + !! + !! Args: + !! E [in] -> Incident neutron energy for which temperature majorant is found + !! matIdx [in] -> Index of material for which the material temperature majorant is found + !! + subroutine updateTotalTempMajXS(self, E, matIdx) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + integer(shortInt), intent(in) :: matIdx + integer(shortInt) :: nucIdx, i + real(defReal) :: dens, corrFact, nucTempMaj + + associate (matCache => cache_materialCache(matIdx), & + mat => self % materials(matIdx)) + + ! Clean current total XS + matCache % trackXS = ZERO + + ! loop through all nuclides in material and find sum of majorants + do i = 1, size(mat % nuclides) + + ! Get nuclide data + nucIdx = mat % nuclides(i) + dens = mat % dens(i) + + call self % updateTotalTempNucXS(E, mat % kT, nucIdx) + + ! Sum nuclide majorants to find material majorant + corrFact = cache_nuclideCache(nucIdx) % doppCorr + nucTempMaj = cache_nuclideCache(nucIdx) % tempMajXS * corrFact + matCache % trackXS = matCache % trackXS + dens * nucTempMaj + + end do + + end associate + + end subroutine updateTotalTempMajXS + + !! + !! Make sure that totalXS of material with matIdx is at energy E + !! in ceNeutronCache + !! + !! See ceNeutronDatabase for more details + !! + subroutine updateTotalMatXS(self, E, matIdx, rand) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + integer(shortInt), intent(in) :: matIdx + class(RNG), optional, intent(inout) :: rand + integer(shortInt) :: i, nucIdx + real(defReal) :: dens + + associate (matCache => cache_materialCache(matIdx), & + mat => self % materials(matIdx)) + + ! Set new energy and clean current total XS + matCache % E_tot = E + matCache % xss % total = ZERO + + if (mat % useTMS(E)) then + ! When TMS is in use, the total xs is retrieved sampling the nuclides' relative + ! energies given the temperature difference between material temperature and + ! temperature of the nuclides' base cross sections + call self % updateRelEnMacroXSs(E, matIdx, rand) + + else + ! Construct total macro XS + do i = 1, size(mat % nuclides) + dens = mat % dens(i) + nucIdx = mat % nuclides(i) + + ! Update if needed + if (cache_nuclideCache(nucIdx) % E_tot /= E) then + call self % updateTotalNucXS(E, nucIdx, rand) + end if + + ! Add microscopic XSs + matCache % xss % total = matCache % xss % total + & + dens * cache_nuclideCache(nucIdx) % xss % total + end do + + end if + + end associate + + end subroutine updateTotalMatXS + !! !! Make sure that the macroscopic XSs for the material with matIdx are set !! to energy E in ceNeutronCache @@ -399,35 +495,122 @@ subroutine updateMacroXSs(self, E, matIdx, rand) integer(shortInt) :: i, nucIdx real(defReal) :: dens - associate (mat => cache_materialCache(matIdx)) - ! Set new energy - mat % E_tot = E - mat % E_tail = E + associate(mat => self % materials(matIdx), & + matCache => cache_materialCache(matIdx)) ! Clean current xss - call mat % xss % clean() + call matCache % xss % clean() - ! Construct microscopic XSs - do i = 1, size(self % materials(matIdx) % nuclides) - dens = self % materials(matIdx) % dens(i) - nucIdx = self % materials(matIdx) % nuclides(i) + if (mat % useTMS(E)) then + ! When TMS is in use, the xss are retrieved sampling the nuclides' relative + ! energies given the temperature difference between material temperature and + ! temperature of the nuclides' base cross sections + call self % updateRelEnMacroXSs(E, matIdx, rand) - ! Update if needed - if (cache_nuclideCache(nucIdx) % E_tail /= E .or. cache_nuclideCache(nucIdx) % E_tot /= E) then - call self % updateMicroXSs(E, nucIdx, rand) - end if + else - ! Add microscopic XSs - call mat % xss % add(cache_nuclideCache(nucIdx) % xss, dens) - end do + ! Set new energy + matCache % E_tot = E + matCache % E_tail = E + + ! Construct microscopic XSs + do i = 1, size(mat % nuclides) + dens = mat % dens(i) + nucIdx = mat % nuclides(i) + + ! Update if needed + if (cache_nuclideCache(nucIdx) % E_tail /= E .or. cache_nuclideCache(nucIdx) % E_tot /= E) then + call self % updateMicroXSs(E, nucIdx, rand) + end if + + ! Add microscopic XSs + call matCache % xss % add(cache_nuclideCache(nucIdx) % xss, dens) + end do + + end if end associate end subroutine updateMacroXSs + !! + !! Subroutine to update the macroscopic cross sections in a given material + !! at given temperature, sampling a relative energy per each nuclide and applying + !! a Doppler correction factor + !! + !! Args: + !! E [in] -> Incident neutron energy for which the relative energy xss are found + !! matIdx [in] -> Index of material for which the relative energy xss are found + !! + subroutine updateRelEnMacroXSs(self, E, matIdx, rand) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + integer(shortInt), intent(in) :: matIdx + class(RNG), optional, intent(inout) :: rand + integer(shortInt) :: i, nucIdx + real(defReal) :: dens, nuckT, A, deltakT, eRel, eMin, & + eMax, doppCorr + character(100), parameter :: Here = 'updateRelEnMacroXSs (aceNeutronDatabase_class.f90)' + + associate(mat => self % materials(matIdx), & + matCache => cache_materialCache(matIdx)) + + ! Check if relative energy cross sections have been retrieved before + if (E /= matCache % E_rel) then + + ! Clean current xss + call matCache % xssRel % clean() + matCache % E_rel = E + + ! Construct microscopic XSs + do i = 1, size(mat % nuclides) + + dens = mat % dens(i) + nucIdx = mat % nuclides(i) + nuckT = self % nuclides(nucIdx) % getkT() + A = self % nuclides(nucIdx) % getMass() + deltakT = mat % kT - nuckT + + eRel = relativeEnergy_constXS(E, A, deltakT, rand) + + ! Call through system minimum and maximum energies + call self % energyBounds(eMin, eMax) + + ! avoid sampled relative energy from MB dist extending into energies outside system range + if (eRel < eMin) eRel = eMin + if (eMax < eRel) eRel = eMax + + associate(nucCache => cache_nuclideCache(nucIdx)) + + ! Doppler correction factor for low energies + doppCorr = dopplerCorrectionFactor(E, A, deltakT) + + ! Update if needed + if (nucCache % E_tail /= eRel .or. nucCache % E_tot /= eRel) then + call self % updateMicroXSs(eRel, nucIdx, rand) + end if + + ! Add microscopic XSs + call matCache % xssRel % add(nucCache % xss, dens * doppCorr) + + end associate + + end do + + end if + + ! Update cache, and ensure that the energy indicators are reset to avoid wrong look-ups + matCache % xss = matCache % xssRel + matCache % E_tot = ZERO + matCache % E_tail = ZERO + + end associate + + end subroutine updateRelEnMacroXSs + !! !! Make sure that totalXS of nuclide with nucIdx is at energy E - !! in ceNeutronChache + !! in ceNeutronCache !! !! See ceNeutronDatabase for more details !! @@ -436,19 +619,12 @@ subroutine updateTotalNucXS(self, E, nucIdx, rand) real(defReal), intent(in) :: E integer(shortInt), intent(in) :: nucIdx class(RNG), optional, intent(inout) :: rand - logical(defBool) :: needsSab associate (nucCache => cache_nuclideCache(nucIdx), & nuc => self % nuclides(nucIdx) ) - ! Check if the nuclide needs ures probability tables at this energy - nucCache % needsUrr = (nuc % hasProbTab .and. E >= nuc % urrE(1) .and. E <= nuc % urrE(2)) - ! Check if the nuclide needs S(a,b) at this energy - nucCache % needsSabEl = (nuc % hasThData .and. E >= nuc % SabEl(1) .and. E <= nuc % SabEl(2)) - nucCache % needsSabInel = (nuc % hasThData .and. E >= nuc % SabInel(1) .and. E <= nuc % SabInel(2)) - needsSab = (nucCache % needsSabEl .or. nucCache % needsSabInel) - - if (nucCache % needsUrr .or. needsSab) then + ! Check if the nuclide needs ures probability tables or S(a,b) at this energy + if (nuc % needsUrr(E) .or. nuc % needsSabEl(E) .or. nuc % needsSabInel(E)) then call self % updateMicroXSs(E, nucIdx, rand) else @@ -487,7 +663,7 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) ! Overwrites all the micro cross sections in cache ! Check if probability tables should be read - if (nucCache % needsUrr) then + if (nuc % needsUrr(E)) then associate(zaidCache => cache_zaidCache(self % nucToZaid(nucIdx))) if (zaidCache % E /= E) then @@ -500,7 +676,8 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) end associate - elseif (nucCache % needsSabEl .or. nucCache % needsSabInel) then + ! Check if S(a,b) should be read + elseif (nuc % needsSabEl(E) .or. nuc % needsSabInel(E)) then call nuc % getThXSs(nucCache % xss, nucCache % idx, nucCache % f, E) else @@ -512,6 +689,60 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) end subroutine updateMicroXSs + !! + !! Subroutine to retrieve the nuclide total majorant cross section + !! over a calculated energy range (needed for TMS) and update the nuclide + !! cache with majorant value, energy, deltakT and Doppler correction factor + !! + !! See ceNeutronDatabase for more details + !! + subroutine updateTotalTempNucXS(self, E, kT, nucIdx) + class(aceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal), intent(in) :: kT + integer(shortInt), intent(in) :: nucIdx + real(defReal) :: eUpper, eLower, eMin, eMax, nuckT, & + alpha, deltakT, A + character(100), parameter :: Here = 'updateTotalTempNucXS (aceNeutronDatabase_class.f90)' + + associate (nuc => self % nuclides(nucIdx) , & + nucCache => cache_nuclideCache(nucIdx)) + + nuckT = nuc % getkT() + A = nuc % getMass() + deltakT = kT - nuckT + + ! Check if an update is required + if (nucCache % E_maj /= E .or. nucCache % deltakT /= deltakT) then + + ! Find energy limits to define majorant calculation range + alpha = 3.0_defReal * sqrt( deltakT / (E * A) ) + eUpper = E * (ONE + alpha) * (ONE + alpha) + eLower = E * (ONE - alpha) * (ONE - alpha) + + ! Find system minimum and maximum energies + call self % energyBounds(eMin, eMax) + + ! Avoid energy limits being outside system range + if (eLower < eMin .or. ONE < alpha) eLower = eMin + if (eUpper > eMax) eUpper = eMax + + ! Doppler g correction factor for low energies + nucCache % doppCorr = dopplerCorrectionFactor(E, A, deltakT) + + ! Get nuclide total majorant cross section in the energy range + nucCache % tempMajXS = nuc % getMajXS(eLower, eUpper, N_TOTAL) + + ! Save additional info + nucCache % deltakT = deltakT + nucCache % E_maj = E + + end if + + end associate + + end subroutine updateTotalTempNucXS + !! !! Initialise Database from dictionary and pointer to self !! @@ -536,6 +767,9 @@ subroutine init(self, dict, ptr, silent ) logical(defBool) :: isFissileMat integer(shortInt),dimension(:),allocatable :: nucIdxs, zaidDBRC character(nameLen),dimension(:),allocatable :: nucDBRC + real(defReal) :: A, nuckT, eUpSab, eUpSabNuc, & + eLowURR, eLowUrrNuc, alpha, & + deltakT, eUpper, eLower integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 character(100), parameter :: Here = 'init (aceNeutronDatabase_class.f90)' @@ -660,6 +894,17 @@ subroutine init(self, dict, ptr, silent ) i = nucSet % next(i) end do + ! Calculate energy bounds + self % eBounds(1) = self % nuclides(1) % eGrid(1) + j = size(self % nuclides(1) % eGrid) + self % eBounds(2) = self % nuclides(1) % eGrid(j) + + do i = 2, size(self % nuclides) + self % eBounds(1) = max(self % eBounds(1), self % nuclides(i) % eGrid(1)) + j = size(self % nuclides(i) % eGrid) + self % eBounds(2) = min(self % eBounds(2), self % nuclides(i) % eGrid(j)) + end do + ! Build Material definitions allocate(self % materials(mm_nMat())) allocate(nucIdxs(maxNuc)) @@ -667,35 +912,82 @@ subroutine init(self, dict, ptr, silent ) mat => mm_getMatPtr(i) ! Load nuclide indices on storage space + ! Find if material is fissile isFissileMat = .false. + ! Loop over nuclides do j = 1, size(mat % nuclides) name = trim(mat % nuclides(j) % toChar()) + if (mat % nuclides(j) % hasSab) then zaid = trim(mat % nuclides(j) % toChar()) file = trim(mat % nuclides(j) % file_Sab) name = zaid // '+' // file deallocate(zaid, file) end if + + ! Find nuclide definition to see if fissile nucIdxs(j) = nucSet % get(name) isFissileMat = isFissileMat .or. self % nuclides(nucIdxs(j)) % isFissile() + end do ! Load data into material - call self % materials(i) % set( matIdx = i, & + call self % materials(i) % set( matIdx = i, & database = ptr_ceDatabase, & - fissile = isFissileMat ) + temp = mat % T, & + hasTMS = mat % hasTMS, & + fissile = isFissileMat ) call self % materials(i) % setComposition( mat % dens, nucIdxs(1:size(mat % nuclides))) - end do - ! Calculate energy bounds - self % Ebounds(1) = self % nuclides(1) % eGrid(1) - j = size(self % nuclides(1) % eGrid) - self % Ebounds(2) = self % nuclides(1) % eGrid(j) + eUpSab = self % eBounds(1) + eLowURR = self % eBounds(2) + + if (mat % hasTMS) then + + ! Loop again to find energy limits of S(a,b) and URES for TMS applicability + do j = 1, size(mat % nuclides) + + ! Find nuclide information + idx = nucIdxs(j) + nuckT = self % nuclides(idx) % getkT() + A = self % nuclides(idx) % getMass() + deltakT = self % materials(i) % kT - nuckT + + ! Call fatal error if material temperature is lower then base nuclide temperature + if (deltakT < ZERO) then + call fatalError(Here, "Material temperature must be greater than the nuclear data temperature.") + end if + + ! Find nuclide upper S(a,b) energy + eUpSabNuc = max(self % nuclides(idx) % SabEl(2), self % nuclides(idx) % SabInel(2)) + + ! Find energy limits to define majorant calculation range + if (eUpSabNuc > ZERO) then + alpha = 4.0_defReal * sqrt( deltakT / (eUpSabNuc * A) ) + eUpper = eUpSabNuc * (ONE + alpha) * (ONE + alpha) + else + eUpper = ZERO + end if + + eLowUrrNuc = self % nuclides(idx) % urrE(1) + + if (eLowUrrNuc /= ZERO) then + alpha = 4.0_defReal * sqrt( deltakT / (eLowUrrNuc * A) ) + eLower = eLowUrrNuc * (ONE - alpha) * (ONE - alpha) + else + eLower = self % eBounds(2) + end if + + eUpSab = max(eUpSab, eUpper) + eLowURR = min(eLowURR, eLower) + + end do + + end if + + ! Load data into material + call self % materials(i) % set(eUpperSab = eUpSab, eLowerURR = eLowURR) - do i = 2, size(self % nuclides) - self % Ebounds(1) = max(self % Ebounds(1), self % nuclides(i) % eGrid(1)) - j = size(self % nuclides(i) % eGrid) - self % Ebounds(2) = min(self % Ebounds(2), self % nuclides(i) % eGrid(j)) end do ! Read unionised majorant flag @@ -821,7 +1113,7 @@ subroutine activate(self, activeMat, silent) ! Configure Cache if (self % hasUrr) then - call cache_init(size(self % materials), size(self % nuclides), 1, maxval(self % nucToZaid)) + call cache_init(size(self % materials), size(self % nuclides), nZaid = maxval(self % nucToZaid)) else call cache_init(size(self % materials), size(self % nuclides)) end if @@ -856,9 +1148,9 @@ subroutine initMajorant(self, loud) sizeGrid, eIdx, nucIdxLast, eIdxLast, & urrIdx type(intMap) :: nucSet - real(defReal) :: eRef, eNuc, E, maj, total, dens, urrMaj, & + real(defReal) :: eRef, eNuc, E, maj, trackXS, dens, urrMaj, & nucXS, f, eMax, eMin - logical(defBool) :: needsUrr + class(RNG), allocatable :: rand integer(shortInt), parameter :: IN_SET = 1, NOT_PRESENT = 0 real(defReal), parameter :: NUDGE = 1.0e-06_defReal @@ -901,7 +1193,7 @@ subroutine initMajorant(self, loud) ! Allocate temporary grid vector and initialise to largest value allowed allocate(tmpGrid(sizeGrid)) - tmpGrid = self % EBounds(2) + tmpGrid = self % eBounds(2) ! Loop over the energy grid i = 1 @@ -926,7 +1218,7 @@ subroutine initMajorant(self, loud) eNuc = self % nuclides(nucIdx) % eGrid(eIdx) ! Check if the energy from the nuclide grid is out of bounds - if (eNuc < self % EBounds(1) .or. eNuc > self % EBounds(2)) then + if (eNuc < self % eBounds(1) .or. eNuc > self % eBounds(2)) then j = nucSet % next(j) cycle end if @@ -1031,6 +1323,12 @@ subroutine initMajorant(self, loud) ! Allocate unionised majorant allocate(self % majorant(size(self % eGridUnion))) + ! Initialise RNG needed to call update XS routines. The initial seed doesn't + ! matter because the RNG is only used to sample from probability tables, which + ! are corrected for the majorant anyway + allocate(rand) + call rand % init(1_longInt) + ! Loop over all the energies do i = 1, size(self % eGridUnion) @@ -1038,8 +1336,8 @@ subroutine initMajorant(self, loud) E = self % eGridUnion(i) ! Correct for energies higher or lower than the allowed boundaries - if (E < self % EBounds(1)) E = self % EBounds(1) - if (E > self % EBounds(2)) E = self % EBounds(2) + if (E < self % eBounds(1)) E = self % eBounds(1) + if (E > self % eBounds(2)) E = self % eBounds(2) ! Initialise majorant value for this energy maj = ZERO @@ -1049,19 +1347,20 @@ subroutine initMajorant(self, loud) ! Get material index matIdx = self % activeMat(j) - total = ZERO - ! Loop over nuclides + ! Get material tracking cross section + call self % updateTrackMatXS(E, matIdx, rand) + trackXS = cache_materialCache(matIdx) % trackXS + + ! Loop over nuclides to check and correct for ures do k = 1, size(self % materials(matIdx) % nuclides) dens = self % materials(matIdx) % dens(k) nucIdx = self % materials(matIdx) % nuclides(k) associate (nuc => self % nuclides(nucIdx)) - needsUrr = (nuc % hasProbTab .and. E >= nuc % urrE(1) .and. E <= nuc % urrE(2)) - ! Check if present nuclide uses URR tables - if (needsUrr) then + if (nuc % needsUrr(E)) then ! Find maximum URR table total XS urrIdx = binarySearch(nuc % probTab % eGrid, E) @@ -1070,25 +1369,22 @@ subroutine initMajorant(self, loud) ! Check if URR tables contain xs or multiplicative factor if (nuc % IFF == 1) then call nuc % search(eIdx, f, E) - nucXS = nuc % totalXS(eIdx, f) * urrMaj + nucXS = nuc % totalXS(eIdx, f) * urrMaj else nucXS = urrMaj end if - else - call self % updateTotalNucXS(E, nucIdx) - nucXS = cache_nuclideCache(nucIdx) % xss % total + ! Update total material cross section + trackXS = trackXS + dens * (nucXS - cache_nuclideCache(nucIdx) % xss % total) end if end associate - ! Update total material cross section - total = total + dens * nucXS - end do - maj = max(maj, total) + ! Select majorant cross section + maj = max(maj, trackXS) end do diff --git a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 index 343bc6b0e..5715e645c 100644 --- a/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 +++ b/NuclearData/ceNeutronData/aceDatabase/aceNeutronNuclide_class.f90 @@ -101,7 +101,7 @@ module aceNeutronNuclide_class !! microXSs -> return interpolated ceNeutronMicroXSs package given index and inter. factor !! getUrrXSs -> return ceNeutronMicroXSs accounting for ures probability tables !! getThXSs -> return ceNeutronMicroXSs accounting for S(a,b) scattering treatment - !! elScatteringMaj -> returns the elastic scattering majorant within an energy range given as input + !! getMajXS -> returns a majorant cross section on request within an energy range given as input !! init -> build nuclide from aceCard !! initUrr -> build list and mapping of nuclides to maintain temperature correlation !! when reading ures probability tables @@ -136,6 +136,7 @@ module aceNeutronNuclide_class procedure :: invertInelastic procedure :: xsOf procedure :: elScatteringXS + procedure :: needsSabEl procedure :: kill ! Local interface @@ -145,7 +146,9 @@ module aceNeutronNuclide_class procedure :: microXSs procedure :: getUrrXSs procedure :: getThXSs - procedure :: elScatteringMaj + procedure :: getMajXS + procedure :: needsUrr + procedure :: needsSabInel procedure :: init procedure :: initUrr procedure :: initSab @@ -174,29 +177,24 @@ function invertInelastic(self, E, rand) result(MT) character(100), parameter :: Here = 'invertInelastic (aceNeutronNuclide_class.f90)' ! Check if it's thermal inelastic scattering or not - if (nuclideCache(self % getNucIdx()) % needsSabInel) then + if (self % needsSabInel(E)) then MT = N_N_ThermINEL return end if ! Normal (without S(a,b)) inelastic scattering ! Obtain bin index and interpolation factor - if (nuclideCache(self % getNucIdx()) % E_tot == E) then - idx = nuclideCache(self % getNucIdx()) % idx - f = nuclideCache(self % getNucIdx()) % f - else - call self % search(idx, f, E) - end if + call self % search(idx, f, E) ! Get inelastic XS XS = self % mainData(IESCATTER_XS, idx+1) * f + (ONE-f) * self % mainData(IESCATTER_XS, idx) ! Invert XS = XS * rand % get() - do i=1,self % nMT + do i = 1,self % nMT ! Get index in MT reaction grid idxT = idx - self % MTdata(i) % firstIdx + 1 - if( idxT < 1 ) cycle + if ( idxT < 1 ) cycle ! Get top and bottom XS topXS = self % MTdata(i) % xs(idxT+1) @@ -204,7 +202,7 @@ function invertInelastic(self, E, rand) result(MT) ! Decrement total inelastic and exit if sampling is finished XS = XS - topXS * f - (ONE-f) * bottomXS - if(XS <= ZERO) then + if (XS <= ZERO) then MT = self % MTdata(i) % MT return end if @@ -489,7 +487,7 @@ elemental subroutine getThXSs(self, xss, idx, f, E) xss % elasticScatter = self % thData % getElXS(E) ! If ineleastic scatter is on, reads S(a,b) tables for inelastic scatter - if (nuclideCache(self % getNucIdx()) % needsSabInel) then + if (self % needsSabInel(E)) then xss % inelasticScatter = self % thData % getInelXS(E) else xss % inelasticScatter = data(IESCATTER_XS, 2) * f + (ONE-f) * data(IESCATTER_XS, 1) @@ -589,24 +587,40 @@ end subroutine getUrrXSs !! an energy range given by an upper and lower energy bound. !! !! Args: - !! upperE [in] -> Upper bound of energy range - !! upperE [in] -> Upper bound of energy range + !! eLower [in] -> Lower bound of energy range + !! eUpper [in] -> Upper bound of energy range + !! MT [in] -> MT number of the requested reaction cross section !! maj [out] -> Maximum scattering cross section within energy range !! - function elScatteringMaj(self, lowerE, upperE) result (maj) + function getMajXS(self, eLower, eUpper, MT) result (maj) class(aceNeutronNuclide), intent(in) :: self - real(defReal), intent(in) :: lowerE - real(defReal), intent(in) :: upperE + real(defReal), intent(in) :: eLower + real(defReal), intent(in) :: eUpper + integer(shortInt), intent(in) :: MT real(defReal) :: maj - integer(shortInt) :: idx + integer(shortInt) :: reaction, idx real(defReal) :: f, E, xs + character(100), parameter :: Here = 'getMajXS (aceNeutronNuclide_class.f90)' + + ! Select desired reaction based on requested MT number + select case (MT) + + case (N_TOTAL) + reaction = TOTAL_XS + + case (N_N_ELASTIC) + reaction = ESCATTER_XS + + case default + call fatalError(Here, 'Unsupported MT number requested: '//numToChar(MT)) + + end select ! Search for idx, f, and xs for the lower energy limit - call self % search(idx, f, lowerE) + call self % search(idx, f, eLower) ! Conservative: choose the xs at the energy point before the lower energy limit - f = 0 - maj = self % scatterXS(idx, f) + maj = self % mainData(reaction, idx) majorantLoop: do @@ -614,20 +628,69 @@ function elScatteringMaj(self, lowerE, upperE) result (maj) idx = idx + 1 ! Find XS and energy at index - xs = self % mainData(ESCATTER_XS, idx) - E = self % eGrid(idx) + xs = self % mainData(reaction, idx) + E = self % eGrid(idx) ! Compare cross sections and possibly update majorant - if (xs > maj) then - maj = xs - end if + maj = max(xs, maj) ! Exit loop after getting to the upper energy limit - if (E > upperE) exit majorantLoop + if (E >= eUpper) exit majorantLoop end do majorantLoop - end function elScatteringMaj + end function getMajXS + + !! + !! Function that checks whether this nuclide at the provided energy should + !! read unresolved resonance probability tables or not + !! + !! Args: + !! E [in] -> incident neutron energy + !! + !! Returns true or false + !! + elemental function needsUrr(self, E) result(doesIt) + class(aceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + logical(defBool) :: doesIt + + doesIt = self % hasProbTab .and. E >= self % urrE(1) .and. E <= self % urrE(2) + + end function needsUrr + + !! + !! Function that checks whether this nuclide at the provided energy should + !! has S(a,b) inelastic scattering data or not + !! + !! Args: + !! E [in] -> incident neutron energy + !! + !! Returns true or false + !! + elemental function needsSabInel(self, E) result(doesIt) + class(aceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + logical(defBool) :: doesIt + + doesIt = self % hasThData .and. E >= self % SabInel(1) .and. E <= self % SabInel(2) + + end function needsSabInel + + !! + !! Function that checks whether this nuclide at the provided energy should + !! has S(a,b) elastic scattering data or not + !! + !! See ceNeutronNuclide documentation + !! + elemental function needsSabEl(self, E) result(doesIt) + class(aceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + logical(defBool) :: doesIt + + doesIt = self % hasThData .and. E >= self % SabEl(1) .and. E <= self % SabEl(2) + + end function needsSabEl !! !! Initialise from an ACE Card @@ -785,11 +848,11 @@ subroutine init(self, ACE, nucIdx, database) ! Calculate Inelastic scattering XS do i = 1,self % nMT - do j=1,size(self % mainData, 2) + do j = 1,size(self % mainData, 2) ! Find bottom and Top of the grid bottom = self % MTdata(i) % firstIdx top = size(self % MTdata(i) % xs) - if( j>= bottom .and. j <= top + bottom) then + if (j>= bottom .and. j <= top + bottom) then self % mainData(IESCATTER_XS, j) = self % mainData(IESCATTER_XS, j) + & self % MTdata(i) % xs(j-bottom + 1) end if @@ -797,7 +860,7 @@ subroutine init(self, ACE, nucIdx, database) end do ! Recalculate totalXS - if(self % isFissile()) then + if (self % isFissile()) then K = FISSION_XS else K = CAPTURE_XS @@ -814,7 +877,7 @@ subroutine init(self, ACE, nucIdx, database) call self % idxMT % add(N_N_ELASTIC, -ESCATTER_XS) call self % idxMT % add(N_DISAP, -CAPTURE_XS) - if(self % isFissile()) then + if (self % isFissile()) then call self % idxMT % add(N_FISSION, -FISSION_XS) end if diff --git a/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 b/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 index 345b96b39..2806f3cf2 100644 --- a/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 +++ b/NuclearData/ceNeutronData/ceNeutronCache_mod.f90 @@ -33,7 +33,11 @@ module ceNeutronCache_mod !! E_tail -> Energy of all XSs in xss except total !! f -> Interpolation factor for the nuclide at energy E_tot !! idx -> Index on a nuclide grid for energy E_tot - !! xss -> Cached Cross-Section values + !! xss -> Cached cross-section values + !! E_track -> Energy of the tracking xs + !! trackXS -> Cached tracking xs; this can be different to xss % total when using TMS + !! E_rel -> Base energy for which relative energy cross sections are found (for TMS) + !! xssRel -> Cached effective cross-section values at energy relative to E_rel (for TMS) !! type, public :: cacheMatDat real(defReal) :: E_tot = ZERO @@ -41,6 +45,15 @@ module ceNeutronCache_mod real(defReal) :: f = ZERO integer(shortInt) :: idx = 0 type(neutronMacroXSs) :: xss + + ! Tracking data + real(defReal) :: E_track = ZERO + real(defReal) :: trackXS = ZERO + + ! TMS data + real(defReal) :: E_rel = ZERO + type(neutronMacroXSs) :: xssRel + end type cacheMatDat !! @@ -52,12 +65,10 @@ module ceNeutronCache_mod !! f -> Interpolation factor for the nuclide at energy E_tot !! idx -> Index on a nuclide grid for energy E_tot !! xss -> Cached Cross-Sections values - !! needsSabInel -> Flag that tells if the nuclide is using thermal inelastic - !! scattering data - !! needsSabEl -> Flag that tells if the nuclide is using thermal elastic - !! scattering data - !! needsUrr -> Flag that tells if the nuclide is using unresolved resonance - !! probability tables + !! E_maj -> Energy at which the nuclide temperature majorant xs is stored (for TMS) + !! deltakT -> Difference between TMS material and nuclide thermal energy (for TMS) [MeV] + !! tempMajXS -> Temperature majorant xs value (for TMS) + !! doppCorr -> Doppler correction factor value (for TMS) !! type, public :: cacheNucDat real(defReal) :: E_tot = ZERO @@ -65,9 +76,13 @@ module ceNeutronCache_mod real(defReal) :: f = ZERO integer(shortInt) :: idx = 0 type(neutronMicroXSs) :: xss - logical(defBool) :: needsSabInel = .false. - logical(defBool) :: needsSabEl = .false. - logical(defBool) :: needsUrr = .false. + + ! TMS data + real(defReal) :: E_maj = ZERO + real(defReal) :: deltakT = ZERO + real(defReal) :: tempMajXS = ZERO + real(defReal) :: doppCorr = ONE + end type cacheNucDat !! @@ -78,8 +93,8 @@ module ceNeutronCache_mod !! xs -> value of the cross section !! type, public :: cacheSingleXS - real(defReal) :: E - real(defReal) :: xs + real(defReal) :: E = ZERO + real(defReal) :: xs = ZERO end type cacheSingleXS !! @@ -140,10 +155,10 @@ subroutine init(nMat, nNuc, nMaj, nZaid) nLoc = 1 end if - ! Chack the provided data + ! Check the provided data if (nMat < 1) call fatalError(Here,'Number of materials must be +ve! Not: '//numToChar(nMat)) - if (nNuc < 1) call fatalError(Here,'Number of nuclides must be +ve! Not: '//numToChar(nMat)) - if (nLoc < 1) call fatalError(Here,'Number of majorant XSs must be +ve! Not: '//numToChar(nMat)) + if (nNuc < 1) call fatalError(Here,'Number of nuclides must be +ve! Not: '//numToChar(nNuc)) + if (nLoc < 1) call fatalError(Here,'Number of majorant XSs must be +ve! Not: '//numToChar(nLoc)) ! Allocate space ! Need to do in parallel region to allocate each copy @@ -168,6 +183,7 @@ end subroutine init !! Return Cache Module (Singleton) to uninitialised state !! subroutine kill() + ! Need to deallocate on all threads !$omp parallel if (allocated(materialCache)) deallocate (materialCache) @@ -176,6 +192,7 @@ subroutine kill() if (allocated(trackingCache)) deallocate (trackingCache) if (allocated(zaidCache)) deallocate (zaidCache) !$omp end parallel + end subroutine kill diff --git a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 index 1050c5d5b..2f9eb99b9 100644 --- a/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronDatabase_inter.f90 @@ -45,48 +45,75 @@ module ceNeutronDatabase_inter !! updateMacroXSs -> update Macroscopic XSs for a selected material !! updateTotalXS -> update Total XS for a selected nuclide !! updateMicroXSs -> update Microscopic XSs for a selected nuclide - !! getScattMicroMajXS -> returns elastic scattering microscopic xs majorant + !! getScattMicroMajXS -> returns nuclide elastic scattering temperature majorant (for DBRC) + !! updateTotalTempNucXS -> returns nuclide total temperature majorant (for TMS) !! type, public, abstract, extends(nuclearDatabase) :: ceNeutronDatabase type(intMap) :: mapDBRCnuc contains + ! nuclearDatabase Interface Implementation procedure :: getTrackingXS + procedure :: getTrackMatXS procedure :: getTotalMatXS procedure :: getMajorantXS ! Procedures implemented by a specific CE Neutron Database - procedure(updateTotalMatXS),deferred :: updateTotalMatXS - procedure(updateMajorantXS),deferred :: updateMajorantXS - procedure(updateMacroXSs),deferred :: updateMacroXSs - procedure(updateTotalXS),deferred :: updateTotalNucXS - procedure(updateMicroXSs),deferred :: updateMicroXSs - procedure(energyBounds),deferred :: energyBounds - procedure(getScattMicroMajXS),deferred :: getScattMicroMajXS + procedure(updateMajorantXS), deferred :: updateMajorantXS + procedure(updateTotalMatXS), deferred :: updateTrackMatXS + procedure(updateTotalMatXS), deferred :: updateTotalMatXS + procedure(updateMacroXSs), deferred :: updateMacroXSs + procedure(updateTotalXS), deferred :: updateTotalNucXS + procedure(updateMicroXSs), deferred :: updateMicroXSs + procedure(updateTotalTempNucXS), deferred :: updateTotalTempNucXS + procedure(energyBounds), deferred :: energyBounds + procedure(getScattMicroMajXS), deferred :: getScattMicroMajXS end type ceNeutronDatabase abstract interface !! !! Return energy bounds for data in the database !! - !! E_min and E_max are minimun and maximumum energy such that data + !! eMin and eMax are minimun and maximumum energy such that data !! for ALL nuclides if avalible !! !! Args: - !! E_min [out] -> minimum value of energy [MeV] - !! E_max [out] -> maximum value of energy [MeV] + !! eMin [out] -> minimum value of energy [MeV] + !! eMax [out] -> maximum value of energy [MeV] !! !! Errors: !! None !! - subroutine energyBounds(self, E_min, E_max) + subroutine energyBounds(self, eMin, eMax) import :: ceNeutronDatabase, defReal class(ceNeutronDatabase), intent(in) :: self - real(defReal), intent(out) :: E_min - real(defReal), intent(out) :: E_max + real(defReal), intent(out) :: eMin + real(defReal), intent(out) :: eMax end subroutine energyBounds + !! + !! Make sure that trackXS of material with matIdx is at energy E = E_track + !! in ceNeutronChache + !! + !! The tracking xs correspons to the material total cross section unless TMS + !! is used. In that case, this is the material temperature majorant xs. + !! + !! Assume that call to this procedure implies that data is NOT up-to-date + !! + !! Args: + !! E [in] -> required energy [MeV] + !! matIdx [in] -> material index that needs to be updated + !! rand [inout] -> random number generator + !! + subroutine updateTrackMatXS(self, E, matIdx, rand) + import :: ceNeutronDatabase, defReal, shortInt, RNG + class(ceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + integer(shortInt), intent(in) :: matIdx + class(RNG), optional, intent(inout) :: rand + end subroutine updateTrackMatXS + !! !! Make sure that totalXS of material with matIdx is at energy E !! in ceNeutronChache @@ -196,7 +223,32 @@ subroutine updateMicroXSs(self, E, nucIdx, rand) end subroutine updateMicroXSs !! - !! Subroutine to get the elastic scattering majorant cross section in a nuclide + !! Subroutine to retrieve the nuclide total majorant cross section over a range + !! of relative energies a nuclide can see given the material temperature. The + !! energy range is calculated based on the nuclide and material kT, on the atomic + !! mass of the nuclide, and the incident neutron energy + !! + !! The nuclide cache is updated with the 'temperature' majorant value, incident + !! neutron energy, deltakT and Doppler correction factor + !! + !! Args: + !! E [in] -> required energy [MeV] + !! kT [in] -> thermal energy of TMS material + !! nucIdx [in] -> material index that needs to be updated + !! + !! Errors: + !! FatalError if material kT is smaller than the nuclide kT + !! + subroutine updateTotalTempNucXS(self, E, kT, nucIdx) + import :: ceNeutronDatabase, defReal, shortInt + class(ceNeutronDatabase), intent(in) :: self + real(defReal), intent(in) :: E + real(defReal), intent(in) :: kT + integer(shortInt), intent(in) :: nucIdx + end subroutine updateTotalTempNucXS + + !! + !! Function to get the elastic scattering majorant cross section in a nuclide !! over a certain energy range, defined as a function of a given temperature !! !! NOTE: This function is called by the collision operator to apply DBRC; nucIdx @@ -242,7 +294,7 @@ function getTrackingXS(self, p, matIdx, what) result(xs) select case(what) case (MATERIAL_XS) - xs = self % getTotalMatXS(p, matIdx) + xs = self % getTrackMatXS(p, matIdx) case (MAJORANT_XS) xs = self % getMajorantXS(p) @@ -252,6 +304,7 @@ function getTrackingXS(self, p, matIdx, what) result(xs) ! READ ONLY - read from previously updated cache if (p % E == trackingCache(1) % E) then xs = trackingCache(1) % xs + return else call fatalError(Here, 'Tracking cache failed to update during tracking') end if @@ -267,6 +320,37 @@ function getTrackingXS(self, p, matIdx, what) result(xs) end function getTrackingXS + !! + !! Return tracking XS for matIdx + !! + !! This is the regular material total cross section unless TMS is used. + !! If TMS is used, this is the material temperature majorant cross section. + !! + !! See nuclearDatabase_inter for details! + !! + !! Error: + !! fatalError if particle is not CE Neutron + !! + function getTrackMatXS(self, p, matIdx) result(xs) + class(ceNeutronDatabase), intent(inout) :: self + class(particle), intent(in) :: p + integer(shortInt), intent(in) :: matIdx + real(defReal) :: xs + character(100),parameter :: Here = 'getTrackMatXS (ceNeutronDatabase_inter.f90)' + + ! Check dynamic type of the particle + if (p % isMG .or. p % type /= P_NEUTRON) then + call fatalError(Here, 'Dynamic type of the partcle is not CE Neutron but:'//p % typeToChar()) + end if + + ! Check Cache and update if needed + if (materialCache(matIdx) % E_track /= p % E) call self % updateTrackMatXS(p % E, matIdx, p % pRNG) + + ! Return Cross-Section + xs = materialCache(matIdx) % trackXS + + end function getTrackMatXS + !! !! Return Total XS for matIdx !! diff --git a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 index e8088fc3e..e10dc5585 100644 --- a/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 +++ b/NuclearData/ceNeutronData/ceNeutronMaterial_class.f90 @@ -1,9 +1,10 @@ module ceNeutronMaterial_class use numPrecision - use genericProcedures, only : fatalError - use RNG_class, only : RNG - use particle_class, only : particle + use universalVariables + use genericProcedures, only : fatalError, numToChar + use RNG_class, only : RNG + use particle_class, only : particle ! Nuclear Data Handles use materialHandle_inter, only : materialHandle @@ -12,10 +13,14 @@ module ceNeutronMaterial_class ! CE Neutron Interfaces use ceNeutronDatabase_inter, only : ceNeutronDatabase + use ceNeutronNuclide_inter, only : ceNeutronNuclide, ceNeutronNuclide_CptrCast ! Cache use ceNeutronCache_mod, only : materialCache, nuclideCache + ! Scattering procedures + use scatteringKernels_func, only : relativeEnergy_constXS, dopplerCorrectionFactor + implicit none private @@ -48,10 +53,14 @@ module ceNeutronMaterial_class !! type, public, extends(neutronMaterial) :: ceNeutronMaterial integer(shortInt) :: matIdx = 0 + real(defReal) :: kT = ZERO class(ceNeutronDatabase), pointer :: data => null() real(defReal), dimension(:), allocatable :: dens integer(shortInt), dimension(:), allocatable :: nuclides - logical(defBool) :: fissile =.false. + logical(defBool) :: fissile = .false. + logical(defBool) :: hasTMS = .false. + real(defReal) :: eUpperSab = ZERO + real(defReal) :: eLowerURR = ZERO contains ! Superclass procedures @@ -64,6 +73,7 @@ module ceNeutronMaterial_class procedure, non_overridable :: setComposition procedure, non_overridable :: getMacroXSs_byE procedure :: isFissile + procedure :: useTMS procedure, non_overridable :: sampleNuclide procedure, non_overridable :: sampleFission procedure, non_overridable :: sampleScatter @@ -80,10 +90,14 @@ elemental subroutine kill(self) class(ceNeutronMaterial), intent(inout) :: self self % matIdx = 0 + self % kT = ZERO self % data => null() - if(allocated(self % dens)) deallocate(self % dens ) - if(allocated(self % nuclides)) deallocate (self % nuclides) + if (allocated(self % dens)) deallocate(self % dens) + if (allocated(self % nuclides)) deallocate (self % nuclides) self % fissile = .false. + self % hasTMS = .false. + self % eUpperSab = ZERO + self % eLowerURR = ZERO end subroutine kill @@ -105,6 +119,7 @@ subroutine getMacroXSs_byP(self, xss, p) call fatalError(Here,'MG neutron given to CE data') end if + end subroutine getMacroXSs_byP !! @@ -118,7 +133,7 @@ end subroutine getMacroXSs_byP !! nucIdxs [in] -> correpsonding array with nucIdxs !! !! Errors: - !! FatalError if arrays have diffrent size + !! FatalError if arrays have different size !! FatalError if dens contains -ve values !! FatalError if dens has size of 0 -> no composition !! @@ -129,13 +144,13 @@ subroutine setComposition(self, dens, nucIdxs) character(100), parameter :: Here = 'setComposition (ceNeutronMaterial_class.f90)' ! Check input - if(size(dens) /= size(nucIdxs)) call fatalError(Here,'Diffrent sizes of density and nuclide vector') - if(any(dens < ZERO)) call fatalError(Here,'-ve nuclide densities are present') - if(size(dens) == 0) call fatalError(Here,'Empty composition is not allowed') + if (size(dens) /= size(nucIdxs)) call fatalError(Here,'Different sizes of density and nuclide vector') + if (any(dens < ZERO)) call fatalError(Here,'-ve nuclide densities are present') + if (size(dens) == 0) call fatalError(Here,'Empty composition is not allowed') ! Clean any current content - if(allocated(self % dens)) deallocate(self % dens) - if(allocated(self % nuclides)) deallocate(self % nuclides) + if (allocated(self % dens)) deallocate(self % dens) + if (allocated(self % nuclides)) deallocate(self % nuclides) ! Load values self % dens = dens @@ -147,25 +162,52 @@ end subroutine setComposition !! Set matIdx, pointer to a database and fissile flag !! !! All arguments are optional. Use with keyword association e.g. - !! call mat % set( matIdx = 7) + !! call mat % set(matIdx = 7) !! !! Use this procedure ONLY during build. NEVER during transport. !! IT IS NOT THREAD SAFE! !! + !! NOTE: eUpperSab and eLowerURR are fed by the aceNeutronDatabase, and they are the + !! strictest (respecitvely highest and lowest) energy limits among all nuclides + !! in the material composition. + !! !! Args: !! matIdx [in] -> material index !! database [in] -> pointer to a database that updates XSs on the ceNeutronCache - !! fissile [in] -> flag indicating whether fission data is present - !! - subroutine set(self, matIdx, database, fissile) - class(ceNeutronMaterial), intent(inout) :: self - integer(shortInt), intent(in),optional :: matIdx - class(ceNeutronDatabase),pointer, optional,intent(in) :: database - logical(defBool),intent(in), optional :: fissile + !! fissile [in] -> flag indicating whether fission data is present + !! hasTMS [in] -> flag indicating whether TMS is on + !! temp [in] -> TMS material temperature + !! eUpperSab [in] -> upper energy of S(a,b) range in the material + !! eLowerURR [in] -> lower energy of ures range in the material + !! + subroutine set(self, matIdx, database, fissile, hasTMS, temp, eUpperSab, eLowerURR) + class(ceNeutronMaterial), intent(inout) :: self + integer(shortInt), intent(in), optional :: matIdx + class(ceNeutronDatabase), pointer, optional, intent(in) :: database + logical(defBool), intent(in), optional :: fissile + logical(defBool), intent(in), optional :: hasTMS + real(defReal), intent(in), optional :: temp + real(defReal), intent(in), optional :: eUpperSab + real(defReal), intent(in), optional :: eLowerURR + character(100), parameter :: Here = 'set (ceNeutronMaterial_class.f90)' + + if (present(database)) self % data => database + if (present(fissile)) self % fissile = fissile + if (present(matIdx)) self % matIdx = matIdx + if (present(hasTMS)) self % hasTMS = hasTMS + if (present(temp)) self % kT = (kBoltzmann * temp) / joulesPerMeV + + if (present(eUpperSab)) then + if (eUpperSab < ZERO) call fatalError (Here, 'Upper Sab energy limit of material '& + &//numToChar(matIdx)//' is negative.') + self % eUpperSab = eUpperSab + end if - if(present(matIdx)) self % matIdx = matIdx - if(present(database)) self % data => database - if(present(fissile)) self % fissile = fissile + if (present(eLowerURR)) then + if (eLowerURR < ZERO) call fatalError (Here, 'Lower URR energy limit of material '& + &//numToChar(matIdx)//' is negative.') + self % eLowerURR = eLowerURR + end if end subroutine set @@ -196,13 +238,13 @@ subroutine getMacroXSs_byE(self, xss, E, rand) end subroutine getMacroXSs_byE !! - !! Return .true. if nuclide is fissile + !! Return .true. if material is fissile !! !! Args: !! None !! !! Result: - !! .TRUE. if fissile, .FALSE. otherwise + !! .true. if fissile, .false. otherwise !! !! Errors: !! None @@ -215,6 +257,28 @@ elemental function isFissile(self) result(isIt) end function isFissile + !! + !! Return .true. if TMS is on in the material and the provided energy is not + !! within the ures or S(a,b) range of any nuclide in the material. + !! + !! Args: + !! E [in] -> test energy + !! + !! Result: + !! .true. if conditions for using TMS are satisfied, .false. otherwise + !! + !! Errors: + !! None + !! + elemental function useTMS(self, E) result(shouldIt) + class(ceNeutronMaterial), intent(in) :: self + real(defReal), intent(in) :: E + logical(defBool) :: shouldIt + + shouldIt = self % hasTMS .and. (E > self % eUpperSab) .and. (E < self % eLowerURR) + + end function useTMS + !! !! Sample collision nuclide at energy E !! @@ -224,48 +288,116 @@ end function isFissile !! Args: !! E [in] -> incident energy [MeV] !! rand [inout] -> random number generator - !! - !! Result: - !! nucIdx of the sampled nuclide for collision + !! nucIdx [out] -> sampled nuclide index + !! eOut [out] -> relative energy between neutron and target (may be /= E in case of TMS) !! !! Errors: !! fatalError if sampling fails for some reason (E.G. random number > 1) !! fatalError if E is out-of-bounds of the present data !! - function sampleNuclide(self, E, rand) result(nucIdx) + subroutine sampleNuclide(self, E, rand, nucIdx, eOut) class(ceNeutronMaterial), intent(in) :: self real(defReal), intent(in) :: E class(RNG), intent(inout) :: rand - integer(shortInt) :: nucIdx - real(defReal) :: xs + integer(shortInt), intent(out) :: nucIdx + real(defReal), intent(out) :: eOut + class(ceNeutronNuclide), pointer :: nuc integer(shortInt) :: i + real(defReal) :: P_acc, eMin, eMax, A, eRel, & + trackMatXS, totNucXS, dens character(100), parameter :: Here = 'sampleNuclide (ceNeutronMaterial_class.f90)' - ! Get total material XS - if(E /= materialCache(self % matIdx) % E_tot) then - call self % data % updateTotalMatXS(E, self % matIdx, rand) + ! Get material tracking XS + if (E /= materialCache(self % matIdx) % E_track) then + call self % data % updateTrackMatXS(E, self % matIdx, rand) end if - xs = materialCache(self % matIdx) % xss % total * rand % get() + trackMatXS = materialCache(self % matIdx) % trackXS * rand % get() + + ! Loop over nuclides + do i = 1,size(self % nuclides) - ! Loop over all nuclides - do i=1,size(self % nuclides) nucIdx = self % nuclides(i) - if (E /= nuclideCache(nucIdx) % E_tot) call self % data % updateTotalNucXS(E, nucIdx, rand) - xs = xs - nuclideCache(nucIdx) % xss % total * self % dens(i) - if(xs < ZERO) return + dens = self % dens(i) + + associate (nucCache => nuclideCache(nucIdx)) + + ! Retrieve nuclide XS from cache + if (self % useTMS(E)) then + + ! If the material is using TMS, the nuclide temperature majorant is needed + ! The check for the right values stored in cache happens inside the subroutine + call self % data % updateTotalTempNucXS(E, self % kT, nucIdx) + + totNucXS = nucCache % tempMajXS * nucCache % doppCorr + + else + + ! Update nuclide cache if needed + if (E /= nucCache % E_tot) call self % data % updateTotalNucXS(E, nucIdx, rand) + totNucXS = nucCache % xss % total + + end if + + trackMatXS = trackMatXS - totNucXS * dens + + ! Nuclide temporarily accepted: check TMS condition + if (trackMatXS < ZERO) then + + ! Save energy to be used to sample reaction + eOut = E + + if (self % useTMS(E)) then + + ! If the material is using TMS, retrieve nuclide and nuclide information + nuc => ceNeutronNuclide_CptrCast(self % data % getNuclide(nucIdx)) + if (.not. associated(nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + + A = nuc % getMass() + + ! Sample relative energy + eRel = relativeEnergy_constXS(E, A, nucCache % deltakT, rand) + + ! Call through system minimum and maximum energies + call self % data % energyBounds(eMin, eMax) + + ! Ensure relative energy is within energy bounds + if (eRel < eMin) eRel = eMin + if (eMax < eRel) eRel = eMax + + ! Get relative energy nuclide cross section + call self % data % updateTotalNucXS(eRel, nucIdx, rand) + + ! Calculate acceptance probability using ratio of relative energy xs to temperature majorant + P_acc = nucCache % xss % total * nucCache % doppCorr / totNucXS + + ! Accept or reject the sampled nuclide + if (rand % get() >= P_acc) nucIdx = REJECTED + + ! Overwrite energy to be used to sample reaction + eOut = eRel + + end if + + ! Exit function, return the sampled nucIdx + return + + end if + + end associate + end do ! Print error message as the inversion failed call fatalError(Here,'Nuclide sampling loop failed to terminate') - end function sampleNuclide + end subroutine sampleNuclide !! !! Sample fission nuclide given that a fission neutron was produced !! - !! Basicly samples from P(nucIdx| fission neutron produced in material) - !! Usefull when generating fission sites + !! Basically samples from P(nucIdx| fission neutron produced in material) + !! Useful when generating fission sites !! !! As such it uses nu*sigma_f !! @@ -287,30 +419,52 @@ function sampleFission(self, E, rand) result(nucIdx) class(ceNeutronMaterial), intent(in) :: self real(defReal), intent(in) :: E class(RNG), intent(inout) :: rand - integer(shortInt) :: nucIdx - real(defReal) :: xs - integer(shortInt) :: i + class(ceNeutronNuclide), pointer :: nuc + integer(shortInt) :: nucIdx, i + real(defReal) :: xs, doppCorr, A, nuckT, deltakT character(100), parameter :: Here = 'sampleFission (ceNeutronMaterial_class.f90)' ! Short-cut for nonFissile material - if(.not.self % fissile) then + if (.not. self % fissile) then nucIdx = 0 return end if ! Calculate material macroscopic nuFission - if(E /= materialCache(self % matIdx) % E_tail) then - call self % data % updateMacroXSs(E, self % matIdx, rand) - end if + ! The cache is updated without checking the energy to get the correct results with TMS + ! The relative energy flag cached is cleaned to make sure cross sections are updated + materialCache(self % matIdx) % E_rel = ZERO + call self % data % updateMacroXSs(E, self % matIdx, rand) xs = materialCache(self % matIdx) % xss % nuFission * rand % get() ! Loop over all nuclides - do i=1,size(self % nuclides) + do i = 1,size(self % nuclides) + nucIdx = self % nuclides(i) - if(E /= nuclideCache(nucIdx) % E_tail) call self % data % updateMicroXSs(E, nucIdx, rand) - xs = xs - nuclideCache(nucIdx) % xss % nuFission * self % dens(i) - if(xs < ZERO) return + + ! If the material uses TMS, the Doppler correction factor is needed + if (self % useTMS(E)) then + + nuc => ceNeutronNuclide_CptrCast(self % data % getNuclide(nucIdx)) + if (.not. associated(nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + + A = nuc % getMass() + nuckT = nuc % getkT() + deltakT = self % kT - nuckT + doppCorr = dopplerCorrectionFactor(E, A, deltakT) + + else + doppCorr = ONE + end if + + ! The nuclide cache should be at the right energy after updating the material + ! In the case of TMS where the macro xss are at a relative energy, the nuclide + ! xss to be used are at the relative energy just sampled + xs = xs - nuclideCache(nucIdx) % xss % nuFission * self % dens(i) * doppCorr + + if (xs < ZERO) return + end do ! Print error message as the inversion failed @@ -340,26 +494,49 @@ function sampleScatter(self, E, rand) result(nucIdx) class(ceNeutronMaterial), intent(in) :: self real(defReal), intent(in) :: E class(RNG), intent(inout) :: rand - integer(shortInt) :: nucIdx - real(defReal) :: xs - integer(shortInt) :: i + class(ceNeutronNuclide), pointer :: nuc + integer(shortInt) :: nucIdx, i + real(defReal) :: xs, doppCorr, A, nuckT, deltakT character(100), parameter :: Here = 'sampleScatter (ceNeutronMaterial_class.f90)' ! Calculate material macroscopic cross section of all scattering - if(E /= materialCache(self % matIdx) % E_tail) then - call self % data % updateMacroXSs(E, self % matIdx, rand) - end if + ! The cache is updated without checking the energy to get the correct results with TMS + ! The relative energy flag cached is cleaned to make sure cross sections are updated + materialCache(self % matIdx) % E_rel = ZERO + call self % data % updateMacroXSs(E, self % matIdx, rand) xs = rand % get() * (materialCache(self % matIdx) % xss % elasticScatter + & materialCache(self % matIdx) % xss % inelasticScatter) ! Loop over all nuclides - do i=1,size(self % nuclides) + do i = 1,size(self % nuclides) + nucIdx = self % nuclides(i) - if(E /= nuclideCache(nucIdx) % E_tail) call self % data % updateMicroXSs(E, nucIdx, rand) + + ! If the material uses TMS, the Doppler correction factor is needed + if (self % useTMS(E)) then + + ! If the material is using TMS, the Doppler correction factor is needed + nuc => ceNeutronNuclide_CptrCast(self % data % getNuclide(nucIdx)) + if (.not. associated(nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + + A = nuc % getMass() + nuckT = nuc % getkT() + deltakT = self % kT - nuckT + doppCorr = dopplerCorrectionFactor(E, A, deltakT) + + else + doppCorr = ONE + end if + + ! The nuclide cache should be at the right energy after updating the material + ! In the case of TMS where the macro xss are at a relative energy, the nuclide + ! xss to be used are at the relative energy just sampled xs = xs - (nuclideCache(nucIdx) % xss % elasticScatter + & - nuclideCache(nucIdx) % xss % inelasticScatter ) * self % dens(i) - if(xs < ZERO) return + nuclideCache(nucIdx) % xss % inelasticScatter ) * self % dens(i) * doppCorr + + if (xs < ZERO) return + end do ! Print error message as the inversion failed @@ -389,28 +566,51 @@ function sampleScatterWithFission(self, E, rand) result(nucIdx) class(ceNeutronMaterial), intent(in) :: self real(defReal), intent(in) :: E class(RNG), intent(inout) :: rand - integer(shortInt) :: nucIdx - real(defReal) :: xs - integer(shortInt) :: i + class(ceNeutronNuclide), pointer :: nuc + integer(shortInt) :: nucIdx, i + real(defReal) :: xs, doppCorr, A, nuckT, deltakT character(100), parameter :: Here = 'sampleScatterWithFission (ceNeutronMaterial_class.f90)' - ! Calculate material macroscopic cross section of all scattering - if(E /= materialCache(self % matIdx) % E_tail) then - call self % data % updateMacroXSs(E, self % matIdx, rand) - end if + ! Calculate material macroscopic cross section of all scattering and fission + ! The cache is updated without checking the energy to get the correct results with TMS + ! The relative energy flag cached is cleaned to make sure cross sections are updated + materialCache(self % matIdx) % E_rel = ZERO + call self % data % updateMacroXSs(E, self % matIdx, rand) xs = rand % get() * (materialCache(self % matIdx) % xss % elasticScatter + & materialCache(self % matIdx) % xss % inelasticScatter + & materialCache(self % matIdx) % xss % fission) ! Loop over all nuclides - do i=1,size(self % nuclides) + do i = 1,size(self % nuclides) + nucIdx = self % nuclides(i) - if(E /= nuclideCache(nucIdx) % E_tail) call self % data % updateMicroXSs(E, nucIdx, rand) + + ! If the material uses TMS, the Doppler correction factor is needed + if (self % useTMS(E)) then + + ! If the material is using TMS, the Doppler correction factor is needed + nuc => ceNeutronNuclide_CptrCast(self % data % getNuclide(nucIdx)) + if (.not. associated(nuc)) call fatalError(Here, 'Failed to retrieve CE Neutron Nuclide') + + A = nuc % getMass() + nuckT = nuc % getkT() + deltakT = self % kT - nuckT + doppCorr = dopplerCorrectionFactor(E, A, deltakT) + + else + doppCorr = ONE + end if + + ! The nuclide cache should be at the right energy after updating the material + ! In the case of TMS where the macro xss are at a relative energy, the nuclide + ! xss to be used are at the relative energy just sampled xs = xs - (nuclideCache(nucIdx) % xss % elasticScatter + & nuclideCache(nucIdx) % xss % inelasticScatter + & - nuclideCache(nucIdx) % xss % fission ) * self % dens(i) - if(xs < ZERO) return + nuclideCache(nucIdx) % xss % fission) * self % dens(i) * doppCorr + + if (xs < ZERO) return + end do ! Print error message as the inversion failed diff --git a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 index 286a04e93..645c6f79e 100644 --- a/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 +++ b/NuclearData/ceNeutronData/ceNeutronNuclide_inter.f90 @@ -79,6 +79,7 @@ module ceNeutronNuclide_inter procedure(invertInelastic),deferred :: invertInelastic procedure(xsOf), deferred :: xsOf procedure(elScatteringXS), deferred :: elScatteringXS + procedure(needsSabEl), deferred :: needsSabEl end type ceNeutronNuclide @@ -153,7 +154,26 @@ function elScatteringXS(self, E) result(xs) end function elScatteringXS + !! + !! Function that checks whether this nuclide at the provided energy should + !! have S(a,b) elastic scattering data or not + !! + !! Args: + !! E [in] -> incident neutron energy + !! + !! Result: + !! True or false + !! + elemental function needsSabEl(self, E) result(doesIt) + import :: ceNeutronNuclide, defReal, defBool + class(ceNeutronNuclide), intent(in) :: self + real(defReal), intent(in) :: E + logical(defBool) :: doesIt + + end function needsSabEl + end interface + contains !! @@ -176,11 +196,11 @@ function getTotalXS(self, E, rand) result(xs) real(defReal) :: xs ! Check Cache and update if needed - if (nuclideCache(self % getNucIdx()) % E_tot /= E) then + if (nuclideCache(self % nucIdx) % E_tot /= E) then call self % data % updateTotalNucXS(E, self % nucIdx, rand) end if - xs = nuclideCache(self % getNucIdx()) % xss % total + xs = nuclideCache(self % nucIdx) % xss % total end function getTotalXS @@ -202,11 +222,11 @@ subroutine getMicroXSs(self, xss, E, rand) class(RNG), intent(inout) :: rand ! Check Cache and update if needed - if(nuclideCache(self % getNucIdx()) % E_tail /= E) then + if (nuclideCache(self % nucIdx) % E_tail /= E) then call self % data % updateMicroXSs(E, self % nucIdx, rand) end if - xss = nuclideCache(self % getNucIdx()) % xss + xss = nuclideCache(self % nucIdx) % xss end subroutine getMicroXSs @@ -240,18 +260,18 @@ subroutine set(self, nucIdx, database, fissile, mass, kT, dbrc) logical(defBool), intent(in), optional :: dbrc character(100), parameter :: Here = 'set (ceNuetronNuclide_inter.f90)' - if(present(nucIdx)) self % nucIdx = nucIdx - if(present(database)) self % data => database - if(present(fissile)) self % fissile = fissile - if(present(dbrc)) self % DBRC = dbrc + if (present(nucIdx)) self % nucIdx = nucIdx + if (present(database)) self % data => database + if (present(fissile)) self % fissile = fissile + if (present(dbrc)) self % DBRC = dbrc - if(present(mass)) then - if(mass <= ZERO) call fatalError(Here,"Mass of nuclide cannot be -ve: "//numToChar(mass)) + if (present(mass)) then + if (mass <= ZERO) call fatalError(Here,"Mass of nuclide cannot be -ve: "//numToChar(mass)) self % mass = mass end if - if(present(kT)) then - if(kT < ZERO) call fatalError(Here, "Temperature of nuclide cannot be -ve: "//numToChar(kT)) + if (present(kT)) then + if (kT < ZERO) call fatalError(Here, "Temperature of nuclide cannot be -ve: "//numToChar(kT)) self % kT = kT end if diff --git a/NuclearData/materialMenu_mod.f90 b/NuclearData/materialMenu_mod.f90 index 729e209da..6d8460e58 100644 --- a/NuclearData/materialMenu_mod.f90 +++ b/NuclearData/materialMenu_mod.f90 @@ -100,6 +100,7 @@ module materialMenu_mod real(defReal),dimension(:),allocatable :: dens type(nuclideInfo),dimension(:),allocatable :: nuclides type(dictionary) :: extraInfo + logical(defBool) :: hasTMS = .false. contains procedure :: init => init_materialItem procedure :: kill => kill_materialItem @@ -200,11 +201,13 @@ subroutine display() print '(A60)', repeat('<>',30) print '(A)', "^^ MATERIAL DEFINITIONS ^^" + do i = 1,size(materialDefs) call materialDefs(i) % display() ! Print separation line print '(A)', " ><((((*> + <*))))><" end do + print '(A60)', repeat('<>',30) end subroutine display @@ -285,10 +288,20 @@ subroutine init_materialItem(self, name, idx, dict) ! Return to initial state call self % kill() - ! Load easy components c + ! Load easy components properties self % name = name self % matIdx = idx - call dict % get(self % T,'temp') + + ! Check TMS flag and read temperature + call dict % getOrDefault(self % hasTMS, 'tms', .false.) + + if (self % hasTMS .and. .not. dict % isPresent('temp')) then + call fatalError(Here, 'The material temperature must be specified when TMS is on') + end if + + call dict % getOrDefault(self % T, 'temp', ZERO) + if (self % T < ZERO) call fatalError(Here, 'The temperature of material '//numToChar(idx)//& + ' is negative: '//numToChar(self % T)) ! Get composition dictionary and load composition compDict => dict % getDictPtr('composition') @@ -298,12 +311,14 @@ subroutine init_materialItem(self, name, idx, dict) allocate(self % nuclides(size(keys))) allocate(self % dens(size(keys))) - hasSab = .false. + ! Check if S(a,b) files are specified if (dict % isPresent('moder')) then moderDict => dict % getDictPtr('moder') call moderDict % keys(moderKeys) hasSab = .true. + else + hasSab = .false. end if ! Load definitions diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 771d0b730..082783270 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -63,6 +63,7 @@ module baseMgNeutronDatabase_class contains ! Superclass Interface procedure :: getTrackingXS + procedure :: getTrackMatXS procedure :: getTotalMatXS procedure :: getMajorantXS procedure :: matNamesMap @@ -102,7 +103,7 @@ function getTrackingXS(self, p, matIdx, what) result(xs) select case(what) case (MATERIAL_XS) - xs = self % getTotalMatXS(p, matIdx) + xs = self % getTrackMatXS(p, matIdx) case (MAJORANT_XS) xs = self % getMajorantXS(p) @@ -112,6 +113,7 @@ function getTrackingXS(self, p, matIdx, what) result(xs) ! READ ONLY - read from previously updated cache if (p % G == trackingCache(1) % G) then xs = trackingCache(1) % xs + return else call fatalError(Here, 'Tracking cache failed to update during tracking') end if @@ -128,7 +130,23 @@ function getTrackingXS(self, p, matIdx, what) result(xs) end function getTrackingXS !! - !! Get Total XS given a particle + !! Get tracking XS given a particle. In MG, it is always identical to the material + !! total XS. + !! + !! See nuclearDatabase documentation for details + !! + function getTrackMatXS(self, p, matIdx) result(xs) + class(baseMgNeutronDatabase), intent(inout) :: self + class(particle), intent(in) :: p + integer(shortInt), intent(in) :: matIdx + real(defReal) :: xs + + xs = self % getTotalMatXS(p, matIdx) + + end function getTrackMatXS + + !! + !! Get total XS given a particle !! !! See nuclearDatabase documentation for details !! @@ -162,7 +180,7 @@ function getTotalMatXS(self, p, matIdx) result(xs) end function getTotalMatXS !! - !! Get Majorant XS given a particle + !! Get majorant XS given a particle !! !! See nuclearDatabase documentation for details !! diff --git a/NuclearData/nuclearDatabase_inter.f90 b/NuclearData/nuclearDatabase_inter.f90 index dea78836f..d1e25113a 100644 --- a/NuclearData/nuclearDatabase_inter.f90 +++ b/NuclearData/nuclearDatabase_inter.f90 @@ -22,6 +22,7 @@ module nuclearDatabase_inter !! !! Interface: !! getTrackingXS -> returns XS used to sample track length + !! getTrackMatXS -> returns material tracking xs, which could be different from the total (e.g., with TMS) !! getTotalMatXS -> returns total Material XS given a particle !! getMajorantXS -> returns majorant XS given particle and list of active materials !! matNamesMap -> returns pointer to map of material names to matIdx @@ -35,6 +36,7 @@ module nuclearDatabase_inter procedure(init), deferred :: init procedure(activate), deferred :: activate procedure(getTrackingXS), deferred :: getTrackingXS + procedure(getTrackMatXS), deferred :: getTrackMatXS procedure(getTotalMatXS), deferred :: getTotalMatXS procedure(getMajorantXS), deferred :: getMajorantXS procedure(matNamesMap), deferred :: matNamesMap @@ -84,7 +86,7 @@ subroutine activate(self, activeMat, silent) end subroutine activate !! - !! Return value of Tracking XS for a particle and a given request + !! Return value of tracking XS for a particle and a given request !! !! Reads all relevant state information from the particle (e.g. E or G) !! It is the XS used to sample track length: it might be the same as the @@ -112,7 +114,33 @@ function getTrackingXS(self, p, matIdx, what) result(xs) end function getTrackingXS !! - !! Return value of Material Total XS for a particle + !! Return value of materials tracking XS for a particle + !! + !! Reads all relevant state information from the particle (e.g. E or G) + !! It is the XS used to sample track length in a material: it might be the same + !! as the material total XS, or a material temperature majorant when TMS is used + !! + !! Args: + !! p [in] -> Particle at a given state + !! matIdx [in] -> Material index + !! + !! Result: + !! Value of material tracking XS [1/cm] + !! + !! Errors: + !! Undefined behaviour if the state of the particle is invalid e.g. -ve energy + !! Undefined behavior if matIdx does not correspond to a defined material + !! + function getTrackMatXS(self, p, matIdx) result(xs) + import :: nuclearDatabase, particle, shortInt, defReal + class(nuclearDatabase), intent(inout) :: self + class(particle), intent(in) :: p + integer(shortInt), intent(in) :: matIdx + real(defReal) :: xs + end function getTrackMatXS + + !! + !! Return value of material total XS for a particle !! !! Reads all relevalnt state information from the particle (e.g. E or G) !! @@ -136,7 +164,7 @@ function getTotalMatXS(self, p, matIdx) result(xs) end function getTotalMatXS !! - !! Return value of Majorant XS for a particle + !! Return value of majorant XS for a particle !! !! Reads all relevalnt state information from the particle (e.g. E or G) !! Majorant XS is the largest of TRANSPORT XSs for ACTIVE materials diff --git a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 index 3112f9538..e6032e73b 100644 --- a/NuclearData/testNeutronData/testNeutronDatabase_class.f90 +++ b/NuclearData/testNeutronData/testNeutronDatabase_class.f90 @@ -45,6 +45,7 @@ module testNeutronDatabase_class procedure :: init procedure :: activate procedure :: getTrackingXS + procedure :: getTrackMatXS procedure :: getTotalMatXS procedure :: getMajorantXS procedure :: matNamesMap @@ -179,7 +180,22 @@ function getTrackingXS(self, p, matIdx, what) result(xs) end function getTrackingXS !! - !! Return value of Material Total XS for a particle + !! Return value of material tracking XS for a particle + !! + !! See nuclearDatabase_inter for details + !! + function getTrackMatXS(self, p, matIdx) result(xs) + class(testNeutronDatabase), intent(inout) :: self + class(particle), intent(in) :: p + integer(shortInt), intent(in) :: matIdx + real(defReal) :: xs + + xs = self % xsVal + + end function getTrackMatXS + + !! + !! Return value of material total XS for a particle !! !! See nuclearDatabase_inter for details !! diff --git a/ParticleObjects/particle_class.f90 b/ParticleObjects/particle_class.f90 index e5bd009d6..cf0f92787 100644 --- a/ParticleObjects/particle_class.f90 +++ b/ParticleObjects/particle_class.f90 @@ -70,6 +70,7 @@ module particle_class ! Private procedures procedure,private :: equal_particleState + end type particleState !! @@ -658,7 +659,7 @@ subroutine particleState_fromParticle(LHS,RHS) LHS % uniqueID = RHS % coords % uniqueId LHS % cellIdx = RHS % coords % cell() LHS % collisionN = RHS % collisionN - LHS % broodID = RHS % broodID + LHS % broodID = RHS % broodID end subroutine particleState_fromParticle @@ -682,7 +683,7 @@ function equal_particleState(LHS,RHS) result(isEqual) isEqual = isEqual .and. LHS % cellIdx == RHS % cellIdx isEqual = isEqual .and. LHS % uniqueID == RHS % uniqueID isEqual = isEqual .and. LHS % collisionN == RHS % collisionN - isEqual = isEqual .and. LHS % broodID == RHS % broodID + isEqual = isEqual .and. LHS % broodID == RHS % broodID if( LHS % isMG ) then isEqual = isEqual .and. LHS % G == RHS % G @@ -725,7 +726,7 @@ elemental subroutine kill_particleState(self) self % cellIdx = -1 self % uniqueID = -1 self % collisionN = 0 - self % broodID = 0 + self % broodID = 0 end subroutine kill_particleState diff --git a/SharedModules/numPrecision.f90 b/SharedModules/numPrecision.f90 index ec7d22a43..dfed315e5 100644 --- a/SharedModules/numPrecision.f90 +++ b/SharedModules/numPrecision.f90 @@ -19,13 +19,14 @@ module numPrecision ZERO = 0._defReal, & ONE = 1.0_defReal, & TWO = 2.0_defReal, & - TWO_PI = TWO * PI, & - HALF = 0.5_defReal + TWO_PI = TWO * PI, & + SQRT_PI = sqrt(PI), & + HALF = 0.5_defReal real(defReal), public, parameter :: floatTol = 1.0e-12 !*** Should be replaced real(defReal), public, parameter :: FP_REL_TOL = 1.0e-7_defReal contains - + end module numPrecision diff --git a/SharedModules/universalVariables.f90 b/SharedModules/universalVariables.f90 index b6ee050d5..1b447271c 100644 --- a/SharedModules/universalVariables.f90 +++ b/SharedModules/universalVariables.f90 @@ -64,10 +64,11 @@ module universalVariables P_NEUTRON_MG = 2 ! Search error codes - integer(shortInt), parameter :: valueOutsideArray = -1,& - tooManyIter = -2,& + integer(shortInt), parameter :: valueOutsideArray = -1, & + tooManyIter = -2, & targetNotFound = -3, & - NOT_FOUND = -3 + NOT_FOUND = -3, & + REJECTED = -4 ! Integer indexes for type of tracking cross section requested integer(shortInt), parameter :: MATERIAL_XS = 1, & @@ -78,6 +79,7 @@ module universalVariables ! Neutron mass and speed of light in vacuum from from https://physics.nist.gov/cuu/Constants/index.html real(defReal), parameter :: neutronMass = 939.56542194_defReal, & ! Neutron mass in MeV (m*c^2) lightSpeed = 2.99792458e10_defReal, & ! Light speed in cm/s + kBoltzmann = 1.380649e-23_defReal, & ! Bolztmann constant in J/K energyPerFission = 200.0_defReal ! MeV ! Unit conversion diff --git a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 index d688c8bfd..f2086382c 100644 --- a/Tallies/TallyClerks/Tests/collisionClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/collisionClerk_test.f90 @@ -178,8 +178,9 @@ subroutine testScoring(this) call res2Dict % store('value', 1.3_defReal) ! Configure dictionary for the clerk - call clerkDict % init(6) + call clerkDict % init(7) call clerkDict % store('type','collisionClerk') + call clerkDict % store('handleVirtual', 0) call clerkDict % store(res1Name, res1Dict) call clerkDict % store(res2Name, res2Dict) @@ -297,7 +298,6 @@ subroutine testScoringVirtual(this) ! Configure dictionary for the clerk call clerkDict % init(6) call clerkDict % store('type','collisionClerk') - call clerkDict % store('handleVirtual', 1) call clerkDict % store(res1Name, res1Dict) call clerkDict % store(res2Name, res2Dict) diff --git a/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 b/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 index 9831fcb96..dee2593cb 100644 --- a/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/keffImplicitClerk_test.f90 @@ -129,6 +129,7 @@ subroutine test1CycleBatch(this) @assertTrue(.false.,'Result is not a keffResult') end select + end subroutine test1CycleBatch !! diff --git a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 index 85a93fdd6..211039780 100644 --- a/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 +++ b/Tallies/TallyClerks/Tests/mgXsClerk_test.f90 @@ -230,7 +230,7 @@ subroutine testScoring_clerk2(this) @assertEqual([HALF, ZERO, HALF], chi(1,:), TOL, 'Chi' ) @assertEqual([ZERO, ZERO, 4.0_defReal], transOS(1,:), TOL, 'Transport XS O.S.' ) @assertEqual([ZERO, ZERO, 5.5_defReal], transFL(1,:), TOL, 'Transport XS F.L.' ) - @assertEqual([ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, TWO, ZERO], P0(1,:), TOL, 'P0' ) + @assertEqual([ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, TWO, ZERO], P0(1,:), TOL, 'P0' ) @assertEqual([ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, 1.5_defReal, ZERO], P1(1,:), TOL, 'P1' ) @assertEqual([ONE, ONE, ONE, ONE, ONE, ONE, ONE, TWO, ONE], prod(1,:), TOL, 'prod' ) diff --git a/Tallies/TallyClerks/collisionClerk_class.f90 b/Tallies/TallyClerks/collisionClerk_class.f90 index 0c37c9c11..67cec49af 100644 --- a/Tallies/TallyClerks/collisionClerk_class.f90 +++ b/Tallies/TallyClerks/collisionClerk_class.f90 @@ -62,7 +62,7 @@ module collisionClerk_class integer(shortInt) :: width = 0 ! Settings - logical(defBool) :: virtual = .false. + logical(defBool) :: handleVirtual = .true. contains ! Procedures used during build @@ -120,7 +120,7 @@ subroutine init(self, dict, name) self % width = size(responseNames) ! Handle virtual collisions - call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + call dict % getOrDefault(self % handleVirtual,'handleVirtual', .true.) end subroutine init @@ -134,23 +134,23 @@ elemental subroutine kill(self) call kill_super(self) ! Kill and deallocate filter - if(allocated(self % filter)) then + if (allocated(self % filter)) then deallocate(self % filter) end if ! Kill and deallocate map - if(allocated(self % map)) then + if (allocated(self % map)) then call self % map % kill() deallocate(self % map) end if ! Kill and deallocate responses - if(allocated(self % response)) then + if (allocated(self % response)) then deallocate(self % response) end if self % width = 0 - self % virtual = .false. + self % handleVirtual = .true. end subroutine kill @@ -194,29 +194,23 @@ subroutine reportInColl(self, p, xsData, mem, virtual) logical(defBool), intent(in) :: virtual type(particleState) :: state integer(shortInt) :: binIdx, i - integer(longInt) :: adrr + integer(longInt) :: addr real(defReal) :: scoreVal, flux character(100), parameter :: Here = 'reportInColl (collisionClerk_class.f90)' ! Return if collision is virtual but virtual collision handling is off - if (self % virtual) then - ! Retrieve tracking cross section from cache - flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) - else - if (virtual) return - flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if + if ((.not. self % handleVirtual) .and. virtual) return ! Get current particle state state = p ! Check if within filter - if(allocated( self % filter)) then - if(self % filter % isFail(state)) return + if (allocated(self % filter)) then + if (self % filter % isFail(state)) return end if ! Find bin index - if(allocated(self % map)) then + if (allocated(self % map)) then binIdx = self % map % map(state) else binIdx = 1 @@ -225,13 +219,20 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if invalid bin index if (binIdx == 0) return + ! Calculate flux with the right cross section according to virtual collision handling + if (self % handleVirtual) then + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) + else + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) + end if + ! Calculate bin address - adrr = self % getMemAddress() + self % width * (binIdx -1) - 1 + addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 ! Append all bins - do i = 1,self % width + do i = 1, self % width scoreVal = self % response(i) % get(p, xsData) * flux - call mem % score(scoreVal, adrr + i) + call mem % score(scoreVal, addr + i) end do @@ -268,13 +269,13 @@ subroutine print(self, outFile, mem) call outFile % startBlock(self % getName()) ! If collision clerk has map print map information - if( allocated(self % map)) then + if (allocated(self % map)) then call self % map % print(outFile) end if ! Write results. ! Get shape of result array - if(allocated(self % map)) then + if (allocated(self % map)) then resArrayShape = [size(self % response), self % map % binArrayShape()] else resArrayShape = [size(self % response)] @@ -285,7 +286,7 @@ subroutine print(self, outFile, mem) call outFile % startArray(name, resArrayShape) ! Print results to the file - do i=1,product(resArrayShape) + do i = 1, product(resArrayShape) call mem % getResult(val, std, self % getMemAddress() - 1 + i) call outFile % addResult(val,std) diff --git a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 index 06da8f2d8..b6182d5cb 100644 --- a/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 +++ b/Tallies/TallyClerks/collisionProbabilityClerk_class.f90 @@ -21,9 +21,6 @@ module collisionProbabilityClerk_class use tallyMap_inter, only : tallyMap use tallyMapFactory_func, only : new_tallyMap - ! Tally Response - !use macroResponse_class, only : macroResponse - implicit none private @@ -72,7 +69,6 @@ module collisionProbabilityClerk_class integer(shortInt) :: N = 0 !! Number of bins !type(macroResponse) :: resp - contains ! Procedures used during build procedure :: init @@ -92,6 +88,7 @@ module collisionProbabilityClerk_class ! Deconstructor procedure :: kill + end type collisionProbabilityClerk !! @@ -192,7 +189,7 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Find starting index in the map ! It is important that preCollision is not changed by a collisionProcessor ! before the particle is fed to the tally, otherwise results will be meaningless - sIdx = self % map % map( p % preCollision) + sIdx = self % map % map(p % preCollision) ! Find collision index in the map state = p diff --git a/Tallies/TallyClerks/keffImplicitClerk_class.f90 b/Tallies/TallyClerks/keffImplicitClerk_class.f90 index ad5f52e21..008c50e02 100644 --- a/Tallies/TallyClerks/keffImplicitClerk_class.f90 +++ b/Tallies/TallyClerks/keffImplicitClerk_class.f90 @@ -33,10 +33,9 @@ module keffImplicitClerk_class IMP_ABS = 2 ,& ! Implicit neutron absorbtion ANA_LEAK = 3 ,& ! Analog Leakage K_EFF = 4 ! k-eff estimate - !! !! A simple implicit k-eff estimator based on collison estimator of reaction rates, - !! and an analog estimators of (N,XN) reactions and leakage + !! and on analog estimators of (N,XN) reactions and leakage !! !! Private Members: !! targetSTD -> Target Standard Deviation for convergance check @@ -57,7 +56,7 @@ module keffImplicitClerk_class private real(defReal) :: targetSTD = ZERO ! Settings - logical(defBool) :: virtual = .false. + logical(defBool) :: handleVirtual = .true. contains ! Duplicate interface of the tallyClerk ! Procedures used during build @@ -78,6 +77,7 @@ module keffImplicitClerk_class procedure :: display procedure :: print procedure :: getResult + end type keffImplicitClerk contains @@ -106,7 +106,7 @@ subroutine init(self, dict, name) end if ! Handle virtual collisions - call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + call dict % getOrDefault(self % handleVirtual,'handleVirtual', .true.) end subroutine init @@ -121,7 +121,7 @@ elemental subroutine kill(self) ! Kill self self % targetSTD = ZERO - self % virtual = .false. + self % handleVirtual = .true. end subroutine kill @@ -169,17 +169,18 @@ subroutine reportInColl(self, p, xsData, mem, virtual) character(100), parameter :: Here = 'reportInColl (keffImplicitClerk_class.f90)' ! Return if collision is virtual but virtual collision handling is off - if (self % virtual) then - ! Retrieve tracking cross section from cache + if ((.not. self % handleVirtual) .and. virtual) return + + ! Ensure we're not in void (could happen when scoring virtual collisions) + if (p % matIdx() == VOID_MAT) return + + ! Calculate flux with the right cross section according to virtual collision handling + if (self % handleVirtual) then flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) else - if (virtual) return flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) end if - ! Ensure we're not in void (could happen when scoring virtual collisions) - if (p % matIdx() == VOID_MAT) return - ! Get material pointer mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) if (.not.associated(mat)) then @@ -251,12 +252,12 @@ subroutine reportHist(self, p, xsData, mem) type(scoreMemory), intent(inout) :: mem real(defReal) :: histWgt - if( p % fate == leak_FATE) then + if (p % fate == leak_FATE) then ! Obtain and score history weight histWgt = p % w ! Score analog leakage - call mem % score( histWgt, self % getMemAddress() + ANA_LEAK) + call mem % score(histWgt, self % getMemAddress() + ANA_LEAK) end if @@ -274,14 +275,14 @@ subroutine reportCycleEnd(self, end, mem) integer(longInt) :: addr real(defReal) :: nuFiss, absorb, leakage, scatterMul, k_est - if( mem % lastCycle()) then + if (mem % lastCycle()) then addr = self % getMemAddress() nuFiss = mem % getScore(addr + IMP_PROD) absorb = mem % getScore(addr + IMP_ABS) leakage = mem % getScore(addr + ANA_LEAK) scatterMul = mem % getScore(addr + SCATTER_PROD) - k_est = nuFiss / (absorb + leakage - scatterMul ) + k_est = nuFiss / (absorb + leakage - scatterMul) call mem % accumulate(k_est, addr + K_EFF) end if @@ -315,7 +316,7 @@ subroutine display(self, mem) real(defReal) :: k, STD ! Get current k-eff estimate - call mem % getResult(k, STD, self % getMemAddress() + K_EFF ) + call mem % getResult(k, STD, self % getMemAddress() + K_EFF) ! Print to console print '(A,F8.5,A,F8.5)', 'k-eff (implicit): ', k, ' +/- ', STD diff --git a/Tallies/TallyClerks/mgXsClerk_class.f90 b/Tallies/TallyClerks/mgXsClerk_class.f90 index b3199f117..80ea66204 100644 --- a/Tallies/TallyClerks/mgXsClerk_class.f90 +++ b/Tallies/TallyClerks/mgXsClerk_class.f90 @@ -91,7 +91,7 @@ module mgXsClerk_class logical(defBool) :: PN = .false. ! Settings - logical(defBool) :: virtual = .false. + logical(defBool) :: handleVirtual = .true. contains ! Procedures used during build @@ -155,6 +155,9 @@ subroutine init(self, dict, name) self % width = ARRAY_SCORE_SIZE + MATRIX_SCORE_SMALL * self % energyN end if + ! Handle virtual collisions + call dict % getOrDefault(self % handleVirtual,'handleVirtual', .true.) + end subroutine init !! @@ -178,7 +181,7 @@ elemental subroutine kill(self) self % energyN = 0 self % width = 0 self % PN = .false. - self % virtual = .false. + self % handleVirtual = .false. end subroutine kill @@ -223,18 +226,12 @@ subroutine reportInColl(self, p, xsData, mem, virtual) type(neutronMacroXSs) :: xss class(neutronMaterial), pointer :: mat real(defReal) :: nuFissXS, captXS, fissXS, scattXS, flux - integer(shortInt) :: enIdx, matIdx, binIdx + integer(shortInt) :: enIdx, locIdx, binIdx integer(longInt) :: addr character(100), parameter :: Here =' reportInColl (mgXsClerk_class.f90)' ! Return if collision is virtual but virtual collision handling is off - if (self % virtual) then - ! Retrieve tracking cross section from cache - flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) - else - if (virtual) return - flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if + if ((.not. self % handleVirtual) .and. virtual) return ! Get current particle state state = p @@ -248,35 +245,54 @@ subroutine reportInColl(self, p, xsData, mem, virtual) end if ! Space if (allocated(self % spaceMap)) then - matIdx = self % spaceMap % map(state) + locIdx = self % spaceMap % map(state) else - matIdx = 1 + locIdx = 1 end if ! Return if invalid bin index - if ((enIdx == self % energyN + 1) .or. matIdx == 0) return + if ((enIdx == self % energyN + 1) .or. locIdx == 0) return ! Calculate bin address - binIdx = self % energyN * (matIdx - 1) + enIdx + binIdx = self % energyN * (locIdx - 1) + enIdx addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 - ! Ensure we're not in void (could happen when scoring virtual collisions) - if (p % matIdx() == VOID_MAT) return - - ! Get material pointer - mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) - if (.not.associated(mat)) then - call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') + ! Calculate flux with the right cross section according to virtual collision handling + if (self % handleVirtual) then + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) + else + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) end if - ! Retrieve material cross sections - call mat % getMacroXSs(xss, p) + ! Check if the particle is in void. This call might happen when handling virtual collisions. + ! This is relevant in the case of homogenising materials that include void: the flux + ! in void will be different than zero, and the zero reaction rates have to be averaged + if (p % matIdx() /= VOID_MAT) then - ! Calculate reaction rates - nuFissXS = xss % nuFission * flux - captXS = xss % capture * flux - fissXS = xss % fission * flux - scattXS = (xss % elasticScatter + xss % inelasticScatter) * flux + ! Get material pointer + mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) + if (.not.associated(mat)) then + call fatalError(Here,'Unrecognised type of material was retrived from nuclearDatabase') + end if + + ! Retrieve material cross sections + call mat % getMacroXSs(xss, p) + + ! Calculate reaction rates + nuFissXS = xss % nuFission * flux + captXS = xss % capture * flux + fissXS = xss % fission * flux + scattXS = (xss % elasticScatter + xss % inelasticScatter) * flux + + else + + ! Reaction rates in void are zero + nuFissXS = ZERO + captXS = ZERO + fissXS = ZERO + scattXS = ZERO + + end if ! Add scores to counters call mem % score(flux, addr + FLUX_idx) @@ -301,7 +317,7 @@ subroutine reportOutColl(self, p, MT, muL, xsData, mem) type(scoreMemory), intent(inout) :: mem type(particleState) :: preColl, postColl real(defReal) :: score, prod, mu, mu2, mu3, mu4, mu5 - integer(shortInt) :: enIdx, matIdx, binIdx, binEnOut + integer(shortInt) :: enIdx, locIdx, binIdx, binEnOut integer(longInt) :: addr ! Get pre and post collision particle state @@ -335,16 +351,16 @@ subroutine reportOutColl(self, p, MT, muL, xsData, mem) end if ! Space if (allocated(self % spaceMap)) then - matIdx = self % spaceMap % map(preColl) + locIdx = self % spaceMap % map(preColl) else - matIdx = 1 + locIdx = 1 end if ! Return if invalid bin index - if ((enIdx == self % energyN + 1) .or. matIdx == 0) return + if ((enIdx == self % energyN + 1) .or. locIdx == 0) return ! Calculate bin address - binIdx = self % energyN * (matIdx - 1) + enIdx + binIdx = self % energyN * (locIdx - 1) + enIdx addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 ! Score a scattering event from group g @@ -427,7 +443,7 @@ subroutine reportSpawn(self, MT, pOld, pNew, xsData, mem) class(particleState), intent(in) :: pNew class(nuclearDatabase), intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem - integer(longInt) :: addr, binIdx, enIdx, matIdx + integer(longInt) :: addr, binIdx, enIdx, locIdx if (MT == N_FISSION) then @@ -440,16 +456,16 @@ subroutine reportSpawn(self, MT, pOld, pNew, xsData, mem) end if ! Space if (allocated(self % spaceMap)) then - matIdx = self % spaceMap % map(pNew) + locIdx = self % spaceMap % map(pNew) else - matIdx = 1 + locIdx = 1 end if ! Return if invalid bin index - if ((enIdx == self % energyN + 1) .or. matIdx == 0) return + if ((enIdx == self % energyN + 1) .or. locIdx == 0) return ! Calculate bin address - binIdx = self % energyN * (matIdx - 1) + enIdx + binIdx = self % energyN * (locIdx - 1) + enIdx addr = self % getMemAddress() + self % width * (binIdx - 1) - 1 ! Score energy group of fission neutron diff --git a/Tallies/TallyClerks/simpleFMClerk_class.f90 b/Tallies/TallyClerks/simpleFMClerk_class.f90 index 93c72fe2e..a4e026aee 100644 --- a/Tallies/TallyClerks/simpleFMClerk_class.f90 +++ b/Tallies/TallyClerks/simpleFMClerk_class.f90 @@ -65,7 +65,7 @@ module simpleFMClerk_class real(defReal),dimension(:),allocatable :: startWgt integer(shortInt) :: N = 0 !! Number of bins ! Settings - logical(defBool) :: virtual = .false. + logical(defBool) :: handleVirtual = .true. contains ! Procedures used during build @@ -87,6 +87,7 @@ module simpleFMClerk_class ! Deconstructor procedure :: kill + end type simpleFMClerk !! @@ -98,7 +99,7 @@ module simpleFMClerk_class !! type,public, extends( tallyResult) :: FMresult integer(shortInt) :: N = 0 ! Size of FM - real(defReal), dimension(:,:,:),allocatable :: FM ! FM proper + real(defReal), dimension(:,:,:),allocatable :: FM ! FM proper end type FMResult contains @@ -129,7 +130,7 @@ subroutine init(self, dict, name) call self % resp % build(macroNuFission) ! Handle virtual collisions - call dict % getOrDefault(self % virtual,'handleVirtual', .false.) + call dict % getOrDefault(self % handleVirtual,'handleVirtual', .true.) end subroutine init @@ -174,11 +175,13 @@ subroutine reportCycleStart(self, start, mem) self % startWgt = ZERO ! Loop through a population and calculate starting weight in each bin - do i=1,start % popSize() - associate( state => start % get(i) ) + do i = 1,start % popSize() + + associate (state => start % get(i)) idx = self % map % map(state) - if(idx > 0) self % startWgt(idx) = self % startWgt(idx) + state % wgt + if (idx > 0) self % startWgt(idx) = self % startWgt(idx) + state % wgt end associate + end do end subroutine reportCycleStart @@ -194,21 +197,15 @@ subroutine reportInColl(self, p, xsData, mem, virtual) class(nuclearDatabase),intent(inout) :: xsData type(scoreMemory), intent(inout) :: mem logical(defBool), intent(in) :: virtual + class(neutronMaterial), pointer :: mat type(particleState) :: state integer(shortInt) :: sIdx, cIdx integer(longInt) :: addr real(defReal) :: score, flux - class(neutronMaterial), pointer :: mat - character(100), parameter :: Here = 'reportInColl simpleFMClear_class.f90' + character(100), parameter :: Here = 'reportInColl simpleFMClerk_class.f90' ! Return if collision is virtual but virtual collision handling is off - if (self % virtual) then - ! Retrieve tracking cross section from cache - flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) - else - if (virtual) return - flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) - end if + if ((.not. self % handleVirtual) .and. virtual) return ! Ensure we're not in void (could happen when scoring virtual collisions) if (p % matIdx() == VOID_MAT) return @@ -222,6 +219,13 @@ subroutine reportInColl(self, p, xsData, mem, virtual) ! Return if material is not fissile if (.not. mat % isFissile()) return + ! Calculate flux with the right cross section according to virtual collision handling + if (self % handleVirtual) then + flux = p % w / xsData % getTrackingXS(p, p % matIdx(), TRACKING_XS) + else + flux = p % w / xsData % getTotalMatXS(p, p % matIdx()) + end if + ! Find starting index in the map sIdx = self % map % map(p % preHistory) @@ -230,7 +234,7 @@ subroutine reportInColl(self, p, xsData, mem, virtual) cIdx = self % map % map(state) ! Defend against invalid collision or starting bin - if(cIdx == 0 .or. sIdx == 0 ) return + if (cIdx == 0 .or. sIdx == 0) return ! Calculate fission neutron production score = self % resp % get(p, xsData) * flux @@ -254,18 +258,18 @@ subroutine reportCycleEnd(self, end, mem) integer(longInt) :: addrFM real(defReal) :: normFactor - if(mem % lastCycle()) then + if (mem % lastCycle()) then ! Set address to the start of Fission Matrix - ! Decrease by 1 to get correct addres on the fisrt iteration of the loop + ! Decrease by 1 to get correct address on the first iteration of the loop addrFM = self % getMemAddress() - 1 ! Normalise and accumulate estimates - do i=1,self % N + do i = 1,self % N ! Calculate normalisation factor normFactor = self % startWgt(i) - if(normFactor /= ZERO) normFactor = ONE / normFactor + if (normFactor /= ZERO) normFactor = ONE / normFactor - do j=1,self % N + do j = 1,self % N ! Normalise FM column addrFM = addrFM + 1 call mem % closeBin(normFactor, addrFM) @@ -294,7 +298,7 @@ pure subroutine getResult(self, res, mem) ! Allocate result to FMresult ! Do not deallocate if already allocated to FMresult ! Its not to nice -> clean up - if(allocated(res)) then + if (allocated(res)) then select type(res) class is (FMresult) ! Do nothing @@ -315,7 +319,7 @@ pure subroutine getResult(self, res, mem) ! Check size and reallocate space if needed ! This is horrible. Hove no time to polish. Blame me (MAK) if (allocated(res % FM)) then - if( any(shape(res % FM) /= [self % N, self % N, 2])) then + if (any(shape(res % FM) /= [self % N, self % N, 2])) then deallocate(res % FM) allocate(res % FM(self % N, self % N, 2)) end if @@ -329,7 +333,7 @@ pure subroutine getResult(self, res, mem) ! Load entries addr = self % getMemAddress() - 1 do i = 1,self % N - do j=1, self % N + do j = 1, self % N addr = addr + 1 call mem % getResult(val, STD, addr) res % FM(j, i, 1) = val @@ -338,6 +342,7 @@ pure subroutine getResult(self, res, mem) end do end select + end subroutine getResult !! @@ -379,7 +384,7 @@ subroutine print(self, outFile, mem) call outFile % startArray(name, [self % N, self % N]) - do i=1,self % N * self % N + do i = 1,self % N * self % N addr = addr + 1 call mem % getResult(val, std, addr) call outFile % addResult(val, std) @@ -401,11 +406,11 @@ elemental subroutine kill(self) ! Call superclass call kill_super(self) - if(allocated(self % map)) deallocate(self % map) - if(allocated(self % startWgt)) deallocate(self % startWgt) + if (allocated(self % map)) deallocate(self % map) + if (allocated(self % startWgt)) deallocate(self % startWgt) self % N = 0 - self % virtual = .false. + self % handleVirtual = .true. call self % resp % kill() diff --git a/Tallies/TallyResponses/macroResponse_class.f90 b/Tallies/TallyResponses/macroResponse_class.f90 index a718a99af..59012772f 100644 --- a/Tallies/TallyResponses/macroResponse_class.f90 +++ b/Tallies/TallyResponses/macroResponse_class.f90 @@ -2,6 +2,7 @@ module macroResponse_class use numPrecision use endfConstants + use universalVariables, only : VOID_MAT use genericProcedures, only : fatalError, numToChar use dictionary_class, only : dictionary use particle_class, only : particle, P_NEUTRON @@ -121,14 +122,15 @@ function get(self, p, xsData) result(val) val = ZERO - ! Return 0.0 if particle is not neutron - if(p % type /= P_NEUTRON) return + ! Return zero if particle is not neutron or if the particle is in void + if (p % type /= P_NEUTRON) return + if (p % matIdx() == VOID_MAT) return ! Get pointer to active material data mat => neutronMaterial_CptrCast(xsData % getMaterial(p % matIdx())) ! Return if material is not a neutronMaterial - if(.not.associated(mat)) return + if (.not.associated(mat)) return call mat % getMacroXSs(xss, p) val = xss % get(self % MT) diff --git a/Tallies/TallyResponses/microResponse_class.f90 b/Tallies/TallyResponses/microResponse_class.f90 index 76d3d7635..225c20fce 100644 --- a/Tallies/TallyResponses/microResponse_class.f90 +++ b/Tallies/TallyResponses/microResponse_class.f90 @@ -2,6 +2,7 @@ module microResponse_class use numPrecision use endfConstants + use universalVariables, only : VOID_MAT use genericProcedures, only : fatalError, numToChar use dictionary_class, only : dictionary use particle_class, only : particle, P_NEUTRON @@ -153,17 +154,19 @@ function get(self, p, xsData) result(val) val = ZERO - ! Return 0.0 if particle is not neutron - if(p % type /= P_NEUTRON) return + ! Return zero if particle is not neutron or if the particle is in void + if (p % type /= P_NEUTRON) return + if (p % matIdx() == VOID_MAT) return ! Get pointer to active material data mat => neutronMaterial_CptrCast(xsData % getMaterial(self % matIdx)) ! Return if material is not a neutronMaterial - if(.not.associated(mat)) return + if (.not.associated(mat)) return ! Get the macroscopic cross section for the material call mat % getMacroXSs(xss, p) + ! Normalise the macroscopic cross section with the atomic density val = xss % get(self % MT) / self % dens diff --git a/TransportOperator/transportOperatorDT_class.f90 b/TransportOperator/transportOperatorDT_class.f90 index 46fbb9a9e..a19f05854 100644 --- a/TransportOperator/transportOperatorDT_class.f90 +++ b/TransportOperator/transportOperatorDT_class.f90 @@ -36,6 +36,7 @@ module transportOperatorDT_class procedure :: transit => deltaTracking ! Override procedure procedure :: init + end type transportOperatorDT contains @@ -84,7 +85,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Obtain the local cross-section - sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTrackMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual ! Exit the loop if the collision is real, report collision if virtual diff --git a/TransportOperator/transportOperatorHT_class.f90 b/TransportOperator/transportOperatorHT_class.f90 index 038a0fc1e..e7ea82435 100644 --- a/TransportOperator/transportOperatorHT_class.f90 +++ b/TransportOperator/transportOperatorHT_class.f90 @@ -33,12 +33,14 @@ module transportOperatorHT_class !! type, public, extends(transportOperator) :: transportOperatorHT real(defReal) :: cutoff ! Cutoff threshold between ST and DT + contains procedure :: transit => tracking_selection procedure, private :: deltaTracking procedure, private :: surfaceTracking ! Override procedure procedure :: init + end type transportOperatorHT contains @@ -56,7 +58,7 @@ subroutine tracking_selection(self, p, tally, thisCycle, nextCycle) majorant_inv = ONE / self % xsData % getTrackingXS(p, p % matIdx(), MAJORANT_XS) ! Obtain the local cross-section - sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTrackMatXS(p, p % matIdx()) ! Calculate ratio between local cross-section and majorant ratio = sigmaT*majorant_inv @@ -114,7 +116,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end if ! Obtain the local cross-section - sigmaT = self % xsData % getTotalMatXS(p, p % matIdx()) + sigmaT = self % xsData % getTrackMatXS(p, p % matIdx()) ! Roll RNG to determine if the collision is real or virtual ! Exit the loop if the collision is real, report collision if virtual @@ -127,6 +129,7 @@ subroutine deltaTracking(self, p, tally, thisCycle, nextCycle) end do DTLoop call tally % reportTrans(p) + end subroutine deltaTracking !! diff --git a/TransportOperator/transportOperator_inter.f90 b/TransportOperator/transportOperator_inter.f90 index ddfdf5b6d..a15af04e1 100644 --- a/TransportOperator/transportOperator_inter.f90 +++ b/TransportOperator/transportOperator_inter.f90 @@ -112,7 +112,7 @@ subroutine transport(self, p, tally, thisCycle, nextCycle) call self % transit(p, tally, thisCycle, nextCycle) ! Send history reports if particle died - if( p % isDead) then + if (p % isDead) then call tally % reportHist(p) end if diff --git a/docs/User Manual.rst b/docs/User Manual.rst index d16829b97..5c0bb881e 100644 --- a/docs/User Manual.rst +++ b/docs/User Manual.rst @@ -776,7 +776,7 @@ Materials definition The *materials* definition is structured as: :: materials { - { temp ; + { tms <0 or 1>; temp ; composition { } *keywords* } { temp ; @@ -784,15 +784,19 @@ The *materials* definition is structured as: :: *keywords* } } -In this case, ``materialName`` can be any name chosen by the user; ``temp`` is the -material temperature in [K]. +In this case, ``materialName`` can be any name chosen by the user; the keyword ``tms`` +(*optional*, default = 0) activates Target Motion Sampling (TMS) if set to 1; TMS uses +the material temperature defined under ``temp`` [K]. ``temp`` is *optional* unless TMS +is used. .. note:: - At the moment ``temp`` is not used in any way since SCONE has no way to treat - the temperature dependence of cross-sections. It is included for future use. - To change the temperature, a user needs to set appropriate suffix to each - individual nuclide in the composition definition. + When using TMS, the temperature specified by ``temp`` must be higher than the + temperatures of the nuclides in the material composition. +.. note:: + *IMPORTANT*: When using TMS, all the tallies based on the collision estimator have to + allow scoring virtual collisions, otherwise the results will be biased. The tallies + based on the track length estimator will be biased too. The ``composition`` dictionary must always be included, but it can be empty in multi-group simulations. In continuous energy simulations, it should include a @@ -928,8 +932,12 @@ The **tally clerks** determine which kind of estimator will be used. The options that defines the domains of integration of each tally - filter (*optional*): can filter out particles with certain properties, preventing them from scoring results - - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions - are tallied with a collisionClerk as well as physical collisions + - handleVirtual (*optional*, default = 1): if set to 1, delta tracking virtual collisions + and TMS rejected collisions are tallied with a collisionClerk as well as physical collisions + +.. note:: + If TMS is on, the collisionClerk is biased for results in the TMS materials unless virtual + collisions are scored (use ) * trackClerk @@ -940,6 +948,9 @@ The **tally clerks** determine which kind of estimator will be used. The options - filter (*optional*): can filter out particles with certain properties, preventing them from scoring results +.. note:: + If TMS is on, the trackClerk is biased for results in the TMS materials + Example: :: tally { @@ -955,14 +966,18 @@ Example: :: * keffAnalogClerk, analog k_eff estimator * keffImplicitClerk, implicit k_eff estimator - - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions - are tallied with a collisionClerk as well as physical collisions + - handleVirtual (*optional*, default = 1): if set to 1, delta tracking virtual collisions + and TMS rejected collisions are tallied with a collisionClerk as well as physical collisions + +.. note:: + If TMS is on, the keffImplicitClerk is biased for results in the TMS materials unless virtual + collisions are scored (use ) Example: :: tally { k_eff1 { type keffAnalogClerk; } - k_eff2 { type keffImplicitClerk; handleVirtual 1; } + k_eff2 { type keffImplicitClerk; handleVirtual 0; } } * centreOfMassClerk, geometrical 3D center of mass estimator @@ -1009,8 +1024,12 @@ Example: :: tally map - PN (*optional*, default = 0): 1 for true; 0 for false; flag that indicates whether to calculate scattering matrices only up to P1 (``PN 0``) or P7 (``PN 1``) - - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions - are tallied with a collisionClerk as well as physical collisions + - handleVirtual (*optional*, default = 1): if set to 1, delta tracking virtual collisions + and TMS rejected collisions are tallied with a collisionClerk as well as physical collisions + +.. note:: + If TMS is on, the mgXsClerk is biased for results in the TMS materials unless virtual + collisions are scored (use ) Example: :: @@ -1039,8 +1058,12 @@ Example: :: - map: contains a dictionary with the ``tallyMap`` definition, that defines the bins of the matrix - - handleVirtual (*optional*, default = 0): if set to 1, delta tracking virtual collisions - are tallied with a collisionClerk as well as physical collisions + - handleVirtual (*optional*, default = 1): if set to 1, delta tracking virtual collisions + and TMS rejected collisions are tallied with a collisionClerk as well as physical collisions + +.. note:: + If TMS is on, the simpleFMClerk is biased for results in the TMS materials unless virtual + collisions are scored (use ) Example: :: From 97d1cbcbe10c9691cec518e84693418678f0d739 Mon Sep 17 00:00:00 2001 From: valeriaRaffuzzi <108435337+valeriaRaffuzzi@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:52:39 +0100 Subject: [PATCH 132/133] Update .gitignore to ignore build folder --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1e75e7994..d51b089f5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ __pycache__/ cream.egg-info/ *.pyc +# Ignore build folder +Build +build + # Ignore all hidden files (except gitignore) .* -!/.gitignore \ No newline at end of file +!/.gitignore From ec1e15555cdadfa8ec85718ebfae627cc58baf89 Mon Sep 17 00:00:00 2001 From: "V. Raffuzzi" Date: Wed, 4 Sep 2024 18:12:15 +0100 Subject: [PATCH 133/133] Updating recent test and Installation doc --- SharedModules/Tests/colours_test.f90 | 2 +- docs/Installation.rst | 30 +++++++++++++--------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/SharedModules/Tests/colours_test.f90 b/SharedModules/Tests/colours_test.f90 index 3aba28b02..1083e5601 100644 --- a/SharedModules/Tests/colours_test.f90 +++ b/SharedModules/Tests/colours_test.f90 @@ -1,7 +1,7 @@ module colours_test use numPrecision use colours_func, only : rgb24bit - use pFUnit_mod + use funit implicit none diff --git a/docs/Installation.rst b/docs/Installation.rst index 5e56f9431..b51aded2c 100644 --- a/docs/Installation.rst +++ b/docs/Installation.rst @@ -27,10 +27,10 @@ Requirements .. admonition:: Optional - pFUnit 3 test framework and Python interpreter + pFUnit 4 test framework and Python interpreter Both the unit and the integration tests in SCONE use pFUnit framework. To run it requires a - python interpreter. Not that we use version 3.0 despite, newer 4.0 being available. This is - to retain support for gfortran in versions older then 8.3 (required by pFUnit 4.0). + python interpreter. NOTE that version 4.0 (contrarily to the older 3.0) requires the use of + gfortran version 8.3 or newer. Getting gfortran '''''''''''''''' @@ -109,26 +109,24 @@ This is only required if the unit tests are to be build. python --version -#. Create a folder for the local installation of pFUnit e.g. in your home - directory and download the pFUnit repository and enter the source code folder:: +#. Download the pFUnit repository and enter the source code folder:: - mkdir pFUnit + git clone https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git cd pFUnit - git clone git://git.code.sf.net/p/pfunit/code pfunit-code - cd pfunit-code + +#. Create a build folder and compile the code:: + + mkdir build + cd build + cmake ./.. + make tests + make install #. Export environmental variables required by pFUnit:: export F90=gfortran export F90_VENDOR=GNU -#. Build and test pFUnit by typing:: - - make tests - -#. Install pFUnit in any directory you have access to e.g. :: - - make install INSTALL_DIR=~/pFUnit LAPACK and BLAS ''''''''''''''' @@ -168,7 +166,7 @@ Compiling SCONE to directory in which pFUnit was installed. It may be worth adding the line to your ``.bashrc`` :: - export PFUNIT_INSTALL=~/pFUnit + export PFUNIT_DIR=~/pFUnit/build/ #. If your LAPACK installation is not in default system directories use LAPACK_INSTALL enviromental variable to help CMAKE find the library. e.g. ::