From aec85e900606eeb03f8175c731f793a5c3359fef Mon Sep 17 00:00:00 2001 From: Paul Cosgrove Date: Sun, 5 Jun 2022 17:39:11 +0100 Subject: [PATCH 01/15] Most of TRRM implementation - nearly! --- CMakeLists.txt | 1 + .../Surfaces/QuadSurfaces/plane_class.f90 | 30 +- Geometry/Surfaces/box_class.f90 | 56 + Geometry/Surfaces/squareCylinder_class.f90 | 63 + Geometry/Surfaces/surface_inter.f90 | 54 +- Geometry/Tests/geometryStd_iTest.f90 | 57 +- Geometry/Universes/CMakeLists.txt | 2 + .../Universes/Tests/azimPinUniverse_test.f90 | 401 ++++++ Geometry/Universes/azimPinUniverse_class.f90 | 459 +++++++ Geometry/Universes/universeFactory_func.f90 | 21 +- Geometry/geomGraph_class.f90 | 59 +- Geometry/geometryStd_class.f90 | 165 ++- Geometry/geometry_inter.f90 | 262 ++-- InputFiles/C5G7 | 211 +++ InputFiles/TRRM/C5G7_RoddedB_TRRM | 1131 +++++++++++++++ InputFiles/TRRM/C5G7_TRRM | 301 ++++ InputFiles/XS/Ua_1_0_XSS | 18 + InputFiles/XS_C5G7/CR | 31 + InputFiles/XS_C5G7/FC | 34 + InputFiles/XS_C5G7/GT | 31 + InputFiles/XS_C5G7/MOX43 | 36 + InputFiles/XS_C5G7/MOX7 | 36 + InputFiles/XS_C5G7/MOX87 | 34 + InputFiles/XS_C5G7/UO2 | 34 + InputFiles/XS_C5G7/moder | 31 + IntegrationTestFiles/PhysicsPackages/SlabTRRM | 60 + .../PhysicsPackages/XS/Ua_1_0_XSS | 18 + .../reactionMG/multiScatterMG_class.f90 | 4 + NuclearData/materialMenu_mod.f90 | 2 +- .../baseMgNeutronDatabase_class.f90 | 4 +- .../baseMgNeutronMaterial_class.f90 | 166 ++- .../mgNeutronData/mgNeutronDatabase_inter.f90 | 25 +- .../mgNeutronData/mgNeutronMaterial_inter.f90 | 92 +- NuclearData/nuclearDataReg_mod.f90 | 6 +- PhysicsPackages/CMakeLists.txt | 6 +- PhysicsPackages/Tests/randomRay_iTest.f90 | 46 + PhysicsPackages/eigenPhysicsPackage_class.f90 | 74 +- .../fixedSourcePhysicsPackage_class.f90 | 53 +- .../physicsPackageFactory_func.f90 | 21 +- PhysicsPackages/physicsPackage_inter.f90 | 14 +- .../randomRayPhysicsPackage_class.f90 | 662 +++++++++ .../rayVolPhysicsPackage_class.f90 | 31 +- PhysicsPackages/vizPhysicsPackage_class.f90 | 15 +- RandomRayObjects/CMakeLists.txt | 8 + RandomRayObjects/arraysRR_class.f90 | 1213 +++++++++++++++++ RandomRayObjects/constantsRR.f90 | 16 + RandomRayObjects/dataRR_class.f90 | 472 +++++++ RandomRayObjects/mathsRR_func.f90 | 71 + RandomRayObjects/rayHandling_func.f90 | 345 +++++ SharedModules/CMakeLists.txt | 2 + SharedModules/Tests/exponentialRA_test.f90 | 54 + SharedModules/exponentialRA_func.f90 | 63 + SharedModules/numPrecision.f90 | 5 +- Tallies/tallyAdmin_class.f90 | 2 +- Visualisation/VTK/outputVTK_class.f90 | 9 +- Visualisation/visualiser_class.f90 | 332 ++++- 56 files changed, 7115 insertions(+), 334 deletions(-) create mode 100644 Geometry/Universes/Tests/azimPinUniverse_test.f90 create mode 100644 Geometry/Universes/azimPinUniverse_class.f90 create mode 100644 InputFiles/C5G7 create mode 100644 InputFiles/TRRM/C5G7_RoddedB_TRRM create mode 100644 InputFiles/TRRM/C5G7_TRRM create mode 100644 InputFiles/XS/Ua_1_0_XSS create mode 100644 InputFiles/XS_C5G7/CR create mode 100644 InputFiles/XS_C5G7/FC create mode 100644 InputFiles/XS_C5G7/GT create mode 100644 InputFiles/XS_C5G7/MOX43 create mode 100644 InputFiles/XS_C5G7/MOX7 create mode 100644 InputFiles/XS_C5G7/MOX87 create mode 100644 InputFiles/XS_C5G7/UO2 create mode 100644 InputFiles/XS_C5G7/moder create mode 100644 IntegrationTestFiles/PhysicsPackages/SlabTRRM create mode 100644 IntegrationTestFiles/PhysicsPackages/XS/Ua_1_0_XSS create mode 100644 PhysicsPackages/Tests/randomRay_iTest.f90 create mode 100644 PhysicsPackages/randomRayPhysicsPackage_class.f90 create mode 100644 RandomRayObjects/CMakeLists.txt create mode 100644 RandomRayObjects/arraysRR_class.f90 create mode 100644 RandomRayObjects/constantsRR.f90 create mode 100644 RandomRayObjects/dataRR_class.f90 create mode 100644 RandomRayObjects/mathsRR_func.f90 create mode 100644 RandomRayObjects/rayHandling_func.f90 create mode 100644 SharedModules/Tests/exponentialRA_test.f90 create mode 100644 SharedModules/exponentialRA_func.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 61d595b91..47a66f35a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,7 @@ add_subdirectory(SharedModules) add_subdirectory(Visualisation) add_subdirectory(ParticleObjects) add_subdirectory(NamedGrids) +add_subdirectory(RandomRayObjects) add_subdirectory(NuclearData) add_subdirectory(Geometry) diff --git a/Geometry/Surfaces/QuadSurfaces/plane_class.f90 b/Geometry/Surfaces/QuadSurfaces/plane_class.f90 index dfb913868..bb3da58b2 100644 --- a/Geometry/Surfaces/QuadSurfaces/plane_class.f90 +++ b/Geometry/Surfaces/QuadSurfaces/plane_class.f90 @@ -39,6 +39,9 @@ module plane_class procedure :: distance procedure :: going procedure :: kill + + ! Local procedure + procedure :: build end type plane @@ -97,9 +100,34 @@ subroutine init(self, dict) self % norm = coeffs(1:3) self % offset = coeffs(4) + end subroutine init + + !! + !! Build plane from components + !! + !! Args: + !! id [in] -> Surface ID + !! norm [in] -> normal vector of plane (normalised if not already) + !! offset [in] -> offset of plane + !! + !! Errors: + !! fatalError if id or radius are -ve + !! + subroutine build(self, id, norm, offset) + class(plane), intent(inout) :: self + integer(shortInt), intent(in) :: id + real(defReal), dimension(:), intent(in) :: norm + real(defReal), intent(in) :: offset + character(100), parameter :: Here = 'build (plane_class.f90)' + if (id < 1) call fatalError(Here,'Invalid surface id provided. ID must be > 1') - end subroutine init + call self % setID(id) + + self % norm = norm / norm2(norm) + self % offset = offset + + end subroutine build !! !! Return axis-aligned bounding box for the surface diff --git a/Geometry/Surfaces/box_class.f90 b/Geometry/Surfaces/box_class.f90 index 5ba5c841e..c2bb415c8 100644 --- a/Geometry/Surfaces/box_class.f90 +++ b/Geometry/Surfaces/box_class.f90 @@ -51,6 +51,7 @@ module box_class procedure :: kill procedure :: setBC procedure :: explicitBC + procedure :: explicitRayBC procedure :: transformBC end type box @@ -325,6 +326,61 @@ subroutine setBC(self, BC) end subroutine setBC + !! + !! Apply explicit BCs, treating vacuums as reflective. + !! + !! See surface_inter for details + !! + !! Note: + !! - Go through all directions in order to account for corners + !! + subroutine explicitRayBC(self, r, u, hitVacuum) + class(box), intent(in) :: self + real(defReal), dimension(3), intent(inout) :: r + real(defReal), dimension(3), intent(inout) :: u + logical(defBool), intent(out) :: hitVacuum + integer(shortInt) :: ax, bc + real(defReal) :: r0 + character(100), parameter :: Here = 'explicitRayBC (box_class.f90)' + + hitVacuum = .FALSE. + + ! Loop over directions + axis : do ax = 1, 3 + ! Find position wrt origin + r0 = r(ax) - self % origin(ax) + + ! Skip if particle is well inside the domain + if (abs(r0) <= self % halfwidth(ax) - self % surfTol()) cycle axis + + ! Choose correct BC + if (r0 < ZERO) then + bc = self % BC(2*ax - 1) + else + bc = self % BC(2*ax) + end if + + ! Apply BC + select case(bc) + case (VACUUM_BC) + ! Treat as reflective but note the vacuum hit + u(ax) = -u(ax) + hitVacuum = .TRUE. + + case (REFLECTIVE_BC) + u(ax) = -u(ax) + + case (PERIODIC_BC) + ! Calculate displacement and perform translation + r(ax) = r(ax) - TWO * sign(self % halfwidth(ax), r0) + + case default + call fatalError(Here, 'Unrecognised BC: '// numToChar(bc)) + end select + end do axis + + end subroutine explicitRayBC + !! !! Apply explicit BCs !! diff --git a/Geometry/Surfaces/squareCylinder_class.f90 b/Geometry/Surfaces/squareCylinder_class.f90 index 5e41d95ec..f02cefea9 100644 --- a/Geometry/Surfaces/squareCylinder_class.f90 +++ b/Geometry/Surfaces/squareCylinder_class.f90 @@ -67,6 +67,7 @@ module squareCylinder_class procedure :: kill procedure :: setBC procedure :: explicitBC + procedure :: explicitRayBC procedure :: transformBC end type squareCylinder @@ -431,6 +432,68 @@ subroutine explicitBC(self, r, u) end subroutine explicitBC + !! + !! Apply explicit BCs for ray problems: enforces a reflection when + !! a vacuum was hit and reports this + !! + !! See surface_inter for details + !! + !! Note: + !! - Go through all directions in order to account for corners + !! + subroutine explicitRayBC(self, r, u, hitVacuum) + class(squareCylinder), intent(in) :: self + real(defReal), dimension(3), intent(inout) :: r + real(defReal), dimension(3), intent(inout) :: u + logical(defBool), intent(out) :: hitVacuum + integer(shortInt) :: ax, bc, i + real(defReal) :: r0 + character(100), parameter :: Here = 'explicitRayBC (squareCylinder_class.f90)' + + hitVacuum = .FALSE. + + ! Loop over directions + ! Becouse of the mix of 2D and 3D vectors to get right component use: + ! i -> for 2D vectors + ! ax -> for 3D vectors (r & u) + axis : do i = 1, 2 + ax = self % plane(i) + + ! Find position wrt origin + r0 = r(ax) - self % origin(i) + + ! Skip if particle is well inside the domain + if (abs(r0) <= self % halfwidth(i) - self % surfTol()) cycle axis + + ! Choose correct BC + if (r0 < ZERO) then + bc = self % BC(2*ax - 1) + else + bc = self % BC(2*ax) + end if + + ! Apply BC + select case(bc) + case (VACUUM_BC) + ! Treat as reflective but state that a vacuum was struck + u(ax) = -u(ax) + hitVacuum = .TRUE. + + case (REFLECTIVE_BC) + u(ax) = -u(ax) + + case (PERIODIC_BC) + ! Calculate displacement and perform translation + r(ax) = r(ax) - TWO * sign(self % halfwidth(i), r0) + + case default + call fatalError(Here, 'Unrecognised BC: '// numToChar(bc)) + + end select + end do axis + + end subroutine explicitRayBC + !! !! Apply co-ordinate transform BC !! diff --git a/Geometry/Surfaces/surface_inter.f90 b/Geometry/Surfaces/surface_inter.f90 index 789c5313f..e9724536e 100644 --- a/Geometry/Surfaces/surface_inter.f90 +++ b/Geometry/Surfaces/surface_inter.f90 @@ -29,21 +29,22 @@ module surface_inter !! surfId -> Surface ID for this surface !! !! Interface: - !! setId -> Set surface ID - !! id -> Return surface ID - !! setTol -> Set surface tolerance - !! surfTol -> Get value of surface tolerance - !! setBC -> Load boundary conditions in surface-specific order - !! myType -> Returns a string with surface type name - !! init -> Initialise surface from a dictionary - !! boundingBox -> Return definition of axis-aligned bounding box over the surface - !! kill -> Return to unitinitialised state - !! halfspace -> Return halfspace ocupied by a particle - !! evaluate -> Return remainder of the surface equation c = F(r) - !! distance -> Return distance to the surface - !! going -> Determine to which halfspace particle is currently going - !! explicitBC -> Apply explicit BCs - !! transformBC -> Apply transform BCs + !! setId -> Set surface ID + !! id -> Return surface ID + !! setTol -> Set surface tolerance + !! surfTol -> Get value of surface tolerance + !! setBC -> Load boundary conditions in surface-specific order + !! myType -> Returns a string with surface type name + !! init -> Initialise surface from a dictionary + !! boundingBox -> Return definition of axis-aligned bounding box over the surface + !! kill -> Return to unitinitialised state + !! halfspace -> Return halfspace ocupied by a particle + !! evaluate -> Return remainder of the surface equation c = F(r) + !! distance -> Return distance to the surface + !! going -> Determine to which halfspace particle is currently going + !! explicitBC -> Apply explicit BCs + !! explicitRayBC -> Apply explicit BCs for ray problems + !! transformBC -> Apply transform BCs !! type, public, abstract :: surface private @@ -68,6 +69,7 @@ module surface_inter procedure(distance), deferred :: distance procedure(going), deferred :: going procedure :: explicitBC + procedure :: explicitRayBC procedure :: transformBC end type surface @@ -375,6 +377,28 @@ subroutine explicitBC(self, r, u) end subroutine explicitBC + !! + !! Apply explicit BCs, treating vacuums as reflective. + !! Used for ray problems + !! + !! FatalError by default. Override in a subclass to change it! + !! + !! Args: + !! r [inout] -> Position pre and post BC. Assume that (F(r) ~= 0) + !! u [inout] -> Direction pre and post BC. Assume that norm2(u) = 1.0 + !! hitVacuum [out] -> Was a vacuum boundary struck? + !! + subroutine explicitRayBC(self, r, u, hitVacuum) + class(surface), intent(in) :: self + real(defReal), dimension(3), intent(inout) :: r + real(defReal), dimension(3), intent(inout) :: u + logical(defBool), intent(out) :: hitVacuum + character(100), parameter :: Here = 'explicitRayBC (surface_inter.f90)' + + call fatalError(Here,'The boundary surface has not implemented ray handling!') + + end subroutine explicitRayBC + !! !! Apply co-ordinate transform BC !! diff --git a/Geometry/Tests/geometryStd_iTest.f90 b/Geometry/Tests/geometryStd_iTest.f90 index e1daa3299..69549595f 100644 --- a/Geometry/Tests/geometryStd_iTest.f90 +++ b/Geometry/Tests/geometryStd_iTest.f90 @@ -3,10 +3,13 @@ module geometryStd_iTest use numPrecision use universalVariables use dictionary_class, only : dictionary + use dictParser_func, only : charToDict use charMap_class, only : charMap use dictParser_func, only : fileToDict use coord_class, only : coordList + use geometry_inter, only : geometry use geometryStd_class, only : geometryStd + use visualiser_class, only : visualiser use pFUnit_mod implicit none @@ -19,7 +22,7 @@ module geometryStd_iTest !! @Test subroutine test_lattice_geom() - type(geometryStd) :: geom + class(geometryStd), target, allocatable :: geom character(*), parameter :: path = './IntegrationTestFiles/Geometry/test_lat' type(charMap) :: mats integer(shortInt) :: i, idx, matIdx, uniqueID, event @@ -32,8 +35,11 @@ subroutine test_lattice_geom() integer(shortInt), dimension(10,10) :: img real(defReal), dimension(6) :: aabb real(defReal) :: maxDist + class(geometry), pointer :: geomP + type(visualiser) :: viz + type(dictionary) :: vizDict real(defReal), parameter :: TOL = 1.0E-7_defReal - + ! Load dictionary call fileToDict(dict, path) @@ -44,10 +50,11 @@ subroutine test_lattice_geom() do i = 1, size(keys) call mats % add(keys(i), i) end do - + ! Build geometry + allocate(geom) call geom % init(dict, mats, silent=.true.) - + ! Get material at few locations name = 'water' idx = mats % get(name) @@ -66,7 +73,7 @@ subroutine test_lattice_geom() u = [ZERO, ZERO, ONE] call coords % init(r, u) call geom % placeCoord(coords) - + ! Verify positions @assertEqual(r, coords % lvl(1) % r, TOL) @assertEqual(r, coords % lvl(2) % r, TOL) @@ -77,9 +84,14 @@ subroutine test_lattice_geom() @assertEqual(u, coords % lvl(2) % dir, TOL) @assertEqual(u, coords % lvl(3) % dir, TOL) + ! Construct visualiser and verify slice plotting + geomP => geom + call charToDict(vizDict, ' ') + call viz % init(geomP, vizDict, 'test') + ! Slice plot -> Material - call geom % slicePlot(img, [ZERO, ZERO, ZERO], 'z', 'material') - + call viz % slicePlot(img, [ZERO, ZERO, ZERO], 'z', 'material') + ! Verify some pixels name = 'water' idx = mats % get(name) @@ -96,10 +108,10 @@ subroutine test_lattice_geom() ! Slice plot -> UniqueID r = [-0.63_defReal, -0.63_defReal, 0.0_defReal] - call geom % slicePlot(img, r, 'z', 'uniqueID', [1.26_defReal, 1.26_defReal]) + call viz % slicePlot(img, r, 'z', 'uniqueID', [1.26_defReal, 1.26_defReal]) ! Verify some pixels - ! Note that this test depends on universe leyout order in gromGraph + ! Note that this test depends on universe layout order in geomGraph ! If it changes this test fill fail @assertEqual(2, img(5,5)) @assertEqual(3, img(1,1)) @@ -125,7 +137,7 @@ subroutine test_lattice_geom() @assertEqual(r_ref, coords % lvl(1) % r, TOL) @assertEqual(u_ref, coords % lvl(1) % dir, TOL) @assertEqual(idx, coords % matIdx) - + !*** Test global movement r = [ZERO, ZERO, ZERO] u = [ZERO, -ONE, ZERO] @@ -222,7 +234,7 @@ end subroutine test_lattice_geom !! @Test subroutine test_tilted_cylinder() - type(geometryStd) :: geom + class(geometryStd), target, allocatable :: geom character(*), parameter :: path = './IntegrationTestFiles/Geometry/test_cyl' type(charMap) :: mats integer(shortInt) :: idxW, idxF, i @@ -232,7 +244,10 @@ subroutine test_tilted_cylinder() character(nameLen), dimension(:), allocatable :: keys integer(shortInt), dimension(20,20) :: img integer(shortInt), dimension(20,20,20) :: img3 - real(defReal), dimension(3) :: r + class(geometry), pointer :: geomP + type(visualiser) :: viz + type(dictionary) :: vizDict + real(defReal), dimension(3) :: r ! Load dictionary call fileToDict(dict, path) @@ -246,6 +261,7 @@ subroutine test_tilted_cylinder() end do ! Build geometry + allocate(geom) call geom % init(dict, mats, silent=.true.) ! Get fuel and water index @@ -254,21 +270,26 @@ subroutine test_tilted_cylinder() name = 'mox43' idxF = mats % get(name) + + ! Construct visualiser and verify slice plotting + geomP => geom + call charToDict(vizDict, ' ') + call viz % init(geomP, vizDict, 'test') !*** Test slice normal to x & y ! X-axis at 1.0 r = [1.0_defReal, 0.0_defReal, 0.0_defReal] - call geom % slicePlot(img, r, 'x', 'material') + call viz % slicePlot(img, r, 'x', 'material') ! Test some pixels @assertEqual(idxW, img(8, 11)) @assertEqual(idxW, img(17, 3)) @assertEqual(idxF, img(10, 10)) @assertEqual(idxF, img(18, 1)) - + ! Y-axis at 3.0 r = [0.0_defReal, 3.0_defReal, 0.0_defReal] - call geom % slicePlot(img, r, 'y', 'material') + call viz % slicePlot(img, r, 'y', 'material') @assertEqual(idxW, img(15, 1)) @assertEqual(idxW, img(13, 4)) @@ -278,17 +299,17 @@ subroutine test_tilted_cylinder() !*** Test voxel plot ! Full plot ! Value of r is irrelevant - call geom % voxelPlot(img3, r, 'material') + call viz % voxelPlot(img3, r, 'material') ! Checksome against 2D plot r = [0.0_defReal, 2.75_defReal, 0.0_defReal] - call geom % slicePlot(img, r, 'y', 'material') + call viz % slicePlot(img, r, 'y', 'material') @assertEqual(img, img3(:,16,:)) ! Small box all inside fuel r = [ 1.0_defReal, 0.0_defReal, 0.0_defReal] - call geom % voxelPlot(img3, r, 'material', [0.5_defReal, 0.5_defReal, 0.5_defReal]) + call viz % voxelPlot(img3, r, 'material', [0.5_defReal, 0.5_defReal, 0.5_defReal]) @assertEqual(idxF, img3) diff --git a/Geometry/Universes/CMakeLists.txt b/Geometry/Universes/CMakeLists.txt index 00dcd9153..e5890e52c 100644 --- a/Geometry/Universes/CMakeLists.txt +++ b/Geometry/Universes/CMakeLists.txt @@ -4,6 +4,7 @@ add_sources( ./universe_inter.f90 ./universeShelf_class.f90 ./cellUniverse_class.f90 ./pinUniverse_class.f90 + ./azimPinUniverse_class.f90 ./latUniverse_class.f90 ./rootUniverse_class.f90 ) @@ -12,6 +13,7 @@ add_sources( ./universe_inter.f90 add_unit_tests( ./Tests/universe_test.f90 ./Tests/cellUniverse_test.f90 ./Tests/pinUniverse_test.f90 + ./Tests/azimPinUniverse_test.f90 ./Tests/latUniverse_test.f90 ./Tests/rootUniverse_test.f90 ./Tests/uniFills_test.f90 diff --git a/Geometry/Universes/Tests/azimPinUniverse_test.f90 b/Geometry/Universes/Tests/azimPinUniverse_test.f90 new file mode 100644 index 000000000..6a73ec7a1 --- /dev/null +++ b/Geometry/Universes/Tests/azimPinUniverse_test.f90 @@ -0,0 +1,401 @@ +module azimPinUniverse_test + + use numPrecision + use universalVariables, only : INF, SURF_TOL + use dictionary_class, only : dictionary + use dictParser_func, only : charToDict + use charMap_class, only : charMap + use coord_class, only : coord + use surfaceShelf_class, only : surfaceShelf + use cellShelf_class, only : cellShelf + use azimPinUniverse_class, only : azimPinUniverse, MOVING_IN, MOVING_OUT, MOVING_CLOCK, & + MOVING_ANTI, MOVING_CLOCK_FORWARD, MOVING_CLOCK_BACK + use pfUnit_mod + implicit none + + ! Parameters + character(*), parameter :: UNI_DEF1 = & + "id 7; type azimPinUniverse; naz 4; origin (0.0 0.0 0.0); rotation (0.0 0.0 0.0); & + &radii (2.5 1.5 0.0); fills (u<7> u<14> void);" + character(*), parameter :: UNI_DEF2 = & + "id 8; type azimPinUniverse; naz 8; origin (0.0 0.0 0.0); rotation (0.0 0.0 0.0); & + &radii (4.0 2.5 1.5 0.0); fills (u<20> u<7> u<14> void);" + + ! Variables + type(surfaceShelf) :: surfs + type(cellShelf) :: cells + type(charMap) :: mats + type(azimPinUniverse) :: uni1, uni2 + + +contains + + !! + !! Set-up test enviroment + !! +@Before + subroutine setup() + character(nameLen) :: name + integer(shortInt), dimension(:), allocatable :: fill + type(dictionary) :: dict + integer(shortInt), dimension(:), allocatable :: fillArray + + ! Load void material + name = 'void' + call mats % add(name, 13) + + ! Build universe + call charToDict(dict, UNI_DEF1) + call uni1 % init(fill, dict, cells, surfs, mats) + + ! Set index + call uni1 % setIdx(3) + + ! Verify fill array + @assertEqual([-14, -14, -14, -14, -7, -7, -7, -7, 13, 13, 13, 13], fill) + + ! Build second universe + fillArray = [-14, -14, -14, -14, -14, -14, -14, -14,-7, -7, -7, -7, -7, -7, -7, -7, & + -20, -20, -20, -20, -20, -20, -20, -20, 13, 13, 13, 13, 13, 13, 13, 13] + call charToDict(dict, UNI_DEF2) + call uni2 % init(fill, dict, cells, surfs, mats) + call uni2 % setIdx(26) + @assertEqual(fillArray, fill) + + end subroutine setup + + !! + !! Clean after test + !! +@After + subroutine clean() + + call surfs % kill() + call cells % kill() + call mats % kill() + call uni1 % kill() + call uni2 % kill() + + end subroutine clean + + !! + !! Test miscellaneous functionality + !! +@Test + subroutine test_misc() + real(defReal), dimension(3,3) :: mat + + ! Get id + @assertEqual(7, uni1 % id()) + + ! Set ID + call uni1 % setId(7) + @assertEqual(7, uni1 % id()) + + end subroutine test_misc + + !! + !! Test entering a universe + !! +@Test + subroutine test_enter() + type(coord) :: new + real(defReal), dimension(3) :: r_ref, u_ref, r, dir + real(defReal), parameter :: TOL = 1.0E-7_defReal + + ! ** Enter into local cell 1 + r = [1.0_defReal, 0.0_defReal, 0.0_defReal ] + dir = [ZERO, ZERO, ONE] + + call uni1 % enter(new, r, dir) + + ! Verify location + r_ref = r + u_ref = dir + @assertEqual(r_ref, new % r, TOL) + @assertEqual(u_ref, new % dir, TOL) + @assertEqual(3, new % uniIdx) + @assertEqual(1, new % localID) + @assertEqual(0, new % cellIdx) + + ! ** Enter into local cell 2 + r = [0.0_defReal, 1.0_defReal, 0.0_defReal ] + dir = [ZERO, ZERO, ONE] + + call uni1 % enter(new, r, dir) + + ! Verify location + r_ref = r + u_ref = dir + @assertEqual(r_ref, new % r, TOL) + @assertEqual(u_ref, new % dir, TOL) + @assertEqual(3, new % uniIdx) + @assertEqual(2, new % localID) + @assertEqual(0, new % cellIdx) + + ! ** Enter into local cell 8 + r = [0.0_defReal, -2.3_defReal, -980.0_defReal ] + dir = [ZERO, ZERO, ONE] + + call uni1 % enter(new, r, dir) + + ! Verify location + r_ref = r + u_ref = dir + @assertEqual(r_ref, new % r, TOL) + @assertEqual(u_ref, new % dir, TOL) + @assertEqual(3, new % uniIdx) + @assertEqual(8, new % localID) + @assertEqual(0, new % cellIdx) + + ! ** Enter into local cell 11 + r = [-2.6_defReal, 0.0_defReal, -980.0_defReal ] + dir = [ZERO, ZERO, ONE] + + call uni1 % enter(new, r, dir) + + ! Verify location + r_ref = r + u_ref = dir + @assertEqual(r_ref, new % r, TOL) + @assertEqual(u_ref, new % dir, TOL) + @assertEqual(3, new % uniIdx) + @assertEqual(11, new % localID) + @assertEqual(0, new % cellIdx) + + ! VERIFY THAT ROTATION IS NOT SET (all angles were 0.0) + @assertFalse(new % isRotated) + + ! In universe 2, enter local cell 21 + r = [-3.0_defReal, 0.1_defReal, 32.0_defReal] + call uni2 % enter(new, r, dir) + + ! Verify location + r_ref = r + u_ref = dir + @assertEqual(r_ref, new % r, TOL) + @assertEqual(u_ref, new % dir, TOL) + @assertEqual(26, new % uniIdx) + @assertEqual(21, new % localID) + @assertEqual(0, new % cellIdx) + + end subroutine test_enter + + !! + !! Test distance calculation + !! +@Test + subroutine test_distance() + real(defReal) :: d, ref + integer(shortInt) :: surfIdx + type(coord) :: pos + real(defReal), parameter :: TOL = 1.0E-6_defReal + + ! ** In local cell 1 distance to radial boundary + pos % r = [1.0_defReal, 0.0_defReal, 0.0_defReal] + pos % dir = [ONE, ZERO, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 1 + + call uni1 % distance(d, surfIdx, pos) + + ref = 0.5_defReal + @assertEqual(ref, d, ref * tol) + @assertEqual(MOVING_OUT, surfIdx) + + ! ** In local cell 1 distance to anti-clockwise boundary + pos % r = [1.0_defReal, 0.0_defReal, 0.0_defReal] + pos % dir = [-SQRT2_2, SQRT2_2, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 1 + + call uni1 % distance(d, surfIdx, pos) + + ref = SQRT2_2 + @assertEqual(ref, d, ref * tol) + @assertEqual(MOVING_ANTI, surfIdx) + + ! ** In local cell 3 distance to clockwise boundary + pos % r = [-1.0_defReal, 0.0_defReal, 0.0_defReal] + pos % dir = [SQRT2_2, SQRT2_2, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 3 + + call uni1 % distance(d, surfIdx, pos) + + ref = SQRT2_2 + @assertEqual(ref, d, ref * tol) + @assertEqual(MOVING_CLOCK, surfIdx) + + ! ** In local cell 4 distance to clockwise boundary + ! ** Moves back around! + pos % r = [0.0_defReal, -1.0_defReal, 0.0_defReal] + pos % dir = [SQRT2_2, SQRT2_2, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 4 + + call uni1 % distance(d, surfIdx, pos) + + ref = SQRT2_2 + @assertEqual(ref, d, ref * tol) + @assertEqual(MOVING_CLOCK_FORWARD, surfIdx) + + ! ** In outermost cell moving away + pos % r = [2.0_defReal, 1.6_defReal, 0.0_defReal] + pos % dir = [ONE, ZERO, ZERO] + pos % localId = 9 + + call uni1 % distance(d, surfIdx, pos) + @assertEqual(INF, d) + ! Surface momento is undefined -> No crossing + + ! In ordinary cell in-between + pos % r = [0.0_defReal, 1.6_defReal, 0.0_defReal] + pos % dir = [ZERO, -ONE, ZERO] + pos % localId = 5 + + call uni1 % distance(d, surfIdx, pos) + ref = 0.1_defReal + @assertEqual(ref, d, ref * tol) + @assertEqual(MOVING_IN, surfIdx) + + ! Universe 2 + + + end subroutine test_distance + + !! + !! Test cell-to cell crossing + !! +@Test + subroutine test_cross() + type(coord) :: pos + integer(shortInt) :: idx + real(defReal) :: eps + + ! Cross from cell 2 to cell 6 + eps = HALF * SURF_TOL + pos % r = [0.0_defReal, 1.5_defReal-eps, 0.0_defReal] + pos % dir = [ZERO, ONE, ZERO] + pos % uniIdx = 8 + pos % cellIdx = 0 + pos % localId = 2 + + idx = MOVING_OUT + call uni1 % cross(pos, idx) + + @assertEqual(6, pos % localId) + + ! Cross from cell 6 to cell 2 + eps = HALF * SURF_TOL + pos % r = [0.0_defReal, 1.5_defReal+eps, 0.0_defReal] + pos % dir = [ZERO, -ONE, ZERO] + + idx = MOVING_IN + call uni1 % cross(pos, idx) + + @assertEqual(2, pos % localId) + + ! Cross from cell 1 to cell 4 + eps = HALF * SURF_TOL + pos % r = [SQRT2_2, -SQRT2_2, ZERO] + pos % dir = [-SQRT2_2, -SQRT2_2, ZERO] + pos % r = pos % r - eps * pos % dir + pos % localID = 1 + + idx = MOVING_CLOCK_BACK + call uni1 % cross(pos, idx) + + @assertEqual(4, pos % localId) + + ! Universe 2 + ! + + end subroutine test_cross + + !! + !! Test cell offset + !! +@Test + subroutine test_cellOffset() + type(coord) :: pos + + ! Cell 2 + pos % r = [0.0_defReal, 1.0_defReal, 0.0_defReal] + pos % dir = [ZERO, ONE, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 2 + + @assertEqual([ZERO, ZERO, ZERO], uni1 % cellOffset(pos) ) + + ! Cell 11 + pos % r = [-7.0_defReal, 0.0_defReal, 0.0_defReal] + pos % dir = [ZERO, ONE, ZERO] + pos % uniIdx = 3 + pos % cellIdx = 0 + pos % localId = 11 + + @assertEqual([ZERO, ZERO, ZERO], uni1 % cellOffset(pos) ) + + end subroutine test_cellOffset + + !! + !! Test surface transitions + !! + !! Check that there is no problem with distance calculations + !! if particle is placed very close to an annulus or plane surface + !! (within SURF_TOL) + !! +@Test + subroutine test_edgeCases() + type(coord) :: pos + integer(shortInt) :: idx, localID, cellIdx + real(defReal) :: eps, d + real(defReal), parameter :: TOL = 1.0E-7_defReal + + ! At boundary between cell 2 and 6 + eps = HALF * SURF_TOL + pos % r = [0.0_defReal, 1.5_defReal-eps, 0.0_defReal] + pos % dir = [ONE, -0.00001_defReal, ZERO] + pos % dir = pos % dir / norm2(pos % dir) + pos % uniIdx = 8 + pos % cellIdx = 0 + + ! Should find particle in cell 2 + ! And return very small distance -> MOVING OUT + call uni1 % findCell(localID, cellIdx, pos % r, pos % dir) + @assertEqual(2, localID) + + pos % localID = 2 + call uni1 % distance(d, idx, pos) + + @assertEqual(ZERO, d, 1.0E-3_defReal) + @assertEqual(MOVING_OUT, idx) + + ! At boundary between cell 4 and 1 + eps = 1.1*SURF_TOL + pos % r = [SQRT2_2, -SQRT2_2, ZERO] + pos % dir = [-SQRT2_2, -SQRT2_2, ZERO] + pos % r = pos % r + eps * pos % dir + pos % dir = -pos % dir + + ! Should find particle in cell 4 + ! And return very small distance -> MOVING_CLOCK_FORWARD + call uni1 % findCell(localID, cellIDx, pos % r, pos % dir) + @assertEqual(4, localID) + + pos % localID = 4 + call uni1 % distance(d, idx, pos) + + @assertEqual(ZERO, d, 1.0E-3_defReal) + @assertEqual(MOVING_CLOCK_FORWARD, idx) + + end subroutine test_edgeCases + + +end module azimPinUniverse_test diff --git a/Geometry/Universes/azimPinUniverse_class.f90 b/Geometry/Universes/azimPinUniverse_class.f90 new file mode 100644 index 000000000..291a84eee --- /dev/null +++ b/Geometry/Universes/azimPinUniverse_class.f90 @@ -0,0 +1,459 @@ +module azimPinUniverse_class + + use numPrecision + use universalVariables, only : INF, targetNotFound + use genericProcedures, only : fatalError, numToChar, swap + use dictionary_class, only : dictionary + use coord_class, only : coord + use charMap_class, only : charMap + use surfaceShelf_class, only : surfaceShelf + use cylinder_class, only : cylinder + use plane_class, only : plane + use cell_inter, only : cell + use cellShelf_class, only : cellShelf + use universe_inter, only : universe, kill_super => kill, charToFill + implicit none + private + + ! Parameters + ! Are public for use in unit tests + integer(shortInt), parameter, public :: MOVING_IN = -1, MOVING_OUT = -2, & + MOVING_ANTI = -3, MOVING_CLOCK = -4, & + MOVING_CLOCK_BACK = -5, & + MOVING_CLOCK_FORWARD = -6 + + !! + !! Universe that represents a single pin + !! A version of the pinUniverse which is equi-azimuthally divided. + !! + !! Is composed from co-centring cylinders divided azimuthally by planes. + !! In the most central cylinder and first azimuthal segment, the cell will + !! have an ID of 1. This increases by 1 while proceeding across azimuthal + !! segments. Proceeding radially outwards, the ID is incremented by the + !! number of azimuthal regions. + !! + !! Sample Dictionary Input: + !! azimPinUni { + !! id 7; + !! type azimPinUniverse; + !! naz 4; + !! #origin (1.0 0.0 0.1);# + !! #rotation (30.0 0.0 0.0);# + !! radii (3.0 4.5 0.0 1.0 ); + !! fills (u<3> void clad u<4>); + !! } + !! + !! naz corresponds to the number of azimuthal regions produced. Must be a multiple of 2. + !! Takes origin at 0 degrees, i.e., the centre of the first azimuthal slice. + !! 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 cells 1 to 4 + !! are filled with u<4>, cell 5 to 8 with u<3> etc. + !! + !! !!!!! + !! TODO: Just for the moment, there are no azimuthally different fills. This should be remedied! + !! !!!!! + !! + !! Public Members: + !! nAz -> Number of azimuthal regions + !! r_sqr -> Array of radius^2 for each annulus + !! theta -> Array of azimuthal boundary angles in radians. + !! annuli -> Array of cylinder surfaces that represent diffrent annuli + !! planes -> Array of planes for providing azimuthal division + !! normals -> Array of plane normals for convenience + !! + !! Interface: + !! universe interface + !! + type, public, extends(universe) :: azimPinUniverse + private + integer(shortInt) :: nAz + real(defReal), dimension(:), allocatable :: r_sq + real(defReal), dimension(:), allocatable :: theta + type(cylinder), dimension(:), allocatable :: annuli + type(plane), dimension(:), allocatable :: planes + real(defReal), dimension(:,:), allocatable :: normals + contains + ! Superclass procedures + procedure :: init + procedure :: kill + procedure :: findCell + procedure :: distance + procedure :: cross + procedure :: cellOffset + end type azimPinUniverse + +contains + + !! + !! Initialise Universe + !! + !! See universe_inter for details. + !! + !! Errors: + !! fatalError for invalid input + !! + subroutine init(self, fill, dict, cells, surfs, mats) + class(azimPinUniverse), intent(inout) :: self + integer(shortInt), dimension(:), allocatable, intent(out) :: fill + class(dictionary), intent(in) :: dict + type(cellShelf), intent(inout) :: cells + type(surfaceShelf), intent(inout) :: surfs + type(charMap), intent(in) :: mats + integer(shortInt) :: id, idx, N, i, j + real(defReal), dimension(:), allocatable :: radii, temp + character(nameLen), dimension(:), allocatable :: fillNames + real(defReal) :: dTheta, theta0 + character(100), parameter :: Here = 'init (azimPinUniverse_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 azimuthal division + call dict % get(self % naz, 'naz') + if (self % nAz < 2) call fatalError(Here,'Number of azimuthal regions must be 2 or more') + + ! Use binary logic to check if nAz is a power of 2 + if (IAND(self % nAz, self % nAz - 1) /= 0) call fatalError(Here, 'Number of azimuthal regions must be a power of 2') + + ! 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: '//numToChar(size(temp))) + end if + call self % setTransform(rotation=temp) + end if + + ! Load radii and fill data + call dict % get(radii, 'radii') + call dict % get(fillNames, 'fills') + + ! Check values + if (size(radii) /= size(fillNames)) then + call fatalError(Here, 'Size of radii and fills does not match') + + else if (any(radii < ZERO)) then + call fatalError(Here, 'Found -ve value of radius.') + + end if + + ! Sort radii with selection sort + ! Start with value 0.0 that represents outermost element + ! Change 0.0 to infinity + N = size(radii) + idx = minloc(radii, 1) + if (radii(idx) /= ZERO) call fatalError(Here, 'Did not find outermost element with radius 0.0.') + call swap( radii(idx), radii(N)) + call swap( fillNames(idx), fillNames(N)) + radii(N) = INF * 1.1_defReal + + do i = N-1,1,-1 + idx = maxloc(radii(1:i), 1) + call swap( radii(idx), radii(i)) + call swap( fillNames(idx), fillNames(i)) + end do + + ! Check for duplicate values of radii + do i = 1, N-1 + if (radii(i) == radii(i+1)) then + call fatalError(Here, 'Duplicate value of radius: '//numToChar(radii(i))) + end if + end do + + ! Load data & Build cylinders + self % r_sq = radii * radii + + allocate(self % annuli(N)) + do i = 1, N + call self % annuli(i) % build(id=1, origin=[ZERO, ZERO, ZERO], & + type='zCylinder', radius=radii(i) ) + end do + + ! Load data and build planes + allocate(self % theta(self % nAz)) + allocate(self % planes(self % nAz/2)) + allocate(self % normals(self % nAz/2,2)) + dTheta = TWO_PI / self % nAz + theta0 = HALF * dTheta + do i = 1, self % nAz + self % theta(i) = theta0 + theta0 = theta0 + dTheta + end do + + ! Build the planes, rotated at angle theta from the line x = 0 + do i = 1, self % nAz/2 + self % normals(i,1) = -sin(self % theta(i)) + self % normals(i,2) = cos(self % theta(i)) + call self % planes(i) % build(id=1, & + norm = [self % normals(i,1), self % normals(i,2), ZERO], offset=ZERO) + end do + + ! Create fill array + allocate(fill(self % nAz * N)) + + do i = 1, N + do j = 1, self % nAz + fill((i-1)*self % nAz + j) = charToFill(fillNames(i), mats, Here) + end do + end do + + end subroutine init + + !! + !! Find local cell ID given a point + !! + !! See universe_inter for details. + !! + subroutine findCell(self, localID, cellIdx, r, u) + class(azimPinUniverse), intent(inout) :: self + integer(shortInt), intent(out) :: localID + integer(shortInt), intent(out) :: cellIdx + real(defReal), dimension(3), intent(in) :: r + real(defReal), dimension(3), intent(in) :: u + real(defReal) :: r_sq, theta, mul, planeDir + integer(shortInt) :: aIdx, rIdx, pIdx + + r_sq = r(1)*r(1) + r(2)*r(2) + theta = atan2(r(2),r(1)) + ! Correct theta for negative values + if (theta < ZERO) theta = TWO_PI + theta + + cellIdx = 0 + + ! Need to include surface tolerance. Determine multiplier by direction + if ( r(1)*u(1) + r(2)*u(2) >= ZERO) then + mul = -ONE + else + mul = ONE + end if + + ! Find local cell + ! Start by finding annular region + do rIdx = 1, size(self % r_sq) + if( r_sq < self % r_sq(rIdx) + mul * self % annuli(rIdx) % surfTol() ) exit + end do + ! If reached here without exiting, rIdx = size(self % r_sq) + 1 + + ! Find azimuthal segment + do aIdx = 1, self % nAz + if (aIdx > self % nAz/2) then + pIdx = aIdx - self % nAz/2 + planeDir = -ONE + else + pIdx = aIdx + planeDir = ONE + end if + ! Surface tolerance multiplier determined by relative direction of particle + ! and theta + if (planeDir*self % normals(pIdx,1)*u(1) + planeDir*self % normals(pIdx,2)*u(2) >= ZERO) then + mul = -ONE + else + mul = ONE + end if + if (theta < self % theta(aIdx) + mul * self % planes(pIdx) % surfTol() ) exit + end do + ! If exceeded the search, theta is <2pi but greater than the largest theta. + ! Therefore, it lies in the negative theta portion of the first segment. + if (aIdx == self % nAz + 1) aIdx = 1 + localID = aIdx + self % nAz * (rIdx - 1) + + end subroutine findCell + + !! + !! Return distance to the next boundary between local cells in the universe + !! + !! See universe_inter for details. + !! + !! Errors: + !! fatalError is localID is invalid + !! + subroutine distance(self, d, surfIdx, coords) + class(azimPinUniverse), intent(inout) :: self + real(defReal), intent(out) :: d + integer(shortInt), intent(out) :: surfIdx + type(coord), intent(in) :: coords + real(defReal) :: d_out_annul, d_in_annul + real(defReal) :: d_plus, d_minus, dAz + integer(shortInt) :: id, aIdx, rIdx, searchIdxP, searchIdxM + integer(shortInt) :: sense, minus_sense, plus_sense + character(100), parameter :: Here = 'distance (azimPinUniverse_class.f90)' + + ! Get local id + id = coords % localID + + if (id < 1 .or. id > (size(self % r_sq) + 1) * self % nAz) then + call fatalError(Here, 'Invalid local ID: '//numToChar(id)) + end if + + ! Identify annulus index and azimuthal index + rIdx = (id - 1) / self % nAz + 1 + aIdx = id - (self % nAz * (rIdx - 1)) + + ! Check distance to annuli + ! Outer distance + if (rIdx > size(self % r_sq)) then + d_out_annul = INF + else + d_out_annul = self % annuli(rIdx) % distance(coords % r, coords % dir) + end if + + ! Inner distance + if (rIdx == 1) then + d_in_annul = INF + else + d_in_annul = self % annuli(rIdx-1) % distance(coords % r, coords % dir) + end if + + ! Select distance and surface + if ( d_in_annul < d_out_annul) then + surfIdx = MOVING_IN + d = d_in_annul + + else + surfIdx = MOVING_OUT + d = d_out_annul + end if + + ! Check distance to azimuthal planes + + ! Check whether in the first or second half of azimuthal segments + ! If in second half, find the same azimuthal indices as in the first half + searchIdxP = aIdx + if (aIdx > self % nAz/2) searchIdxP = searchIdxP - self % nAz/2 + + ! Set default senses for which cell will be entered + minus_sense = MOVING_CLOCK + plus_sense = MOVING_ANTI + + ! Check for first or last cells circling round + if (aIdx == 1) then + minus_sense = MOVING_CLOCK_BACK + else if (aIdx == self % nAz) then + plus_sense = MOVING_CLOCK_FORWARD + end if + + ! If in the first cell or nAz/2 + 1 cell, find correct plane + if (searchIdxP == 1) then + searchIdxM = self % nAz/2 + else + searchIdxM = searchIdxP - 1 + end if + + ! Identify which two planes (or only one if nAz = 2) + ! Check to see if in second half of azimuthal segments + if (self % nAz > 2) then + d_plus = self % planes(searchIdxP) % distance(coords % r, coords % dir) + d_minus = self % planes(searchIdxM) % distance(coords % r, coords % dir) + else + d_plus = self % planes(1) % distance(coords % r, coords % dir) + d_minus = INF + end if + + ! Choose minimum azimuthal + if (d_plus < d_minus) then + dAz = d_plus + sense = plus_sense + else + dAz = d_minus + sense = minus_sense + end if + + ! Compare radial distance with azimuthal + if (dAz < d) then + surfIdx = sense + d = dAz + end if + + end subroutine distance + + !! + !! Cross between local cells + !! + !! See universe_inter for details. + !! + !! Errors: + !! fatalError if surface from distance is not MOVING_IN or MOVING_OUT + !! + subroutine cross(self, coords, surfIdx) + class(azimPinUniverse), intent(inout) :: self + type(coord), intent(inout) :: coords + integer(shortInt), intent(in) :: surfIdx + character(100), parameter :: Here = 'cross (azimPinUniverse_class.f90)' + + ! Need to determine whether completing a circle, i.e., moving from + ! the last azimuthal segment to the first and vice versa + if (surfIdx == MOVING_CLOCK) then + coords % localID = coords % localID - 1 + + else if (surfIdx == MOVING_ANTI) then + coords % localID = coords % localID + 1 + + else if (surfIdx == MOVING_CLOCK_BACK) then + coords % localID = coords % localID + self % nAz - 1 + + else if (surfIdx == MOVING_CLOCK_FORWARD) then + coords % localID = coords % localID - self % nAz + 1 + + else if (surfIdx == MOVING_IN) then + coords % localID = coords % localID - self % nAz + + else if (surfIdx == MOVING_OUT) then + coords % localID = coords % localID + self % nAz + + else + call fatalError(Here, 'Unknown surface memento: '//numToChar(surfIdx)) + + end if + + end subroutine cross + + !! + !! Return offset for the current cell + !! + !! See universe_inter for details. + !! + function cellOffset(self, coords) result (offset) + class(azimPinUniverse), intent(in) :: self + type(coord), intent(in) :: coords + real(defReal), dimension(3) :: offset + + ! There is no cell offset + offset = ZERO + + end function cellOffset + + !! + !! Return to uninitialised state + !! + elemental subroutine kill(self) + class(azimPinUniverse), intent(inout) :: self + + ! Superclass + call kill_super(self) + + ! Kill local + if(allocated(self % r_sq)) deallocate(self % r_sq) + if(allocated(self % annuli)) deallocate(self % annuli) + if(allocated(self % theta)) deallocate(self % theta) + if(allocated(self % planes)) deallocate(self % planes) + if(allocated(self % normals)) deallocate(self % normals) + self % nAz = 0 + + end subroutine kill + +end module azimPinUniverse_class diff --git a/Geometry/Universes/universeFactory_func.f90 b/Geometry/Universes/universeFactory_func.f90 index 551cc6a23..1c42f0c1f 100644 --- a/Geometry/Universes/universeFactory_func.f90 +++ b/Geometry/Universes/universeFactory_func.f90 @@ -11,19 +11,21 @@ module universeFactory_func use universe_inter, only : universe ! Universes - use rootUniverse_class, only : rootUniverse - use cellUniverse_class, only : cellUniverse - use pinUniverse_class, only : pinUniverse - use latUniverse_class, only : latUniverse + use rootUniverse_class, only : rootUniverse + use cellUniverse_class, only : cellUniverse + use pinUniverse_class, only : pinUniverse + use azimPinUniverse_class, only : azimPinUniverse + use latUniverse_class, only : latUniverse implicit none private ! 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',& - 'cellUniverse',& - 'pinUniverse ',& - 'latUniverse '] + character(nameLen), dimension(*), parameter :: AVAILABLE_UNI = ['rootUniverse ',& + 'cellUniverse ',& + 'pinUniverse ',& + 'azimPinUniverse ',& + 'latUniverse '] ! Public Interface public :: new_universe_ptr @@ -69,6 +71,9 @@ subroutine new_universe_ptr(ptr, fill, dict, cells, surfs, mats) case ('pinUniverse') allocate(pinUniverse :: ptr) + case ('azimPinUniverse') + allocate(azimPinUniverse :: ptr) + case ('latUniverse') allocate(latUniverse :: ptr) diff --git a/Geometry/geomGraph_class.f90 b/Geometry/geomGraph_class.f90 index f722b490f..e9804ed71 100644 --- a/Geometry/geomGraph_class.f90 +++ b/Geometry/geomGraph_class.f90 @@ -51,26 +51,32 @@ module geomGraph_class !! array -> Array with graph data !! uniqueCells -> Number of uniqueCells in the structure !! usedMats -> Sorted list of matIdxs which are used in the geometry + !! isExtended -> Logical stating whether or not the graph is extended !! !! Interface: - !! init -> Build fron uniFills and dictionary definition - !! getFill -> Get filling invormation at location given by uniRootIr & localID - !! kill -> Return to uninitialised state + !! init -> Build fron uniFills and dictionary definition + !! getFill -> Get filling invormation at location given by uniRootIr & localID + !! getMatFromUID -> Get material ID given a cell unique ID + !! kill -> Return to uninitialised state !! type, public :: geomGraph type(location), dimension(:), allocatable :: array integer(shortInt) :: uniqueCells = 0 integer(shortInt), dimension(:), allocatable :: usedMats + integer(shortInt), dimension(:), allocatable :: matsByCell + logical(defBool) :: isExtended = .FALSE. contains procedure :: init procedure :: getFill + procedure :: getMatFromUID procedure :: kill ! Private procedures procedure, private :: buildShrunk procedure, private :: buildExtended procedure, private :: setUniqueIDs + procedure, private :: buildMatArrayByCell end type geomGraph contains @@ -145,7 +151,27 @@ elemental subroutine getFill(self, idx, id, uniRootID, localID) id = self % array(uniRootId + localID -1) % id end subroutine getFill + + !! + !! Given a valid unique ID, returns a material index. + !! No checks, so make sure not to feed something incorrect... + !! + !! Args: + !! ID -> uniqueID of a cell + !! + !! Result: + !! matIdx -> material index of the cell's contents + !! + !! + pure function getMatFromUID(self, ID) result(matIdx) + class(geomGraph), intent(in) :: self + integer(shortInt), intent(in) :: ID + integer(shortInt) :: matIdx + matIdx = self % matsByCell(ID) + + end function getMatFromUID + !! !! Return to uninitialised state !! @@ -229,6 +255,8 @@ subroutine buildShrunk(self, fills) ! Set unique IDs -> Enumerate sinks call self % setUniqueIDs() + call self % buildMatArrayByCell() + end subroutine buildShrunk !! @@ -291,6 +319,10 @@ subroutine buildExtended(self, fills) ! Set unique IDs -> Enumerate sinks call self % setUniqueIDs() + self % isExtended = .TRUE. + + call self % buildMatArrayByCell() + end subroutine buildExtended !! @@ -344,6 +376,27 @@ subroutine setUniqueIDs(self) end subroutine setUniqueIDs + !! + !! Builds an array of material indices corresponding to cell uniqueIDs. + !! This allows for more quickly finding matIdxs given a unique ID. + !! + subroutine buildMatArrayByCell(self) + class(geomGraph), intent(inout) :: self + integer(shortInt) :: i, cells, fill + + allocate(self % matsByCell(self % uniqueCells)) + + cells = 0 + do i = 1, size(self % array) + fill = self % array(i) % idx + if (fill > 0) then ! It is material filling + cells = cells + 1 + self % matsByCell(cells) = fill + end if + end do + + end subroutine buildMatArrayByCell + !! !! Put universe data on the array !! diff --git a/Geometry/geometryStd_class.f90 b/Geometry/geometryStd_class.f90 index c5ba6e00d..7dc45103a 100644 --- a/Geometry/geometryStd_class.f90 +++ b/Geometry/geometryStd_class.f90 @@ -30,14 +30,16 @@ module geometryStd_class !! universes. !! !! Boundary conditions in diffrent movement models are handeled: - !! move -> explicitBC - !! moveGlobal -> explicitBC - !! teleport -> Co-ordinate transfrom + !! move -> explicitBC + !! moveGlobal -> explicitBC + !! moveRay -> explicitBC with vacuum handled as reflective + !! moveRayGlobal -> explicitBC with vacuum handled as reflective + !! teleport -> Co-ordinate transfrom !! !! Sample Dictionary Input: !! geometry { !! type geometryStd; - !! + !! !! } !! !! Public Members: @@ -59,9 +61,12 @@ module geometryStd_class procedure :: bounds procedure :: move_noCache procedure :: move_withCache + procedure :: moveRay_noCache + procedure :: moveRay_withCache procedure :: moveGlobal procedure :: teleport procedure :: activeMats + procedure :: numberOfCells ! Private procedures procedure, private :: diveToMat @@ -270,6 +275,8 @@ subroutine move_withCache(self, coords, maxDist, event, cache) character(100), parameter :: Here = 'move_withCache (geometryStd_class.f90)' if (.not.coords % isPlaced()) then + print *, coords % lvl(1) % r + print *, coords % lvl(1) % dir call fatalError(Here, 'Coordinate list is not placed in the geometry') end if @@ -314,6 +321,142 @@ subroutine move_withCache(self, coords, maxDist, event, cache) end if end subroutine move_withCache + + !! + !! Given coordinates placed in the geometry move point through the geometry + !! + !! See geometry_inter for details + !! + !! Uses explicit BC while treating vacuum boundaries as reflective + !! + subroutine moveRay_noCache(self, coords, maxDist, event, hitVacuum) + class(geometryStd), intent(in) :: self + type(coordList), intent(inout) :: coords + real(defReal), intent(inout) :: maxDist + integer(shortInt), intent(out) :: event + logical(defBool), intent(out) :: hitVacuum + integer(shortInt) :: surfIdx, level + real(defReal) :: dist + class(surface), pointer :: surf + class(universe), pointer :: uni + character(100), parameter :: Here = 'moveRay_noCache (geometryStd_class.f90)' + + hitVacuum = .FALSE. + + if (.not.coords % isPlaced()) then + print *, coords % lvl(1) % r + print *, coords % lvl(1) % dir + call fatalError(Here, 'Coordinate list is not placed in the geometry') + end if + + ! Find distance to the next surface + call self % closestDist(dist, surfIdx, level, coords) + + if (maxDist < dist) then ! Moves within cell + call coords % moveLocal(maxDist, coords % nesting) + event = COLL_EV + maxDist = maxDist ! Left for explicitness. Compiler will not stand it anyway + + else if (surfIdx == self % geom % borderIdx .and. level == 1) then ! Hits domain boundary + ! Move global to the boundary + call coords % moveGlobal(dist) + event = BOUNDARY_EV + maxDist = dist + + ! Get boundary surface and apply BCs + surf => self % geom % surfs % getPtr(self % geom % borderIdx) + call surf % explicitRayBC(coords % lvl(1) % r, coords % lvl(1) % dir, hitVacuum) + + ! Place back in geometry + call self % placeCoord(coords) + + else ! Crosses to diffrent local cell + ! Move to boundary at hit level + call coords % moveLocal(dist, level) + event = CROSS_EV + maxDist = dist + + ! Get universe and cross to the next cell + uni => self % geom % unis % getPtr_fast(coords % lvl(level) % uniIdx) + call uni % cross(coords % lvl(level), surfIdx) + + ! Get material + call self % diveToMat(coords, level) + + end if + + end subroutine moveRay_noCache + + + !! + !! Given coordinates placed in the geometry move point through the geometry + !! + !! See geometry_inter for details + !! + !! Uses explicit BC while treating vacuum boundaries as reflective + !! + subroutine moveRay_withCache(self, coords, maxDist, event, cache, hitVacuum) + class(geometryStd), intent(in) :: self + type(coordList), intent(inout) :: coords + real(defReal), intent(inout) :: maxDist + integer(shortInt), intent(out) :: event + type(distCache), intent(inout) :: cache + logical(defBool), intent(out) :: hitVacuum + integer(shortInt) :: surfIdx, level + real(defReal) :: dist + class(surface), pointer :: surf + class(universe), pointer :: uni + character(100), parameter :: Here = 'moveRay_withCache (geometryStd_class.f90)' + + hitVacuum = .FALSE. + + if (.not.coords % isPlaced()) then + print *, coords % lvl(1) % r + print *, coords % lvl(1) % dir + call fatalError(Here, 'Coordinate list is not placed in the geometry') + end if + + ! Find distance to the next surface + call self % closestDist_cache(dist, surfIdx, level, coords, cache) + + if (maxDist < dist) then ! Moves within cell + call coords % moveLocal(maxDist, coords % nesting) + event = COLL_EV + maxDist = maxDist ! Left for explicitness. Compiler will not stand it anyway + cache % lvl = 0 + + else if (surfIdx == self % geom % borderIdx .and. level == 1) then ! Hits domain boundary + ! Move global to the boundary + call coords % moveGlobal(dist) + event = BOUNDARY_EV + maxDist = dist + cache % lvl = 0 + + ! Get boundary surface and apply BCs + surf => self % geom % surfs % getPtr(self % geom % borderIdx) + call surf % explicitRayBC(coords % lvl(1) % r, coords % lvl(1) % dir, hitVacuum) + + ! Place back in geometry + call self % placeCoord(coords) + + else ! Crosses to diffrent local cell + ! Move to boundary at hit level + call coords % moveLocal(dist, level) + event = CROSS_EV + maxDist = dist + cache % dist(1:level-1) = cache % dist(1:level-1) - dist + cache % lvl = level - 1 + + ! Get universe and cross to the next cell + uni => self % geom % unis % getPtr_fast(coords % lvl(level) % uniIdx) + call uni % cross(coords % lvl(level), surfIdx) + + ! Get material + call self % diveToMat(coords, level) + + end if + + end subroutine moveRay_withCache !! !! Move a particle in the top (global) level in the geometry @@ -417,6 +560,20 @@ function activeMats(self) result(matList) end if end function activeMats + + !! + !! Returns the number of unique cells present in the geometry + !! + !! See geometry_inter for details + !! + function numberOfCells(self) result(n) + class(geometryStd), intent(in) :: self + integer(shortInt) :: n + + ! Takes the number of cells from geomGraph + n = self % geom % graph % uniqueCells + + end function numberOfCells !! !! Descend down the geometry structure untill material is reached diff --git a/Geometry/geometry_inter.f90 b/Geometry/geometry_inter.f90 index 973007549..45e2066eb 100644 --- a/Geometry/geometry_inter.f90 +++ b/Geometry/geometry_inter.f90 @@ -30,23 +30,23 @@ module geometry_inter type, public, abstract :: geometry contains ! Generic procedures - generic :: move => move_noCache, move_withCache + generic :: move => move_noCache, move_withCache, moveRay_withCache, moveRay_noCache ! Deferred procedures - procedure(init), deferred :: init - procedure(kill), deferred :: kill - procedure(placeCoord), deferred :: placeCoord - procedure(whatIsAt), deferred :: whatIsAt - procedure(bounds), deferred :: bounds - procedure(move_noCache), deferred :: move_noCache - procedure(move_withCache), deferred :: move_withCache - procedure(moveGlobal), deferred :: moveGlobal - procedure(teleport), deferred :: teleport - procedure(activeMats), deferred :: activeMats + procedure(init), deferred :: init + procedure(kill), deferred :: kill + procedure(placeCoord), deferred :: placeCoord + procedure(whatIsAt), deferred :: whatIsAt + procedure(bounds), deferred :: bounds + procedure(move_noCache), deferred :: move_noCache + procedure(move_withCache), deferred :: move_withCache + procedure(moveRay_noCache), deferred :: moveRay_noCache + procedure(moveRay_withCache), deferred :: moveRay_withCache + procedure(moveGlobal), deferred :: moveGlobal + procedure(teleport), deferred :: teleport + procedure(activeMats), deferred :: activeMats + procedure(numberOfCells), deferred :: numberOfCells - ! Common procedures - procedure :: slicePlot - procedure :: voxelplot end type geometry abstract interface @@ -133,13 +133,13 @@ end function bounds !! !! Given coordinates placed in the geometry move point through the geometry !! - !! Move by up to maxDist stopping at domain boundary or untill matIdx or uniqueID changes + !! Move by up to maxDist stopping at domain boundary or untill matIdx or uniqueID changes. !! When particle hits boundary, boundary conditions are applied before returning. !! !! Following events can be returned: !! COLL_EV -> Particle moved by entire maxDist. Collision happens !! BOUNDARY_EV -> Particle hit domain boundary - !! CROSS_EV -> Partilce crossed to a region with different matIdx or uniqueID + !! CROSS_EV -> Particle crossed to a region with different matIdx or uniqueID !! LOST_EV -> Something gone wrong in tracking and particle is lost !! !! Args: @@ -164,7 +164,7 @@ end subroutine move_noCache !! !! Given coordinates placed in the geometry move point through the geometry !! - !! Move by up to maxDist stopping at domain boundary or untill matIdx or uniqueID changes + !! Move by up to maxDist stopping at domain boundary or until matIdx or uniqueID changes. !! When particle hits boundary, boundary conditions are applied before returning. !! !! Use distance cache to avoid needless recalculation of the next crossing at @@ -173,12 +173,12 @@ end subroutine move_noCache !! Following events can be returned: !! COLL_EV -> Particle moved by entire maxDist. Collision happens !! BOUNDARY_EV -> Particle hit domain boundary - !! CROSS_EV -> Partilce crossed to a region with different matIdx or uniqueID + !! CROSS_EV -> Particle crossed to a region with different matIdx or uniqueID !! LOST_EV -> Something gone wrong in tracking and particle is lost !! !! Args: !! coords [inout] -> Coordinate list of the particle to be moved through the geometry - !! maxDict [inout] -> Maximum distance to move the position. If movment is stopped + !! maxDict [inout] -> Maximum distance to move the position. If movement is stopped !! prematurely (e.g. hitting boundary), maxDist is set to the distance the particle has !! moved by. !! event [out] -> Event flag that specifies what finished the movement. @@ -196,6 +196,47 @@ subroutine move_withCache(self, coords, maxDist, event, cache) type(distCache), intent(inout) :: cache end subroutine move_withCache + !! + !! Move, but ensuring that vacuum boundaries are treated as reflective and communicating + !! a vacuum strike back. + !! This is implemented for handling Random Ray/MoC problems where rays are not terminated + !! as they strike a vacuum boundary, but are instead reflected. + !! + !! Identical in interface to move, with the exception that a flag is included + !! for identifying a vacuum boundary hit: + !! + !! hitVacuum [out] -> false if a vacuum was not hit, true if it was. + !! + subroutine moveRay_noCache(self, coords, maxDist, event, hitVacuum) + import :: geometry, coordList, defReal, shortInt, defBool + class(geometry), intent(in) :: self + type(coordList), intent(inout) :: coords + real(defReal), intent(inout) :: maxDist + integer(shortInt), intent(out) :: event + logical(defBool), intent(out) :: hitVacuum + end subroutine moveRay_noCache + + !! + !! Move, but ensuring that vacuum boundaries are treated as reflective and communicating + !! a vacuum strike back. + !! This is implemented for handling Random Ray/MoC problems where rays are not terminated + !! as they strike a vacuum boundary, but are instead reflected. + !! + !! Identical in interface to move_withCache, with the exception that a flag is included + !! for identifying a vacuum boundary hit: + !! + !! hitVacuum [out] -> false if a vacuum was not hit, true if it was. + !! + subroutine moveRay_withCache(self, coords, maxDist, event, cache, hitVacuum) + import :: geometry, coordList, defReal, shortInt, distCache, defBool + class(geometry), intent(in) :: self + type(coordList), intent(inout) :: coords + real(defReal), intent(inout) :: maxDist + integer(shortInt), intent(out) :: event + type(distCache), intent(inout) :: cache + logical(defBool), intent(out) :: hitVacuum + end subroutine moveRay_withCache + !! !! Move a particle in the top (global) level in the geometry !! @@ -207,7 +248,7 @@ end subroutine move_withCache !! BOUNDARY_EV -> Particle hit domain boundary !! !! Args: - !! coords [inout] -> Initialised (but not necesserly placed) coordList for a particle to be + !! coords [inout] -> Initialised (but not necessarily placed) coordList for a particle to be !! moved. Will become placed on exit. !! maxDict [inout] -> Maximum distance to move the position. If movment is stopped !! prematurely (e.g. hitting boundary), maxDist is set to the distance the particle has @@ -232,9 +273,9 @@ end subroutine moveGlobal !! applied and movement continious untill full distance is reached. !! !! Args: - !! coords [inout] -> Initialised (but not necesserly placed) coordList for a particle to be - !! moved. Will become placed on exit. - !! dist [in] -> Distance by which move the particle + !! coords [inout] -> Initialised (but not necessarily placed) coordList for a particle to be + !! moved. Will become placed on exit. + !! dist [in] -> Distance by which to move the particle !! !! Errors: !! If maxDist < 0.0 behaviour is unspecified @@ -262,168 +303,23 @@ function activeMats(self) result(matList) integer(shortInt), dimension(:), allocatable :: matList end function activeMats + !! + !! Returns the number of unique cells present in the geometry + !! + !! Args: + !! None + !! + !! Result: + !! Integer of the number of unique (material containing) cells in the geometry. + !! + function numberOfCells(self) result(n) + import :: geometry, shortInt + class(geometry), intent(in) :: self + integer(shortInt) :: n + end function numberOfCells + end interface contains - !! - !! Produce a 2D plot of the geometry - !! - !! Resolution is determined by a size of provided output matrix - !! By default plot plane is normal to z-axis, witch width determined by bounds of the - !! geometry. - !! - !! Args: - !! img [out] -> Rank 2 matrix. It is effectively a bitmap image - !! centre [in] -> Location of the centre of the image - !! dir [in] -> Axis normal to plot plane. In {'x','y','z'} - !! what [in] -> What to plot 'material' or 'uniqueID' - !! width [in] -> Optional. Width of the plot in both directions. Direction lower in - !! sequence {x,y,z} is given first. - !! - subroutine slicePlot(self, img, centre, dir, what, width) - class(geometry), intent(in) :: self - integer(shortInt), dimension(:,:), intent(out) :: img - real(defReal), dimension(3), intent(in) :: centre - character(1), intent(in) :: dir - character(*), intent(in) :: what - real(defReal), dimension(2), optional, intent(in) :: width - real(defReal), dimension(3) :: low, top , step, point, corner - real(defReal), dimension(6) :: aabb - integer(shortInt), dimension(2) :: plane - integer(shortInt) :: ax, i, j, matIdx, uniqueID - logical(defBool) :: printMat - character(100), parameter :: Here = 'slicePlot (geometry_inter.f90)' - - ! Select plane of the plot - select case (dir) - case ('x') - ax = X_AXIS - plane = [Y_AXIS, Z_AXIS] - - case ('y') - ax = Y_AXIS - plane = [X_AXIS, Z_AXIS] - - case ('z') - ax = Z_AXIS - plane = [X_AXIS, Y_AXIS] - - case default - call fatalError(Here, 'Unknown normal axis: '//dir) - ax = X_AXIS - plane = 0 ! Make compiler happy - end select - - ! Find lower and upper corner of the plot - if (present(width)) then - low(plane) = centre(plane) - width * HALF - top(plane) = centre(plane) + width * HALF - low(ax) = centre(ax) - top(ax) = centre(ax) - - else - aabb = self % bounds() - low = aabb(1:3) - top = aabb(4:6) - low(ax) = centre(ax) - top(ax) = centre(ax) - - end if - - ! Calculate step size in all directions - step(ax) = ZERO - step(plane) = (top(plane) - low(plane)) / shape(img) - - ! Select what to print - select case (what) - case ('material') - printMat = .true. - - case('uniqueID') - printMat = .false. - - case default - call fatalError(Here, 'Target of plot must be material or uniqueID. Not: '//trim(what)) - printMat = .false. ! Make compiler happy - - end select - - ! Print the image - corner = low - HALF * step - point(ax) = corner(ax) - - !$omp parallel do firstprivate(point) private(matIdx, uniqueID) - do j = 1, size(img, 2) - point(plane(2)) = corner(plane(2)) + step(plane(2)) * j - - do i = 1, size(img, 1) - point(plane(1)) = corner(plane(1)) + step(plane(1)) * i - - ! Find material and paint image - call self % whatIsAt(matIdx, uniqueID, point) - - ! Paint the pixel - if (printMat) then - img(i, j) = matIdx - else - img(i, j) = uniqueID - end if - - end do - end do - !$omp end parallel do - - end subroutine slicePlot - - !! - !! Produce a 3D Voxel plot of the geometry - !! - !! Resolution is determined by a size of provided output matrix - !! By default, bounds of the plot correspond to the bounds of the geometry - !! - !! Args: - !! img [out] -> Rank 3 matrix, It is effectively a 3D bitmap - !! centre [in] -> Location of the centre of the image - !! what [in] -> What to plot 'material' or 'uniqueID' - !! width [in] -> Optional. Width of the plot in all directions. - !! - subroutine voxelPlot(self, img, centre, what, width) - class(geometry), intent(in) :: self - integer(shortInt), dimension(:,:,:), intent(out) :: img - real(defReal), dimension(3), intent(in) :: centre - character(*), intent(in) :: what - real(defReal), dimension(3), optional, intent(in) :: width - real(defReal), dimension(3) :: width_l, centre_l, point - real(defReal), dimension(6) :: aabb - real(defReal) :: stepZ - integer(shortInt) :: i - - ! Get local value of width and centre - if (present(width)) then - width_l = width - centre_l = centre - - else - aabb = self % bounds() - centre_l = (aabb(1:3) + aabb(4:6)) * HALF - width_l = aabb(4:6) - aabb(1:3) - - end if - - ! Calculate step in z direction - stepZ = width_l(3) / size(img, 3) - - ! Build voxel plot from multiple slice plots - point = centre_l - point(3) = centre_l(3) - width_l(3) * HALF - stepZ * HALF - do i = 1, size(img, 3) - point(3) = point(3) + stepZ - call self % slicePlot(img(:,:,i), point, 'z', what, width_l(1:2)) - - end do - - end subroutine voxelPlot - - end module geometry_inter diff --git a/InputFiles/C5G7 b/InputFiles/C5G7 new file mode 100644 index 000000000..587f61027 --- /dev/null +++ b/InputFiles/C5G7 @@ -0,0 +1,211 @@ +type eigenPhysicsPackage; + +pop 12000; +active 20; +inactive 300; +XSdata mg; +dataType mg; +outputFile C5G7_MGMC_2D ; + +collisionOperator { neutronMG {type neutronMGstd; } } + +transportOperator { type transportOperatorST; } + +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);} + pin1 { id 1; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (UO2 UO2 UO2 water water water);} + pin2 { id 2; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (GT GT GT water water water);} + pin3 { id 3; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (mox43 mox43 mox43 water water water);} + pin4 { id 4; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (mox7 mox7 mox7 water water water);} + pin5 { id 5; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (mox87 mox87 mox87 water water water);} + pin6 { id 6; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.66 0.78 0.0 ); fills (FC FC FC water water 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 uniqueID; + centre (0.0 0.0 10.0); + axis z; + res (1000 1000); } +// myVTK { +// type vtk; +// what uniqueID; +// corner (-32.13 -32.13 -214.1); +// width (64.26 64.26 428.2); +// vox (700 700 50); +// } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + numberOfGroups 7; + + water { + temp 300; + xsFile ./XS_C5G7/moder; + composition { } + } + + 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 { } + } + +} +} + + diff --git a/InputFiles/TRRM/C5G7_RoddedB_TRRM b/InputFiles/TRRM/C5G7_RoddedB_TRRM new file mode 100644 index 000000000..4a64d3e05 --- /dev/null +++ b/InputFiles/TRRM/C5G7_RoddedB_TRRM @@ -0,0 +1,1131 @@ +type randomRayPhysicsPackage; + +pop 117000; +active 950; +inactive 1525; +dead 12.56; +termination 628.12; +plot 0; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_RoddedB_TRRM ; + + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 0 1 1 0); + 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 azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (UO2 UO2 UO2 water water water);} + pin2 { id 2; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (GT GT GT water water water);} + pin3 { id 3; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox43 mox43 mox43 water water water);} + pin4 { id 4; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox7 mox7 mox7 water water water);} + pin5 { id 5; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox87 mox87 mox87 water water water);} + pin6 { id 6; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (FC FC FC water water water);} + + // Control rod + pin7 { id 7; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0); rotation (22.5 0 0); fills (CR CR CR water water 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 +); +} + +latJustRods { + id 21; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat water; + map ( + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 7 40 40 7 40 40 7 40 40 40 40 40 + 40 40 40 7 40 40 40 40 40 40 40 40 40 7 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 7 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 40 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 7 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 7 40 40 40 40 40 40 40 40 40 7 40 40 40 + 40 40 40 40 40 7 40 40 7 40 40 7 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.126 0.126 0.0); +shape (10 10 0); +padMat water; +map ( +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latUO2Rod{ + id 80; + 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 7 1 1 7 1 1 7 1 1 1 1 1 + 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 7 1 1 7 1 1 7 1 1 7 1 1 7 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 7 1 1 7 1 1 6 1 1 7 1 1 7 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 7 1 1 7 1 1 7 1 1 7 1 1 7 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 + 1 1 1 1 1 7 1 1 7 1 1 7 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 +); +} + +latMOXRod{ + id 90; + 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 7 4 4 7 4 4 7 4 4 4 4 3 + 3 4 4 7 4 5 5 5 5 5 5 5 4 7 4 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 7 5 5 2 5 5 7 5 5 7 5 5 7 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 7 5 5 7 5 5 6 5 5 7 5 5 7 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 7 5 5 7 5 5 7 5 5 7 5 5 7 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 4 7 4 5 5 5 5 5 5 5 4 7 4 4 3 + 3 4 4 4 4 7 4 4 7 4 4 7 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.357); + shape (3 3 180); + padMat water; + map ( + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +); +} + +} + +} + +viz { +// bmp1 { +// type bmp; +// output material_yz; +// what material; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } +// bmp2 { +// type bmp; +// output material_xy; +// what material; +// centre (0.0 0.0 31.0); +// axis z; +// res (2000 2000); } +// bmp3 { +// type bmp; +// output ID_yz; +// what uniqueID; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } +// myVTK { +// type vtk; +// what uniqueID; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } + myVTK { + type vtk; + what uniqueID; + corner (-21.42 -32.13 -32.13); + width (0.1 64.26 64.26); + vox (1 2000 2000); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + numberOfGroups 7; + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + + // Control rod + CR { + temp 300; + xsFile ../XS_C5G7/CR; + composition { } + } +} +} + + diff --git a/InputFiles/TRRM/C5G7_TRRM b/InputFiles/TRRM/C5G7_TRRM new file mode 100644 index 000000000..0eff860b6 --- /dev/null +++ b/InputFiles/TRRM/C5G7_TRRM @@ -0,0 +1,301 @@ +type randomRayPhysicsPackage; + +pop 1750; +active 2600; +inactive 1000; +dead 20; +termination 220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_TRRM; + +fissionMap {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;} +} +fluxMap {type multiMap; + maps (xax yax); + xax { type spaceMap; axis x; grid lin; min -32.13; max 32.13; N 51;} + yax { type spaceMap; axis y; grid lin; min -32.13; max 32.13; N 51;} +} + +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 azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (UO2 UO2 UO2 water water water);} + pin2 { id 2; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (GT GT GT water water water);} + pin3 { id 3; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox43 mox43 mox43 water water water);} + pin4 { id 4; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox7 mox7 mox7 water water water);} + pin5 { id 5; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox87 mox87 mox87 water water water);} + pin6 { id 6; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (FC FC FC water water 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 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.126 0.126 0.0); +shape (10 10 0); +padMat water; +map ( +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +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 60 +20 10 60 +50 50 70 +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner (-32.13 -32.13 -1.0); + width (64.26 64.26 2.0); + vox (2000 2000 1); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + +} +} + + diff --git a/InputFiles/XS/Ua_1_0_XSS b/InputFiles/XS/Ua_1_0_XSS new file mode 100644 index 000000000..294ac4b76 --- /dev/null +++ b/InputFiles/XS/Ua_1_0_XSS @@ -0,0 +1,18 @@ +// This XSS are for a Ua-1-0-IN/SL Benchamrk Problem +// Source: A. Sood, R. A. Forster, and D. K. Parsons, +// ‘Analytical Benchmark Test Set For Criticality Code Verification’ +// + +numberOfGroups 1; + +capture (0.013056); +fission (0.065280); +nu (2.7); +chi (1.0); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.248064 +); + diff --git a/InputFiles/XS_C5G7/CR b/InputFiles/XS_C5G7/CR new file mode 100644 index 000000000..e4dbeae5b --- /dev/null +++ b/InputFiles/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/XS_C5G7/FC b/InputFiles/XS_C5G7/FC new file mode 100644 index 000000000..441cd9895 --- /dev/null +++ b/InputFiles/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/XS_C5G7/GT b/InputFiles/XS_C5G7/GT new file mode 100644 index 000000000..77ed9f30f --- /dev/null +++ b/InputFiles/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/XS_C5G7/MOX43 b/InputFiles/XS_C5G7/MOX43 new file mode 100644 index 000000000..46054ba02 --- /dev/null +++ b/InputFiles/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/XS_C5G7/MOX7 b/InputFiles/XS_C5G7/MOX7 new file mode 100644 index 000000000..3db4c6cb1 --- /dev/null +++ b/InputFiles/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/XS_C5G7/MOX87 b/InputFiles/XS_C5G7/MOX87 new file mode 100644 index 000000000..6d47c4a11 --- /dev/null +++ b/InputFiles/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/XS_C5G7/UO2 b/InputFiles/XS_C5G7/UO2 new file mode 100644 index 000000000..ffb187b5d --- /dev/null +++ b/InputFiles/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/XS_C5G7/moder b/InputFiles/XS_C5G7/moder new file mode 100644 index 000000000..029b934f1 --- /dev/null +++ b/InputFiles/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 +); + diff --git a/IntegrationTestFiles/PhysicsPackages/SlabTRRM b/IntegrationTestFiles/PhysicsPackages/SlabTRRM new file mode 100644 index 000000000..bc2b3e13a --- /dev/null +++ b/IntegrationTestFiles/PhysicsPackages/SlabTRRM @@ -0,0 +1,60 @@ +type randomRayPhysicsPackage; + +pop 10; +active 10; +inactive 50; +termination 100; +dead 1; +XSdata mg; +dataType mg; + +geometry { + type geometryStd; + boundary (1 1 1 1 1 1); + graph {type extended;} + + surfaces + { + squareBound { id 1; type box; origin ( 0.0 0.0 0.0); halfwidth (9.4959 10.0 10.0); } + } + + + cells + { + } + + universes + { + + root + { + id 1; + type rootUniverse; + border 1; + fill fuel; + } + } +} + +nuclearData { + + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + + +materials { + + fuel { + temp 273; + composition { + } + xsFile ./IntegrationTestFiles/PhysicsPackages/XS/Ua_1_0_XSS; + } + +} + +} + + + diff --git a/IntegrationTestFiles/PhysicsPackages/XS/Ua_1_0_XSS b/IntegrationTestFiles/PhysicsPackages/XS/Ua_1_0_XSS new file mode 100644 index 000000000..294ac4b76 --- /dev/null +++ b/IntegrationTestFiles/PhysicsPackages/XS/Ua_1_0_XSS @@ -0,0 +1,18 @@ +// This XSS are for a Ua-1-0-IN/SL Benchamrk Problem +// Source: A. Sood, R. A. Forster, and D. K. Parsons, +// ‘Analytical Benchmark Test Set For Criticality Code Verification’ +// + +numberOfGroups 1; + +capture (0.013056); +fission (0.065280); +nu (2.7); +chi (1.0); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.248064 +); + diff --git a/NuclearData/Reactions/reactionMG/multiScatterMG_class.f90 b/NuclearData/Reactions/reactionMG/multiScatterMG_class.f90 index 275e30277..70f478fe7 100644 --- a/NuclearData/Reactions/reactionMG/multiScatterMG_class.f90 +++ b/NuclearData/Reactions/reactionMG/multiScatterMG_class.f90 @@ -346,6 +346,10 @@ subroutine buildFromDict(self, dict) ! Calculate P0 total scattering XSs ! Behold the GLORY of Fortran you lowly C++ slaves! + ! ...Sadly slightly diminished by a compiler bug which + ! sizes scatterXSs as 1 before it's allocated. But this + ! should work without the allocation, normally! + allocate(self % scatterXSs(nG)) self % scatterXSs = sum(self % P0, 1) end subroutine buildFromDict diff --git a/NuclearData/materialMenu_mod.f90 b/NuclearData/materialMenu_mod.f90 index 729e209da..4c71ac075 100644 --- a/NuclearData/materialMenu_mod.f90 +++ b/NuclearData/materialMenu_mod.f90 @@ -227,7 +227,7 @@ function matName(idx) result(name) character(nameLen) :: name if( idx <= 0 .or. nMat() < idx) then - name = '' + name = 'Unknown material!' else name = materialDefs(idx) % name diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 index 771d0b730..0a64ed189 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronDatabase_class.f90 @@ -63,6 +63,8 @@ module baseMgNeutronDatabase_class contains ! Superclass Interface procedure :: getTrackingXS + + ! Local interface procedure :: getTotalMatXS procedure :: getMajorantXS procedure :: matNamesMap @@ -72,8 +74,6 @@ module baseMgNeutronDatabase_class procedure :: kill procedure :: init procedure :: activate - - ! Local interface procedure :: initMajorant procedure :: nGroups diff --git a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 index dc98bdc35..0ab258e33 100644 --- a/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 +++ b/NuclearData/mgNeutronData/baseMgNeutron/baseMgNeutronMaterial_class.f90 @@ -71,16 +71,25 @@ module baseMgNeutronMaterial_class real(defReal),dimension(:,:), allocatable :: data class(multiScatterMG), allocatable :: scatter type(fissionMG), allocatable :: fission + integer(shortInt) :: nG contains ! Superclass procedures procedure :: kill procedure :: getMacroXSs_byG procedure :: getTotalXS + procedure :: getNuFissionXS + procedure :: getFissionXS + procedure :: getChi + procedure :: getScatterXS ! Local procedures procedure :: init procedure :: nGroups + procedure :: getTotalPtr + procedure :: getNuFissionPtr + procedure :: getChiPtr + procedure :: getScatterPtr end type baseMgNeutronMaterial @@ -159,6 +168,108 @@ function getTotalXS(self, G, rand) result(xs) end function getTotalXS + !! + !! Return NuFission XS for energy group G + !! + !! See mgNeutronMaterial documentationfor details + !! + function getNuFissionXS(self, G, rand) result(xs) + class(baseMgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: xs + character(100), parameter :: Here = ' getNuFissionXS (baseMgNeutronMaterial_class.f90)' + + ! Verify bounds + if (self % isFissile()) then + if(G < 1 .or. self % nGroups() < G) then + call fatalError(Here,'Invalid group number: '//numToChar(G)// & + ' Data has only: ' // numToChar(self % nGroups())) + xs = ZERO ! Avoid warning + end if + xs = self % data(NU_FISSION, G) + else + xs = ZERO + end if + + end function getNuFissionXS + + !! + !! Return Fission XS for energy group G + !! + !! See mgNeutronMaterial documentationfor details + !! + function getFissionXS(self, G, rand) result(xs) + class(baseMgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: xs + character(100), parameter :: Here = ' getFissionXS (baseMgNeutronMaterial_class.f90)' + + ! Verify bounds + if (self % isFissile()) then + if(G < 1 .or. self % nGroups() < G) then + call fatalError(Here,'Invalid group number: '//numToChar(G)// & + ' Data has only: ' // numToChar(self % nGroups())) + xs = ZERO ! Avoid warning + end if + xs = self % data(FISSION_XS, G) + else + xs = ZERO + end if + + end function getFissionXS + + !! + !! Return chi for energy group G + !! + !! See mgNeutronMaterial documentationfor details + !! + function getChi(self, G, rand) result(chi) + class(baseMgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: chi + character(100), parameter :: Here = ' getChi (baseMgNeutronMaterial_class.f90)' + + if (self % isFissile()) then + ! Verify bounds + if(G < 1 .or. self % nGroups() < G) then + call fatalError(Here,'Invalid group number: '//numToChar(G)// & + ' Data has only: ' // numToChar(self % nGroups())) + chi = ZERO ! Avoid warning + end if + + chi = self % fission % data(G,2) + else + chi = ZERO + end if + + end function getChi + + !! + !! Return scatter XS for incoming energy group Gin and outgoing group Gout + !! + !! See mgNeutronMaterial documentationfor details + !! + function getScatterXS(self, Gin, Gout, rand) result(xs) + class(baseMgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: Gin + integer(shortInt), intent(in) :: Gout + class(RNG), intent(inout) :: rand + real(defReal) :: xs + character(100), parameter :: Here = ' getScatterXS (baseMgNeutronMaterial_class.f90)' + + ! Verify bounds + if(Gin < 1 .or. self % nGroups() < Gin .or. Gout < 1 .or. self % nGroups() < Gout) then + call fatalError(Here,'Invalid group numbers: '//numToChar(Gin)//' and '//numToChar(Gout) & + //' Data has only: ' // numToChar(self % nGroups())) + xs = ZERO ! Avoid warning + end if + xs = self % scatter % P0(Gout,Gin) + + end function getScatterXS + !! !! Initialise Base MG Neutron Material fromdictionary @@ -192,6 +303,7 @@ subroutine init(self, dict, scatterKey) ! Read number of groups call dict % get(nG, 'numberOfGroups') if(nG < 1) call fatalError(Here,'Number of groups is invalid' // numToChar(nG)) + self % nG = nG ! Set fissile flag call self % set(fissile = dict % isPresent('fission')) @@ -286,13 +398,65 @@ pure function nGroups(self) result(nG) integer(shortInt) :: nG if(allocated(self % data)) then - nG = size(self % data,2) + nG = self % nG else nG = 0 end if end function nGroups + + !! + !! Return pointer to Total XSs + !! + function getTotalPtr(self) result(xs) + class(baseMgNeutronMaterial), intent(in), target :: self + real(defReal), dimension(:), pointer :: xs + + xs => self % data(TOTAL_XS, :) + + end function getTotalPtr + + !! + !! Return pointer to NuFission XSs + !! + function getNuFissionPtr(self) result(xs) + class(baseMgNeutronMaterial), intent(in), target :: self + real(defReal), dimension(:), pointer :: xs + + if (self % isFissile()) then + xs => self % data(NU_FISSION, :) + else + xs => null() + end if + + end function getNuFissionPtr + + !! + !! Return pointer to Chis + !! + function getChiPtr(self) result(chi) + class(baseMgNeutronMaterial), intent(in), target :: self + real(defReal), dimension(:), pointer :: chi + + if (self % isFissile()) then + chi => self % fission % data(:,2) + else + chi => null() + end if + + end function getChiPtr + + !! + !! Return pointer to scatter XSs + !! + function getScatterPtr(self) result(xs) + class(baseMgNeutronMaterial), intent(in), target :: self + real(defReal), dimension(:,:), pointer :: xs + + xs => self % scatter % P0(:, :) + end function getScatterPtr + !! !! Cast materialHandle pointer to baseMgNeutronMaterial type pointer !! diff --git a/NuclearData/mgNeutronData/mgNeutronDatabase_inter.f90 b/NuclearData/mgNeutronData/mgNeutronDatabase_inter.f90 index e2c905cb4..6a2debc62 100644 --- a/NuclearData/mgNeutronData/mgNeutronDatabase_inter.f90 +++ b/NuclearData/mgNeutronData/mgNeutronDatabase_inter.f90 @@ -1,7 +1,7 @@ module mgNeutronDatabase_inter use numPrecision - + ! Nuclear Data Interfaces & Objects use nuclearDatabase_inter, only : nuclearDatabase @@ -16,7 +16,7 @@ module mgNeutronDatabase_inter !! !! An abstract class that groups all MG Neutron Data objects !! - !! It does nothing, It adds nothing, + !! It does nothing, It adds nothing, (other than give the number of groups) !! It just provides a common superclass for related classes !! and holds the number of energy groups !! @@ -25,8 +25,29 @@ module mgNeutronDatabase_inter !! type, public, abstract, extends(nuclearDatabase) :: mgNeutronDatabase integer(shortInt) :: nG = 0 + contains end type mgNeutronDatabase + abstract interface + + !! + !! Returns the number of energy groups used + !! + !! Args: + !! None + !! + !! Result: + !! Integer number of energy groups + !! + pure function nGroups(self) result(ng) + import :: mgNeutronDatabase, shortInt + class(mgNeutronDatabase), intent(in) :: self + integer(shortInt) :: ng + end function nGroups + + + end interface + contains !! diff --git a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 index 4b8aa0cfa..fe8543633 100644 --- a/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 +++ b/NuclearData/mgNeutronData/mgNeutronMaterial_inter.f90 @@ -51,6 +51,10 @@ module mgNeutronMaterial_inter ! Local procedures procedure(getMacroXSs_byG), deferred :: getMacroXSs_byG procedure(getTotalXS), deferred :: getTotalXS + procedure(getNuFissionXS), deferred :: getNuFissionXS + procedure(getFissionXS), deferred :: getFissionXS + procedure(getChi), deferred :: getChi + procedure(getScatterXS), deferred :: getScatterXS procedure :: isFissile procedure :: set @@ -96,9 +100,95 @@ function getTotalXS(self, G, rand) result(xs) class(RNG), intent(inout) :: rand real(defReal) :: xs end function getTotalXS - end interface + !! + !! Return Macroscopic nu*Fission XS in a given group for the material + !! + !! Args: + !! G [in] -> Requested energygroup + !! rand [inout] -> Random number generator + !! + !! Result: + !! xs -> nuSigmaF value + !! + !! Errors: + !! fatalError if G is out-of-bounds for the stored data + !! + function getNuFissionXS(self, G, rand) result(xs) + import :: mgNeutronMaterial, defReal, shortInt, RNG + class(mgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: xs + end function getNuFissionXS + + !! + !! Return Macroscopic Fission XS in a given group for the material + !! + !! Args: + !! G [in] -> Requested energygroup + !! rand [inout] -> Random number generator + !! + !! Result: + !! xs -> nuSigmaF value + !! + !! Errors: + !! fatalError if G is out-of-bounds for the stored data + !! + function getFissionXS(self, G, rand) result(xs) + import :: mgNeutronMaterial, defReal, shortInt, RNG + class(mgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: xs + end function getFissionXS + + !! + !! Return fission spectrum (chi) in a given group for the material + !! + !! Args: + !! G [in] -> Requested energygroup + !! rand [inout] -> Random number generator + !! + !! Result: + !! chi -> fission spectrum value + !! + !! Errors: + !! fatalError if G is out-of-bounds for the stored data + !! + function getChi(self, G, rand) result(chi) + import :: mgNeutronMaterial, defReal, shortInt, RNG + class(mgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: G + class(RNG), intent(inout) :: rand + real(defReal) :: chi + end function getChi + + !! + !! Return Macroscopic Scatter XSs for ingoing energy Gin and outgoing + !! energy Gout for the material + !! + !! Args: + !! Gin [in] -> Requested ingoing energygroup + !! Gout [in] -> Requested outgoing energygroup + !! rand [inout] -> Random number generator + !! + !! Result: + !! xs -> scatter XS + !! + !! Errors: + !! fatalError if Gin or Gout are out-of-bounds for the stored data + !! + function getScatterXS(self, Gin, Gout, rand) result(xs) + import :: mgNeutronMaterial, defReal, shortInt, RNG + class(mgNeutronMaterial), intent(in) :: self + integer(shortInt), intent(in) :: Gin + integer(shortInt), intent(in) :: Gout + class(RNG), intent(inout) :: rand + real(defReal) :: xs + end function getScatterXS + end interface contains diff --git a/NuclearData/nuclearDataReg_mod.f90 b/NuclearData/nuclearDataReg_mod.f90 index 8b16e96e7..ec2f72b6d 100644 --- a/NuclearData/nuclearDataReg_mod.f90 +++ b/NuclearData/nuclearDataReg_mod.f90 @@ -298,7 +298,7 @@ subroutine activate(type, name, activeMat, silent) if(.not.allocated(databases(idx) % nd)) call make(name, silent = silent_loc) ! Activate - call databases(idx) % nd % activate(activeMat) + call databases(idx) % nd % activate(activeMat, silent_loc) ptr => databases(idx) % nd ! Register as active @@ -415,13 +415,13 @@ function getNeutronCE() result(ptr) end function getNeutronCE !! - !! Return pointer to an active Neutron CE Database + !! Return pointer to an active Neutron MG Database !! !! Args: !! None !! !! Result: - !! ceNeutronDatabase class pointer + !! mgNeutronDatabase class pointer !! !! Errors: !! If there is no active database returns NULL ptr diff --git a/PhysicsPackages/CMakeLists.txt b/PhysicsPackages/CMakeLists.txt index a1db7a1f4..75e7a9e40 100644 --- a/PhysicsPackages/CMakeLists.txt +++ b/PhysicsPackages/CMakeLists.txt @@ -3,8 +3,10 @@ add_sources( ./physicsPackage_inter.f90 ./physicsPackageFactory_func.f90 ./eigenPhysicsPackage_class.f90 - ./fixedSourcePhysicsPackage_class.f90 + ./fixedSourcePhysicsPackage_class.f90 ./vizPhysicsPackage_class.f90 ./rayVolPhysicsPackage_class.f90 + ./randomRayPhysicsPackage_class.f90 ) - #./dynamPhysicsPackage_class.f90) + +add_integration_tests(./Tests/randomRay_iTest.f90) diff --git a/PhysicsPackages/Tests/randomRay_iTest.f90 b/PhysicsPackages/Tests/randomRay_iTest.f90 new file mode 100644 index 000000000..95300eeeb --- /dev/null +++ b/PhysicsPackages/Tests/randomRay_iTest.f90 @@ -0,0 +1,46 @@ +module randomRay_iTest + + use numPrecision + use dictionary_class, only : dictionary + use dictParser_func, only : charToDict + use charMap_class, only : charMap + use dictParser_func, only : fileToDict + use randomRayPhysicsPackage_class, only : randomRayPhysicsPackage + use pFUnit_mod + + implicit none + + +contains + + !! + !! Random ray integration test. + !! Homogeneous, reflected box. + !! Should have a precise eigenvalue, the ratio of nuSigmaF/SigmaA. + !! Uncertainties will not be present as all points in phase space are identical. + !! +@Test + subroutine test_random_ray() + type(randomRayPhysicsPackage) :: pp + character(*), parameter :: path = './IntegrationTestFiles/PhysicsPackages/SlabTRRM' + type(dictionary) :: dict + real(defReal) :: keff + real(defReal), parameter :: TOL = 1.0E-5_defReal + + ! Load dictionary + call fileToDict(dict, path) + + ! Initialise physics package and run + call pp % init(dict, loud = .false.) + call pp % run() + + ! Extract and verify keff + keff = pp % keffScore(1) + @assertEqual(keff, 2.25_defReal, TOL) + + ! Kill physics package + call pp % kill() + + end subroutine test_random_ray + +end module randomRay_iTest diff --git a/PhysicsPackages/eigenPhysicsPackage_class.f90 b/PhysicsPackages/eigenPhysicsPackage_class.f90 index 4ede0e8f4..4821e693e 100644 --- a/PhysicsPackages/eigenPhysicsPackage_class.f90 +++ b/PhysicsPackages/eigenPhysicsPackage_class.f90 @@ -103,6 +103,9 @@ module eigenPhysicsPackage_class ! Timer bins integer(shortInt) :: timerMain + real(defReal) :: activeTime + real(defReal) :: inactiveTime + integer(shortInt) :: timerParticle real (defReal) :: time_transport = 0.0 real (defReal) :: CPU_time_start real (defReal) :: CPU_time_end @@ -123,17 +126,23 @@ module eigenPhysicsPackage_class subroutine run(self) class(eigenPhysicsPackage), intent(inout) :: self - print *, repeat("<>",50) - print *, "/\/\ EIGENVALUE CALCULATION /\/\" + if (self % loud) then + print *, repeat("<>",50) + print *, "/\/\ EIGENVALUE CALCULATION /\/\" + end if call self % generateInitialState() call self % cycles(self % inactiveTally, self % inactiveAtch, self % N_inactive) + self % inactiveTime = timerTime(self % timerParticle) call self % cycles(self % activeTally, self % activeAtch, self % N_active) + self % activeTime = timerTime(self % timerParticle) call self % collectResults() - print * - print *, "\/\/ END OF EIGENVALUE CALCULATION \/\/" - print * + if (self % loud) then + print * + print *, "\/\/ END OF EIGENVALUE CALCULATION \/\/" + print * + end if end subroutine !! @@ -162,7 +171,7 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Initialise neutron neutron % geomIdx = self % geomIdx - + ! Create a collision + transport operator which can be made thread private collOp = self % collOp transOp = self % transOp @@ -175,6 +184,8 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) call timerReset(self % timerMain) call timerStart(self % timerMain) + call timerReset(self % timerParticle) + do i=1,N_cycles ! Send start of cycle report @@ -183,6 +194,7 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) nParticles = self % thisCycle % popSize() + call timerStart(self % timerParticle) !$omp parallel do schedule(dynamic) gen: do n = 1, nParticles @@ -279,14 +291,16 @@ subroutine cycles(self, tally, tallyAtch, N_cycles) ! Display progress - call printFishLineR(i) - print * - print *, 'Cycle: ', numToChar(i), ' of ', numToChar(N_cycles) - print *, 'Pop: ', numToChar(Nstart) , ' -> ', numToChar(Nend) - print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) - print *, 'End time: ', trim(secToChar(end_T)) - print *, 'Time to end: ', trim(secToChar(T_toEnd)) - call tally % display() + if (self % loud) then + call printFishLineR(i) + print * + print *, 'Cycle: ', numToChar(i), ' of ', numToChar(N_cycles) + print *, 'Pop: ', numToChar(Nstart) , ' -> ', numToChar(Nend) + print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) + print *, 'End time: ', trim(secToChar(end_T)) + print *, 'Time to end: ', trim(secToChar(T_toEnd)) + call tally % display() + end if end do ! Load elapsed time @@ -308,10 +322,10 @@ subroutine generateInitialState(self) call self % thisCycle % init(3 * self % pop) call self % nextCycle % init(3 * self % pop) - ! Generate initial source - print *, "GENERATING INITIAL FISSION SOURCE" + ! Generate initial surce + if (self % loud) print *, "GENERATING INITIAL FISSION SOURCE" call self % initSource % generate(self % thisCycle, self % pop, self % pRNG) - print *, "DONE!" + if (self % loud) print *, "DONE!" end subroutine generateInitialState @@ -334,8 +348,14 @@ subroutine collectResults(self) name = 'Inactive_Cycles' call out % printValue(self % N_inactive,name) + name = 'inactive_particles_per_s' + call out % printValue(self % pop * self % N_inactive /self % inactiveTime,name) + name = 'Active_Cycles' call out % printValue(self % N_active,name) + + name = 'active_particles_per_s' + call out % printValue(self % pop * self % N_active / self % activeTime,name) call cpu_time(self % CPU_time_end) name = 'Total_CPU_Time' @@ -365,9 +385,10 @@ end subroutine collectResults !! !! Initialise from individual components and dictionaries for inactive and active tally !! - subroutine init(self, dict) + subroutine init(self, dict, loud) class(eigenPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud class(dictionary),pointer :: tempDict type(dictionary) :: locDict1, locDict2 integer(shortInt) :: seed_temp @@ -383,6 +404,12 @@ subroutine init(self, dict) call cpu_time(self % CPU_time_start) + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + ! Read calculation settings call dict % get( self % pop,'pop') call dict % get( self % N_inactive,'inactive') @@ -413,6 +440,7 @@ subroutine init(self, dict) ! Register timer self % timerMain = registerTimer('transportTime') + self % timerParticle = registerTimer('particleTime') ! Initialise RNG allocate(self % pRNG) @@ -444,20 +472,20 @@ subroutine init(self, dict) ! Build geometry tempDict => dict % getDictPtr('geometry') geomName = 'eigenGeom' - call new_geometry(tempDict, geomName) + call new_geometry(tempDict, geomName, .not. self % loud) self % geomIdx = gr_geomIdx(geomName) self % geom => gr_geomPtr(self % geomIdx) ! Activate Nuclear Data *** All materials are active - call ndReg_activate(self % particleType, nucData, self % geom % activeMats()) + call ndReg_activate(self % particleType, nucData, self % geom % activeMats(), .not. self % loud) self % nucData => ndReg_get(self % particleType) ! Call visualisation if (dict % isPresent('viz')) then - print *, "Initialising visualiser" + if (self % loud) print *, "Initialising visualiser" tempDict => dict % getDictPtr('viz') call viz % init(self % geom, tempDict) - print *, "Constructing visualisation" + if (self % loud) print *, "Constructing visualisation" call viz % makeViz() call viz % kill() endif @@ -546,7 +574,7 @@ subroutine init(self, dict) call self % activeTally % push(self % activeAtch) - call self % printSettings() + if (self % loud) call self % printSettings() end subroutine init diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index b1dbb4e86..01957d9fd 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -112,15 +112,19 @@ module fixedSourcePhysicsPackage_class subroutine run(self) class(fixedSourcePhysicsPackage), intent(inout) :: self - print *, repeat("<>",50) - print *, "/\/\ FIXED SOURCE CALCULATION /\/\" + if (self % loud) then + print *, repeat("<>",50) + print *, "/\/\ FIXED SOURCE CALCULATION /\/\" + end if call self % cycles(self % tally, self % N_cycles) call self % collectResults() - print * - print *, "\/\/ END OF FIXED SOURCE CALCULATION \/\/" - print * + if (self % loud) then + print * + print *, "\/\/ END OF FIXED SOURCE CALCULATION \/\/" + print * + end if end subroutine !! @@ -236,7 +240,7 @@ subroutine cycles(self, tally, N_cycles) ! Update RNG call self % pRNG % stride(self % pop) - + ! Send end of cycle report call tally % reportCycleEnd(self % thisCycle) @@ -249,14 +253,16 @@ subroutine cycles(self, tally, N_cycles) T_toEnd = max(ZERO, end_T - elapsed_T) ! Display progress - call printFishLineR(i) - print * - print *, 'Source batch: ', numToChar(i), ' of ', numToChar(N_cycles) - print *, 'Pop: ', numToChar(self % pop) - print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) - print *, 'End time: ', trim(secToChar(end_T)) - print *, 'Time to end: ', trim(secToChar(T_toEnd)) - call tally % display() + if (self % loud) then + call printFishLineR(i) + print * + print *, 'Source batch: ', numToChar(i), ' of ', numToChar(N_cycles) + print *, 'Pop: ', numToChar(self % pop) + print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) + print *, 'End time: ', trim(secToChar(end_T)) + print *, 'Time to end: ', trim(secToChar(T_toEnd)) + call tally % display() + end if end do end subroutine cycles @@ -296,9 +302,10 @@ end subroutine collectResults !! !! Initialise from individual components and dictionaries for source and tally !! - subroutine init(self, dict) + subroutine init(self, dict, loud) class(fixedSourcePhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud class(dictionary),pointer :: tempDict integer(shortInt) :: seed_temp, commonBufferSize integer(longInt) :: seed @@ -312,6 +319,12 @@ subroutine init(self, dict) call cpu_time(self % CPU_time_start) + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + ! Read calculation settings call dict % get( self % pop,'pop') call dict % get( self % N_cycles,'cycles') @@ -369,20 +382,20 @@ subroutine init(self, dict) ! Build geometry tempDict => dict % getDictPtr('geometry') geomName = 'fixedSourceGeom' - call new_geometry(tempDict, geomName) + call new_geometry(tempDict, geomName, .not. self % loud) self % geomIdx = gr_geomIdx(geomName) self % geom => gr_geomPtr(self % geomIdx) ! Activate Nuclear Data *** All materials are active - call ndReg_activate(self % particleType, nucData, self % geom % activeMats()) + call ndReg_activate(self % particleType, nucData, self % geom % activeMats(), .not. self % loud) self % nucData => ndReg_get(self % particleType) ! Call visualisation if (dict % isPresent('viz')) then - print *, "Initialising visualiser" + if (self % loud) print *, "Initialising visualiser" tempDict => dict % getDictPtr('viz') call viz % init(self % geom, tempDict) - print *, "Constructing visualisation" + if (self % loud) print *, "Constructing visualisation" call viz % makeViz() call viz % kill() endif @@ -429,7 +442,7 @@ subroutine init(self, dict) 'Buffer size should be greater than the shift threshold') end if - call self % printSettings() + if (self % loud) call self % printSettings() end subroutine init diff --git a/PhysicsPackages/physicsPackageFactory_func.f90 b/PhysicsPackages/physicsPackageFactory_func.f90 index 48de37e1c..b041bb77a 100644 --- a/PhysicsPackages/physicsPackageFactory_func.f90 +++ b/PhysicsPackages/physicsPackageFactory_func.f90 @@ -11,10 +11,11 @@ module physicsPackageFactory_func use physicsPackage_inter, only : physicsPackage ! Implementations - use eigenPhysicsPackage_class, only : eigenPhysicsPackage - use fixedSourcePhysicsPackage_class, only : fixedSourcePhysicsPackage - use vizPhysicsPackage_class, only : vizPhysicsPackage - use rayVolPhysicsPackage_class, only : rayVolPhysicsPackage + use eigenPhysicsPackage_class, only : eigenPhysicsPackage + use fixedSourcePhysicsPackage_class, only : fixedSourcePhysicsPackage + use vizPhysicsPackage_class, only : vizPhysicsPackage + use rayVolPhysicsPackage_class, only : rayVolPhysicsPackage + use randomRayPhysicsPackage_class, only : randomRayPhysicsPackage ! use dynamPhysicsPackage_class, only : dynamPhysicsPackage implicit none @@ -24,10 +25,11 @@ module physicsPackageFactory_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 :: AVAILABLE_physicsPackages = [ 'eigenPhysicsPackage ',& - 'fixedSourcePhysicsPackage',& - 'vizPhysicsPackage ',& - 'rayVolPhysicsPackage '] + character(nameLen),dimension(*),parameter :: AVAILABLE_physicsPackages = [ 'eigenPhysicsPackage ',& + 'fixedSourcePhysicsPackage ',& + 'vizPhysicsPackage ',& + 'randomRayPhysicsPackage ',& + 'rayVolPhysicsPackage '] !! !! Public interface @@ -60,6 +62,9 @@ function new_physicsPackage(dict) result(new) case('vizPhysicsPackage') allocate( vizPhysicsPackage :: new) + case('randomRayPhysicsPackage') + allocate( randomRayPhysicsPackage :: new) + case('rayVolPhysicsPackage') allocate( rayVolPhysicsPackage :: new) diff --git a/PhysicsPackages/physicsPackage_inter.f90 b/PhysicsPackages/physicsPackage_inter.f90 index 50db9763b..9f9e71a52 100644 --- a/PhysicsPackages/physicsPackage_inter.f90 +++ b/PhysicsPackages/physicsPackage_inter.f90 @@ -9,10 +9,12 @@ module physicsPackage_inter !! !! Abstract interface of physics Package !! Physics package is controles a calculation flow - !! Each type of calculation has diffrent physics package + !! Each type of calculation has different physics package + !! Loud is for displaying calculation progress !! type, public,abstract :: physicsPackage private + logical(defBool), public :: loud contains procedure(init), deferred :: init procedure(run),deferred :: run @@ -23,11 +25,13 @@ module physicsPackage_inter !! !! Initialise Physics Package from dictionary !! - subroutine init(self,dict) + subroutine init(self,dict,loud) import :: physicsPackage, & - dictionary - class(physicsPackage), intent(inout) :: self - class(dictionary), intent(inout) :: dict + dictionary, & + defBool + class(physicsPackage), intent(inout) :: self + class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud end subroutine init !! diff --git a/PhysicsPackages/randomRayPhysicsPackage_class.f90 b/PhysicsPackages/randomRayPhysicsPackage_class.f90 new file mode 100644 index 000000000..e6b9d47ec --- /dev/null +++ b/PhysicsPackages/randomRayPhysicsPackage_class.f90 @@ -0,0 +1,662 @@ +module randomRayPhysicsPackage_class + + use numPrecision + use universalVariables + use genericProcedures, only : fatalError, numToChar, printFishLineR + use hashFunctions_func, only : FNV_1 + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + use rng_class, only : RNG + use physicsPackage_inter, only : physicsPackage + + ! Timers + use timer_mod, only : registerTimer, timerStart, timerStop, & + timerTime, timerReset, secToChar + + ! Geometry + use geometry_inter, only : geometry + use geometryStd_class, only : geometryStd + use geometryReg_mod, only : gr_geomPtr => geomPtr, gr_geomIdx => geomIdx, & + gr_fieldIdx => fieldIdx, gr_fieldPtr => fieldPtr + use geometryFactory_func, only : new_geometry + + ! Nuclear Data + use nuclearDataReg_mod, only : ndReg_init => init, & + ndReg_getMatNames => getMatNames, & + ndReg_activate => activate, & + ndReg_kill => kill, & + ndReg_getNeutronMG => getNeutronMG + use mgNeutronDatabase_inter, only : mgNeutronDatabase + use baseMgNeutronDatabase_class, only : baseMgNeutronDatabase + use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial, baseMgNeutronMaterial_CptrCast + + ! Visualisation + use visualiser_class, only : visualiser + + ! Tally map for fission rate + use tallyMap_inter, only : tallyMap + use tallyMapFactory_func, only : new_tallyMap + + ! Random ray specific modules + use dataRR_class, only : dataRR + use arraysRR_class, only : arraysRR + use rayHandling_func, only : transportSweep, initialiseRay + + ! Random ray - or a standard particle + use particle_class, only : ray => particle + + implicit none + private + + !! + !! Physics package to perform The Random Ray Method (TRRM) eigenvalue calculations + !! + !! Tracks rays across the geometry, attenuating their flux. After some dead length, + !! rays begin scoring to estimates of the scalar flux and volume. Each ray has a + !! uniform termination length, after which it is stopped and the next ray is tracked. + !! Once all rays have been tracked, a cycle concludes and fluxes, sources, and keff + !! are updated. + !! + !! Both inactive and active cycles occur, as in Monte Carlo. These can be terminated + !! after a specified number of iterations or on reaching some chosen convergence + !! criterion (though the latter hasn't been implemented yet). + !! + !! Calculates relative volume of different materials in the problem by performing + !! random ray tracing in the geometry. The volume is normalised such that the total domain + !! volume is 1.0. + !! + !! IMPORTANT N.B.: Geometry type must be extended! Won't run if shrunk. + !! This is because spatial discretisation is determined by the number of unique cells in the + !! geometry. + !! Also, this is obviously for multi-group calculations only. + !! + !! Sample Input Dictionary: + !! PP { + !! type randomRayPhysicsPackage; + !! dead 10; // Dead length where rays do not score to scalar fluxes + !! termination 100; // Length a ray travels before it is terminated + !! rays 1000; // Number of rays to sample per iteration + !! inactive 100; // Number of convergence cycles + !! active 200; // Number of scoring cycles + !! #seed 86868;# // Optional RNG seed + !! #cache 1;# // Optionally use distance caching to accelerate ray tracing + !! #fissionMap {}# // Optionally output fission rates according to a given map + !! #fluxMap {}# // Optionally output one-group fluxes according to a given map + !! #plot 1;# // Optionally make VTK viewable plot of fluxes and uncertainties + !! #rho 0;# // Optional stabilisation for negative in-group scattering XSs + !! + !! geometry {} + !! nuclearData {} + !! } + !! + !! Private Members + !! geom -> Pointer to the geometry. + !! geomIdx -> Index of the geometry in geometry Registry. + !! rand -> Random number generator. + !! timerMain -> Index of the timer defined to measure calculation time. + !! mgData -> MG database. Calculation obviously cannot be run in CE. + !! nG -> Number of energy groups, kept for convenience. + !! nCells -> Number of unique cells in the geometry, kept for convenience. + !! + !! termination -> Distance a ray can travel before it is terminated + !! dead -> Distance a ray must travel before it becomes active + !! pop -> Number of rays to track per cycle + !! inactive -> Number of inactive cycles to perform + !! active -> Number of active cycles to perform + !! cache -> Logical check whether to use distance caching + !! outputFile -> Output file name + !! outputFormat-> Output file format + !! plotResults -> Plot results? + !! viz -> Output visualiser + !! mapFission -> Output fission rates across a given map? + !! fissionMap -> The map across which to output fission rate results + !! mapFlux -> Output 1G flux across a given map? + !! fluxMap -> The map across which to output 1G flux results + !! + !! keff -> Estimated value of keff + !! keffScore -> Vector holding cumulative keff score and keff^2 score + !! + !! intersectionsTotal -> Total number of ray traces for the calculation + !! + !! Interface: + !! physicsPackage interface + !! + type, public, extends(physicsPackage) :: randomRayPhysicsPackage + private + ! Components + class(geometryStd), pointer :: geom + integer(shortInt) :: geomIdx = 0 + type(RNG) :: rand + type(arraysRR) :: arrays + type(dataRR) :: XSData + class(baseMgNeutronDatabase), pointer :: mgData => null() + integer(shortInt) :: nG = 0 + integer(shortInt) :: nCells = 0 + + ! Settings + real(defReal) :: termination = ZERO + real(defReal) :: dead = ZERO + integer(shortInt) :: pop = 0 + integer(shortInt) :: inactive = 0 + integer(shortInt) :: active = 0 + logical(defBool) :: cache = .false. + real(defReal) :: rho = ZERO + character(pathLen) :: outputFile + character(nameLen) :: outputFormat + logical(defBool) :: plotResults = .false. + logical(defBool) :: printFlux = .false. + logical(defBool) :: printVolume = .false. + logical(defBool) :: printCells = .false. + type(visualiser) :: viz + logical(defBool) :: mapFission = .false. + class(tallyMap), allocatable :: fissionMap + logical(defBool) :: mapFlux = .false. + class(tallyMap), allocatable :: fluxMap + + ! Results space + ! keffScore is public for integration testing + real(defReal) :: keff = ONE + real(defReal), dimension(2), public :: keffScore = ZERO + integer(longInt) :: intersectionsTotal = 0 + + ! Timer bins + integer(shortInt) :: timerMain + integer(shortInt) :: timerTransport + real (defReal) :: time_transport = ZERO + real (defReal) :: CPU_time_start + real (defReal) :: CPU_time_end + + contains + ! Superclass procedures + procedure :: init + procedure :: run + procedure :: kill + + ! Private procedures + procedure, private :: cycles + procedure, private :: printResults + procedure, private :: printSettings + + end type randomRayPhysicsPackage + +contains + + !! + !! Initialise Physics Package from dictionary + !! + !! See physicsPackage_inter for details + !! + subroutine init(self, dict, loud) + class(randomRayPhysicsPackage), intent(inout) :: self + class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud + integer(shortInt) :: seed_temp, ani + logical(defBool) :: lin + integer(longInt) :: seed + character(10) :: time + character(8) :: date + character(:),allocatable :: string + class(dictionary),pointer :: tempDict, graphDict + class(mgNeutronDatabase),pointer :: db + character(nameLen) :: geomName, graphType, nucData + class(geometry), pointer :: geom + type(outputFile) :: test_out + character(100), parameter :: Here = 'init (randomRayPhysicsPackage_class.f90)' + + call cpu_time(self % CPU_time_start) + + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + + ! Load settings + call dict % get( nucData, 'XSdata') + call dict % get(self % termination, 'termination') + call dict % get(self % dead, 'dead') + call dict % get(self % pop, 'pop') + call dict % get(self % active, 'active') + call dict % get(self % inactive, 'inactive') + call dict % getOrDefault(self % keff, 'keff', ONE) + + ! Perform distance caching? + call dict % getOrDefault(self % cache, 'cache', .false.) + + ! Stabilisation factor for negative in-group scattering + call dict % getOrDefault(self % rho, 'rho', ZERO) + + ! Use linear sources? + call dict % getOrDefault(lin, 'lin', .false.) + + ! Use anisotropic scattering? + call dict % getOrDefault(ani, 'ani', 0) + + ! Read outputfile path + 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) + call dict % getOrDefault(self % outputFormat, 'outputFormat', 'asciiMATLAB') + call test_out % init(self % outputFormat) + + ! Check settings + if (self % termination <= ZERO) call fatalError(Here, & + 'Ray termination distance (termination) is less than or equal to zero.') + if (self % pop < 1) call fatalError(Here, 'Must have 1 or more rays (pop).') + if (self % dead < ZERO) call fatalError(Here, 'Dead length must be positive.') + if (self % termination <= self % dead) call fatalError(Here,& + 'Ray termination length must be greater than ray dead length') + if (ani < 0 .or. ani > 3) call fatalError(Here, 'Anisotropy order must be between 0 and 3') + + ! Check whether there is a map for outputting fission rates + ! If so, read and initialise the map to be used + if (dict % isPresent('fissionMap')) then + self % mapFission = .true. + tempDict => dict % getDictPtr('fissionMap') + call new_tallyMap(self % fissionMap, tempDict) + else + self % mapFission = .false. + end if + + ! Check whether there is a map for outputting one-group fluxes + ! If so, read and initialise the map to be used + if (dict % isPresent('fluxMap')) then + self % mapFlux = .true. + tempDict => dict % getDictPtr('fluxMap') + call new_tallyMap(self % fluxMap, tempDict) + else + self % mapFlux = .false. + end if + + ! Register timer + self % timerMain = registerTimer('simulationTime') + self % timerTransport = registerTimer('transportTime') + + ! Initialise RNG + if( dict % isPresent('seed')) then + call dict % get(seed_temp,'seed') + else + ! Obtain time string and hash it to obtain random seed + call date_and_time(date, time) + string = date // time + call FNV_1(string,seed_temp) + end if + seed = seed_temp + call self % rand % init(seed) + + ! Build Nuclear Data + call ndReg_init(dict % getDictPtr("nuclearData")) + + ! Build geometry + tempDict => dict % getDictPtr('geometry') + geomName = 'randomRayGeom' + call new_geometry(tempDict, geomName, silent = .not. self % loud) + self % geomIdx = gr_geomIdx(geomName) + geom => gr_geomPtr(self % geomIdx) + + ! Ensure geometry is geometryStd + select type(geom) + type is (geometryStd) + self % geom => geom + class default + call fatalError(Here,'Unrecognised geometry type') + end select + + ! Ensure that geometry graph is extended + graphDict => tempDict % getDictPtr('graph') + call graphDict % get(graphType,'type') + if (graphType /= 'extended') call fatalError(Here,& + 'Geometry graph type must be "extended" for random ray calculations.') + + ! Activatee nuclear data + call ndReg_activate(P_NEUTRON_MG, nucData, self % geom % activeMats(), silent = .not. self % loud) + + ! Ensure that nuclear data is multi-group + db => ndReg_getNeutronMG() + if (.not. associated(db)) call fatalError(Here,& + 'No MG nuclear database was constructed') + + ! Ensure nuclear data is baseMgNeutronDatabase + select type(db) + type is (baseMgNeutronDatabase) + self % mgData => db + class default + call fatalError(Here,'Unrecognised MG database type') + end select + + ! Store number of energy groups for convenience + self % nG = self % mgData % nGroups() + + ! Call visualisation + if (dict % isPresent('viz')) then + if (self % loud) print *, "Initialising visualiser" + tempDict => dict % getDictPtr('viz') + call self % viz % init(geom, tempDict) + if (self % loud) print *, "Constructing visualisation" + call self % viz % makeViz() + call self % viz % kill() + endif + + ! Check for results plotting and initialise VTK + call dict % getOrDefault(self % plotResults,'plot',.false.) + if (self % plotResults) then + ! Initialise a visualiser to be used when results are available + if (self % loud) print *, "Initialising results visualiser" + tempDict => dict % getDictPtr('viz') + call self % viz % init(geom, tempDict) + if (self % loud) print *, "Constructing geometry visualisation" + call self % viz % initVTK() + end if + + ! Store number of cells in geometry for convenience + self % nCells = self % geom % numberOfCells() + + ! Initialise RR arrays and nuclear data + call self % arrays % init(self % mgData, self % geom, & + self % pop * (self % termination - self % dead), self % rho, lin, ani, .false., self % loud) + + end subroutine init + + !! + !! Run calculation + !! + !! See physicsPackage_inter for details + !! + subroutine run(self) + class(randomRayPhysicsPackage), intent(inout) :: self + + if (self % loud) call self % printSettings() + call self % cycles() + call self % printResults() + + end subroutine run + + !! + !! Perform cycles of The Random Ray Method. + !! + !! Randomly places the ray starting point and direction uniformly. + !! Rays are tracked until they reach some specified termination length. + !! During tracking, fluxes are attenuated (and adjusted according to BCs), + !! scoring to fluxes and volume estimates when the ray has surpassed its + !! specified dead length. + !! + !! Inactive and active iterations occur, terminating subject either to + !! given criteria or when a fixed number of iterations has been passed. + !! + subroutine cycles(self) + class(randomRayPhysicsPackage), target, intent(inout) :: self + type(ray), save :: r + type(RNG), target, save :: pRNG + real(defReal) :: hitRate + real(defReal) :: ONE_KEFF, elapsed_T, end_T, T_toEnd, transport_T, & + N1, Nm1 + logical(defBool) :: keepRunning, isActive + integer(shortInt) :: i, itInac, itAct, it + integer(longInt), save :: ints + integer(longInt) :: intersections + class(arraysRR), pointer :: arrayPtr + !$omp threadprivate(pRNG, r, ints) + + ! Reset and start timer + call timerReset(self % timerMain) + call timerStart(self % timerMain) + + arrayPtr => self % arrays + + ! Stopping criterion is on number of convergence iterations. + ! TODO: Make this on, e.g., entropy during inactive, followed by stochastic noise during active! + itInac = 0 + itAct = 0 + isActive = .false. + keepRunning = .true. + + ! Power iteration + do while( keepRunning ) + + if (isActive) then + itAct = itAct + 1 + else + itInac = itInac + 1 + end if + it = itInac + itAct + + ONE_KEFF = ONE / self % keff + call arrayPtr % updateSource(ONE_KEFF) + + ! Reset and start transport timer + call timerReset(self % timerTransport) + call timerStart(self % timerTransport) + intersections = 0 + + !$omp parallel do schedule(dynamic) reduction(+:intersections) + do i = 1, self % pop + + ! Set seed + pRNG = self % rand + call pRNG % stride(i) + r % pRNG => pRNG + + ! Set ray attributes + call initialiseRay(r, arrayPtr) + + ! Transport ray until termination criterion met + call transportSweep(r, ints, self % nG, self % cache, self % dead, & + self % termination, arrayPtr) + intersections = intersections + ints + + end do + !$omp end parallel do + + self % intersectionsTotal = self % intersectionsTotal + intersections + + call timerStop(self % timerTransport) + + ! Update RNG on master thread + call self % rand % stride(self % pop + 1) + + ! Normalise flux estimate and combines with source + call arrayPtr % normaliseFluxAndVolume(it) + + ! Calculate new k and accumulate stats + self % keff = arrayPtr % calculateKeff(self % keff) + if (isActive) then + self % keffScore(1) = self % keffScore(1) + self % keff + self % keffScore(2) = self % keffScore(2) + self % keff * self % keff + end if + + ! Accumulate flux scores + if (isActive) call arrayPtr % accumulateFluxScores() + + ! Calculate proportion of cells that were hit + hitRate = arrayPtr % getCellHitRate() + call arrayPtr % wipeCellHits() + + ! Evaluate stopping criterion for active or inactive iterations + if (isActive) then + keepRunning = (itAct < self % active) + else + isActive = (itInac >= self % inactive) + end if + + ! Set previous iteration flux to scalar flux + ! and zero scalar flux + call arrayPtr % resetFluxes() + + ! Calculate times + call timerStop(self % timerMain) + elapsed_T = timerTime(self % timerMain) + transport_T = timerTime(self % timerTransport) + self % time_transport = self % time_transport + transport_T + + ! Predict time to end + end_T = real(self % active + self % inactive, defReal) * elapsed_T / it + T_toEnd = max(ZERO, end_T - elapsed_T) + + ! Display progress + if (self % loud) then + call printFishLineR(it) + print * + print *, 'Iteration: ', numToChar(it), ' of ', numToChar(self % active + self % inactive) + if(isActive) then + print *,'Active iterations' + else + print *,'Inactive iterations' + end if + print *, 'Cell hit rate: ', trim(numToChar(real(hitRate,defReal))) + print *, 'keff: ', trim(numToChar(real(self % keff,defReal))) + print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) + print *, 'End time: ', trim(secToChar(end_T)) + print *, 'Time to end: ', trim(secToChar(T_toEnd)) + print *, 'Time per integration (ns): ', & + trim(numToChar(transport_T*10**9/(self % nG * intersections))) + end if + + end do + + ! Finalise flux and keff scores + call arrayPtr % finaliseFluxScores(itAct) + if (itAct /= 1) then + Nm1 = 1.0_defReal/(itAct - 1) + else + Nm1 = 1.0_defReal + end if + N1 = 1.0_defReal/itAct + self % keffScore(1) = self % keffScore(1) * N1 + self % keffScore(2) = self % keffScore(2) * N1 + self % keffScore(2) = sqrt(Nm1*(self % keffScore(2) - & + self % keffScore(1) * self % keffScore(1))) + + end subroutine cycles + + !! + !! Output calculation results to a file + !! + !! Args: + !! None + !! + subroutine printResults(self) + class(randomRayPhysicsPackage), target, intent(inout) :: self + type(outputFile), target :: out + character(nameLen) :: name + class(outputFile), pointer :: outPtr + class(visualiser), pointer :: vizPtr + + call out % init(self % outputFormat, filename = self % outputFile) + + name = 'seed' + call out % printValue(self % rand % getSeed(),name) + + name = 'pop' + call out % printValue(self % pop,name) + + name = 'Inactive_Cycles' + call out % printValue(self % inactive,name) + + name = 'Active_Cycles' + call out % printValue(self % active,name) + + call cpu_time(self % CPU_time_end) + name = 'Total_CPU_Time' + call out % printValue((self % CPU_time_end - self % CPU_time_start),name) + + name = 'Total_Transport_Time' + call out % printValue(self % time_transport,name) + + name = 'Time_Per_Integration' + call out % printValue(self % time_transport/(self % intersectionsTotal * self % nG),name) + + name = 'Clock_Time' + call out % printValue(timerTime(self % timerMain),name) + + ! Print keff + name = 'keff' + call out % startBlock(name) + call out % printResult(self % keffScore(1), self % keffScore(2), name) + call out % endBlock() + + outPtr => out + ! Send fission rates to map output + if (self % mapFission) call self % arrays % outputMap(outPtr, self % fissionMap, .true.) + + ! Send fluxes to map output + if (self % mapFlux) call self % arrays % outputMap(outPtr, self % fluxMap, .false.) + outPtr => null() + + ! Send all fluxes and SDs to VTK + vizPtr => self % viz + if (self % plotResults) call self % arrays % outputToVTK(vizPtr) + + end subroutine printResults + + !! + !! Print settings of the random ray calculation + !! + !! Args: + !! None + !! + subroutine printSettings(self) + class(randomRayPhysicsPackage), intent(in) :: self + + print *, repeat("<>", MAX_COL/2) + print *, "/\/\ RANDOM RAY EIGENVALUE CALCULATION /\/\" + print *, "Using "//numToChar(self % inactive)// " iterations for "& + //"the inactive cycles" + print *, "Using "//numToChar(self % active)// " iterations for "& + //"the active cycles" + print * + print *, "Rays per cycle: "// numToChar(self % pop) + print *, "Ray dead length: "//numToChar(self % dead) + print *, "Ray termination length: "//numToChar(self % termination) + print *, "Initial RNG Seed: "// numToChar(self % rand % getSeed()) + print * + print *, "Number of cells in the geometry: "// numToChar(self % nCells) + print *, "Number of energy groups: "// numToChar(self % nG) + if (self % cache) print *, "Accelerated with distance caching" + print *, repeat("<>", MAX_COL/2) + + end subroutine printSettings + + !! + !! Return to uninitialised state + !! + subroutine kill(self) + class(randomRayPhysicsPackage), intent(inout) :: self + + ! Clean Nuclear Data, Geometry and visualisation + call ndreg_kill() + call self % viz % kill() + + ! Clean contents + self % geom => null() + self % geomIdx = 0 + self % timerMain = 0 + self % timerTransport = 0 + self % mgData => null() + self % nG = 0 + self % nCells = 0 + self % termination = ZERO + self % dead = ZERO + self % pop = 0 + self % inactive = 0 + self % active = 0 + self % cache = .false. + self % mapFission = .false. + self % mapFlux = .false. + self % plotResults = .false. + self % keff = ONE + self % keffScore = ZERO + call self % arrays % kill() + call self % XSData % kill() + if(allocated(self % fissionMap)) then + call self % fissionMap % kill() + deallocate(self % fissionMap) + end if + if(allocated(self % fluxMap)) then + call self % fluxMap % kill() + deallocate(self % fluxMap) + end if + + end subroutine kill + +end module randomRayPhysicsPackage_class diff --git a/PhysicsPackages/rayVolPhysicsPackage_class.f90 b/PhysicsPackages/rayVolPhysicsPackage_class.f90 index 26c7560d8..a2419e349 100644 --- a/PhysicsPackages/rayVolPhysicsPackage_class.f90 +++ b/PhysicsPackages/rayVolPhysicsPackage_class.f90 @@ -126,9 +126,10 @@ module rayVolPhysicsPackage_class !! !! See physicsPackage_inter for details !! - subroutine init(self,dict) + subroutine init(self,dict,loud) class(rayVolPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud integer(shortInt) :: seed_temp integer(longInt) :: seed character(10) :: time @@ -138,6 +139,12 @@ subroutine init(self,dict) character(nameLen) :: geomName character(100), parameter :: Here = 'init (rayVolPhysicsPackage_class.f90)' + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + ! Load settings call dict % get(self % mfp, 'mfp') call dict % get(self % abs_prob, 'abs_prob') @@ -198,9 +205,9 @@ end subroutine init subroutine run(self) class(rayVolPhysicsPackage), intent(inout) :: self - call self % printSettings() + if (self % loud) call self % printSettings() call self % cycles(self % rand) - call self % printResults() + if (self % loud) call self % printResults() end subroutine run @@ -295,14 +302,16 @@ subroutine cycles(self, rand) av_speed = self % totDist / cycle_T * 1.0E-3_defReal ! Display progress - call printFishLineR(gen) - print * - print *, 'Cycle: ', numToChar(gen), ' of ', numToChar(self % N_cycles) - print *, 'Pop: ', numToChar(self % pop) - print '(A, ES12.5)', ' Av. Ray speed: [m/s]: ', av_speed - print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) - print *, 'End time: ', trim(secToChar(end_T)) - print *, 'Time to end: ', trim(secToChar(T_toEnd)) + if (self % loud) then + call printFishLineR(gen) + print * + print *, 'Cycle: ', numToChar(gen), ' of ', numToChar(self % N_cycles) + print *, 'Pop: ', numToChar(self % pop) + print '(A, ES12.5)', ' Av. Ray speed: [m/s]: ', av_speed + print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) + print *, 'End time: ', trim(secToChar(end_T)) + print *, 'Time to end: ', trim(secToChar(T_toEnd)) + end if ! Process scores self % res(:, SCORE) = self % res(:, SCORE) / self % totDist diff --git a/PhysicsPackages/vizPhysicsPackage_class.f90 b/PhysicsPackages/vizPhysicsPackage_class.f90 index 13acb7d68..21ae36bca 100644 --- a/PhysicsPackages/vizPhysicsPackage_class.f90 +++ b/PhysicsPackages/vizPhysicsPackage_class.f90 @@ -57,7 +57,7 @@ module vizPhysicsPackage_class subroutine run(self) class(vizPhysicsPackage), intent(inout) :: self - print *, "Constructing visualisation" + if (self % loud) print *, "Constructing visualisation" call self % viz % makeViz() call self % viz % kill() @@ -66,14 +66,21 @@ subroutine run(self) !! !! Initialise from individual components and dictionaries !! - subroutine init(self, dict) + subroutine init(self, dict, loud) class(vizPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud class(dictionary),pointer :: tempDict class(geometry), pointer :: geom character(nameLen) :: geomName character(100), parameter :: Here ='init (vizPhysicsPackage_class.f90)' + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + ! Register timer self % timerMain = registerTimer('transportTime') @@ -83,13 +90,13 @@ subroutine init(self, dict) ! Build geometry tempDict => dict % getDictPtr('geometry') geomName = 'visualGeom' - call new_geometry(tempDict, geomName) + call new_geometry(tempDict, geomName, .not. self % loud) self % geomIdx = gr_geomIdx(geomName) self % geom => gr_geomPtr(self % geomIdx) ! Call visualisation if (dict % isPresent('viz')) then - print *, "Initialising visualiser" + if (self % loud) print *, "Initialising visualiser" tempDict => dict % getDictPtr('viz') geom => self % geom call self % viz % init(geom, tempDict) diff --git a/RandomRayObjects/CMakeLists.txt b/RandomRayObjects/CMakeLists.txt new file mode 100644 index 000000000..5c5ced04e --- /dev/null +++ b/RandomRayObjects/CMakeLists.txt @@ -0,0 +1,8 @@ + +# Add Source Files to the global list +add_sources( ./arraysRR_class.f90 + ./rayHandling_func.f90 + ./dataRR_class.f90 + ./mathsRR_func.f90 + ./constantsRR.f90 + ) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 new file mode 100644 index 000000000..33f19da66 --- /dev/null +++ b/RandomRayObjects/arraysRR_class.f90 @@ -0,0 +1,1213 @@ +module arraysRR_class + + use numPrecision + use universalVariables + use constantsRR + use genericProcedures, only : fatalError, numToChar, rotateVector, printFishLineR + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + + ! Data + use baseMgNeutronDatabase_class, only : baseMgNeutronDatabase + use dataRR_class, only : dataRR + + ! Geometry + use coord_class, only : coordList + use geometryStd_class, only : geometryStd + + ! Visualisation + use tallyMap_inter, only : tallyMap + use visualiser_class, only : visualiser + use particle_class, only : particleState + + ! For locks + use omp_lib + + implicit none + private + + + !! + !! Object to store all arrays in random ray + !! By default, will have the current flux, previous flux, accumulated flux, + !! source arrays, and geometric arrays. + !! + !! Can be extended to having corresponding flux and source moments, as well + !! as the fixed source and additional geometric info. + !! + !! Private Members + !! nG -> Number of energy groups, kept for convenience. + !! nCells -> Number of unique cells in the geometry, kept for convenience. + !! lengthPerIt -> RR active length per iteration, kept for convenience + !! XSData -> Pointer to nuclear data, for convenience. + !! geom -> Pointer to geometry, for convenience. + !! rho -> Stabilisation factor: 0 is no stabilisation, 1 is aggressive stabilisation + !! ani -> Order of anisotropic flux moments to be stored + !! simulationType -> Identifies which simulation to perform: flat/linear, isotropic/anisotropic + !! + !! scalarFlux -> Array of scalar flux values of length [nG * nCells] + !! prevFlux -> Array of previous scalar flux values of length [nG * nCells] + !! fluxScores -> Array of scalar flux values and squared values to be reported + !! in results [nG * nCells, 2] + !! + !! source -> Array of sources [nG * nCells] + !! fixedSource -> Array of fixed sources [nG * nCells] + !! sourceIdx -> Array of material indices containing fixed sources + !! + !! volumeTracks -> Array of sum of track lengths for computing volumes [nCells] + !! lengthSquared -> Array of sum of lengths^2 for use in cells with zero XS [nCells] + !! volume -> Array of dimensionless cell volumes [nCells] + !! + !! cellHit -> Array of ints whether a cell was visited this iteration [nCells] + !! cellFound -> Array of logicals whether a cell was ever visited [nCells] + !! cellPos -> Array of cell positions [3 * nCells] + !! + !! locks -> Array of OpenMP locks for each geometric cell + !! + type, public :: arraysRR + private + ! Components + class(geometryStd), pointer :: geom => null() + type(dataRR) :: XSData + integer(shortInt) :: nG = 0 + integer(shortInt) :: nCells = 0 + real(defReal) :: lengthPerIt = ZERO + real(defFlt) :: rho = 0.0_defFlt + integer(shortInt) :: ani = 0 + integer(shortInt) :: simulationType = 0 + + ! Flux arrays + real(defFlt), dimension(:), allocatable :: scalarFlux + real(defFlt), dimension(:), allocatable :: prevFlux + real(defReal), dimension(:,:), allocatable :: fluxScores + + ! Source arrays + real(defFlt), dimension(:), allocatable :: source + real(defFlt), dimension(:), allocatable :: fixedSource + integer(shortInt), dimension(:), allocatable :: sourceIdx + + ! Geometry arrays + real(defReal), dimension(:), allocatable :: volumeTracks + real(defReal), dimension(:), allocatable :: lengthSquared + real(defReal), dimension(:), allocatable :: volume + integer(shortInt), dimension(:), allocatable :: cellHit + logical(defBool), dimension(:), allocatable :: cellFound + real(defReal), dimension(:,:), allocatable :: cellPos + + ! OMP locks + integer(kind=omp_lock_kind), dimension(:), allocatable :: locks + + contains + + ! Public procedures + procedure :: init + procedure :: kill + + ! Access procedures + procedure :: getDataPointer + procedure :: getGeomPointer + procedure :: getSourcePointer + procedure :: getFluxPointer + procedure :: getSource + procedure :: getPrevFlux + procedure :: getFluxScore + procedure :: getFluxSD + procedure :: getNG + procedure :: getCellPos + procedure :: hasHit + procedure :: getCellHitRate + procedure :: getSimulationType + procedure :: found + + ! Change individual elements of the type + ! Predominantly for use in the transport sweep + procedure :: incrementVolume + procedure :: incrementLengthSquared + procedure :: hitCell + procedure :: wipeCellHits + procedure :: newFound + procedure :: setLock + procedure :: unsetLock + + ! Basic RR procedures + procedure :: resetFluxes + procedure :: normaliseFluxAndVolume + procedure :: updateSource + procedure :: accumulateFluxScores + procedure :: finaliseFluxScores + procedure :: calculateKeff + + ! Output procedures + procedure :: outputMap + procedure :: outputToVTK + + ! Private procedures + procedure, private :: initialiseFixedSource + + procedure, private :: resetFluxesFlatIso + procedure, private :: resetFluxesLinIso + procedure, private :: resetFluxesLIFA + procedure, private :: resetFluxesFlatAni + + procedure, private :: normaliseFluxAndVolumeFlatIso + procedure, private :: normaliseFluxAndVolumeLinIso + procedure, private :: normaliseFluxAndVolumeLIFA + procedure, private :: normaliseFluxAndVolumeFlatAni + + procedure, private :: sourceUpdateKernelFlatIso + procedure, private :: sourceUpdateKernelLinIso + procedure, private :: sourceUpdateKernelLIFA + procedure, private :: sourceUpdateKernelFlatAni + + procedure, private :: calculateKeffKernel + + end type arraysRR + +contains + + !! + !! Initialise the arrays object + !! + !! The object is fed sizes and requirements by the physics package. + !! This will allocate the necessary arrays + !! + subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, dictFS) + class(arraysRR), intent(inout) :: self + class(baseMgNeutronDatabase), pointer, intent(in) :: db + class(geometryStd), pointer, intent(in) :: geom + real(defReal), intent(in) :: lengthPerIt + real(defReal), intent(in) :: rho + logical(defBool), intent(in) :: lin + integer(shortInt), intent(in) :: ani + logical(defBool), intent(in) :: doKinetics + logical(defBool), intent(in) :: loud + class(dictionary), pointer, intent(inout), optional :: dictFS + integer(shortInt) :: i + character(100), parameter :: Here = 'init (arraysRR_class.f90)' + + call self % XSData % init(db, doKinetics, ani, loud) + self % nG = self % XSdata % getNG() + self % geom => geom + self % nCells = self % geom % numberOfCells() + + self % lengthPerIt = lengthPerIt + self % rho = real(rho, defFlt) + + ! Set simulation type + if (.not. lin .and. ani == 0) then + self % simulationType = flatIso + elseif (lin .and. ani == 0) then + self % simulationType = linearIso + elseif (.not. lin .and. ani > 0) then + self % simulationType = flatAni + else + self % simulationType = linearAni + end if + if (ani >= 0) self % ani = ani + + ! Allocate and initialise arrays + allocate(self % scalarFlux(self % nG * self % nCells)) + allocate(self % prevFlux(self % nG * self % nCells)) + allocate(self % fluxScores(2, self % nG * self % nCells)) + allocate(self % source(self % nG * self % nCells)) + allocate(self % volumeTracks(self % nCells)) + allocate(self % lengthSquared(self % nCells)) + allocate(self % volume(self % nCells)) + allocate(self % cellHit(self % nCells)) + allocate(self % cellFound(self % nCells)) + allocate(self % cellPos(3, self % nCells)) + + self % scalarFlux = 0.0_defFlt + self % prevFlux = 1.0_defFlt + self % fluxScores = ZERO + self % source = 0.0_defFlt + self % volumeTracks = ZERO + self % lengthSquared = ZERO + self % volume = ZERO + self % cellHit = 0 + self % cellFound = .false. + self % cellPos = -INFINITY + + ! Initialise the fixed source if present + if (present(dictFS)) then + allocate(self % fixedSource(self % nG * self % nCells)) + call self % initialiseFixedSource(dictFS) + end if + + ! TODO: allocate linear and anisotropic components, if present + if (lin) then + + end if + + if (ani > 0) then + + end if + + ! Initialise OMP locks + allocate(self % locks(self % nCells)) + do i = 1, self % nCells + call OMP_init_lock(self % locks(i)) + end do + + end subroutine init + + !! + !! Initialises fixed sources to be used in the simulation. + !! Takes a dictionary containing names of materials in the geometry and + !! source strengths in each energy group and places these in the appropriate + !! elements of the fixed source vector. + !! + !! Also sets source material identities for future use with uncollided calculations. + !! + subroutine initialiseFixedSource(self, dict) + class(arraysRR), intent(inout) :: self + class(dictionary), intent(inout) :: dict + character(nameLen),dimension(:), allocatable :: names + real(defReal), dimension(:), allocatable :: sourceStrength + integer(shortInt) :: i, nSource, cIdx + integer(shortInt), save :: g, matIdx, idx, id + logical(defBool) :: found + character(nameLen) :: sourceName + character(nameLen), save :: localName + character(100), parameter :: Here = 'initialiseFixedSource (arraysRR_class.f90)' + !$omp threadprivate(matIdx, localName, idx, g, id) + + call dict % keys(names) + + nSource = size(names) + + ! Use for uncollided flux sampling + allocate(self % sourceIdx(nSource)) + + ! Cycle through entries of the dictionary + do i = 1, nSource + + sourceName = names(i) + call dict % get(sourceStrength, sourceName) + + ! Ensure correct number of energy groups + if (size(sourceStrength) /= self % nG) call fatalError(Here,'Source '//sourceName//& + ' has '//numToChar(size(sourceStrength))//' groups rather than '//numToChar(self % nG)) + + ! Make sure that the source corresponds to a material present in the geometry + found = .false. + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + + id = cIdx + matIdx = self % geom % geom % graph % getMatFromUID(id) + localName = self % XSData % getName(matIdx) + + if (localName == sourceName) then + + if (.not. found) then + !$omp critical + self % sourceIdx(i) = matIdx + !$omp end critical + end if + + found = .true. + do g = 1, self % nG + idx = (cIdx - 1) * self % nG + g + self % fixedSource(idx) = real(sourceStrength(g),defFlt) + end do + + end if + + end do + !$omp end parallel do + + if (.not. found) call fatalError(Here,'The source '//trim(sourceName)//' does not correspond to '//& + 'any material found in the geometry.') + + end do + + end subroutine initialiseFixedSource + + + !! + !! Return a pointer to the flux vector for a given cell + !! + subroutine getFluxPointer(self, cIdx, fluxVec) + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), dimension(:), pointer, intent(out) :: fluxVec + integer(shortInt) :: baseIdx1, baseIdx2 + + baseIdx1 = self % nG * (cIdx - 1) + 1 + baseIdx2 = self % nG * cIdx + fluxVec => self % scalarFlux(baseIdx1:baseIdx2) + + end subroutine getFluxPointer + + !! + !! Return a pointer to the nuclear data object + !! + function getDataPointer(self) result(dataPtr) + class(arraysRR), intent(in), target :: self + class(dataRR), pointer :: dataPtr + + dataPtr => self % XSData + + end function getDataPointer + + !! + !! Return a pointer to the geometry object + !! + function getGeomPointer(self) result(geomPtr) + class(arraysRR), intent(in), target :: self + class(geometryStd), pointer :: geomPtr + + geomPtr => self % geom + + end function getGeomPointer + + !! + !! Return a pointer to the source vector for a given cell + !! + subroutine getSourcePointer(self, cIdx, sourceVec) + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), dimension(:), pointer, intent(out) :: sourceVec + integer(shortInt) :: baseIdx1, baseIdx2 + + baseIdx1 = self % nG * (cIdx - 1) + 1 + baseIdx2 = self % nG * cIdx + sourceVec => self % source(baseIdx1:baseIdx2) + + end subroutine getSourcePointer + + !! + !! Return source value given cell and group + !! + function getSource(self, cIdx, g) result(src) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defFlt) :: src + + src = self % source(self % nG * (cIdx - 1) + g) + + end function getSource + + !! + !! Return previous flux value given cell and group + !! + function getPrevFlux(self, cIdx, g) result(flux) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defFlt) :: flux + + flux = self % prevFlux(self % nG * (cIdx - 1) + g) + + end function getPrevFlux + + !! + !! Return final flux value given cell and group + !! + function getFluxScore(self, cIdx, g) result(flux) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defReal) :: flux + + flux = self % fluxScores(1, self % nG * (cIdx - 1) + g) + + end function getFluxScore + + !! + !! Return final flux standard deviation given cell and group + !! Will return square of flux scores if called before finaliseFluxScores + !! + function getFluxSD(self, cIdx, g) result(flux) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defReal) :: flux + + flux = self % fluxScores(2, self % nG * (cIdx - 1) + g) + + end function getFluxSD + + !! + !! Return cell position given cell ID + !! + function getCellPos(self, cIdx, g) result(x) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defReal), dimension(3) :: x + + x = self % cellPos(1:3, cIdx) + + end function getCellPos + + !! + !! Return the simulation type + !! + function getSimulationType(self) result(simType) + class(arraysRR), intent(in) :: self + integer(shortInt) :: simType + + simType = self % simulationType + + end function getSimulationType + + !! + !! Increment the local volume estimate in cell cIdx. + !! Assumes this is being called inside a lock for thread privacy. + !! + subroutine incrementVolume(self, cIdx, length) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), intent(in) :: length + + self % volumeTracks(cIdx) = self % volumeTracks(cIdx) + length + + end subroutine incrementVolume + + !! + !! Increment the sum of length squared in cell cIdx. + !! Assumes this is being called inside a lock for thread privacy. + !! + subroutine incrementLengthSquared(self, cIdx, length) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), intent(in) :: length + + self % lengthSquared(cIdx) = self % lengthSquared(cIdx) + length * length + + end subroutine incrementLengthSquared + + + !! + !! Check if a cell has been hit + !! + elemental function hasHit(self, cIdx) result (hit) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt) :: hit + + hit = self % cellHit(cIdx) + + end function hasHit + + !! + !! Hit a cell + !! + subroutine hitCell(self, cIdx) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + + self % cellHit(cIdx) = 1 + + end subroutine hitCell + + !! + !! Return the cell hit rate for the given iteration + !! + function getCellHitRate(self) result(hitRate) + class(arraysRR), intent(in) :: self + integer(shortInt) :: totalHit + real(defReal) :: hitRate + + totalHit = sum(self % cellHit) + hitRate = real(totalHit, defReal) / self % nCells + + end function getCellHitRate + + !! + !! Wipe cell hits + !! + subroutine wipeCellHits(self) + class(arraysRR), intent(inout) :: self + + self % cellHit = 0 + + end subroutine wipeCellHits + + !! + !! Has a cell ever been found? + !! + function found(self, cIdx) result(wasFound) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + logical(defBool) :: wasFound + + wasFound = self % cellFound(cIdx) + + end function found + + !! + !! Note that a new cell has been found + !! + subroutine newFound(self, cIdx, r) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(3), intent(in) :: r + + !$omp critical + self % cellFound(cIdx) = .true. + self % cellPos(:,cIdx) = r + !$omp end critical + + end subroutine newFound + + !! + !! Return number of energy groups used + !! + function getNG(self) result(nG) + class(arraysRR), intent(in) :: self + integer(shortInt) :: nG + + nG = self % nG + + end function getNG + + !! + !! Set the OMP lock in a given cell + !! + subroutine setLock(self, cIdx) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + + call OMP_set_lock(self % locks(cIdx)) + + end subroutine setLock + + !! + !! Unset the OMP lock in a given cell + !! + subroutine unsetLock(self, cIdx) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + + call OMP_unset_lock(self % locks(cIdx)) + + end subroutine unsetLock + + !! + !! Calls appropriate normalise flux and volume subroutines + !! + subroutine normaliseFluxAndVolume(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + character(100), parameter :: Here = 'normaliseFluxAndVolume (arraysRR_class.f90)' + + select case(self % simulationType) + case(flatIso) + call self % normaliseFluxAndVolumeFlatIso(it) + case default + call fatalError(Here,'Unsupported simulation type requested') + end select + + end subroutine normaliseFluxAndVolume + + !! + !! Normalise flux and volume by total track length and increments + !! the flux by the neutron source + !! + subroutine normaliseFluxAndVolumeFlatIso(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + real(defReal) :: norm, normVol + real(defReal), save :: vol + real(defFlt), save :: sigGG, D, norm_V + real(defFlt), dimension(:), pointer, save :: total + integer(shortInt), save :: g, matIdx, idx + integer(shortInt) :: cIdx + !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D) + + norm = ONE / self % lengthPerIt + normVol = ONE / (self % lengthPerIt * it) + + !$omp parallel do + do cIdx = 1, self % nCells + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + + ! Update volume due to additional rays + self % volume(cIdx) = self % volumeTracks(cIdx) * normVol + vol = self % volume(cIdx) + + ! Save effort by skipping normalisation if volume is too small + if (vol < volume_tolerance) then + do g = 1, self % nG + idx = self % nG * (cIdx - 1) + g + self % scalarFlux(idx) = 0.0_defFlt + end do + cycle + end if + norm_V = real(norm / vol, defFlt) + + call self % XSData % getTotalPointer(matIdx, total) + + do g = 1, self % nG + + idx = self % nG * (cIdx - 1) + g + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V + + ! Apply the standard MoC post-sweep treatment and + ! stabilisation for negative XSs + if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + + self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) + + sigGG = self % XSData % getScatterXS(matIdx, g, g) + + ! Presumes non-zero total XS + if ((sigGG < 0) .and. (total(g) > 0)) then + D = -self % rho * sigGG / total(g) + else + D = 0.0_defFlt + end if + self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + + D * self % prevFlux(idx) ) / (1 + D) + + ! Alternatively, handle unidentified/void regions + else + self % scalarFlux(idx) = self % scalarFlux(idx) + & + real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + end if + end do + + end do + !$omp end parallel do + + end subroutine normaliseFluxAndVolumeFlatIso + + !! + !! Normalise flux and volume by total track length and increments + !! the flux by the neutron source for linear isotropic sources + !! + subroutine normaliseFluxAndVolumeLinIso(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + + end subroutine normaliseFluxAndVolumeLinIso + + !! + !! Normalise flux and volume by total track length and increments + !! the flux by the neutron source for flat anisotropic sources + !! + subroutine normaliseFluxAndVolumeFlatAni(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + + end subroutine normaliseFluxAndVolumeFlatAni + + !! + !! Normalise flux and volume by total track length and increments + !! the flux by the neutron source for Linear sources with flat + !! anisotropic sources + !! + subroutine normaliseFluxAndVolumeLIFA(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + + end subroutine normaliseFluxAndVolumeLIFA + + !! + !! Update all sources given a prevFlux + !! This nesting allows using combined OMP + SIMD + !! + subroutine updateSource(self, ONE_KEFF) + class(arraysRR), intent(inout) :: self + real(defReal), intent(in) :: ONE_KEFF + real(defFlt) :: ONE_K + integer(shortInt) :: cIdx + character(100), parameter :: Here = 'updateSource (arraysRR_class.f90)' + + ONE_K = real(ONE_KEFF, defFlt) + + select case(self % simulationType) + case(flatIso) + !$omp parallel do + do cIdx = 1, self % nCells + call self % sourceUpdateKernelFlatIso(cIdx, ONE_K) + end do + !$omp end parallel do + case default + call fatalError(Here,'Unsupported simulation type requested') + end select + + end subroutine updateSource + + !! + !! Kernel to update sources given a cell index + !! + subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) + class(arraysRR), target, intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(in) :: ONE_KEFF + real(defFlt) :: scatter, fission + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS, fluxVec + integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 + + ! Identify material + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + + ! Guard against void cells + if (matIdx > self % XSData % getNMat()) then + baseIdx = self % nG * (cIdx - 1) + do g = 1, self % nG + idx = baseIdx + g + self % source(idx) = 0.0_defFlt + end do + return + end if + + ! Obtain XSs + call self % XSData % getProdPointers(matIdx, nuFission, scatterXS, chi) + + baseIdx = self % nG * (cIdx - 1) + fluxVec => self % prevFlux((baseIdx + 1):(baseIdx + self % nG)) + + ! Calculate fission source + fission = 0.0_defFlt + !$omp simd reduction(+:fission) + do gIn = 1, self % nG + fission = fission + fluxVec(gIn) * nuFission(gIn) + end do + fission = fission * ONE_KEFF + + do g = 1, self % nG + + sIdx1 = self % nG * (g - 1) + 1 + sIdx2 = self % nG * g + associate(scatterVec => scatterXS(sIdx1:sIdx2)) + + ! Calculate scattering source + scatter = 0.0_defFlt + !$omp simd reduction(+:scatter) + do gIn = 1, self % nG + scatter = scatter + fluxVec(gIn) * scatterVec(gIn) + end do + + end associate + + ! Output index + idx = baseIdx + g + + self % source(idx) = chi(g) * fission + scatter + if (allocated(self % fixedSource)) then + self % source(idx) = self % source(idx) + self % fixedSource(idx) + end if + + end do + + end subroutine sourceUpdateKernelFlatIso + + !! + !! Kernel to update sources given a cell index for linear sources + !! with isotropic scattering + !! + subroutine sourceUpdateKernelLinIso(self, cIdx, ONE_KEFF) + class(arraysRR), target, intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(in) :: ONE_KEFF + + end subroutine sourceUpdateKernelLinIso + + !! + !! Kernel to update sources given a cell index for flat sources + !! with anisotropic scattering + !! + subroutine sourceUpdateKernelFlatAni(self, cIdx, ONE_KEFF) + class(arraysRR), target, intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(in) :: ONE_KEFF + + end subroutine sourceUpdateKernelFlatAni + + !! + !! Kernel to update sources given a cell index for linear sources + !! with flat anisotropic scattering + !! + subroutine sourceUpdateKernelLIFA(self, cIdx, ONE_KEFF) + class(arraysRR), target, intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(in) :: ONE_KEFF + + end subroutine sourceUpdateKernelLIFA + + + !! + !! Calculate keff + !! Wraps the main kernel call to allow for OMP + SIMD (thanks Fortran) + !! + function calculateKeff(self, k0) result(k1) + class(arraysRR), intent(in) :: self + real(defReal), intent(in) :: k0 + real(defReal) :: k1 + integer(shortInt) :: cIdx + real(defReal) :: fissTotal, prevFissTotal + real(defReal), save :: fissLocal, prevFissLocal + !$omp threadprivate (fissLocal, prevFissLocal) + + fissTotal = ZERO + prevFissTotal = ZERO + !$omp parallel do reduction(+:fissTotal, prevFissTotal) + do cIdx = 1, self % nCells + call self % calculateKeffKernel(cIdx, fissLocal, prevFissLocal) + fissTotal = fissTotal + fissLocal + prevFissTotal = prevFissTotal + prevFissLocal + end do + !$omp end parallel do + + k1 = k0 * fissTotal / prevFissTotal + + end function calculateKeff + + !! + !! Calculate keff for a single cell + !! + subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) + class(arraysRR), target, intent(in) :: self + integer(shortInt), intent (in) :: cIdx + real(defReal), intent(out) :: fissionRate, prevFissionRate + real(defReal) :: vol + integer(shortInt) :: g, matIdx + real(defFlt), dimension(:), pointer :: nuSigmaF, flux, prevFlux + + fissionRate = ZERO + prevFissionRate = ZERO + + ! Identify material + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + + ! Check whether to continue in this cell + if (matIdx > self % XSData % getNMat()) return + if (.not. self % XSData % isFissile(matIdx)) return + vol = self % volume(cIdx) + if (vol < volume_tolerance) return + + call self % XSData % getNuFissPointer(matIdx, nuSigmaF) + flux => self % scalarFlux((self % nG * (cIdx - 1) + 1):(self % nG * cIdx)) + prevFlux => self % prevFlux((self % nG * (cIdx - 1) + 1):(self % nG * cIdx)) + + !$omp simd reduction(+: fissionRate, prevFissionRate) + do g = 1, self % nG + fissionRate = fissionRate + real(flux(g) * nuSigmaF(g), defReal) + prevFissionRate = prevFissionRate + real(prevFlux(g) * nuSigmaF(g), defReal) + end do + + fissionRate = fissionRate * vol + prevFissionRate = prevFissionRate * vol + + end subroutine calculateKeffKernel + + !! + !! Reset fluxes + !! + subroutine resetFluxes(self) + class(arraysRR), intent(inout) :: self + character(100), parameter :: Here = 'resetFluxes (arraysRR_class.f90)' + + select case(self % simulationType) + case(flatIso) + call self % resetFluxesFlatIso() + case default + call fatalError(Here,'Unsupported simulation type requested') + end select + + end subroutine resetFluxes + + !! + !! Sets prevFlux to scalarFlux and zero's scalarFlux + !! + subroutine resetFluxesFlatIso(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: idx + + !$omp parallel do + do idx = 1, size(self % scalarFlux) + self % prevFlux(idx) = self % scalarFlux(idx) + self % scalarFlux(idx) = 0.0_defFlt + end do + !$omp end parallel do + + end subroutine resetFluxesFlatIso + + !! + !! Sets prevFlux to scalarFlux and zero's scalarFlux + !! for linear sources with isotropic scattering + !! + subroutine resetFluxesLinIso(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: idx + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + self % prevFlux(idx) = self % scalarFlux(idx) + self % scalarFlux(idx) = 0.0_defFlt + end do + !$omp end parallel do + + end subroutine resetFluxesLinIso + + !! + !! Sets prevFlux to scalarFlux and zero's scalarFlux + !! for flat sources with anisotropic scattering + !! + subroutine resetFluxesFlatAni(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: idx + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + self % prevFlux(idx) = self % scalarFlux(idx) + self % scalarFlux(idx) = 0.0_defFlt + end do + !$omp end parallel do + + end subroutine resetFluxesFlatAni + + !! + !! Sets prevFlux to scalarFlux and zero's scalarFlux + !! for linear sources with flat anisotropic scattering + !! + subroutine resetFluxesLIFA(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: idx + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + self % prevFlux(idx) = self % scalarFlux(idx) + self % scalarFlux(idx) = 0.0_defFlt + end do + !$omp end parallel do + + end subroutine resetFluxesLIFA + + + !! + !! Accumulate flux scores for stats + !! + subroutine accumulateFluxScores(self) + class(arraysRR), intent(inout) :: self + real(defReal), save :: flux + integer(shortInt) :: idx + !$omp threadprivate(flux) + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + flux = real(self % scalarFlux(idx),defReal) + self % fluxScores(1, idx) = self % fluxScores(1, idx) + flux + self % fluxScores(2, idx) = self % fluxScores(2, idx) + flux * flux + end do + !$omp end parallel do + + end subroutine accumulateFluxScores + + !! + !! Finalise flux scores for stats + !! + subroutine finaliseFluxScores(self,it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + integer(shortInt) :: idx + real(defReal) :: N1, Nm1 + + if (it /= 1) then + Nm1 = 1.0_defReal/(it - 1) + else + Nm1 = 1.0_defReal + end if + N1 = 1.0_defReal/it + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + self % fluxScores(1, idx) = self % fluxScores(1, idx) * N1 + self % fluxScores(2, idx) = self % fluxScores(2, idx) * N1 + self % fluxScores(2, idx) = Nm1 * (self % fluxScores(2, idx) - & + self % fluxScores(1, idx) * self % fluxScores(1, idx)) + if (self % fluxScores(2, idx) <= ZERO) then + self % fluxScores(2, idx) = ZERO + else + self % fluxScores(2, idx) = sqrt(self % fluxScores(2, idx)) + end if + end do + !$omp end parallel do + + end subroutine finaliseFluxScores + + !! + !! Outputs integral flux or fission rate when + !! given a tally map + !! + subroutine outputMap(self, out, map, doFission) + class(arraysRR), intent(in) :: self + class(outputFile), intent(inout) :: out + class(tallyMap), pointer, intent(in) :: map + logical(defBool), intent(in) :: doFission + character(nameLen) :: name + integer(shortInt) :: cIdx + integer(shortInt),dimension(:),allocatable :: resArrayShape + type(particleState), save :: s + real(defReal), save :: vol + real(defFlt), save :: sig + integer(shortInt), save :: i, matIdx, g + real(defReal), dimension(:), allocatable :: res, resSD + !$omp threadprivate(s, vol, sig, i, matIdx, g) + + resArrayShape = [map % binArrayShape()] + allocate(res(map % bins(0))) + allocate(resSD(map % bins(0))) + res = ZERO + resSD = ZERO + + ! Find whether cells are in map and sum their contributions + !$omp parallel do reduction(+: res, resSD) + do cIdx = 1, self % nCells + + vol = self % volume(cIdx) + if (vol < volume_tolerance) cycle + + ! Fudge a particle state to search tally map + s % r = self % cellPos(:,cIdx) + i = map % map(s) + + if (i > 0) then + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + do g = 1, self % nG + if (doFission) then + sig = self % XSData % getFissionXS(matIdx, g) + else + sig = 1.0_defFlt + end if + res(i) = res(i) + vol * self % getFluxScore(cIdx,g) * sig + ! Neglects uncertainty in volume - assumed small. + resSD(i) = resSD(i) + & + self % getFluxSD(cIdx,g)**2 * vol * vol * sig * sig + end do + end if + + end do + !$omp end parallel do + + do i = 1,size(resSD) + resSD(i) = sqrt(resSD(i)) + if (res(i) > 0) resSD(i) = resSD(i) / res(i) + end do + + if (doFission) then + name = 'fiss1G' + else + name = 'flux1G' + end if + call out % startBlock(name) + call out % startArray(name, resArrayShape) + ! Add all map elements to results + do i = 1, map % bins(0) + call out % addResult(res(i), resSD(i)) + end do + call out % endArray() + ! Output tally map + call map % print(out) + call out % endBlock() + + deallocate(res) + deallocate(resSD) + + end subroutine outputMap + + !! + !! Send all arrays of interest to VTK output + !! + subroutine outputToVTK(self, viz) + class(arraysRR), intent(in) :: self + class(visualiser), intent(inout) :: viz + real(defReal), dimension(:), allocatable :: resVec + character(nameLen) :: name + integer(shortInt) :: cIdx, g + + allocate(resVec(self % nCells)) + + ! Output all fluxes (assuming finalisation of scores happened) + do g = 1, self % nG + name = 'flux_g'//numToChar(g) + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = self % getFluxScore(cIdx,g) + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + end do + + ! Output all flux uncertainties + do g = 1, self % nG + name = 'std_g'//numToChar(g) + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = self % getFluxSD(cIdx,g) /self % getFluxScore(cIdx,g) + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + end do + + ! Output final iteration sources + do g = 1, self % nG + name = 'source_'//numToChar(g) + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = real(self % getSource(cIdx,g),defReal) + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + end do + + ! Output final volume estimates + ! TODO: scale to be absolute, not relative + name = 'volume' + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = self % volume(cIdx) + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + + call viz % finaliseVTK + + end subroutine outputToVTK + + !! + !! Return to uninitialised state + !! + subroutine kill(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: i + + ! Clean contents + if(allocated(self % scalarFlux)) deallocate(self % scalarFlux) + if(allocated(self % prevFlux)) deallocate(self % prevFlux) + if(allocated(self % fluxScores)) deallocate(self % fluxScores) + if(allocated(self % source)) deallocate(self % source) + if(allocated(self % fixedSource)) deallocate(self % fixedSource) + if(allocated(self % sourceIdx)) deallocate(self % sourceIdx) + if(allocated(self % volumeTracks)) deallocate(self % volumeTracks) + if(allocated(self % lengthSquared)) deallocate(self % lengthSquared) + if(allocated(self % volume)) deallocate(self % volume) + if(allocated(self % cellHit)) deallocate(self % cellHit) + if(allocated(self % cellFound)) deallocate(self % cellFound) + if(allocated(self % cellPos)) deallocate(self % cellPos) + + if(allocated(self % locks)) then + do i = 1, self % nCells + call OMP_destroy_lock(self % locks(i)) + end do + deallocate(self % locks) + end if + + self % geom => null() + call self % XSData % kill() + self % nG = 0 + self % nCells = 0 + self % lengthPerIt = ZERO + self % rho = 0.0_defFlt + self % simulationType = 0 + self % ani = 0 + + end subroutine kill + +end module arraysRR_class diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 new file mode 100644 index 000000000..3eaf242d9 --- /dev/null +++ b/RandomRayObjects/constantsRR.f90 @@ -0,0 +1,16 @@ +module constantsRR + + use numPrecision + + implicit none + + ! Parameter for when to skip a tiny volume + real(defReal), parameter, public :: volume_tolerance = 1.0E-12 + + ! Parameters to identify the simulation type + integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 + + +contains + +end module constantsRR diff --git a/RandomRayObjects/dataRR_class.f90 b/RandomRayObjects/dataRR_class.f90 new file mode 100644 index 000000000..7ec4ec101 --- /dev/null +++ b/RandomRayObjects/dataRR_class.f90 @@ -0,0 +1,472 @@ +module dataRR_class + + use numPrecision + use universalVariables + use rng_class, only : RNG + use genericProcedures, only : fatalError + + ! Nuclear Data + use materialMenu_mod, only : mm_nMat => nMat, mm_matName => matName + use materialHandle_inter, only : materialHandle + use baseMgNeutronDatabase_class, only : baseMgNeutronDatabase + use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial, baseMgNeutronMaterial_CptrCast + + implicit none + private + + !! + !! Nuclear data in a random ray-friendly format. + !! + !! Stores data and provides access in a manner which is more performant + !! than is done for MC MG data at present. + !! + !! TODO: Add kinetic data and higher-order scattering matrices + !! + type, public :: dataRR + private + ! Components + integer(shortInt) :: nG = 0 + integer(shortInt) :: nG2 = 0 + integer(shortInt) :: nMat = 0 + + ! Data space - absorb all nuclear data for speed + real(defFlt), dimension(:), allocatable :: sigmaT + real(defFlt), dimension(:), allocatable :: nuSigmaF + real(defFlt), dimension(:), allocatable :: sigmaF + real(defFlt), dimension(:), allocatable :: sigmaS + real(defFlt), dimension(:), allocatable :: chi + logical(defBool), dimension(:), allocatable :: fissile + character(nameLen), dimension(:), allocatable :: names + + ! Optional kinetic data + logical(defBool) :: doKinetics = .false. + integer(shortInt) :: nP = 0 + real(defFlt), dimension(:), allocatable :: chiD + real(defFlt), dimension(:), allocatable :: chiP + real(defFlt), dimension(:), allocatable :: beta + real(defFlt), dimension(:), allocatable :: invSpeed + + ! Optional higher-order scattering matrices up to P3 + real(defFlt), dimension(:), allocatable :: sigmaS1 + real(defFlt), dimension(:), allocatable :: sigmaS2 + real(defFlt), dimension(:), allocatable :: sigmaS3 + + contains + + procedure :: init + procedure :: kill + + ! TODO: add an XS update procedure, e.g., given multiphysics + ! TODO: add full handling of kinetic data + ! TODO: add full handling of higher-order anisotropy + + ! Access procedures + procedure :: getProdPointers + !procedure :: getAllPointers + procedure :: getTotalPointer + procedure :: getNuFissPointer + procedure :: getChiPointer + procedure :: getScatterPointer + procedure :: getScatterVecPointer + procedure :: getTotalXS + procedure :: getFissionXS + procedure :: getScatterXS + procedure :: getNG + procedure :: getNMat + procedure :: getNPrec + procedure :: getName + procedure :: isFissile + + ! Private procedures + procedure, private :: getIdxs + procedure, private :: getScatterIdxs + !procedure, private :: getKineticIdxs + + + end type dataRR + +contains + + !! + !! Initialise necessary nuclear data. + !! Can optionally include kinetic parameters. + !! + subroutine init(self, db, doKinetics, aniOrder, loud) + class(dataRR), intent(inout) :: self + class(baseMgNeutronDatabase),pointer, intent(in) :: db + logical(defBool), intent(in) :: doKinetics + integer(shortInt), intent(in) :: aniOrder + logical(defBool), intent(in) :: loud + integer(shortInt) :: g, g1, m, matP1 + type(RNG) :: rand + logical(defBool) :: fiss + class(baseMgNeutronMaterial), pointer :: mat + class(materialHandle), pointer :: matPtr + character(100), parameter :: Here = 'init (dataRR_class.f90)' + + self % doKinetics = doKinetics + + ! Store number of energy groups for convenience + self % nG = db % nGroups() + self % nG2 = self % nG * self % nG + + ! Initialise local nuclear data + ! Allocate nMat + 1 materials to catch any undefined materials + ! TODO: clean nuclear database afterwards! It is no longer used + ! and takes up memory. + self % nMat = mm_nMat() + matP1 = self % nMat + 1 + allocate(self % sigmaT(matP1 * self % nG)) + self % sigmaT = 0.0_defFlt + allocate(self % nuSigmaF(matP1 * self % nG)) + self % nuSigmaF = 0.0_defFlt + allocate(self % sigmaF(matP1 * self % nG)) + self % sigmaF = 0.0_defFlt + allocate(self % chi(matP1 * self % nG)) + self % chi = 0.0_defFlt + allocate(self % sigmaS(matP1 * self % nG * self % nG)) + self % sigmaS = 0.0_defFlt + allocate(self % fissile(matP1)) + self % fissile = .false. + allocate(self % names(matP1)) + self % names = 'unnamed' + + ! Create a dummy RNG to satisfy the mgDatabase access interface + call rand % init(1_longInt) + + if (loud) print *,'Initialising random ray nuclear data' + do m = 1, self % nMat + matPtr => db % getMaterial(m) + mat => baseMgNeutronMaterial_CptrCast(matPtr) + fiss = .false. + do g = 1, self % nG + self % sigmaT(self % nG * (m - 1) + g) = real(mat % getTotalXS(g, rand),defFlt) + self % nuSigmaF(self % nG * (m - 1) + g) = real(mat % getNuFissionXS(g, rand),defFlt) + self % sigmaF(self % nG * (m - 1) + g) = real(mat % getFissionXS(g, rand),defFlt) + if (self % nuSigmaF(self % nG * (m - 1) + g) > 0) fiss = .true. + self % chi(self % nG * (m - 1) + g) = real(mat % getChi(g, rand),defFlt) + ! Include scattering multiplicity + do g1 = 1, self % nG + self % sigmaS(self % nG * self % nG * (m - 1) + self % nG * (g - 1) + g1) = & + real(mat % getScatterXS(g1, g, rand) * mat % scatter % prod(g1, g) , defFlt) + end do + end do + self % fissile(m) = fiss + self % names(m) = mm_matName(m) + end do + + ! Initialise data necessary for kinetic/noise calculations + if (self % doKinetics) then + print *,'Including kinetic data' + call fatalError(Here,'Kinetic data not yet supported') + + end if + + ! Initialise higher-order scattering matrices + if (aniOrder > 0) then + print *,'Including anisotropic scattering data' + call fatalError(Here,'Anisotropy not yet supported') + + end if + + end subroutine init + + !! + !! Calculate the lower and upper indices for accessing the XS array + !! (excluding scattering and kinetic data) + !! + pure subroutine getIdxs(self, matIdx, idx1, idx2) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(out) :: idx1, idx2 + + idx1 = (matIdx - 1) * self % nG + 1 + idx2 = matIdx * self % nG + + end subroutine getIdxs + + !! + !! Calculate the lower and upper indices for accessing the scattering XS array + !! + pure subroutine getScatterIdxs(self, matIdx, idx1, idx2) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(out) :: idx1, idx2 + + idx1 = (matIdx - 1) * self % nG2 + 1 + idx2 = matIdx * self % nG2 + + end subroutine getScatterIdxs + + !! + !! Return if a material is fissile + !! + elemental function isFissile(self, matIdx) result(isFiss) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + logical(defBool) :: isFiss + integer(shortInt) :: mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + isFiss = self % fissile(mIdx) + + end function isFissile + + !! + !! Return the number of groups + !! + elemental function getNG(self) result(nG) + class(dataRR), intent(in) :: self + integer(shortInt) :: nG + + nG = self % nG + + end function getNG + + !! + !! Return the number of materials + !! + elemental function getNMat(self) result(nM) + class(dataRR), intent(in) :: self + integer(shortInt) :: nM + + nM = self % nMat + + end function getNMat + + !! + !! Return the number of precursors + !! + elemental function getNPrec(self) result(nP) + class(dataRR), intent(in) :: self + integer(shortInt) :: nP + + nP = self % nP + + end function getNPrec + + !! + !! Return the name of a given material + !! + elemental function getName(self, matIdx) result(matName) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + character(nameLen) :: matName + + matName = self % names(matIdx) + + end function getName + + + !! + !! Get scatter pointer + !! + subroutine getScatterPointer(self, matIdx, sigS) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defFlt), dimension(:), pointer, intent(out) :: sigS + integer(shortInt) :: idx1, idx2, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + call self % getScatterIdxs(mIdx, idx1, idx2) + sigS => self % sigmaS(idx1:idx2) + + end subroutine getScatterPointer + + !! + !! Get scatter vector pointer + !! + subroutine getScatterVecPointer(self, matIdx, gOut, sigS) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + integer(shortInt), intent(in) :: gOut + real(defFlt), dimension(:), pointer, intent(out) :: sigS + integer(shortInt) :: idx1, idx2, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + idx1 = (matIdx - 1) * self % nG2 + (gOut - 1) * self % nG + 1 + idx2 = (matIdx - 1) * self % nG2 + gOut * self % nG + sigS => self % sigmaS(idx1:idx2) + + end subroutine getScatterVecPointer + + + !! + !! Get chi pointer + !! + subroutine getChiPointer(self, matIdx, chi) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defFlt), dimension(:), pointer, intent(out) :: chi + integer(shortInt) :: idx1, idx2, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + call self % getIdxs(mIdx, idx1, idx2) + chi => self % chi(idx1:idx2) + + end subroutine getChiPointer + + !! + !! Return pointers to all commonly used XSs for neutron production + !! This is done for a given material, across all energies + !! + subroutine getProdPointers(self, matIdx, nuSigF, sigS, chi) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defFlt), dimension(:), pointer, intent(out) :: nuSigF, sigS, chi + integer(shortInt) :: idx1, idx2, idx1s, idx2s, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + call self % getIdxs(mIdx, idx1, idx2) + call self % getScatterIdxs(mIdx, idx1s, idx2s) + nuSigF => self % nuSigmaF(idx1:idx2) + chi => self % chi(idx1:idx2) + sigS => self % sigmaS(idx1s:idx2s) + + end subroutine getProdPointers + + !! + !! Return pointers to only the total XS + !! This is done for a given material, across all energies + !! + subroutine getTotalPointer(self, matIdx, sigT) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defFlt), dimension(:), pointer, intent(out) :: sigT + integer(shortInt) :: idx1, idx2, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + call self % getIdxs(mIdx, idx1, idx2) + sigT => self % sigmaT(idx1:idx2) + + end subroutine getTotalPointer + + !! + !! Return pointers to only the nuFission XS + !! This is done for a given material, across all energies + !! + subroutine getNuFissPointer(self, matIdx, nuFiss) + class(dataRR), target, intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defFlt), dimension(:), pointer, intent(out) :: nuFiss + integer(shortInt) :: idx1, idx2, mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + call self % getIdxs(mIdx, idx1, idx2) + nuFiss => self % nuSigmaF(idx1:idx2) + + end subroutine getNuFissPointer + + !! + !! Return total XS in a given material and group + !! + elemental function getTotalXS(self, matIdx, g) result(sigT) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx, g + real(defFlt) :: sigT + integer(shortInt) :: mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + sigT = self % sigmaT((mIdx - 1) * self % nG + g) + + end function getTotalXS + + !! + !! Return fission XS in a given material and group + !! + elemental function getFissionXS(self, matIdx, g) result(sigF) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx, g + real(defFlt) :: sigF + integer(shortInt) :: mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + sigF = self % sigmaF((mIdx - 1) * self % nG + g) + + end function getFissionXS + + !! + !! Return scatter XS in a given material, ingoing group, and outgoing group + !! + elemental function getScatterXS(self, matIdx, gIn, gOut) result(sigS) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx, gIn, gOut + real(defFlt) :: sigS + integer(shortInt) :: mIdx + + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + sigS = self % sigmaS((mIdx - 1) * self % nG2 + self % nG * (gIn - 1) + gOut) + + end function getScatterXS + + + !! + !! Return to uninitialised state + !! + subroutine kill(self) + class(dataRR), intent(inout) :: self + + ! Clean contents + self % nG = 0 + self % nG2 = 0 + self % nMat = 0 + self % nP = 0 + self % doKinetics = .false. + if(allocated(self % sigmaT)) deallocate(self % sigmaT) + if(allocated(self % sigmaS)) deallocate(self % sigmaS) + if(allocated(self % nuSigmaF)) deallocate(self % nuSigmaF) + if(allocated(self % sigmaF)) deallocate(self % sigmaF) + if(allocated(self % chi)) deallocate(self % chi) + if(allocated(self % fissile)) deallocate(self % fissile) + if(allocated(self % names)) deallocate(self % names) + if(allocated(self % chiD)) deallocate(self % chiD) + if(allocated(self % chiP)) deallocate(self % chiP) + if(allocated(self % beta)) deallocate(self % beta) + if(allocated(self % invSpeed)) deallocate(self % invSpeed) + if(allocated(self % sigmaS1)) deallocate(self % sigmaS1) + if(allocated(self % sigmaS2)) deallocate(self % sigmaS2) + if(allocated(self % sigmaS3)) deallocate(self % sigmaS3) + + end subroutine kill + +end module dataRR_class diff --git a/RandomRayObjects/mathsRR_func.f90 b/RandomRayObjects/mathsRR_func.f90 new file mode 100644 index 000000000..829805675 --- /dev/null +++ b/RandomRayObjects/mathsRR_func.f90 @@ -0,0 +1,71 @@ +module mathsRR_func + + !! + !! This module contains maths used in random ray. + !! First it has a function for efficiently computing an exponential + !! for use in MoC implementations using a rational approximation. + !! This is based on the implementation given in Minray: + !! github.com/jtramm/minray/blob/master/cpu_srce/flux_attenuation_kernel.c + !! I believe this originates from the M&C 2019 publication: + !! "Adding a third level of parallelism to OpenMOC" + !! + !! TODO: Add functions for efficient spherical harmonics evaluation. + !! + + use numPrecision + use genericProcedures, only : fatalError + + implicit none + private + + public :: F1 + + ! Numerator coefficients in rational approximation + real(defFlt), parameter :: c1n = -1.0000013559236386308, c2n = 0.23151368626911062025,& + c3n = -0.061481916409314966140, c4n = 0.0098619906458127653020, c5n = -0.0012629460503540849940, & + c6n = 0.00010360973791574984608, c7n = -0.000013276571933735820960 + + ! Denominator coefficients in rational approximation + real(defFlt), parameter :: c0d = ONE, c1d = -0.73151337729389001396, c2d = 0.26058381273536471371, & + c3d = -0.059892419041316836940, c4d = 0.0099070188241094279067, c5d = -0.0012623388962473160860, & + c6d = 0.00010361277635498731388, c7d = -0.000013276569500666698498 + +contains + + !! + !! Computes x = [1 - exp(-tau)]/tau for use in MoC calcs + !! Tau is the optical distance. + !! F1 is a common name in MoC literature + !! + elemental function F1(tau) result(x) + real(defFlt), intent(in) :: tau + real(defFlt) :: x + real(defFlt) :: den, num + + x = -tau + den = c7d + den = den * x + c6d + den = den * x + c5d + den = den * x + c4d + den = den * x + c3d + den = den * x + c2d + den = den * x + c1d + den = den * x + c0d + + num = c7n + num = num * x + c6n + num = num * x + c5n + num = num * x + c4n + num = num * x + c3n + num = num * x + c2n + num = num * x + c1n + ! Reintroduce this to give 1-exp(-tau) + !num = num * x + !x = num / den + + x = -num / den + + end function F1 + + +end module mathsRR_func diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 new file mode 100644 index 000000000..2a7048daa --- /dev/null +++ b/RandomRayObjects/rayHandling_func.f90 @@ -0,0 +1,345 @@ +module rayHandling_func + + use numPrecision + use universalVariables + use constantsRR + use genericProcedures, only : fatalError, numToChar, rotateVector + use dictionary_class, only : dictionary + use rng_class, only : RNG + + ! Geometry + use coord_class, only : coordList + use geometry_inter, only : distCache + use geometryStd_class, only : geometryStd + + ! Random ray modules + use arraysRR_class, only : arraysRR + use dataRR_class, only : dataRR + use mathsRR_func, only : F1 + + ! Random ray - or a standard particle + use particle_class, only : ray => particle + + implicit none + private + + !! + !! Set of functions and subroutines to handle everything to do with rays + !! in random ray + !! + !! TODO: add uncollided sweep and volume tracing + !! + public :: initialiseRay + public :: transportSweep + private :: moveRay + private :: checkRayLength + private :: transportSweepFlatIso + private :: transportSweepLinIso + private :: transportSweepLIFA + private :: transportSweepFlatAni + +contains + + subroutine initialiseRay(r, arrays) + type(ray), intent(inout) :: r + class(arraysRR), pointer, intent(in) :: arrays + class(geometryStd), pointer :: geom + real(defReal) :: mu, phi + real(defReal), dimension(6) :: b + real(defReal), dimension(3) :: lb, ub, u, rand3, x + integer(shortInt) :: i, matIdx, cIdx + character(100), parameter :: Here = 'initialiseRay (rayHandling_func.f90)' + + geom => arrays % getGeomPointer() + + i = 0 + mu = TWO * r % pRNG % get() - ONE + phi = TWO_PI * r % pRNG % get() + u = rotateVector([ONE, ZERO, ZERO], mu, phi) + + b = geom % bounds() + lb = b(1:3) + ub = b(4:6) + + rejection : do + rand3(1) = r % pRNG % get() + rand3(2) = r % pRNG % get() + rand3(3) = r % pRNG % get() + x = lb + (ub - lb) * rand3 + + ! Exit if point is inside the geometry + call geom % whatIsAt(matIdx, cIdx, x, u) + if (matIdx /= OUTSIDE_MAT) exit rejection + + i = i + 1 + if (i > 5000) then + call fatalError(Here, 'Infinite loop when searching for ray start in the geometry.') + end if + end do rejection + + ! Place in the geometry & process the ray + call r % build(x, u, 1, ONE) + call geom % placeCoord(r % coords) + + if (.not. arrays % found(cIdx)) call arrays % newFound(cIdx, x) + + end subroutine initialiseRay + + !! + !! Move ray across a cell, into the next + !! Use distance caching or standard ray tracing + !! Distance caching seems a little bit more unstable + !! due to FP error accumulation, but is faster. + !! This can be fixed by resetting the cache after X number + !! of distance calculations. + !! + subroutine moveRay(r, doCache, ints, geom, length, event, cache, hitVacuum) + type(ray), intent(inout) :: r + logical(defBool), intent(in) :: doCache + integer(longInt), intent(inout) :: ints + class(geometryStd), pointer, intent(in) :: geom + real(defReal), intent(inout) :: length + integer(shortInt), intent(out) :: event + type(distCache), intent(inout) :: cache + logical(defBool), intent(out) :: hitVacuum + + if (doCache) then + if (mod(ints,20_longInt) == 0) cache % lvl = 0 + call geom % moveRay_withCache(r % coords, length, event, cache, hitVacuum) + else + call geom % moveRay_noCache(r % coords, length, event, hitVacuum) + end if + ints = ints + 1 + + end subroutine moveRay + + !! + !! Set maximum flight distance and ensure ray is active + !! + subroutine checkRayLength(totalLength, dead, termination, activeRay, length) + real(defReal), intent(in) :: totalLength + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + logical(defBool), intent(inout) :: activeRay + real(defReal), intent(out) :: length + + if (totalLength >= dead) then + length = termination - totalLength + activeRay = .true. + else + length = dead - totalLength + end if + + end subroutine checkRayLength + + !! + !! Moves ray through geometry, updating angular flux and + !! scoring scalar flux and volume. + !! Records the number of integrations/ray movements. + !! + subroutine transportSweep(r, ints, nG, doCache, dead, termination, arrays) + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + integer(shortInt) :: simType + character(100), parameter :: Here = 'transportSweep (rayHandling_func.f90)' + + simType = arrays % getSimulationType() + + select case(simType) + case (flatIso) + call transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays) + case default + call fatalError(Here,'Unsupported simulation type') + end select + + end subroutine transportSweep + + !! + !! Transport sweep for flat isotropic sources + !! + subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays) + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(in) :: arrays + class(dataRR), pointer :: XSData + class(geometryStd), pointer :: geom + integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 + real(defReal) :: totalLength, length + logical(defBool) :: activeRay, hitVacuum + type(distCache) :: cache + real(defFlt) :: lenFlt + real(defFlt), dimension(nG) :: attenuate, delta, fluxVec, tau + real(defFlt), pointer, dimension(:) :: scalarVec, sourceVec, totVec + + XSData => arrays % getDataPointer() + geom => arrays % getGeomPointer() + + ! Set initial angular flux to angle average of cell source + cIdx = r % coords % uniqueID + matIdx = r % coords % matIdx + call XSData % getTotalPointer(matIdx, totVec) + + ! Catch for regions with voids + ! Assumes these are defined as 'void' + ! TODO: Use a more robust criterion, as for branching later + if (matIdx <= XSData % getNMat()) then + do g = 1, nG + fluxVec(g) = arrays % getSource(cIdx,g) / totVec(g) + end do + else + do g = 1, nG + fluxVec(g) = arrays % getPrevFlux(cIdx,g) + end do + end if + + ints = 0 + matIdx0 = matIdx + totalLength = ZERO + activeRay = .false. + do while (totalLength < termination) + + ! Get material and cell the ray is moving through + matIdx = r % coords % matIdx + cIdx = r % coords % uniqueID + if (matIdx0 /= matIdx) then + matIdx0 = matIdx + + ! Cache total cross section + call XSData % getTotalPointer(matIdx, totVec) + end if + + ! Set maximum flight distance and ensure ray is active + call checkRayLength(totalLength, dead, termination, activeRay, length) + + ! Move ray + call moveRay(r, doCache, ints, geom, length, event, cache, hitVacuum) + totalLength = totalLength + length + + ! Set new cell's position. Use half distance across cell + ! to try and avoid FP error + if (.not. arrays % found(cIdx)) then + call arrays % newFound(cIdx, r % rGlobal() + length * HALF * r % dirGlobal()) + end if + + lenFlt = real(length,defFlt) + call arrays % getSourcePointer(cIdx, sourceVec) + + ! Branch for voids etc + ! TODO: Should use a better branching criterion. Maybe create it in data? + ! Standard route + if (matIdx <= XSData % getNMat()) then + + !$omp simd + do g = 1, nG + tau(g) = totVec(g) * lenFlt + attenuate(g) = lenFlt * F1(tau(g)) + delta(g) = (totVec(g) * fluxVec(g) - sourceVec(g)) * attenuate(g) + fluxVec(g) = fluxVec(g) - delta(g) + end do + + ! Accumulate to scalar flux + if (activeRay) then + + call arrays % setLock(cIdx) + call arrays % getFluxPointer(cIdx, scalarVec) + !$omp simd + do g = 1, nG + scalarVec(g) = scalarVec(g) + delta(g) + end do + call arrays % incrementVolume(cIdx, length) + call arrays % unsetLock(cIdx) + if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + + end if + + ! Route for void materials + else + + ! Accumulate to scalar flux + if (activeRay) then + + call arrays % setLock(cIdx) + call arrays % getFluxPointer(cIdx, scalarVec) + !$omp simd + do g = 1, nG + scalarVec(g) = scalarVec(g) + fluxVec(g) * lenFlt + end do + call arrays % incrementVolume(cIdx, length) + call arrays % incrementLengthSquared(cIdx, length) + call arrays % unsetLock(cIdx) + if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + + end if + + !$omp simd + do g = 1, nG + fluxVec(g) = fluxVec(g) + sourceVec(g) * lenFlt + end do + + end if + + ! Check for a vacuum hit + if (hitVacuum) then + !$omp simd + do g = 1, nG + fluxVec(g) = 0.0_defFlt + end do + end if + + end do + + end subroutine transportSweepFlatIso + + !! + !! Transport sweep for flat isotropic sources + !! + subroutine transportSweepLinIso(r, ints, nG, doCache, dead, termination, arrays) + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + + end subroutine transportSweepLinIso + + !! + !! Transport sweep for LIFA sources + !! + subroutine transportSweepLIFA(r, ints, nG, doCache, dead, termination, arrays) + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + + end subroutine transportSweepLIFA + + !! + !! Transport sweep for flat aniisotropic sources + !! + subroutine transportSweepFlatAni(r, ints, nG, doCache, dead, termination, arrays) + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + + end subroutine transportSweepFlatAni + + +end module rayHandling_func diff --git a/SharedModules/CMakeLists.txt b/SharedModules/CMakeLists.txt index 2a8baa4ce..e145825af 100644 --- a/SharedModules/CMakeLists.txt +++ b/SharedModules/CMakeLists.txt @@ -9,6 +9,7 @@ add_sources( ./genericProcedures.f90 ./grid_class.f90 ./energyGrid_class.f90 ./statisticalTests_func.f90 + ./exponentialRA_func.f90 ./timer_mod.f90 ./charLib_func.f90 ./openmp_func.f90 @@ -19,6 +20,7 @@ add_unit_tests( ./Tests/grid_test.f90 ./Tests/energyGrid_test.f90 ./Tests/sort_test.f90 ./Tests/statisticalTests_test.f90 + ./Tests/exponentialRA_test.f90 ./Tests/hashFunctions_test.f90 ./Tests/timer_test.f90 ./Tests/conversions_test.f90 diff --git a/SharedModules/Tests/exponentialRA_test.f90 b/SharedModules/Tests/exponentialRA_test.f90 new file mode 100644 index 000000000..003af78d0 --- /dev/null +++ b/SharedModules/Tests/exponentialRA_test.f90 @@ -0,0 +1,54 @@ +module exponentialRA_test + + use numPrecision + use exponentialRA_func, only : exponential + use pfUnit_mod + + implicit none + +contains + + !! + !! Test exponential rational approximation on a few values + !! ExponentialRA evaluated (1 - exp(-x)) + !! This is compared against the analytic equivalent + !! +@Test + subroutine testExponentialRA() + real(defFlt) :: x, res, resRA + real(defFlt), parameter :: tol = 1E-5 + + x = 0.5 + res = ONE - exp(-x) + resRA = exponential(x) + + @assertEqual(res, resRA, tol) + + x = 0.2_defFlt + res = ONE - exp(-x) + resRA = exponential(x) + + @assertEqual(res, resRA, tol) + + x = 0.03_defFlt + res = ONE - exp(-x) + resRA = exponential(x) + + @assertEqual(res, resRA, tol) + + x = 3.0_defFlt + res = ONE - exp(-x) + resRA = exponential(x) + + @assertEqual(res, resRA, tol) + + + x = 0.0001_defFlt + res = ONE - exp(-x) + resRA = exponential(x) + + @assertEqual(res, resRA, tol) + end subroutine testExponentialRA + + +end module exponentialRA_test diff --git a/SharedModules/exponentialRA_func.f90 b/SharedModules/exponentialRA_func.f90 new file mode 100644 index 000000000..a2fdcc155 --- /dev/null +++ b/SharedModules/exponentialRA_func.f90 @@ -0,0 +1,63 @@ +module exponentialRA_func + !! This module contains a function for efficiently computing an exponential + !! for use in MoC implementations. RA stands for rational approximation. + !! This is based on the implementation given in Minray: + !! github.com/jtramm/minray/blob/master/cpu_srce/flux_attenuation_kernel.c + !! I believe this originates from the M&C 2019 publication: + !! "Adding a third level of parallelism to OpenMOC" + !! + + use numPrecision + use genericProcedures, only : fatalError + + implicit none + private + + public :: exponential + + ! Numerator coefficients in rational approximation + real(defFlt), parameter :: c1n = -1.0000013559236386308, c2n = 0.23151368626911062025,& + c3n = -0.061481916409314966140, c4n = 0.0098619906458127653020, c5n = -0.0012629460503540849940, & + c6n = 0.00010360973791574984608, c7n = -0.000013276571933735820960 + + ! Denominator coefficients in rational approximation + real(defFlt), parameter :: c0d = ONE, c1d = -0.73151337729389001396, c2d = 0.26058381273536471371, & + c3d = -0.059892419041316836940, c4d = 0.0099070188241094279067, c5d = -0.0012623388962473160860, & + c6d = 0.00010361277635498731388, c7d = -0.000013276569500666698498 + +contains + + !! + !! Computes x = 1 - exp(-tau) for use in MoC calcs + !! Tau is the optical distance + !! + elemental function exponential(tau) result(x) + real(defFlt), intent(in) :: tau + real(defFlt) :: x + real(defFlt) :: den, num + + x = -tau + den = c7d + den = den * x + c6d + den = den * x + c5d + den = den * x + c4d + den = den * x + c3d + den = den * x + c2d + den = den * x + c1d + den = den * x + c0d + + num = c7n + num = num * x + c6n + num = num * x + c5n + num = num * x + c4n + num = num * x + c3n + num = num * x + c2n + num = num * x + c1n + num = num * x + + x = num / den + + end function exponential + + +end module exponentialRA_func diff --git a/SharedModules/numPrecision.f90 b/SharedModules/numPrecision.f90 index ec7d22a43..eb90a9907 100644 --- a/SharedModules/numPrecision.f90 +++ b/SharedModules/numPrecision.f90 @@ -3,6 +3,7 @@ module numPrecision private ! Variables Kind and Length parameters integer, public, parameter :: defReal = 8, & + defFlt = 4, & shortInt = 4, & longInt = 8, & defBool = 4, & @@ -20,7 +21,9 @@ module numPrecision ONE = 1.0_defReal, & TWO = 2.0_defReal, & TWO_PI = TWO * PI, & - HALF = 0.5_defReal + HALF = 0.5_defReal,& + FOUR_PI = TWO * TWO_PI, & + ONE_FOUR_PI = ONE /(FOUR_PI) real(defReal), public, parameter :: floatTol = 1.0e-12 !*** Should be replaced real(defReal), public, parameter :: FP_REL_TOL = 1.0e-7_defReal diff --git a/Tallies/tallyAdmin_class.f90 b/Tallies/tallyAdmin_class.f90 index a81b530f0..9370ffcac 100644 --- a/Tallies/tallyAdmin_class.f90 +++ b/Tallies/tallyAdmin_class.f90 @@ -740,7 +740,7 @@ recursive subroutine reportCycleEnd(self,end) !$omp end parallel do ! Calculate normalisation factor - if( self % normBInAddr /= NO_NORM ) then + if( self % normBinAddr /= NO_NORM ) then normScore = self % mem % getScore(self % normBinAddr) if (normScore == ZERO) then call fatalError(Here, 'Normalisation score from clerk:' // self % normClerkName // 'is 0') diff --git a/Visualisation/VTK/outputVTK_class.f90 b/Visualisation/VTK/outputVTK_class.f90 index b1a7e0dcc..9b170a646 100644 --- a/Visualisation/VTK/outputVTK_class.f90 +++ b/Visualisation/VTK/outputVTK_class.f90 @@ -50,10 +50,10 @@ module outputVTK_class integer(shortInt), dimension(2), private :: version = [3,0] real(defReal), dimension(3), private :: corner real(defReal), dimension(3), private :: width - integer(shortInt), dimension(3), private :: nVox + integer(shortInt), dimension(3) :: nVox integer(shortInt), private :: nCells integer(shortInt), private :: nOutput - real(defReal), dimension(:,:,:,:), allocatable, private :: values + real(defReal), dimension(:,:,:,:), allocatable :: values character(nameLen), dimension(:), allocatable, private :: dataName logical(defBool), dimension(:), allocatable, private :: dataReal contains @@ -278,7 +278,8 @@ subroutine output(self, name) write(file,'(A)') 'DATASET STRUCTURED_POINTS' write(file,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ',self % nVox(1),' ',self % nVox(2),' ',self % nVox(3) write(file,'(A,F0.3,A,F0.3,A,F0.3)') 'ORIGIN ',self % corner(1),' ',self % corner(2),' ',self % corner(3) - write(file,'(A,F0.3,A,F0.3,A,F0.3)') 'SPACING ',self % width(1),' ',self % width(2),' ',self % width(3) + write(file,'(A,F0.3,A,F0.3,A,F0.3)') 'SPACING ',self % width(1)/self % nVox(1),' ',self % width(2)/self % nVox(2),& + ' ',self % width(3) / self % nVox(3) write(file,'(A,I0)') 'POINT_DATA ',self % nCells ! Output dataset attributes - begins with POINT_DATA or CELL_DATA followed by number of cells/points @@ -294,7 +295,7 @@ subroutine output(self, name) write(file,'(A)') 'LOOKUP_TABLE default' if (self % dataReal(l)) then - write(file,'(F0.3)') self % values(l,:,:,:) + write(file,'(F0.6)') self % values(l,:,:,:) else write(file,'(I0)') int(self % values(l,:,:,:),shortInt) endif diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index a0cdcd768..35c127b29 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -29,9 +29,12 @@ module visualiser_class !! vizDict -> dictionary containing visualisations to be generated !! !! Interface: - !! init -> initialises visualiser - !! makeViz -> constructs requested visualisations - !! kill -> cleans up visualiser + !! init -> initialises visualiser + !! makeViz -> constructs requested visualisations + !! kill -> cleans up visualiser + !! initVTK -> initialise a VTK file for later data addition + !! addVTKData -> Add a VTK field to a file + !! finaliseVTK -> Conclude writing to a VTK and output !! !! Sample dictionary input: !! viz{ @@ -46,12 +49,18 @@ module visualiser_class character(nameLen), private :: name class(geometry), pointer, private :: geom => null() type(dictionary), private :: vizDict + type(outputVTK), private :: vtk contains procedure :: init procedure :: makeViz procedure :: kill procedure, private :: makeVTK procedure, private :: makeBmpImg + procedure :: slicePlot + procedure :: voxelPlot + procedure :: initVTK + procedure :: addVTKData + procedure :: finaliseVTK end type contains @@ -70,14 +79,19 @@ module visualiser_class !! 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 + subroutine init(self, geom, vizDict, str) + class(visualiser), intent(inout) :: self + class(geometry), pointer, intent(inout) :: geom + class(dictionary), intent(in) :: vizDict + character(namelen), intent(in), optional :: str + character(:), allocatable :: string ! Obtain file name - call getInputFile(string) + if (present(str)) then + string = str + else + call getInputFile(string) + end if self % name = string ! Point to geometry @@ -173,9 +187,12 @@ subroutine makeVTK(self, dict) ! Obtain geometry data call dict % get(corner, 'corner') call dict % get(width, 'width') - center = corner + width/TWO call dict % get(nVox, 'vox') + ! Avoid uninitialised warning + allocate(center(size(corner))) + center = corner + width/TWO + if (size(corner) /= 3) then call fatalError(here,'Voxel plot requires corner to have 3 values') endif @@ -188,7 +205,7 @@ subroutine makeVTK(self, dict) allocate(voxelMat(nVox(1), nVox(2), nVox(3))) ! Have geometry obtain data - call self % geom % voxelPlot(voxelMat, center, what, width) + call self % 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 @@ -198,6 +215,17 @@ subroutine makeVTK(self, dict) end subroutine makeVTK + !! + !! Output an already constructed VTK and clean up + !! + subroutine finaliseVTK(self) + class(visualiser), intent(inout) :: self + + call self % vtk % output(self % name) + call self % vtk % kill() + + end subroutine finaliseVTK + !! !! Generate a BMP slice image of the geometry !! @@ -304,9 +332,9 @@ subroutine makeBmpImg(self, dict) ! Get plot if (useWidth) then - call self % geom % slicePlot(img, centre, dir, what, width) + call self % slicePlot(img, centre, dir, what, width) else - call self % geom % slicePlot(img, centre, dir, what) + call self % slicePlot(img, centre, dir, what) end if ! Translate to an image @@ -394,5 +422,283 @@ elemental function uniqueIDColour(uniqueID) result(colour) end function uniqueIDColour + !! + !! Produce a 2D plot of the geometry + !! + !! Resolution is determined by a size of provided output matrix + !! By default plot plane is normal to z-axis, with width determined by bounds of the + !! geometry. + !! + !! Args: + !! img [out] -> Rank 2 matrix. It is effectively a bitmap image + !! centre [in] -> Location of the centre of the image + !! dir [in] -> Axis normal to plot plane. In {'x','y','z'} + !! what [in] -> What to plot 'material' or 'uniqueID' + !! width [in] -> Optional. Width of the plot in both directions. Direction lower in + !! sequence {x,y,z} is given first. + !! + subroutine slicePlot(self, img, centre, dir, what, width) + class(visualiser), intent(in) :: self + integer(shortInt), dimension(:,:), intent(out) :: img + real(defReal), dimension(3), intent(in) :: centre + character(1), intent(in) :: dir + character(*), intent(in) :: what + real(defReal), dimension(2), optional, intent(in) :: width + real(defReal), dimension(3) :: low, top , step, point, corner + real(defReal), dimension(6) :: aabb + integer(shortInt), dimension(2) :: plane + integer(shortInt) :: ax, i, j, matIdx, uniqueID + logical(defBool) :: printMat + character(100), parameter :: Here = 'slicePlot (visualiser_class.f90)' + + ! Select plane of the plot + select case (dir) + case ('x') + ax = X_AXIS + plane = [Y_AXIS, Z_AXIS] + + case ('y') + ax = Y_AXIS + plane = [X_AXIS, Z_AXIS] + + case ('z') + ax = Z_AXIS + plane = [X_AXIS, Y_AXIS] + + case default + call fatalError(Here, 'Unknown normal axis: '//dir) + ax = X_AXIS + plane = 0 ! Make compiler happy + end select + + ! Find lower and upper corner of the plot + if (present(width)) then + low(plane) = centre(plane) - width * HALF + top(plane) = centre(plane) + width * HALF + low(ax) = centre(ax) + top(ax) = centre(ax) + + else + aabb = self % geom % bounds() + low = aabb(1:3) + top = aabb(4:6) + low(ax) = centre(ax) + top(ax) = centre(ax) + + end if + + ! Calculate step size in all directions + step(ax) = ZERO + step(plane) = (top(plane) - low(plane)) / shape(img) + + ! Select what to print + select case (what) + case ('material') + printMat = .true. + + case('uniqueID') + printMat = .false. + + case default + call fatalError(Here, 'Target of plot must be material or uniqueID. Not: '//trim(what)) + printMat = .false. ! Make compiler happy + + end select + + ! Print the image + corner = low - HALF * step + point(ax) = corner(ax) + + !$omp parallel do firstprivate(point) private(matIdx, uniqueID) + do j = 1, size(img, 2) + point(plane(2)) = corner(plane(2)) + step(plane(2)) * j + + do i = 1, size(img, 1) + point(plane(1)) = corner(plane(1)) + step(plane(1)) * i + + ! Find material and paint image + call self % geom % whatIsAt(matIdx, uniqueID, point) + + ! Paint the pixel + if (printMat) then + img(i, j) = matIdx + else + img(i, j) = uniqueID + end if + + end do + end do + !$omp end parallel do + + end subroutine slicePlot + + !! + !! Produce a 3D Voxel plot of the geometry + !! + !! Resolution is determined by a size of provided output matrix + !! By default, bounds of the plot correspond to the bounds of the geometry + !! + !! Args: + !! img [out] -> Rank 3 matrix, It is effectively a 3D bitmap + !! centre [in] -> Location of the centre of the image + !! what [in] -> What to plot 'material' or 'uniqueID' + !! width [in] -> Optional. Width of the plot in all directions. + !! + subroutine voxelPlot(self, img, centre, what, width) + class(visualiser), intent(in) :: self + integer(shortInt), dimension(:,:,:), intent(out) :: img + real(defReal), dimension(3), intent(in) :: centre + character(*), intent(in) :: what + real(defReal), dimension(3), optional, intent(in) :: width + real(defReal), dimension(3) :: width_l, centre_l, point + real(defReal), dimension(6) :: aabb + real(defReal) :: stepZ + integer(shortInt) :: i + + ! Get local value of width and centre + if (present(width)) then + width_l = width + centre_l = centre + + else + aabb = self % geom % bounds() + centre_l = (aabb(1:3) + aabb(4:6)) * HALF + width_l = aabb(4:6) - aabb(1:3) + + end if + + ! Calculate step in z direction + stepZ = width_l(3) / size(img, 3) + + ! Build voxel plot from multiple slice plots + point = centre_l + point(3) = centre_l(3) - width_l(3) * HALF - stepZ * HALF + do i = 1, size(img, 3) + point(3) = point(3) + stepZ + call self % slicePlot(img(:,:,i), point, 'z', what, width_l(1:2)) + + end do + + end subroutine voxelPlot + + !! + !! Initialise a VTK output with data addition after + !! + !! Creates the VTK file corresponding to the contents of vizDict but does not + !! output it. Allows more complex fields to be plotted, e.g., based on results. + !! Accepts the first VTK dictionary it finds. + !! + !! VTK dictionary is the standard dictionary used above. + !! + !! 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 initVTK(self) + class(visualiser), intent(inout) :: self + character(nameLen),dimension(:), allocatable :: keysArr + integer(shortInt) :: i + character(nameLen) :: vizType + logical(defBool) :: vtkFound + class(dictionary), pointer :: dict + integer(shortInt), dimension(:,:,:), allocatable:: voxelMat + real(defReal), dimension(3) :: corner ! corner of the mesh + real(defReal), dimension(3) :: center ! center of the mesh + real(defReal), dimension(3) :: width ! corner of the mesh + real(defReal), dimension(:), allocatable :: temp ! temporary vector + integer(shortInt), dimension(:), allocatable :: nVox ! number of mesh voxels + character(nameLen) :: what + character(nameLen) :: here ='initVTK (visualiser_class.f90)' + + ! Loop through each sub-dictionary and generate visualisation + ! (if the visualisation method is available) + call self % vizDict % keys(keysArr,'dict') + vtkFound = .FALSE. + do i=1,size(keysArr) + dict => self % vizDict % getDictPtr(keysArr(i)) + call dict % get(vizType,'type') + if (vizType == 'vtk') then + vtkFound = .TRUE. + exit + end if + end do + + if (.NOT. vtkFound) call fatalError(Here,'No VTK data provided in dictionary') + + call self % vtk % init(dict) + + ! Identify whether plotting 'material' or 'cellID' + call dict % getOrDefault(what, 'what', 'material') + + ! Obtain geometry data + call dict % get(temp, 'corner') + if (size(temp) /= 3) then + call fatalError(Here, "'center' must have size 3. Has: "//numToChar(size(temp))) + end if + corner = temp + + call dict % get(temp, 'width') + if (size(temp) /= 3) then + call fatalError(Here, "'width' must have size 3. Has: "//numToChar(size(temp))) + end if + width = temp + + 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') + end if + if (size(width) /= 3) then + call fatalError(here,'Voxel plot requires width to have 3 values') + end if + if (size(nVox) /= 3) then + call fatalError(here,'Voxel plot requires vox to have 3 values') + end if + allocate(voxelMat(nVox(1), nVox(2), nVox(3))) + + ! Have geometry obtain data + call self % voxelPlot(voxelMat, center, what, width) + + ! VTK data set will use 'what' variable as a name + call self % vtk % addData(voxelMat, what) + + end subroutine initVTK + + !! + !! Add additional data to a VTK file based on an array of values. + !! The array index will correspond to either the material or uniqueID at + !! a given position in the geometry. + !! + !! Assumes the VTK has already been initialised and uses the first VTK + !! set of values, i.e., index 1, to check which values to add. + !! + subroutine addVTKData(self,dataArray, dataName) + class(visualiser), intent(inout) :: self + real(defReal), dimension(:), intent(in) :: dataArray + character(nameLen), intent(in) :: dataName + integer(shortInt) :: i + integer(shortInt), save :: j, k + real(defReal), dimension(:,:,:), allocatable :: values + integer(shortInt), dimension(3) :: nVox + !$omp threadprivate(j, k) + + nVox = self % vtk % nVox + allocate(values(nVox(1),nVox(2),nVox(3))) + !$omp parallel do schedule(static) + do i = 1, self % vtk % nVox(1) + do j = 1, self % vtk % nVox(2) + do k = 1, self % vtk % nVox(3) + values(i,j,k) = dataArray(int(self % vtk % values(1,i,j,k))) + end do + end do + end do + !$omp end parallel do + + call self % vtk % addDataReal(values, dataName) + + end subroutine addVTKData + end module visualiser_class From e86be6789affc251663dfce8147ffc5ba9ab9c9a Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sat, 29 Jun 2024 11:58:50 +0100 Subject: [PATCH 02/15] Fixing build errors for debug and no OMP --- Geometry/Tests/geometryStd_iTest.f90 | 6 ++++-- RandomRayObjects/arraysRR_class.f90 | 8 ++++++++ RandomRayObjects/rayHandling_func.f90 | 6 ++++++ Visualisation/visualiser_class.f90 | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Geometry/Tests/geometryStd_iTest.f90 b/Geometry/Tests/geometryStd_iTest.f90 index 69549595f..8d7ce2923 100644 --- a/Geometry/Tests/geometryStd_iTest.f90 +++ b/Geometry/Tests/geometryStd_iTest.f90 @@ -87,7 +87,8 @@ subroutine test_lattice_geom() ! Construct visualiser and verify slice plotting geomP => geom call charToDict(vizDict, ' ') - call viz % init(geomP, vizDict, 'test') + name = 'test' + call viz % init(geomP, vizDict, name) ! Slice plot -> Material call viz % slicePlot(img, [ZERO, ZERO, ZERO], 'z', 'material') @@ -274,7 +275,8 @@ subroutine test_tilted_cylinder() ! Construct visualiser and verify slice plotting geomP => geom call charToDict(vizDict, ' ') - call viz % init(geomP, vizDict, 'test') + name = 'test' + call viz % init(geomP, vizDict, name) !*** Test slice normal to x & y ! X-axis at 1.0 diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 33f19da66..a7f64a795 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -246,7 +246,9 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di ! Initialise OMP locks allocate(self % locks(self % nCells)) do i = 1, self % nCells +#ifdef _OPENMP call OMP_init_lock(self % locks(i)) +#endif end do end subroutine init @@ -572,7 +574,9 @@ subroutine setLock(self, cIdx) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: cIdx +#ifdef _OPENMP call OMP_set_lock(self % locks(cIdx)) +#endif end subroutine setLock @@ -583,7 +587,9 @@ subroutine unsetLock(self, cIdx) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: cIdx +#ifdef _OPENMP call OMP_unset_lock(self % locks(cIdx)) +#endif end subroutine unsetLock @@ -1194,7 +1200,9 @@ subroutine kill(self) if(allocated(self % locks)) then do i = 1, self % nCells +#ifdef _OPENMP call OMP_destroy_lock(self % locks(i)) +#endif end do deallocate(self % locks) end if diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 2a7048daa..958c5ba8d 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -153,6 +153,12 @@ subroutine transportSweep(r, ints, nG, doCache, dead, termination, arrays) select case(simType) case (flatIso) call transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays) + case (linearIso) + call transportSweepLinIso(r, ints, nG, doCache, dead, termination, arrays) + case (flatAni) + call transportSweepFlatAni(r, ints, nG, doCache, dead, termination, arrays) + case (linearAni) + call transportSweepLIFA(r, ints, nG, doCache, dead, termination, arrays) case default call fatalError(Here,'Unsupported simulation type') end select diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index 35c127b29..dd9714a30 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -83,7 +83,7 @@ subroutine init(self, geom, vizDict, str) class(visualiser), intent(inout) :: self class(geometry), pointer, intent(inout) :: geom class(dictionary), intent(in) :: vizDict - character(namelen), intent(in), optional :: str + character(nameLen), intent(in), optional :: str character(:), allocatable :: string ! Obtain file name From eda7d1fa0746d77f5de37f2532d38a03a295e598 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 3 Jul 2024 11:00:01 +0100 Subject: [PATCH 03/15] Complete linear source random ray --- Geometry/Universes/azimPinUniverse_class.f90 | 217 +++++--- InputFiles/TRRM/C5G7_TRRM | 4 +- InputFiles/TRRM/C5G7_TRRM_coarse | 294 ++++++++++ RandomRayObjects/arraysRR_class.f90 | 534 ++++++++++++++++++- RandomRayObjects/constantsRR.f90 | 25 +- RandomRayObjects/mathsRR_func.f90 | 85 ++- RandomRayObjects/rayHandling_func.f90 | 266 ++++++++- 7 files changed, 1302 insertions(+), 123 deletions(-) create mode 100644 InputFiles/TRRM/C5G7_TRRM_coarse diff --git a/Geometry/Universes/azimPinUniverse_class.f90 b/Geometry/Universes/azimPinUniverse_class.f90 index 291a84eee..df38b7010 100644 --- a/Geometry/Universes/azimPinUniverse_class.f90 +++ b/Geometry/Universes/azimPinUniverse_class.f90 @@ -32,6 +32,11 @@ module azimPinUniverse_class !! segments. Proceeding radially outwards, the ID is incremented by the !! number of azimuthal regions. !! + !! This has been generalised to allow different numbers of azimuthal divisions + !! in each radial division, e.g., a pin cell with 4 azimuthal divisions in the + !! fuel but 8 azimuthal divisions in the moderator + !! + !! Simplified input for uniform azimuthal division !! Sample Dictionary Input: !! azimPinUni { !! id 7; @@ -43,9 +48,25 @@ module azimPinUniverse_class !! fills (u<3> void clad u<4>); !! } !! + !! Input for non-uniform azimuthal division + !! Sample Dictionary Input: + !! azimPinUni { + !! id 7; + !! type azimPinUniverse; + !! nazR (4 8); + !! #origin (1.0 0.0 0.1);# + !! #rotation (30.0 0.0 0.0);# + !! radii (3.0 0.0 ); + !! fills (u<3> water ); + !! } + !! !! naz corresponds to the number of azimuthal regions produced. Must be a multiple of 2. !! Takes origin at 0 degrees, i.e., the centre of the first azimuthal slice. !! There must be 0.0 entry, which indicates outermost annulus (infinite radius). + !! + !! Alternatively, nazR is the number of azimuthal divisions per radial region, from + !! the centre radiating outwards. + !! !! `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 cells 1 to 4 !! are filled with u<4>, cell 5 to 8 with u<3> etc. @@ -55,7 +76,7 @@ module azimPinUniverse_class !! !!!!! !! !! Public Members: - !! nAz -> Number of azimuthal regions + !! nAz -> Number of azimuthal regions in each radial ring !! r_sqr -> Array of radius^2 for each annulus !! theta -> Array of azimuthal boundary angles in radians. !! annuli -> Array of cylinder surfaces that represent diffrent annuli @@ -67,12 +88,12 @@ module azimPinUniverse_class !! type, public, extends(universe) :: azimPinUniverse private - integer(shortInt) :: nAz - real(defReal), dimension(:), allocatable :: r_sq - real(defReal), dimension(:), allocatable :: theta - type(cylinder), dimension(:), allocatable :: annuli - type(plane), dimension(:), allocatable :: planes - real(defReal), dimension(:,:), allocatable :: normals + integer(shortInt), dimension(:), allocatable :: nAz + real(defReal), dimension(:), allocatable :: r_sq + real(defReal), dimension(:), allocatable :: theta + type(cylinder), dimension(:), allocatable :: annuli + type(plane), dimension(:), allocatable :: planes + real(defReal), dimension(:,:), allocatable :: normals contains ! Superclass procedures procedure :: init @@ -100,8 +121,9 @@ 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, j + integer(shortInt) :: id, idx, N, i, j, r, nAzTotal real(defReal), dimension(:), allocatable :: radii, temp + integer(shortInt), dimension(:), allocatable :: tempInt character(nameLen), dimension(:), allocatable :: fillNames real(defReal) :: dTheta, theta0 character(100), parameter :: Here = 'init (azimPinUniverse_class.f90)' @@ -110,13 +132,46 @@ subroutine init(self, fill, dict, cells, surfs, mats) call dict % get(id, 'id') if (id <= 0) call fatalError(Here, 'Universe ID must be +ve. Is: '//numToChar(id)) call self % setId(id) + + ! Load radii and fill data + call dict % get(radii, 'radii') + call dict % get(fillNames, 'fills') + + ! Check values + if (size(radii) /= size(fillNames)) then + call fatalError(Here, 'Size of radii and fills does not match') + + else if (any(radii < ZERO)) then + call fatalError(Here, 'Found -ve value of radius.') + + end if ! Load azimuthal division - call dict % get(self % naz, 'naz') - if (self % nAz < 2) call fatalError(Here,'Number of azimuthal regions must be 2 or more') + if (dict % isPresent('naz') .and. dict % isPresent('nazR')) then + call fatalError(Here,'Cannot have both a naz and nazR entry') + + ! Only one azimuthal discretisation + elseif (dict % isPresent('naz')) then + allocate(self % nAz(size(radii))) + call dict % get(N, 'naz') + self % nAz = N + + ! Variable azimuthal discretisation + elseif (dict % isPresent('nazR')) then + call dict % get(tempInt, 'nazR') + if (size(tempInt) /= size(radii)) call fatalError(Here,'Number of radial regions is not consistent '//& + 'between nazR and radii') + allocate(self % nAz(size(tempInt))) + self % nAz = tempInt + else + call fatalError(Here,'Must have either a naz or nazR entry') + end if + if (any(self % nAz < 2)) call fatalError(Here,'Number of azimuthal regions must be 2 or more') ! Use binary logic to check if nAz is a power of 2 - if (IAND(self % nAz, self % nAz - 1) /= 0) call fatalError(Here, 'Number of azimuthal regions must be a power of 2') + do r = 1, size(self % naz) + if (IAND(self % nAz(r), self % nAz(r) - 1) /= 0) call fatalError(Here, 'Number of azimuthal regions must be a power of 2') + end do ! Load origin if (dict % isPresent('origin')) then @@ -139,18 +194,6 @@ subroutine init(self, fill, dict, cells, surfs, mats) call self % setTransform(rotation=temp) end if - ! Load radii and fill data - call dict % get(radii, 'radii') - call dict % get(fillNames, 'fills') - - ! Check values - if (size(radii) /= size(fillNames)) then - call fatalError(Here, 'Size of radii and fills does not match') - - else if (any(radii < ZERO)) then - call fatalError(Here, 'Found -ve value of radius.') - - end if ! Sort radii with selection sort ! Start with value 0.0 that represents outermost element @@ -185,31 +228,40 @@ subroutine init(self, fill, dict, cells, surfs, mats) end do ! Load data and build planes - allocate(self % theta(self % nAz)) - allocate(self % planes(self % nAz/2)) - allocate(self % normals(self % nAz/2,2)) - dTheta = TWO_PI / self % nAz - theta0 = HALF * dTheta - do i = 1, self % nAz - self % theta(i) = theta0 - theta0 = theta0 + dTheta - end do + allocate(self % theta(sum(self % nAz))) + allocate(self % planes(sum(self % nAz)/2)) + allocate(self % normals(sum(self % nAz)/2,2)) - ! Build the planes, rotated at angle theta from the line x = 0 - do i = 1, self % nAz/2 - self % normals(i,1) = -sin(self % theta(i)) - self % normals(i,2) = cos(self % theta(i)) - call self % planes(i) % build(id=1, & - norm = [self % normals(i,1), self % normals(i,2), ZERO], offset=ZERO) + nAzTotal = 0 + do r = 1, N + + dTheta = TWO_PI / self % nAz(r) + theta0 = HALF * dTheta + do i = 1, self % nAz(r) + self % theta(nAzTotal + i) = theta0 + theta0 = theta0 + dTheta + end do + + ! Build the planes, rotated at angle theta from the line x = 0 + do i = 1, self % nAz(r)/2 + self % normals(nAzTotal/2 + i,1) = -sin(self % theta(nAzTotal + i)) + self % normals(nAzTotal/2 + i,2) = cos(self % theta(nAzTotal + i)) + call self % planes(nAzTotal/2 + i) % build(id=1, & + norm = [self % normals(nAzTotal/2 + i,1), self % normals(nAzTotal/2 + i,2), ZERO], offset=ZERO) + end do + + nAzTotal = nAzTotal + self % nAz(r) end do ! Create fill array - allocate(fill(self % nAz * N)) + allocate(fill(nAzTotal)) + nAzTotal = 0 do i = 1, N - do j = 1, self % nAz - fill((i-1)*self % nAz + j) = charToFill(fillNames(i), mats, Here) + do j = 1, self % nAz(i) + fill(nAzTotal + j) = charToFill(fillNames(i), mats, Here) end do + nAzTotal = nAzTotal + self % nAz(i) end do end subroutine init @@ -226,7 +278,7 @@ subroutine findCell(self, localID, cellIdx, r, u) real(defReal), dimension(3), intent(in) :: r real(defReal), dimension(3), intent(in) :: u real(defReal) :: r_sq, theta, mul, planeDir - integer(shortInt) :: aIdx, rIdx, pIdx + integer(shortInt) :: aIdx, rIdx, pIdx, baseAIdx r_sq = r(1)*r(1) + r(2)*r(2) theta = atan2(r(2),r(1)) @@ -249,10 +301,14 @@ subroutine findCell(self, localID, cellIdx, r, u) end do ! If reached here without exiting, rIdx = size(self % r_sq) + 1 + ! Find base azimuthal index given radial zone + baseAIdx = 0 + if (rIdx > 1) baseAIdx = sum(self % nAz(1:(rIdx-1))) + ! Find azimuthal segment - do aIdx = 1, self % nAz - if (aIdx > self % nAz/2) then - pIdx = aIdx - self % nAz/2 + do aIdx = 1, self % nAz(rIdx) + if (aIdx > self % nAz(rIdx)/2) then + pIdx = aIdx - self % nAz(rIdx)/2 planeDir = -ONE else pIdx = aIdx @@ -260,17 +316,17 @@ subroutine findCell(self, localID, cellIdx, r, u) end if ! Surface tolerance multiplier determined by relative direction of particle ! and theta - if (planeDir*self % normals(pIdx,1)*u(1) + planeDir*self % normals(pIdx,2)*u(2) >= ZERO) then + if (planeDir*self % normals(baseAIdx/2 + pIdx,1)*u(1) + planeDir*self % normals(baseAIdx/2 + pIdx,2)*u(2) >= ZERO) then mul = -ONE else mul = ONE end if - if (theta < self % theta(aIdx) + mul * self % planes(pIdx) % surfTol() ) exit + if (theta < self % theta(baseAIdx + aIdx) + mul * self % planes(baseAIdx/2 + pIdx) % surfTol() ) exit end do ! If exceeded the search, theta is <2pi but greater than the largest theta. ! Therefore, it lies in the negative theta portion of the first segment. - if (aIdx == self % nAz + 1) aIdx = 1 - localID = aIdx + self % nAz * (rIdx - 1) + if (aIdx == self % nAz(rIdx) + 1) aIdx = 1 + localID = aIdx + baseAIdx end subroutine findCell @@ -289,20 +345,29 @@ subroutine distance(self, d, surfIdx, coords) type(coord), intent(in) :: coords real(defReal) :: d_out_annul, d_in_annul real(defReal) :: d_plus, d_minus, dAz - integer(shortInt) :: id, aIdx, rIdx, searchIdxP, searchIdxM - integer(shortInt) :: sense, minus_sense, plus_sense + integer(shortInt) :: id, aIdx, rIdx, i, searchIdxP, searchIdxM + integer(shortInt) :: sense, minus_sense, plus_sense, baseIdx character(100), parameter :: Here = 'distance (azimPinUniverse_class.f90)' ! Get local id id = coords % localID - if (id < 1 .or. id > (size(self % r_sq) + 1) * self % nAz) then + if (id < 1 .or. id > sum(self % nAz)) then call fatalError(Here, 'Invalid local ID: '//numToChar(id)) end if ! Identify annulus index and azimuthal index - rIdx = (id - 1) / self % nAz + 1 - aIdx = id - (self % nAz * (rIdx - 1)) + do i = 1, size(self % annuli) + id = id - self % nAz(i) + if (id < 1) then + rIdx = i + aIdx = id + self % nAz(i) + exit + end if + end do + + baseIdx = 0 + if (rIdx > 1) baseIdx = sum(self % nAz(1:(rIdx-1)))/2 ! Check distance to annuli ! Outer distance @@ -333,8 +398,8 @@ subroutine distance(self, d, surfIdx, coords) ! Check whether in the first or second half of azimuthal segments ! If in second half, find the same azimuthal indices as in the first half - searchIdxP = aIdx - if (aIdx > self % nAz/2) searchIdxP = searchIdxP - self % nAz/2 + searchIdxP = aIdx + baseIdx + if (aIdx > self % nAz(rIdx)/2) searchIdxP = searchIdxP - self % nAz(rIdx)/2 ! Set default senses for which cell will be entered minus_sense = MOVING_CLOCK @@ -343,24 +408,24 @@ subroutine distance(self, d, surfIdx, coords) ! Check for first or last cells circling round if (aIdx == 1) then minus_sense = MOVING_CLOCK_BACK - else if (aIdx == self % nAz) then + else if (aIdx == self % nAz(rIdx)) then plus_sense = MOVING_CLOCK_FORWARD end if ! If in the first cell or nAz/2 + 1 cell, find correct plane - if (searchIdxP == 1) then - searchIdxM = self % nAz/2 + if (searchIdxP == baseIdx + 1) then + searchIdxM = self % nAz(rIdx)/2 + baseIdx else searchIdxM = searchIdxP - 1 end if ! Identify which two planes (or only one if nAz = 2) ! Check to see if in second half of azimuthal segments - if (self % nAz > 2) then + if (self % nAz(rIdx) > 2) then d_plus = self % planes(searchIdxP) % distance(coords % r, coords % dir) d_minus = self % planes(searchIdxM) % distance(coords % r, coords % dir) else - d_plus = self % planes(1) % distance(coords % r, coords % dir) + d_plus = self % planes(baseIdx + 1) % distance(coords % r, coords % dir) d_minus = INF end if @@ -393,7 +458,16 @@ subroutine cross(self, coords, surfIdx) class(azimPinUniverse), intent(inout) :: self type(coord), intent(inout) :: coords integer(shortInt), intent(in) :: surfIdx + integer(shortInt) :: aIdx, i character(100), parameter :: Here = 'cross (azimPinUniverse_class.f90)' + + ! Need radial region to work out how much to increment the clock by + ! Identify annulus index and azimuthal index + aIdx = coords % localID + do i = 1, size(self % annuli) + aIdx = aIdx - self % nAz(i) + if (aIdx < 1) exit + end do ! Need to determine whether completing a circle, i.e., moving from ! the last azimuthal segment to the first and vice versa @@ -404,17 +478,24 @@ subroutine cross(self, coords, surfIdx) coords % localID = coords % localID + 1 else if (surfIdx == MOVING_CLOCK_BACK) then - coords % localID = coords % localID + self % nAz - 1 + coords % localID = coords % localID + self % nAz(i) - 1 else if (surfIdx == MOVING_CLOCK_FORWARD) then - coords % localID = coords % localID - self % nAz + 1 + coords % localID = coords % localID - self % nAz(i) + 1 + ! Need to be replaced with find subroutines in the general case, sadly else if (surfIdx == MOVING_IN) then - coords % localID = coords % localID - self % nAz - + if (self % nAz(i) == self % nAz(i-1)) then + coords % localID = coords % localID - self % nAz(i) + else + call self % findCell(coords % localID, coords % cellIdx, coords % r, coords % dir) + end if else if (surfIdx == MOVING_OUT) then - coords % localID = coords % localID + self % nAz - + if (self % nAz(i) == self % nAz(i+1)) then + coords % localID = coords % localID + self % nAz(i) + else + call self % findCell(coords % localID, coords % cellIdx, coords % r, coords % dir) + end if else call fatalError(Here, 'Unknown surface memento: '//numToChar(surfIdx)) @@ -452,7 +533,7 @@ elemental subroutine kill(self) if(allocated(self % theta)) deallocate(self % theta) if(allocated(self % planes)) deallocate(self % planes) if(allocated(self % normals)) deallocate(self % normals) - self % nAz = 0 + if(allocated(self % nAz)) deallocate(self % nAz) end subroutine kill diff --git a/InputFiles/TRRM/C5G7_TRRM b/InputFiles/TRRM/C5G7_TRRM index 0eff860b6..507ae9eb0 100644 --- a/InputFiles/TRRM/C5G7_TRRM +++ b/InputFiles/TRRM/C5G7_TRRM @@ -1,11 +1,11 @@ type randomRayPhysicsPackage; - +lin 0; pop 1750; active 2600; inactive 1000; dead 20; termination 220; -plot 1; +plot 0; cache 1; XSdata mg; dataType mg; diff --git a/InputFiles/TRRM/C5G7_TRRM_coarse b/InputFiles/TRRM/C5G7_TRRM_coarse new file mode 100644 index 000000000..6d3305496 --- /dev/null +++ b/InputFiles/TRRM/C5G7_TRRM_coarse @@ -0,0 +1,294 @@ +type randomRayPhysicsPackage; + +lin 1; +pop 1750; +active 2600; +inactive 1000; +dead 20; +termination 220; +plot 0; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_TRRM_coarse; + +fissionMap {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;} +} +fluxMap {type multiMap; + maps (xax yax); + xax { type spaceMap; axis x; grid lin; min -32.13; max 32.13; N 51;} + yax { type spaceMap; axis y; grid lin; min -32.13; max 32.13; N 51;} +} + +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 azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (UO2 water);} + pin2 { id 2; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (GT water);} + pin3 { id 3; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox43 water);} + pin4 { id 4; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox7 water);} + pin5 { id 5; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox87 water);} + pin6 { id 6; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 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 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.63 0.63 0.0); +shape (2 2 0); +padMat water; +map ( +30 30 +30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +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 60 +20 10 60 +50 50 70 +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner (-32.13 -32.13 -1.0); + width (64.26 64.26 2.0); + vox (2000 2000 1); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + +} +} + + diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index a7f64a795..ea820b7be 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -62,6 +62,20 @@ module arraysRR_class !! cellFound -> Array of logicals whether a cell was ever visited [nCells] !! cellPos -> Array of cell positions [3 * nCells] !! + !! scalarX -> Array of x-spatial moments of scalar flux [nG * nCells] + !! scalarY -> Array of y-spatial moments of scalar flux [nG * nCells] + !! scalarZ -> Array of z-spatial moments of scalar flux [nG * nCells] + !! prevX -> Array of previous x-spatial moments of scalar flux [nG * nCells] + !! prevY -> Array of previous y-spatial moments of scalar flux [nG * nCells] + !! prevZ -> Array of previous z-spatial moments of scalar flux [nG * nCells] + !! sourceX -> Array of source x-spatial moments of scalar flux [nG * nCells] + !! sourceY -> Array of source y-spatial moments of scalar flux [nG * nCells] + !! sourceZ -> Array of source z-spatial moments of scalar flux [nG * nCells] + !! momMat -> Array of symmetric spatial moment matrices [nCells * matSize] + !! momTracks -> Array of weighted tracks used to computer spatial moment matrices [nCells * matSize] + !! centroid -> Array of cell centroid values [nCells * nDim] + !! centroidTracks -> Array of weighted tracks used to computer centroids [nCells * nDim] + !! !! locks -> Array of OpenMP locks for each geometric cell !! type, public :: arraysRR @@ -93,6 +107,21 @@ module arraysRR_class integer(shortInt), dimension(:), allocatable :: cellHit logical(defBool), dimension(:), allocatable :: cellFound real(defReal), dimension(:,:), allocatable :: cellPos + + ! Linear source arrays + real(defFlt), dimension(:), allocatable :: scalarX + real(defFlt), dimension(:), allocatable :: scalarY + real(defFlt), dimension(:), allocatable :: scalarZ + real(defFlt), dimension(:), allocatable :: prevX + real(defFlt), dimension(:), allocatable :: prevY + real(defFlt), dimension(:), allocatable :: prevZ + real(defFlt), dimension(:), allocatable :: sourceX + real(defFlt), dimension(:), allocatable :: sourceY + real(defFlt), dimension(:), allocatable :: sourceZ + real(defReal), dimension(:), allocatable :: momMat + real(defReal), dimension(:), allocatable :: momTracks + real(defReal), dimension(:), allocatable :: centroid + real(defReal), dimension(:), allocatable :: centroidTracks ! OMP locks integer(kind=omp_lock_kind), dimension(:), allocatable :: locks @@ -106,8 +135,8 @@ module arraysRR_class ! Access procedures procedure :: getDataPointer procedure :: getGeomPointer - procedure :: getSourcePointer procedure :: getFluxPointer + procedure :: getSourcePointer procedure :: getSource procedure :: getPrevFlux procedure :: getFluxScore @@ -118,11 +147,17 @@ module arraysRR_class procedure :: getCellHitRate procedure :: getSimulationType procedure :: found + + procedure :: getFluxXYZPointers + procedure :: getSourceXYZPointers + procedure :: getCentroid ! Change individual elements of the type ! Predominantly for use in the transport sweep procedure :: incrementVolume procedure :: incrementLengthSquared + procedure :: incrementCentroid + procedure :: incrementMoments procedure :: hitCell procedure :: wipeCellHits procedure :: newFound @@ -145,22 +180,24 @@ module arraysRR_class procedure, private :: initialiseFixedSource procedure, private :: resetFluxesFlatIso - procedure, private :: resetFluxesLinIso + procedure, private :: resetFluxesLinearIso procedure, private :: resetFluxesLIFA procedure, private :: resetFluxesFlatAni procedure, private :: normaliseFluxAndVolumeFlatIso - procedure, private :: normaliseFluxAndVolumeLinIso + procedure, private :: normaliseFluxAndVolumeLinearIso procedure, private :: normaliseFluxAndVolumeLIFA procedure, private :: normaliseFluxAndVolumeFlatAni procedure, private :: sourceUpdateKernelFlatIso - procedure, private :: sourceUpdateKernelLinIso + procedure, private :: sourceUpdateKernelLinearIso procedure, private :: sourceUpdateKernelLIFA procedure, private :: sourceUpdateKernelFlatAni procedure, private :: calculateKeffKernel + procedure, private :: invertMatrix + end type arraysRR contains @@ -215,7 +252,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di allocate(self % volume(self % nCells)) allocate(self % cellHit(self % nCells)) allocate(self % cellFound(self % nCells)) - allocate(self % cellPos(3, self % nCells)) + allocate(self % cellPos(nDim, self % nCells)) self % scalarFlux = 0.0_defFlt self % prevFlux = 1.0_defFlt @@ -236,6 +273,34 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di ! TODO: allocate linear and anisotropic components, if present if (lin) then + + allocate(self % scalarX(self % nCells * self % nG)) + allocate(self % scalarY(self % nCells * self % nG)) + allocate(self % scalarZ(self % nCells * self % nG)) + allocate(self % prevX(self % nCells * self % nG)) + allocate(self % prevY(self % nCells * self % nG)) + allocate(self % prevZ(self % nCells * self % nG)) + allocate(self % sourceX(self % nCells * self % nG)) + allocate(self % sourceY(self % nCells * self % nG)) + allocate(self % sourceZ(self % nCells * self % nG)) + allocate(self % momMat(self % nCells * matSize)) + allocate(self % momTracks(self % nCells * matSize)) + allocate(self % centroid(self % nCells * nDim)) + allocate(self % centroidTracks(self % nCells * nDim)) + + self % scalarX = 0.0_defFlt + self % scalarY = 0.0_defFlt + self % scalarZ = 0.0_defFlt + self % prevX = 0.0_defFlt + self % prevY = 0.0_defFlt + self % prevZ = 0.0_defFlt + self % sourceX = 0.0_defFlt + self % sourceY = 0.0_defFlt + self % sourceZ = 0.0_defFlt + self % momMat = ZERO + self % momTracks = ZERO + self % centroid = ZERO + self % centroidTracks = ZERO end if @@ -342,6 +407,25 @@ subroutine getFluxPointer(self, cIdx, fluxVec) end subroutine getFluxPointer + !! + !! Return a pointer to the flux spatial moment vectors for a given cell + !! + subroutine getFluxXYZPointers(self, cIdx, xVec, yVec, zVec) + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), dimension(:), pointer, intent(out) :: xVec + real(defFlt), dimension(:), pointer, intent(out) :: yVec + real(defFlt), dimension(:), pointer, intent(out) :: zVec + integer(shortInt) :: baseIdx1, baseIdx2 + + baseIdx1 = self % nG * (cIdx - 1) + 1 + baseIdx2 = self % nG * cIdx + xVec => self % scalarX(baseIdx1:baseIdx2) + yVec => self % scalarY(baseIdx1:baseIdx2) + zVec => self % scalarZ(baseIdx1:baseIdx2) + + end subroutine getFluxXYZPointers + !! !! Return a pointer to the nuclear data object !! @@ -379,6 +463,26 @@ subroutine getSourcePointer(self, cIdx, sourceVec) end subroutine getSourcePointer + !! + !! Return pointers to the source moment vectors for a given cell + !! + subroutine getSourceXYZPointers(self, cIdx, xVec, yVec, zVec) + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), dimension(:), pointer, intent(out) :: xVec + real(defFlt), dimension(:), pointer, intent(out) :: yVec + real(defFlt), dimension(:), pointer, intent(out) :: zVec + integer(shortInt) :: baseIdx1, baseIdx2 + + baseIdx1 = self % nG * (cIdx - 1) + 1 + baseIdx2 = self % nG * cIdx + xVec => self % sourceX(baseIdx1:baseIdx2) + yVec => self % sourceY(baseIdx1:baseIdx2) + zVec => self % sourceZ(baseIdx1:baseIdx2) + + end subroutine getSourceXYZPointers + + !! !! Return source value given cell and group !! @@ -435,16 +539,30 @@ end function getFluxSD !! !! Return cell position given cell ID !! - function getCellPos(self, cIdx, g) result(x) - class(arraysRR), intent(in) :: self - integer(shortInt), intent(in) :: cIdx - integer(shortInt), intent(in) :: g - real(defReal), dimension(3) :: x + function getCellPos(self, cIdx) result(pos) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(nDim) :: pos - x = self % cellPos(1:3, cIdx) + pos = self % cellPos(1:nDim, cIdx) end function getCellPos + !! + !! Return cell centroid given cell ID + !! + function getCentroid(self, cIdx) result(cent) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(nDim) :: cent + integer(shortInt) :: idx0, idx1 + + idx0 = nDim * (cIdx - 1) + 1 + idx1 = nDim * (cIdx - 1) + nDim + cent = self % centroid(idx0:idx1) + + end function getCentroid + !! !! Return the simulation type !! @@ -469,6 +587,7 @@ subroutine incrementVolume(self, cIdx, length) end subroutine incrementVolume + !! !! Increment the sum of length squared in cell cIdx. !! Assumes this is being called inside a lock for thread privacy. @@ -482,6 +601,39 @@ subroutine incrementLengthSquared(self, cIdx, length) end subroutine incrementLengthSquared + !! + !! Increment the local centroid estimate in cell cIdx. + !! rL is the tracklength-weighted centroid + !! Assumes this is being called inside a lock for thread privacy. + !! + subroutine incrementCentroid(self, cIdx, rL) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(nDim), intent(in) :: rL + integer(shortInt) :: idx0, idx1 + + idx0 = nDim * (cIdx - 1) + 1 + idx1 = nDim * (cIdx - 1) + nDim + self % centroidTracks(idx0:idx1) = self % centroidTracks(idx0:idx1) + rL + + end subroutine incrementCentroid + + !! + !! Increment the local moment matrix estimate in cell cIdx. + !! mat is the tracklength-weighted matrix + !! Assumes this is being called inside a lock for thread privacy. + !! + subroutine incrementMoments(self, cIdx, mat) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(matSize), intent(in) :: mat + integer(shortInt) :: idx0, idx1 + + idx0 = matSize * (cIdx - 1) + 1 + idx1 = matSize * (cIdx - 1) + matSize + self % momTracks(idx0:idx1) = self % momTracks(idx0:idx1) + mat + + end subroutine incrementMoments !! !! Check if a cell has been hit @@ -604,6 +756,8 @@ subroutine normaliseFluxAndVolume(self, it) select case(self % simulationType) case(flatIso) call self % normaliseFluxAndVolumeFlatIso(it) + case(LinearIso) + call self % normaliseFluxAndVolumeLinearIso(it) case default call fatalError(Here,'Unsupported simulation type requested') end select @@ -659,9 +813,8 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) - sigGG = self % XSData % getScatterXS(matIdx, g, g) - ! Presumes non-zero total XS + sigGG = self % XSData % getScatterXS(matIdx, g, g) if ((sigGG < 0) .and. (total(g) > 0)) then D = -self % rho * sigGG / total(g) else @@ -686,11 +839,120 @@ end subroutine normaliseFluxAndVolumeFlatIso !! Normalise flux and volume by total track length and increments !! the flux by the neutron source for linear isotropic sources !! - subroutine normaliseFluxAndVolumeLinIso(self, it) + subroutine normaliseFluxAndVolumeLinearIso(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it + real(defFlt) :: norm + real(defReal) :: normVol + real(defReal), save :: invVol + real(defFlt), save :: vol, norm_V, D, sigGG + real(defFlt), dimension(:), pointer, save :: total + integer(shortInt) :: cIdx + integer(shortInt), save :: g, matIdx, idx, dIdx, mIdx + !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG) + + norm = real(ONE / self % lengthPerIt, defFlt) + normVol = ONE / (self % lengthPerIt * it) - end subroutine normaliseFluxAndVolumeLinIso + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + dIdx = (cIdx - 1) * nDim + mIdx = (cIdx - 1) * matSize + + ! Update volume + self % volume(cIdx) = self % volumeTracks(cIdx) * normVol + vol = real(self % volume(cIdx),defFlt) + + ! Save effort by skipping normalisation if volume is too small + if (vol < volume_tolerance) then + do g = 1, self % nG + idx = self % nG * (cIdx - 1) + g + self % scalarFlux(idx) = 0.0_defFlt + self % scalarX(idx) = 0.0_defFlt + self % scalarY(idx) = 0.0_defFlt + self % scalarZ(idx) = 0.0_defFlt + end do + cycle + end if + + if (self % volume(cIdx) > volume_tolerance) then + invVol = ONE / self % volumeTracks(cIdx) + + ! Update centroids + self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol + self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol + self % centroid(dIdx + z) = self % centroidTracks(dIdx + z) * invVol + + ! Update spatial moments + self % momMat(mIdx + xx) = self % momTracks(mIdx + xx) * invVol + self % momMat(mIdx + xy) = self % momTracks(mIdx + xy) * invVol + self % momMat(mIdx + xz) = self % momTracks(mIdx + xz) * invVol + self % momMat(mIdx + yy) = self % momTracks(mIdx + yy) * invVol + self % momMat(mIdx + yz) = self % momTracks(mIdx + yz) * invVol + self % momMat(mIdx + zz) = self % momTracks(mIdx + zz) * invVol + + else + self % centroid(dIdx + x) = ZERO + self % centroid(dIdx + y) = ZERO + self % centroid(dIdx + z) = ZERO + + self % momMat(mIdx + xx) = ZERO + self % momMat(mIdx + xy) = ZERO + self % momMat(mIdx + xz) = ZERO + self % momMat(mIdx + yy) = ZERO + self % momMat(mIdx + yz) = ZERO + self % momMat(mIdx + zz) = ZERO + + end if + + call self % XSData % getTotalPointer(matIdx, total) + norm_V = real(norm / vol, defFlt) + + do g = 1, self % nG + + idx = self % nG * (cIdx - 1) + g + if (vol > volume_tolerance) then + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V + self % scalarX(idx) = self % scalarX(idx) * norm_V + self % scalarY(idx) = self % scalarY(idx) * norm_V + self % scalarZ(idx) = self % scalarZ(idx) * norm_V + end if + + ! Apply the standard MoC post-sweep treatment and + ! stabilisation for negative XSs + if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + + self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) + self % scalarX(idx) = self % scalarX(idx) / total(g) + self % scalarY(idx) = self % scalarY(idx) / total(g) + self % scalarZ(idx) = self % scalarZ(idx) / total(g) + !self % scalarX(idx) = 0.0_defFlt + !self % scalarY(idx) = 0.0_defFlt + !self % scalarZ(idx) = 0.0_defFlt + + ! Presumes non-zero total XS + sigGG = self % XSData % getScatterXS(matIdx, g, g) + if ((sigGG < 0) .and. (total(g) > 0)) then + D = -self % rho * sigGG / total(g) + else + D = 0.0_defFlt + end if + self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + + D * self % prevFlux(idx) ) / (1 + D) + + ! Alternatively, handle unidentified/void regions + else + self % scalarFlux(idx) = self % scalarFlux(idx) + & + real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + end if + + end do + + end do + !$omp end parallel do + + end subroutine normaliseFluxAndVolumeLinearIso !! !! Normalise flux and volume by total track length and increments @@ -733,6 +995,12 @@ subroutine updateSource(self, ONE_KEFF) call self % sourceUpdateKernelFlatIso(cIdx, ONE_K) end do !$omp end parallel do + case(linearIso) + !$omp parallel do + do cIdx = 1, self % nCells + call self % sourceUpdateKernelLinearIso(cIdx, ONE_K) + end do + !$omp end parallel do case default call fatalError(Here,'Unsupported simulation type requested') end select @@ -808,12 +1076,91 @@ end subroutine sourceUpdateKernelFlatIso !! Kernel to update sources given a cell index for linear sources !! with isotropic scattering !! - subroutine sourceUpdateKernelLinIso(self, cIdx, ONE_KEFF) + subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) class(arraysRR), target, intent(inout) :: self integer(shortInt), intent(in) :: cIdx real(defFlt), intent(in) :: ONE_KEFF + real(defFlt) :: scatter, xScatter, yScatter, zScatter, & + fission, xFission, yFission, zFission, & + xSource, ySource, zSource + real(defFlt) :: invMxx, invMxy, invMxz, invMyy, invMyz, invMzz + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS + integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 + real(defFlt), pointer, dimension(:) :: fluxVec, xFluxVec, yFluxVec, zFluxVec + + ! invert moment matrices + call self % invertMatrix(cIdx, invMxx, invMxy, invMxz, invMyy, invMyz, invMzz) + + ! Identify material + matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + + ! Obtain XSs + call self % XSData % getProdPointers(matIdx, nuFission, scatterXS, chi) - end subroutine sourceUpdateKernelLinIso + baseIdx = self % nG * (cIdx - 1) + fluxVec => self % prevFlux((baseIdx+1):(baseIdx + self % nG)) + xFluxVec => self % prevX((baseIdx + 1):(baseIdx + self % nG)) + yFluxVec => self % prevY((baseIdx + 1):(baseIdx + self % nG)) + zFluxVec => self % prevZ((baseIdx + 1):(baseIdx + self % nG)) + + ! Calculate fission source + fission = 0.0_defFlt + xFission = 0.0_defFlt + yFission = 0.0_defFlt + zFission = 0.0_defFlt + + !$omp simd reduction(+:fission, xFission, yFission, zFission) aligned(fluxVec, xFluxVec, yFluxVec, zFluxVec, nuFission) + do gIn = 1, self % nG + fission = fission + fluxVec(gIn) * nuFission(gIn) + xFission = xFission + xFluxVec(gIn) * nuFission(gIn) + yFission = yFission + yFluxVec(gIn) * nuFission(gIn) + zFission = zFission + zFluxVec(gIn) * nuFission(gIn) + end do + fission = fission * ONE_KEFF + xFission = xFission * ONE_KEFF + yFission = yFission * ONE_KEFF + zFission = zFission * ONE_KEFF + + do g = 1, self % nG + + sIdx1 = self % nG * (g - 1) + 1 + sIdx2 = self % nG * g + associate(scatterVec => scatterXS(sIdx1:sIdx2)) + + ! Calculate scattering source + scatter = 0.0_defFlt + xScatter = 0.0_defFlt + yScatter = 0.0_defFlt + zScatter = 0.0_defFlt + !$omp simd reduction(+:scatter, xScatter, yScatter, zScatter) + do gIn = 1, self % nG + scatter = scatter + fluxVec(gIn) * scatterVec(gIn) + xScatter = xScatter + xFluxVec(gIn) * scatterVec(gIn) + yScatter = yScatter + yFluxVec(gIn) * scatterVec(gIn) + zScatter = zScatter + zFluxVec(gIn) * scatterVec(gIn) + end do + + end associate + + ! Output index + idx = baseIdx + g + + self % source(idx) = chi(g) * fission + scatter + xSource = chi(g) * xFission + xScatter + ySource = chi(g) * yFission + yScatter + zSource = chi(g) * zFission + zScatter + + ! Calculate source gradients by inverting the moment matrix + self % sourceX(baseIdx + g) = invMxx * xSource + & + invMxy * ySource + invMxz * zSource + self % sourceY(baseIdx + g) = invMxy * xSource + & + invMyy * ySource + invMyz * zSource + self % sourceZ(baseIdx + g) = invMxz * xSource + & + invMyz * ySource + invMzz * zSource + + end do + + end subroutine sourceUpdateKernelLinearIso !! !! Kernel to update sources given a cell index for flat sources @@ -837,7 +1184,129 @@ subroutine sourceUpdateKernelLIFA(self, cIdx, ONE_KEFF) end subroutine sourceUpdateKernelLIFA - + !! + !! Inverts the spatial moment matrix for use in linear source calculations. + !! + subroutine invertMatrix(self, cIdx, invMxx, invMxy, invMxz, invMyy, invMyz, invMzz) + class(arraysRR), target, intent(in) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(out) :: invMxx, invMxy, invMxz, invMyy, invMyz, invMzz + integer(shortInt) :: condX, condY, condZ, inversionTest + real(defReal) :: det, one_det + + associate(momVec => self % momMat(((cIdx - 1) * matSize + 1):(cIdx * matSize))) + + ! Pre-invert the moment matrix + ! Need to check for poor conditioning by evaluating the + ! diagonal elements of the matrix + condX = 0 + condY = 0 + condZ = 0 + + if (momVec(xx) > condition_tolerance) condX = 1 + if (momVec(yy) > condition_tolerance) condY = 1 + if (momVec(zz) > condition_tolerance) condZ = 1 + + ! Map conditions to test variable + inversionTest = condX * 4 + condY * 2 + condZ + + select case(inversionTest) + case(invertXYZ) + det = momVec(xx) * (momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz)) & + - momVec(yy) * momVec(xz) * momVec(xz) - momVec(zz) * momVec(xy) * momVec(xy) & + + 2 * momVec(xy) * momVec(xz) * momVec(yz) + one_det = ONE/det + invMxx = real(one_det * (momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz)),defFlt) + invMxy = real(one_det * (momVec(xz) * momVec(yz) - momVec(xy) * momVec(zz)),defFlt) + invMxz = real(one_det * (momVec(xy) * momVec(yz) - momVec(yy) * momVec(xz)),defFlt) + invMyy = real(one_det * (momVec(xx) * momVec(zz) - momVec(xz) * momVec(xz)),defFlt) + invMyz = real(one_det * (momVec(xy) * momVec(xz) - momVec(xx) * momVec(yz)),defFlt) + invMzz = real(one_det * (momVec(xx) * momVec(yy) - momVec(xy) * momVec(xy)),defFlt) + + case(invertYZ) + det = momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz) + one_det = ONE/det + invMxx = 0.0_defFlt + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = real(one_det * momVec(zz),defFlt) + invMyz = real(-one_det * momVec(yz),defFlt) + invMzz = real(one_det * momVec(yy),defFlt) + + case(invertXY) + det = momVec(xx) * momVec(yy) - momVec(xy) * momVec(xy) + one_det = ONE/det + invMxx = real(one_det * momVec(yy),defFlt) + invMxy = real(-one_det * momVec(xy),defFlt) + invMxz = 0.0_defFlt + invMyy = real(one_det * momVec(xx),defFlt) + invMyz = 0.0_defFlt + invMzz = 0.0_defFlt + + case(invertXZ) + det = momVec(xx) * momVec(zz) - momVec(xz) * momVec(xz) + one_det = ONE/det + invMxx = real(one_det * momVec(zz),defFlt) + invMxy = 0.0_defFlt + invMxz = real(-one_det * momVec(xz),defFlt) + invMyy = 0.0_defFlt + invMyz = 0.0_defFlt + invMzz = real(one_det * momVec(xx),defFlt) + + case(invertX) + det = momVec(xx) + one_det = ONE/det + invMxx = real(one_det,defFlt) + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = 0.0_defFlt + invMyz = 0.0_defFlt + invMzz = 0.0_defFLt + + case(invertY) + det = momVec(yy) + one_det = ONE/det + invMxx = 0.0_defFlt + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = real(one_det,defFlt) + invMyz = 0.0_defFlt + invMzz = 0.0_defFlt + + case(invertZ) + det = momVec(zz) + one_det = ONE/det + invMxx = 0.0_defFlt + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = 0.0_defFlt + invMyz = 0.0_defFlt + invMzz = real(one_det,defFlt) + + case default + invMxx = 0.0_defFlt + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = 0.0_defFlt + invMyz = 0.0_defFlt + invMzz = 0.0_defFlt + det = ONE + end select + + ! Check for zero determinant + if (abs(det) < det_tolerance) then + invMxx = 0.0_defFlt + invMxy = 0.0_defFlt + invMxz = 0.0_defFlt + invMyy = 0.0_defFlt + invMyz = 0.0_defFlt + invMzz = 0.0_defFlt + end if + + end associate + + end subroutine invertMatrix + !! !! Calculate keff !! Wraps the main kernel call to allow for OMP + SIMD (thanks Fortran) @@ -913,6 +1382,8 @@ subroutine resetFluxes(self) select case(self % simulationType) case(flatIso) call self % resetFluxesFlatIso() + case(linearIso) + call self % resetFluxesLinearIso() case default call fatalError(Here,'Unsupported simulation type requested') end select @@ -939,7 +1410,7 @@ end subroutine resetFluxesFlatIso !! Sets prevFlux to scalarFlux and zero's scalarFlux !! for linear sources with isotropic scattering !! - subroutine resetFluxesLinIso(self) + subroutine resetFluxesLinearIso(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx @@ -947,10 +1418,16 @@ subroutine resetFluxesLinIso(self) do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = 0.0_defFlt + self % prevX(idx) = self % scalarX(idx) + self % scalarX(idx) = 0.0_defFlt + self % prevY(idx) = self % scalarY(idx) + self % scalarY(idx) = 0.0_defFlt + self % prevZ(idx) = self % scalarZ(idx) + self % scalarZ(idx) = 0.0_defFlt end do !$omp end parallel do - end subroutine resetFluxesLinIso + end subroutine resetFluxesLinearIso !! !! Sets prevFlux to scalarFlux and zero's scalarFlux @@ -1184,7 +1661,7 @@ subroutine kill(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: i - ! Clean contents + ! Clean standard contents if(allocated(self % scalarFlux)) deallocate(self % scalarFlux) if(allocated(self % prevFlux)) deallocate(self % prevFlux) if(allocated(self % fluxScores)) deallocate(self % fluxScores) @@ -1198,6 +1675,21 @@ subroutine kill(self) if(allocated(self % cellFound)) deallocate(self % cellFound) if(allocated(self % cellPos)) deallocate(self % cellPos) + ! Clean LS contents + if(allocated(self % scalarX)) deallocate(self % scalarX) + if(allocated(self % scalarX)) deallocate(self % scalarY) + if(allocated(self % scalarX)) deallocate(self % scalarZ) + if(allocated(self % prevX)) deallocate(self % prevX) + if(allocated(self % prevY)) deallocate(self % prevY) + if(allocated(self % prevZ)) deallocate(self % prevZ) + if(allocated(self % sourceX)) deallocate(self % sourceX) + if(allocated(self % sourceY)) deallocate(self % sourceY) + if(allocated(self % sourceZ)) deallocate(self % sourceZ) + if(allocated(self % momMat)) deallocate(self % momMat) + if(allocated(self % momTracks)) deallocate(self % momTracks) + if(allocated(self % centroid)) deallocate(self % centroid) + if(allocated(self % centroidTracks)) deallocate(self % centroidTracks) + if(allocated(self % locks)) then do i = 1, self % nCells #ifdef _OPENMP diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index 3eaf242d9..482877aec 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -4,11 +4,32 @@ module constantsRR implicit none + ! Parameters to identify the simulation type + integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 + ! Parameter for when to skip a tiny volume real(defReal), parameter, public :: volume_tolerance = 1.0E-12 + + ! Parameter for when to ignore components of spatial moment matrices + ! or when the matrix is poorly conditioned + real(defReal), parameter, public :: condition_tolerance = 1.0E-7, & + det_tolerance = 1.0E-10 - ! Parameters to identify the simulation type - integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 + ! Parameters for indexing into matrices and spatial moments with linear sources + integer(shortInt), parameter :: x = 1, y = 2, z = 3, nDim = 3, & + xx = 1, xy = 2, xz = 3, & + yy = 4, yz = 5, zz = 6, & + matSize = 6 + + ! Parameters for deciding how to invert the moment matrix + integer(shortInt), parameter :: invertXYZ = 7, invertXY = 6, & + invertXZ = 5, invertYZ = 3, & + invertX = 4, invertY = 2, & + invertZ = 1 + + ! Convenient arithmetic parameters + real(defFlt), parameter :: one_two = real(HALF,defFlt), & + two_three = real(2.0_defFlt/3.0_defFlt,defFlt) contains diff --git a/RandomRayObjects/mathsRR_func.f90 b/RandomRayObjects/mathsRR_func.f90 index 829805675..7819940bf 100644 --- a/RandomRayObjects/mathsRR_func.f90 +++ b/RandomRayObjects/mathsRR_func.f90 @@ -4,8 +4,6 @@ module mathsRR_func !! This module contains maths used in random ray. !! First it has a function for efficiently computing an exponential !! for use in MoC implementations using a rational approximation. - !! This is based on the implementation given in Minray: - !! github.com/jtramm/minray/blob/master/cpu_srce/flux_attenuation_kernel.c !! I believe this originates from the M&C 2019 publication: !! "Adding a third level of parallelism to OpenMOC" !! @@ -18,18 +16,34 @@ module mathsRR_func implicit none private - public :: F1 + public :: expF1, expG, expG2 - ! Numerator coefficients in rational approximation + ! Numerator coefficients in F1 rational approximation real(defFlt), parameter :: c1n = -1.0000013559236386308, c2n = 0.23151368626911062025,& c3n = -0.061481916409314966140, c4n = 0.0098619906458127653020, c5n = -0.0012629460503540849940, & c6n = 0.00010360973791574984608, c7n = -0.000013276571933735820960 - ! Denominator coefficients in rational approximation + ! Denominator coefficients in F1 rational approximation real(defFlt), parameter :: c0d = ONE, c1d = -0.73151337729389001396, c2d = 0.26058381273536471371, & c3d = -0.059892419041316836940, c4d = 0.0099070188241094279067, c5d = -0.0012623388962473160860, & c6d = 0.00010361277635498731388, c7d = -0.000013276569500666698498 + ! Numerator coefficients in G rational approximation + real(defFlt), parameter :: d0n = 0.5, d1n = 0.176558112351595, d2n = 0.04041584305811143, & + d3n = 0.006178333902037397, d4n = 0.0006429894635552992 , d5n = 0.00006064409107557148 + + ! Denominator coefficients in G rational approximation + real(defFlt), parameter :: d0d = 1.0, d1d = 0.6864462055546078, d2d = 0.2263358514260129, & + d3d = 0.04721469893686252, d4d = 0.006883236664917246, d5d = 0.0007036272419147752 , d6d = 0.00006064409107557148 + + ! Coefficients for numerator in G2 rational approximation + real(defFlt), parameter :: g1n = -0.08335775885589858, g2n = -0.003603942303847604, & + g3n = 0.0037673183263550827, g4n = 0.00001124183494990467, g5n = 0.00016837426505799449 + + ! Coefficients for denominator in G2 rational approximation + real(defFlt), parameter :: g1d = 0.7454048371823628, g2d = 0.23794300531408347, & + g3d = 0.05367250964303789, g4d = 0.006125197988351906, g5d = 0.0010102514456857377 + contains !! @@ -37,7 +51,7 @@ module mathsRR_func !! Tau is the optical distance. !! F1 is a common name in MoC literature !! - elemental function F1(tau) result(x) + elemental function expF1(tau) result(x) real(defFlt), intent(in) :: tau real(defFlt) :: x real(defFlt) :: den, num @@ -65,7 +79,64 @@ elemental function F1(tau) result(x) x = -num / den - end function F1 + end function expF1 + + !! + !! Computes y = 1/x-(1-exp(-x))/x**2 using a 5/6th order rational approximation. + !! From OpenMOC. + !! Commonly referred to as G in MoC literature. Used to compute other exponentials. + !! + elemental function expG(tau) result(x) + real(defFlt), intent(in) :: tau + real(defFlt) :: x + real(defFlt) :: den, num + + x = tau + + den = d6d * x + d5d + den = den * x + d4d + den = den * x + d3d + den = den * x + d2d + den = den * x + d1d + den = den * x + d0d + + num = d5n * x + d4n + num = num * x + d3n + num = num * x + d2n + num = num * x + d1n + num = num * x + d0n + + x = num / den + + end function expG + + !! + !! Computes y = 2/3 - (1 + 2/x) * (1/x + 0.5 - (1 + 1/x) * (1-exp(-x)) / x) + !! using a 5/5th order rational approximation, + !! From OpenMoC. + !! + elemental function expG2(tau) result(x) + real(defFlt), intent(in) :: tau + real(defFlt) :: x + real(defFlt) :: den, num + + x = tau + + num = g5n*x + g4n + num = num*x + g3n + num = num*x + g2n + num = num*x + g1n + num = num*x + + ! Calculate denominator + den = g5d*x + g4d + den = den*x + g3d + den = den*x + g2d + den = den*x + g1d + den = den*x + 1.0_defFlt + + x = num / den + end function expG2 end module mathsRR_func diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 958c5ba8d..2dcbee0e1 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -15,7 +15,7 @@ module rayHandling_func ! Random ray modules use arraysRR_class, only : arraysRR use dataRR_class, only : dataRR - use mathsRR_func, only : F1 + use mathsRR_func, only : expF1, expG, expG2 ! Random ray - or a standard particle use particle_class, only : ray => particle @@ -34,7 +34,7 @@ module rayHandling_func private :: moveRay private :: checkRayLength private :: transportSweepFlatIso - private :: transportSweepLinIso + private :: transportSweepLinearIso private :: transportSweepLIFA private :: transportSweepFlatAni @@ -154,7 +154,7 @@ subroutine transportSweep(r, ints, nG, doCache, dead, termination, arrays) case (flatIso) call transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays) case (linearIso) - call transportSweepLinIso(r, ints, nG, doCache, dead, termination, arrays) + call transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arrays) case (flatAni) call transportSweepFlatAni(r, ints, nG, doCache, dead, termination, arrays) case (linearAni) @@ -183,8 +183,8 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays logical(defBool) :: activeRay, hitVacuum type(distCache) :: cache real(defFlt) :: lenFlt - real(defFlt), dimension(nG) :: attenuate, delta, fluxVec, tau - real(defFlt), pointer, dimension(:) :: scalarVec, sourceVec, totVec + real(defFlt), dimension(nG) :: attenuate, delta, angular, tau + real(defFlt), pointer, dimension(:) :: scalar, source, total XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -192,18 +192,18 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! Set initial angular flux to angle average of cell source cIdx = r % coords % uniqueID matIdx = r % coords % matIdx - call XSData % getTotalPointer(matIdx, totVec) + call XSData % getTotalPointer(matIdx, total) ! Catch for regions with voids ! Assumes these are defined as 'void' ! TODO: Use a more robust criterion, as for branching later if (matIdx <= XSData % getNMat()) then do g = 1, nG - fluxVec(g) = arrays % getSource(cIdx,g) / totVec(g) + angular(g) = arrays % getSource(cIdx,g) / total(g) end do else do g = 1, nG - fluxVec(g) = arrays % getPrevFlux(cIdx,g) + angular(g) = arrays % getPrevFlux(cIdx,g) end do end if @@ -220,7 +220,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays matIdx0 = matIdx ! Cache total cross section - call XSData % getTotalPointer(matIdx, totVec) + call XSData % getTotalPointer(matIdx, total) end if ! Set maximum flight distance and ensure ray is active @@ -237,7 +237,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays end if lenFlt = real(length,defFlt) - call arrays % getSourcePointer(cIdx, sourceVec) + call arrays % getSourcePointer(cIdx, source) ! Branch for voids etc ! TODO: Should use a better branching criterion. Maybe create it in data? @@ -246,20 +246,20 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays !$omp simd do g = 1, nG - tau(g) = totVec(g) * lenFlt - attenuate(g) = lenFlt * F1(tau(g)) - delta(g) = (totVec(g) * fluxVec(g) - sourceVec(g)) * attenuate(g) - fluxVec(g) = fluxVec(g) - delta(g) + tau(g) = total(g) * lenFlt + attenuate(g) = lenFlt * expF1(tau(g)) + delta(g) = (total(g) * angular(g) - source(g)) * attenuate(g) + angular(g) = angular(g) - delta(g) end do ! Accumulate to scalar flux if (activeRay) then call arrays % setLock(cIdx) - call arrays % getFluxPointer(cIdx, scalarVec) + call arrays % getFluxPointer(cIdx, scalar) !$omp simd do g = 1, nG - scalarVec(g) = scalarVec(g) + delta(g) + scalar(g) = scalar(g) + delta(g) end do call arrays % incrementVolume(cIdx, length) call arrays % unsetLock(cIdx) @@ -274,10 +274,10 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays if (activeRay) then call arrays % setLock(cIdx) - call arrays % getFluxPointer(cIdx, scalarVec) + call arrays % getFluxPointer(cIdx, scalar) !$omp simd do g = 1, nG - scalarVec(g) = scalarVec(g) + fluxVec(g) * lenFlt + scalar(g) = scalar(g) + angular(g) * lenFlt end do call arrays % incrementVolume(cIdx, length) call arrays % incrementLengthSquared(cIdx, length) @@ -288,7 +288,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays !$omp simd do g = 1, nG - fluxVec(g) = fluxVec(g) + sourceVec(g) * lenFlt + angular(g) = angular(g) + source(g) * lenFlt end do end if @@ -297,7 +297,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays if (hitVacuum) then !$omp simd do g = 1, nG - fluxVec(g) = 0.0_defFlt + angular(g) = 0.0_defFlt end do end if @@ -306,9 +306,9 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays end subroutine transportSweepFlatIso !! - !! Transport sweep for flat isotropic sources + !! Transport sweep for linear isotropic sources !! - subroutine transportSweepLinIso(r, ints, nG, doCache, dead, termination, arrays) + subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arrays) type(ray), intent(inout) :: r integer(longInt), intent(out) :: ints integer(shortInt), intent(in) :: nG @@ -316,8 +316,228 @@ subroutine transportSweepLinIso(r, ints, nG, doCache, dead, termination, arrays) real(defReal), intent(in) :: dead real(defReal), intent(in) :: termination class(arraysRR), pointer, intent(inout) :: arrays + class(dataRR), pointer :: XSData + class(geometryStd), pointer :: geom + integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 + real(defReal) :: totalLength, length, len2_12 + real(defReal), dimension(nDim) :: mid, r0, rC, mu0, rNorm + real(defReal), dimension(matSize) :: matScore + logical(defBool) :: activeRay, hitVacuum + type(distCache) :: cache + real(defFlt) :: lenFlt, lenFlt2_2 + real(defFlt), dimension(nDim) :: muFlt, r0NormFlt, rNormFlt + real(defFlt), dimension(nG) :: delta, angular, tau, flatQ, gradQ, & + F1, F2, angular0, G0, G1, G2, H, & + xInc, yInc, zInc + real(defFlt), pointer, dimension(:) :: scalar, source, total, & + scalarX, scalarY, scalarZ, & + sourceX, sourceY, sourceZ + + XSData => arrays % getDataPointer() + geom => arrays % getGeomPointer() + + ! Set initial angular flux to angle average of cell source + cIdx = r % coords % uniqueID + matIdx = r % coords % matIdx + call XSData % getTotalPointer(matIdx, total) + + ! Catch for regions with voids + ! Assumes these are defined as 'void' + ! TODO: Use a more robust criterion, as for branching later + if (matIdx <= XSData % getNMat()) then + do g = 1, nG + angular(g) = arrays % getSource(cIdx,g) / total(g) + end do + else + do g = 1, nG + angular(g) = arrays % getPrevFlux(cIdx,g) + end do + end if + + ints = 0 + matIdx0 = matIdx + totalLength = ZERO + activeRay = .false. + do while (totalLength < termination) + + ! Get ray coords for LS calculations + mu0 = r % dirGlobal() + r0 = r % rGlobal() + + ! Get material and cell the ray is moving through + matIdx = r % coords % matIdx + cIdx = r % coords % uniqueID + if (matIdx0 /= matIdx) then + matIdx0 = matIdx + + ! Cache total cross section + call XSData % getTotalPointer(matIdx, total) + end if + + ! Set maximum flight distance and ensure ray is active + call checkRayLength(totalLength, dead, termination, activeRay, length) + + ! Move ray + call moveRay(r, doCache, ints, geom, length, event, cache, hitVacuum) + totalLength = totalLength + length + + ! Calculate the track centre + rC = r0 + length * HALF * mu0 + + ! Set new cell's position + if (.not. arrays % found(cIdx)) then + call arrays % newFound(cIdx, rC) + end if + + call arrays % getSourcePointer(cIdx, source) + call arrays % getSourceXYZPointers(cIdx, sourceX, sourceY, sourceZ) + mid = arrays % getCentroid(cIdx) + + ! Compute the track centroid and entry point in local co-ordinates + ! Convert to floats for speed + rNorm = rC - mid + rNormFlt = real(rNorm,defFlt) + r0NormFlt = real(r0 - mid,defFlt) + muFlt = real(mu0,defFlt) + + ! Calculate source terms + !$omp simd aligned(sourceX, sourceY, sourceZ) + do g = 1, nG + flatQ(g) = rNormFlt(x) * sourceX(g) + flatQ(g) = flatQ(g) + rNormFlt(y) * sourceY(g) + flatQ(g) = flatQ(g) + rNormFlt(z) * sourceZ(g) + flatQ(g) = flatQ(g) + source(g) + + gradQ(g) = muFlt(x) * sourceX(g) + gradQ(g) = gradQ(g) + muFlt(y) * sourceY(g) + gradQ(g) = gradQ(g) + muFlt(z) * sourceZ(g) + end do + + lenFlt = real(length,defFlt) + + ! Compute exponentials necessary for angular flux update + !$omp simd + do g = 1, nG + tau(g) = max(total(g) * lenFlt, 1.0E-8) + end do + + !$omp simd + do g = 1, nG + G0(g) = expG(tau(g)) + end do + + !$omp simd + do g = 1, nG + F1(g) = 1.0_defFlt - tau(g) * G0(g) + end do + + !$omp simd + do g = 1, nG + !F2(g) = (G0(g) - F1(g) * one_two) * lenFlt + F2(g) = G0(g) - F1(g) * one_two + end do + + !$omp simd + do g = 1, nG + delta(g) = (tau(g) * angular(g) - lenFlt * flatQ(g)) * F1(g) & + - gradQ(g) * F2(g) * lenFlt * lenFlt + end do + + ! Create an intermediate flux variable for use in LS scores + !$omp simd + do g = 1, nG + angular0(g) = angular(g) + end do + + !$omp simd + do g = 1, nG + angular(g) = angular(g) - delta(g) + end do + + ! Accumulate to scalar flux + if (activeRay) then + + ! Precompute geometric info to keep it out of the lock + len2_12 = length * length / 12 + matScore(xx) = length * (rNorm(x) * rNorm(x) + mu0(x) * mu0(x) * len2_12) + matScore(xy) = length * (rNorm(x) * rNorm(y) + mu0(x) * mu0(y) * len2_12) + matScore(xz) = length * (rNorm(x) * rNorm(z) + mu0(x) * mu0(z) * len2_12) + matScore(yy) = length * (rNorm(y) * rNorm(y) + mu0(y) * mu0(y) * len2_12) + matScore(yz) = length * (rNorm(y) * rNorm(z) + mu0(y) * mu0(z) * len2_12) + matScore(zz) = length * (rNorm(z) * rNorm(z) + mu0(z) * mu0(z) * len2_12) + rC = rC * length + + ! Compute necessary exponentials outside of the lock + ! Follows those in Gunow + lenFlt2_2 = lenFlt * lenFlt * one_two + + !$omp simd + do g = 1, nG + H(g) = F1(g) - G0(g) + end do + + !$omp simd + do g = 1, nG + G1(g) = one_two - H(g) + end do + + !$omp simd + do g = 1, nG + G2(g) = expG2(tau(g)) + end do + + + ! Make some more condensed variables to help vectorisation + !$omp simd + do g = 1, nG + G1(g) = G1(g) * flatQ(g) * lenFlt + G2(g) = G2(g) * gradQ(g) * lenFlt2_2 + H(g) = H(g) * angular0(g) * tau(g) + H(g) = (G1(g) + G2(g) + H(g)) * lenFlt + flatQ(g) = flatQ(g) * lenFlt + delta(g) + end do + + !$omp simd + do g = 1, nG + xInc(g) = r0NormFlt(x) * flatQ(g) + muFlt(x) * H(g) + yInc(g) = r0NormFlt(y) * flatQ(g) + muFlt(y) * H(g) + zInc(g) = r0NormFlt(z) * flatQ(g) + muFlt(z) * H(g) + end do + + call arrays % setLock(cIdx) + + call arrays % getFluxPointer(cIdx, scalar) + call arrays % getFluxXYZPointers(cIdx, scalarX, scalarY, scalarZ) + + ! Update flux moments + !$omp simd aligned(scalar, scalarX, scalarY, scalarZ) + do g = 1, nG + scalar(g) = scalar(g) + delta(g) + scalarX(g) = scalarX(g) + xInc(g) + scalarY(g) = scalarY(g) + yInc(g) + scalarZ(g) = scalarZ(g) + zInc(g) + end do + + call arrays % incrementVolume(cIdx, length) + call arrays % incrementCentroid(cIdx, rC) + call arrays % incrementMoments(cIdx, matScore) + + call arrays % unsetLock(cIdx) + if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + + end if + + ! Check for a vacuum hit + if (hitVacuum) then + !$omp simd + do g = 1, nG + angular(g) = 0.0_defFlt + end do + end if + + end do - end subroutine transportSweepLinIso + end subroutine transportSweepLinearIso !! !! Transport sweep for LIFA sources From e78f8540543fc311fdac0350b650f3e6dacc00b3 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sun, 7 Jul 2024 13:08:14 +0100 Subject: [PATCH 04/15] Tweaks to LS --- .../randomRayPhysicsPackage_class.f90 | 17 +++++--- RandomRayObjects/arraysRR_class.f90 | 25 ++++++++++-- RandomRayObjects/constantsRR.f90 | 2 + RandomRayObjects/rayHandling_func.f90 | 39 +++++++++++++------ 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/PhysicsPackages/randomRayPhysicsPackage_class.f90 b/PhysicsPackages/randomRayPhysicsPackage_class.f90 index e6b9d47ec..e59fa740d 100644 --- a/PhysicsPackages/randomRayPhysicsPackage_class.f90 +++ b/PhysicsPackages/randomRayPhysicsPackage_class.f90 @@ -141,6 +141,8 @@ module randomRayPhysicsPackage_class integer(shortInt) :: active = 0 logical(defBool) :: cache = .false. real(defReal) :: rho = ZERO + logical(defBool) :: lin = .false. + integer(shortInt) :: ani = 0 character(pathLen) :: outputFile character(nameLen) :: outputFormat logical(defBool) :: plotResults = .false. @@ -190,8 +192,7 @@ subroutine init(self, dict, loud) class(randomRayPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict logical(defBool), intent(in), optional :: loud - integer(shortInt) :: seed_temp, ani - logical(defBool) :: lin + integer(shortInt) :: seed_temp integer(longInt) :: seed character(10) :: time character(8) :: date @@ -227,10 +228,10 @@ subroutine init(self, dict, loud) call dict % getOrDefault(self % rho, 'rho', ZERO) ! Use linear sources? - call dict % getOrDefault(lin, 'lin', .false.) + call dict % getOrDefault(self % lin, 'lin', .false.) ! Use anisotropic scattering? - call dict % getOrDefault(ani, 'ani', 0) + call dict % getOrDefault(self % ani, 'ani', 0) ! Read outputfile path call dict % getOrDefault(self % outputFile,'outputFile','./output') @@ -247,7 +248,7 @@ subroutine init(self, dict, loud) if (self % dead < ZERO) call fatalError(Here, 'Dead length must be positive.') if (self % termination <= self % dead) call fatalError(Here,& 'Ray termination length must be greater than ray dead length') - if (ani < 0 .or. ani > 3) call fatalError(Here, 'Anisotropy order must be between 0 and 3') + if (self % ani < 0 .or. self % ani > 3) call fatalError(Here, 'Anisotropy order must be between 0 and 3') ! Check whether there is a map for outputting fission rates ! If so, read and initialise the map to be used @@ -354,7 +355,7 @@ subroutine init(self, dict, loud) ! Initialise RR arrays and nuclear data call self % arrays % init(self % mgData, self % geom, & - self % pop * (self % termination - self % dead), self % rho, lin, ani, .false., self % loud) + self % pop * (self % termination - self % dead), self % rho, self % lin, self % ani, .false., self % loud) end subroutine init @@ -600,6 +601,8 @@ subroutine printSettings(self) print *, repeat("<>", MAX_COL/2) print *, "/\/\ RANDOM RAY EIGENVALUE CALCULATION /\/\" + if (self % lin) print *, "Using linear source" + if (self % ani > 0) print *, "Using anisotropy order "//numToChar(self % ani) print *, "Using "//numToChar(self % inactive)// " iterations for "& //"the inactive cycles" print *, "Using "//numToChar(self % active)// " iterations for "& @@ -641,6 +644,8 @@ subroutine kill(self) self % inactive = 0 self % active = 0 self % cache = .false. + self % lin = .false. + self % ani = 0 self % mapFission = .false. self % mapFlux = .false. self % plotResults = .false. diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index ea820b7be..cb2a7bf57 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -151,6 +151,7 @@ module arraysRR_class procedure :: getFluxXYZPointers procedure :: getSourceXYZPointers procedure :: getCentroid + procedure :: getVolumePointers ! Change individual elements of the type ! Predominantly for use in the transport sweep @@ -613,9 +614,9 @@ subroutine incrementCentroid(self, cIdx, rL) integer(shortInt) :: idx0, idx1 idx0 = nDim * (cIdx - 1) + 1 - idx1 = nDim * (cIdx - 1) + nDim + idx1 = nDim * cIdx self % centroidTracks(idx0:idx1) = self % centroidTracks(idx0:idx1) + rL - + end subroutine incrementCentroid !! @@ -630,11 +631,27 @@ subroutine incrementMoments(self, cIdx, mat) integer(shortInt) :: idx0, idx1 idx0 = matSize * (cIdx - 1) + 1 - idx1 = matSize * (cIdx - 1) + matSize + idx1 = matSize * cIdx self % momTracks(idx0:idx1) = self % momTracks(idx0:idx1) + mat end subroutine incrementMoments - + + !! + !! + !! + subroutine getVolumePointers(self, cIdx, volTracks, centroidTracks, momTracks) + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(:), pointer :: centroidTracks, momTracks + real(defReal), pointer :: volTracks + + volTracks => self % volumeTracks(cIdx) + centroidTracks => self % centroidTracks((nDim*(cIdx-1)+1):nDim*cIdx) + momTracks => self % momTracks((matSize*(cIdx-1)+1):matSize*cIdx) + + end subroutine getVolumePointers + + !! !! Check if a cell has been hit !! diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index 482877aec..e19e94d5c 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -31,6 +31,8 @@ module constantsRR real(defFlt), parameter :: one_two = real(HALF,defFlt), & two_three = real(2.0_defFlt/3.0_defFlt,defFlt) + real(defReal), parameter :: one_twelve = ONE / 12 + contains diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 2dcbee0e1..0c225da93 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -332,6 +332,8 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra real(defFlt), pointer, dimension(:) :: scalar, source, total, & scalarX, scalarY, scalarZ, & sourceX, sourceY, sourceZ + !real(defReal), pointer, dimension(:) :: cPtr, mPtr + !real(defReal), pointer :: vPtr XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -353,6 +355,10 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra angular(g) = arrays % getPrevFlux(cIdx,g) end do end if + + ! Obtain ray direction for LS calculations + mu0 = r % dirGlobal() + muFlt = real(mu0,defFlt) ints = 0 matIdx0 = matIdx @@ -360,8 +366,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra activeRay = .false. do while (totalLength < termination) - ! Get ray coords for LS calculations - mu0 = r % dirGlobal() + ! Get ray entry position for LS calculations r0 = r % rGlobal() ! Get material and cell the ray is moving through @@ -398,7 +403,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra rNorm = rC - mid rNormFlt = real(rNorm,defFlt) r0NormFlt = real(r0 - mid,defFlt) - muFlt = real(mu0,defFlt) ! Calculate source terms !$omp simd aligned(sourceX, sourceY, sourceZ) @@ -414,9 +418,10 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra end do lenFlt = real(length,defFlt) + lenFlt2_2 = lenFlt * lenFlt * one_two ! Compute exponentials necessary for angular flux update - !$omp simd + !$omp simd aligned(total) do g = 1, nG tau(g) = max(total(g) * lenFlt, 1.0E-8) end do @@ -433,14 +438,13 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra !$omp simd do g = 1, nG - !F2(g) = (G0(g) - F1(g) * one_two) * lenFlt - F2(g) = G0(g) - F1(g) * one_two + F2(g) = 2.0_defFlt * G0(g) - F1(g) end do !$omp simd do g = 1, nG delta(g) = (tau(g) * angular(g) - lenFlt * flatQ(g)) * F1(g) & - - gradQ(g) * F2(g) * lenFlt * lenFlt + - gradQ(g) * F2(g) * lenFlt2_2 end do ! Create an intermediate flux variable for use in LS scores @@ -458,7 +462,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra if (activeRay) then ! Precompute geometric info to keep it out of the lock - len2_12 = length * length / 12 + len2_12 = length * length * one_twelve matScore(xx) = length * (rNorm(x) * rNorm(x) + mu0(x) * mu0(x) * len2_12) matScore(xy) = length * (rNorm(x) * rNorm(y) + mu0(x) * mu0(y) * len2_12) matScore(xz) = length * (rNorm(x) * rNorm(z) + mu0(x) * mu0(z) * len2_12) @@ -469,7 +473,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra ! Compute necessary exponentials outside of the lock ! Follows those in Gunow - lenFlt2_2 = lenFlt * lenFlt * one_two !$omp simd do g = 1, nG @@ -486,7 +489,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra G2(g) = expG2(tau(g)) end do - ! Make some more condensed variables to help vectorisation !$omp simd do g = 1, nG @@ -505,7 +507,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra end do call arrays % setLock(cIdx) - + call arrays % getFluxPointer(cIdx, scalar) call arrays % getFluxXYZPointers(cIdx, scalarX, scalarY, scalarZ) @@ -521,6 +523,17 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra call arrays % incrementVolume(cIdx, length) call arrays % incrementCentroid(cIdx, rC) call arrays % incrementMoments(cIdx, matScore) + + !call arrays % getVolumePointers(cIdx, vPtr, cPtr, mPtr) + !vPtr = vPtr + length + !!$omp simd + !do g = 1,nDim + ! cPtr(g) = cPtr(g) + rC(g) + !end do + !!$omp simd + !do g = 1,nDim + ! mPtr(g) = mPtr(g) + matScore(g) + !end do call arrays % unsetLock(cIdx) if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) @@ -533,6 +546,10 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra do g = 1, nG angular(g) = 0.0_defFlt end do + + ! Update ray direction on reflecting from boundary + mu0 = r % dirGlobal() + muFlt = real(mu0,defFlt) end if end do From 35441dfde07a0a7d640d11e9e685d029cb8ef0fb Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Fri, 12 Jul 2024 22:22:23 +0100 Subject: [PATCH 05/15] Fixed source random ray - basic --- Geometry/Universes/latUniverse_class.f90 | 8 +- InputFiles/TRRM/C5G7_TRRM_coarse | 6 +- InputFiles/TRRM/XS_dog/absorberA | 16 + InputFiles/TRRM/XS_dog/absorberS | 14 + InputFiles/TRRM/XS_dog/voidA | 16 + InputFiles/TRRM/XS_dog/voidS | 14 + InputFiles/TRRM/dogleg_TRRM_absorb | 462 +++++++++++ InputFiles/TRRM/dogleg_TRRM_absorb_coarse | 229 ++++++ InputFiles/TRRM/dogleg_TRRM_scatter | 462 +++++++++++ InputFiles/TRRM/dogleg_TRRM_scatter_coarse | 229 ++++++ PhysicsPackages/CMakeLists.txt | 1 + .../fixedSourceRRPhysicsPackage_class.f90 | 662 ++++++++++++++++ .../physicsPackageFactory_func.f90 | 5 + .../randomRayPhysicsPackage_class.f90 | 9 +- RandomRayObjects/arraysRR_class.f90 | 719 ++++++++++++++---- RandomRayObjects/constantsRR.f90 | 4 +- RandomRayObjects/dataRR_class.f90 | 30 +- RandomRayObjects/rayHandling_func.f90 | 123 ++- 18 files changed, 2753 insertions(+), 256 deletions(-) create mode 100644 InputFiles/TRRM/XS_dog/absorberA create mode 100644 InputFiles/TRRM/XS_dog/absorberS create mode 100644 InputFiles/TRRM/XS_dog/voidA create mode 100644 InputFiles/TRRM/XS_dog/voidS create mode 100644 InputFiles/TRRM/dogleg_TRRM_absorb create mode 100644 InputFiles/TRRM/dogleg_TRRM_absorb_coarse create mode 100644 InputFiles/TRRM/dogleg_TRRM_scatter create mode 100644 InputFiles/TRRM/dogleg_TRRM_scatter_coarse create mode 100644 PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 diff --git a/Geometry/Universes/latUniverse_class.f90 b/Geometry/Universes/latUniverse_class.f90 index ca950e9cd..744432fda 100644 --- a/Geometry/Universes/latUniverse_class.f90 +++ b/Geometry/Universes/latUniverse_class.f90 @@ -41,6 +41,7 @@ module latUniverse_class !! type latUniverse; !! #origin (0.0 0.0 0.0); # !! #rotation (30.0 0.0 0.0); # + !! #offset 1; # !! shape (3 2 2); !! pitch (1.0 1.0 1.0); !! padMat ; @@ -82,6 +83,7 @@ module latUniverse_class real(defReal), dimension(3) :: a_bar = ZERO type(box) :: outline integer(shortInt) :: outLocalID = 0 + logical(defBool) :: offset = .true. contains ! Superclass procedures procedure :: init @@ -121,6 +123,9 @@ subroutine init(self, fill, dict, cells, surfs, mats) ! With: id, origin rotations... call self % setupBase(dict) + ! Perform offsets? + call dict % getOrDefault(self % offset, 'offset', .true.) + ! Load pitch call dict % get(temp, 'pitch') N = size(temp) @@ -332,7 +337,7 @@ function cellOffset(self, coords) result (offset) type(coord), intent(in) :: coords real(defReal), dimension(3) :: offset - if (coords % localID == self % outLocalID) then + if ((coords % localID == self % outLocalID) .or. .not. self % offset) then offset = ZERO else @@ -358,6 +363,7 @@ elemental subroutine kill(self) self % a_bar = ZERO call self % outline % kill() self % outLocalID = 0 + self % offset = .true. end subroutine kill diff --git a/InputFiles/TRRM/C5G7_TRRM_coarse b/InputFiles/TRRM/C5G7_TRRM_coarse index 6d3305496..fa48ce491 100644 --- a/InputFiles/TRRM/C5G7_TRRM_coarse +++ b/InputFiles/TRRM/C5G7_TRRM_coarse @@ -6,7 +6,7 @@ active 2600; inactive 1000; dead 20; termination 220; -plot 0; +plot 1; cache 1; XSdata mg; dataType mg; @@ -30,10 +30,10 @@ geometry { graph {type extended;} surfaces { - Domain { id 3; type box; origin (0.0 0.0 0.0); halfwidth (32.13 32.13 32.13);} + Domain { id 3; type box; origin (0.0 0.0 0.0); halfwidth (32.13 32.13 32.13);} } - cells { } + cells {} universes { root { id 1000; type rootUniverse; border 3; fill u<100>; } diff --git a/InputFiles/TRRM/XS_dog/absorberA b/InputFiles/TRRM/XS_dog/absorberA new file mode 100644 index 000000000..2494eb505 --- /dev/null +++ b/InputFiles/TRRM/XS_dog/absorberA @@ -0,0 +1,16 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +//0.05 //scatter case +0.10 // absorber case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + //0.05 // scatter case + 0.0 // absorber case +); + diff --git a/InputFiles/TRRM/XS_dog/absorberS b/InputFiles/TRRM/XS_dog/absorberS new file mode 100644 index 000000000..5f4b0c316 --- /dev/null +++ b/InputFiles/TRRM/XS_dog/absorberS @@ -0,0 +1,14 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +0.05 //scatter case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.05 // scatter case +); + diff --git a/InputFiles/TRRM/XS_dog/voidA b/InputFiles/TRRM/XS_dog/voidA new file mode 100644 index 000000000..adfd286ba --- /dev/null +++ b/InputFiles/TRRM/XS_dog/voidA @@ -0,0 +1,16 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +//0.5E-4 // scatter case +1.0E-4 // absorber case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + //0.5E-4 // scatter case + 0.0 // absorber case +); + diff --git a/InputFiles/TRRM/XS_dog/voidS b/InputFiles/TRRM/XS_dog/voidS new file mode 100644 index 000000000..5945ee09a --- /dev/null +++ b/InputFiles/TRRM/XS_dog/voidS @@ -0,0 +1,14 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +0.5E-4 // scatter case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.5E-4 // scatter case +); + diff --git a/InputFiles/TRRM/dogleg_TRRM_absorb b/InputFiles/TRRM/dogleg_TRRM_absorb new file mode 100644 index 000000000..cbddd28f0 --- /dev/null +++ b/InputFiles/TRRM/dogleg_TRRM_absorb @@ -0,0 +1,462 @@ +type fixedSourceRRPhysicsPackage; + +pop 10000; +active 2100; +inactive 0; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_absorb; + +integrate (sourceMat); +source { sourceMat ( 1.0 ); } + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.1111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.11111111111111111 1.111111111111111111); + shape ( 9 9 9 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.11111111111111 1.111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat sourceMat; + 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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidA; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + +} +} + + diff --git a/InputFiles/TRRM/dogleg_TRRM_absorb_coarse b/InputFiles/TRRM/dogleg_TRRM_absorb_coarse new file mode 100644 index 000000000..303c3a6c8 --- /dev/null +++ b/InputFiles/TRRM/dogleg_TRRM_absorb_coarse @@ -0,0 +1,229 @@ +type fixedSourceRRPhysicsPackage; + +lin 1; +pop 2000; +active 2000; +inactive 100; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_absorb_coarse; + +integrate (sourceMat); +source { sourceMat ( 1.0 ); } + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.333333333333333 3.33333333333333333 3.333333333333333333 ); + shape ( 3 3 3 ); + padMat absorber; + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.3333333333333333 3.3333333333333333333 3.33333333333333333333); + shape ( 3 3 3 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.3333333333333333333 3.333333333333333333 3.333333333333333 ); + shape ( 3 3 3 ); + padMat sourceMat; + 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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidA; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + +} +} + + diff --git a/InputFiles/TRRM/dogleg_TRRM_scatter b/InputFiles/TRRM/dogleg_TRRM_scatter new file mode 100644 index 000000000..8a9c18ef3 --- /dev/null +++ b/InputFiles/TRRM/dogleg_TRRM_scatter @@ -0,0 +1,462 @@ +type fixedSourceRRPhysicsPackage; +lin 0; +!pop 10000; +pop 3000; +active 2000; +inactive 100; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_scatter; + +source { sourceMat ( 1.0 ); } +integrate (sourceMat absorber); + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.1111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.11111111111111111 1.111111111111111111); + shape ( 9 9 9 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.11111111111111 1.111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidS; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + +} +} + + diff --git a/InputFiles/TRRM/dogleg_TRRM_scatter_coarse b/InputFiles/TRRM/dogleg_TRRM_scatter_coarse new file mode 100644 index 000000000..b281ea096 --- /dev/null +++ b/InputFiles/TRRM/dogleg_TRRM_scatter_coarse @@ -0,0 +1,229 @@ +type fixedSourceRRPhysicsPackage; + +lin 1; +pop 2000; +active 2500; +inactive 500; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_scatter_coarse; +volume 360000; + +source { sourceMat ( 1.0 ); } +integrate (sourceMat absorber); + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.333333333333333333 3.3333333333333333 3.33333333333333333 ); + shape ( 3 3 3 ); + padMat absorber; + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.33333333333333333333 3.333333333333333333 3.333333333333333333); + shape ( 3 3 3 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 3.3333333333333333333 3.3333333333333333333 3.3333333333333333333 ); + shape ( 3 3 3 ); + padMat sourceMat; + 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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidS; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + +} +} + + diff --git a/PhysicsPackages/CMakeLists.txt b/PhysicsPackages/CMakeLists.txt index 75e7a9e40..71ab46f88 100644 --- a/PhysicsPackages/CMakeLists.txt +++ b/PhysicsPackages/CMakeLists.txt @@ -7,6 +7,7 @@ add_sources( ./physicsPackage_inter.f90 ./vizPhysicsPackage_class.f90 ./rayVolPhysicsPackage_class.f90 ./randomRayPhysicsPackage_class.f90 + ./fixedSourceRRPhysicsPackage_class.f90 ) add_integration_tests(./Tests/randomRay_iTest.f90) diff --git a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 new file mode 100644 index 000000000..f3e7087e4 --- /dev/null +++ b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 @@ -0,0 +1,662 @@ +module fixedSourceRRPhysicsPackage_class + + use numPrecision + use universalVariables + use genericProcedures, only : fatalError, numToChar, printFishLineR + use hashFunctions_func, only : FNV_1 + use dictionary_class, only : dictionary + use outputFile_class, only : outputFile + use rng_class, only : RNG + use physicsPackage_inter, only : physicsPackage + + ! Timers + use timer_mod, only : registerTimer, timerStart, timerStop, & + timerTime, timerReset, secToChar + + ! Geometry + use geometry_inter, only : geometry + use geometryStd_class, only : geometryStd + use geometryReg_mod, only : gr_geomPtr => geomPtr, gr_geomIdx => geomIdx, & + gr_fieldIdx => fieldIdx, gr_fieldPtr => fieldPtr + use geometryFactory_func, only : new_geometry + + ! Nuclear Data + use nuclearDataReg_mod, only : ndReg_init => init, & + ndReg_getMatNames => getMatNames, & + ndReg_activate => activate, & + ndReg_kill => kill, & + ndReg_getNeutronMG => getNeutronMG + use mgNeutronDatabase_inter, only : mgNeutronDatabase + use baseMgNeutronDatabase_class, only : baseMgNeutronDatabase + use baseMgNeutronMaterial_class, only : baseMgNeutronMaterial, baseMgNeutronMaterial_CptrCast + + ! Visualisation + use visualiser_class, only : visualiser + + ! Tally map for fission rate + use tallyMap_inter, only : tallyMap + use tallyMapFactory_func, only : new_tallyMap + + ! Random ray specific modules + use dataRR_class, only : dataRR + use arraysRR_class, only : arraysRR + use rayHandling_func, only : transportSweep, initialiseRay + + ! Random ray - or a standard particle + use particle_class, only : ray => particle + + implicit none + private + + !! + !! Physics package to perform The Random Ray Method (TRRM) fixed source calculations + !! + !! TODO: introduce uncollided transport sweep + !! + !! Tracks rays across the geometry, attenuating their flux. After some dead length, + !! rays begin scoring to estimates of the scalar flux and volume. Each ray has a + !! uniform termination length, after which it is stopped and the next ray is tracked. + !! Once all rays have been tracked, a cycle concludes and fluxes, sources, and keff + !! are updated. + !! + !! Both inactive and active cycles occur, as in Monte Carlo eigenvalue calculations. + !! These can be terminated after a specified number of iterations or on reaching some + !! chosen convergence criterion (though the latter hasn't been implemented yet). + !! + !! Calculates relative volume of different materials in the problem by performing + !! random ray tracing in the geometry. The volume is normalised such that the total domain + !! volume is 1.0. + !! + !! IMPORTANT N.B.: Geometry type must be extended! Won't run if shrunk. + !! This is because spatial discretisation is determined by the number of unique cells in the + !! geometry. + !! Also, this is obviously for multi-group calculations only. + !! + !! Sample Input Dictionary: + !! PP { + !! type fixedSourceRRPhysicsPackage; + !! dead 10; // Dead length where rays do not score to scalar fluxes + !! termination 100; // Length a ray travels before it is terminated + !! rays 1000; // Number of rays to sample per iteration + !! inactive 100; // Number of convergence cycles + !! active 200; // Number of scoring cycles + !! #seed 86868;# // Optional RNG seed + !! #cache 1;# // Optionally use distance caching to accelerate ray tracing + !! #fissionMap {}# // Optionally output fission rates according to a given map + !! #fluxMap {}# // Optionally output one-group fluxes according to a given map + !! #plot 1;# // Optionally make VTK viewable plot of fluxes and uncertainties + !! #rho 0;# // Optional stabilisation for negative in-group scattering XSs + !! + !! geometry {} + !! nuclearData {} + !! } + !! + !! Private Members + !! geom -> Pointer to the geometry. + !! geomIdx -> Index of the geometry in geometry Registry. + !! rand -> Random number generator. + !! timerMain -> Index of the timer defined to measure calculation time. + !! mgData -> MG database. Calculation obviously cannot be run in CE. + !! nG -> Number of energy groups, kept for convenience. + !! nCells -> Number of unique cells in the geometry, kept for convenience. + !! + !! termination -> Distance a ray can travel before it is terminated + !! dead -> Distance a ray must travel before it becomes active + !! pop -> Number of rays to track per cycle + !! inactive -> Number of inactive cycles to perform + !! active -> Number of active cycles to perform + !! cache -> Logical check whether to use distance caching + !! outputFile -> Output file name + !! outputFormat-> Output file format + !! plotResults -> Plot results? + !! viz -> Output visualiser + !! mapFlux -> Output 1G flux across a given map? + !! fluxMap -> The map across which to output 1G flux results + !! + !! intersectionsTotal -> Total number of ray traces for the calculation + !! + !! Interface: + !! physicsPackage interface + !! + type, public, extends(physicsPackage) :: fixedSourceRRPhysicsPackage + private + ! Components + class(geometryStd), pointer :: geom + integer(shortInt) :: geomIdx = 0 + type(RNG) :: rand + type(arraysRR) :: arrays + type(dataRR) :: XSData + class(baseMgNeutronDatabase), pointer :: mgData => null() + integer(shortInt) :: nG = 0 + integer(shortInt) :: nCells = 0 + + ! Settings + real(defReal) :: termination = ZERO + real(defReal) :: dead = ZERO + integer(shortInt) :: pop = 0 + integer(shortInt) :: inactive = 0 + integer(shortInt) :: active = 0 + logical(defBool) :: cache = .false. + real(defReal) :: rho = ZERO + logical(defBool) :: lin = .false. + real(defReal) :: keff = ONE + character(pathLen) :: outputFile + character(nameLen) :: outputFormat + logical(defBool) :: plotResults = .false. + logical(defBool) :: printFlux = .false. + logical(defBool) :: printVolume = .false. + logical(defBool) :: printCells = .false. + type(visualiser) :: viz + logical(defBool) :: mapFlux = .false. + class(tallyMap), allocatable :: fluxMap + character(nameLen),dimension(:), allocatable :: intMatNames + real(defReal), dimension(:,:), allocatable :: samplePoints + character(nameLen),dimension(:), allocatable :: sampleNames + + ! Results space + integer(longInt) :: intersectionsTotal = 0 + + ! Timer bins + integer(shortInt) :: timerMain + integer(shortInt) :: timerTransport + real (defReal) :: time_transport = ZERO + real (defReal) :: CPU_time_start + real (defReal) :: CPU_time_end + + contains + ! Superclass procedures + procedure :: init + procedure :: run + procedure :: kill + + ! Private procedures + procedure, private :: cycles + procedure, private :: printResults + procedure, private :: printSettings + + end type fixedSourceRRPhysicsPackage + +contains + + !! + !! Initialise Physics Package from dictionary + !! + !! See physicsPackage_inter for details + !! + subroutine init(self, dict, loud) + class(fixedSourceRRPhysicsPackage), intent(inout) :: self + class(dictionary), intent(inout) :: dict + logical(defBool), intent(in), optional :: loud + integer(shortInt) :: seed_temp, n, nPoints + integer(longInt) :: seed + character(10) :: time + character(8) :: date + character(:),allocatable :: string + class(dictionary),pointer :: tempDict, graphDict + real(defReal), dimension(:), allocatable :: tempArray + class(mgNeutronDatabase),pointer :: db + character(nameLen) :: geomName, graphType, nucData + class(geometry), pointer :: geom + type(outputFile) :: test_out + character(nameLen),dimension(:), allocatable :: names + character(100), parameter :: Here = 'init (fixedSourceRRPhysicsPackage_class.f90)' + + call cpu_time(self % CPU_time_start) + + if (present(loud)) then + self % loud = loud + else + self % loud = .true. + end if + + ! Load settings + call dict % get( nucData, 'XSdata') + call dict % get(self % termination, 'termination') + call dict % get(self % dead, 'dead') + call dict % get(self % pop, 'pop') + call dict % get(self % active, 'active') + call dict % get(self % inactive, 'inactive') + call dict % getOrDefault(self % keff, 'keff', ONE) + + ! Perform distance caching? + call dict % getOrDefault(self % cache, 'cache', .false.) + + ! Stabilisation factor for negative in-group scattering + call dict % getOrDefault(self % rho, 'rho', ZERO) + + ! Use linear sources? + call dict % getOrDefault(self % lin, 'lin', .false.) + + ! Read outputfile path + 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) + call dict % getOrDefault(self % outputFormat, 'outputFormat', 'asciiMATLAB') + call test_out % init(self % outputFormat) + + ! Check settings + if (self % termination <= ZERO) call fatalError(Here, & + 'Ray termination distance (termination) is less than or equal to zero.') + if (self % pop < 1) call fatalError(Here, 'Must have 1 or more rays (pop).') + if (self % dead < ZERO) call fatalError(Here, 'Dead length must be positive.') + if (self % termination <= self % dead) call fatalError(Here,& + 'Ray termination length must be greater than ray dead length') + + ! Check whether there is a map for outputting one-group fluxes + ! If so, read and initialise the map to be used + if (dict % isPresent('fluxMap')) then + self % mapFlux = .true. + tempDict => dict % getDictPtr('fluxMap') + call new_tallyMap(self % fluxMap, tempDict) + else + self % mapFlux = .false. + end if + + ! Check for materials to integrate over + if (dict % isPresent('integrate')) then + call dict % get(names,'integrate') + + allocate(self % intMatNames(size(names))) + self % intMatNames = names + + end if + + ! Return flux values at sample points? + ! Store a set of points to return values at on concluding the simulation + if (dict % isPresent('samplePoints')) then + + tempDict => dict % getDictPtr('samplePoints') + call tempDict % keys(self % sampleNames) + nPoints = size(self % sampleNames) + allocate(self % samplePoints(3, nPoints)) + do n = 1, nPoints + + call tempDict % get(tempArray, self % sampleNames(n)) + if (size(tempArray) /= 3) call fatalError(Here, 'Sample points must be 3 dimensional') + self % samplePoints(:, n) = tempArray + + end do + + end if + + ! Register timer + self % timerMain = registerTimer('simulationTime') + self % timerTransport = registerTimer('transportTime') + + ! Initialise RNG + if( dict % isPresent('seed')) then + call dict % get(seed_temp,'seed') + else + ! Obtain time string and hash it to obtain random seed + call date_and_time(date, time) + string = date // time + call FNV_1(string,seed_temp) + end if + seed = seed_temp + call self % rand % init(seed) + + ! Build Nuclear Data + call ndReg_init(dict % getDictPtr("nuclearData")) + + ! Build geometry + tempDict => dict % getDictPtr('geometry') + geomName = 'randomRayGeom' + call new_geometry(tempDict, geomName, silent = .not. self % loud) + self % geomIdx = gr_geomIdx(geomName) + geom => gr_geomPtr(self % geomIdx) + + ! Ensure geometry is geometryStd + select type(geom) + type is (geometryStd) + self % geom => geom + class default + call fatalError(Here,'Unrecognised geometry type') + end select + + ! Ensure that geometry graph is extended + graphDict => tempDict % getDictPtr('graph') + call graphDict % get(graphType,'type') + if (graphType /= 'extended') call fatalError(Here,& + 'Geometry graph type must be "extended" for random ray calculations.') + + ! Activatee nuclear data + call ndReg_activate(P_NEUTRON_MG, nucData, self % geom % activeMats(), silent = .not. self % loud) + + ! Ensure that nuclear data is multi-group + db => ndReg_getNeutronMG() + if (.not. associated(db)) call fatalError(Here,& + 'No MG nuclear database was constructed') + + ! Ensure nuclear data is baseMgNeutronDatabase + select type(db) + type is (baseMgNeutronDatabase) + self % mgData => db + class default + call fatalError(Here,'Unrecognised MG database type') + end select + + ! Store number of energy groups for convenience + self % nG = self % mgData % nGroups() + + ! Call visualisation + if (dict % isPresent('viz')) then + if (self % loud) print *, "Initialising visualiser" + tempDict => dict % getDictPtr('viz') + call self % viz % init(geom, tempDict) + if (self % loud) print *, "Constructing visualisation" + call self % viz % makeViz() + call self % viz % kill() + endif + + ! Check for results plotting and initialise VTK + call dict % getOrDefault(self % plotResults,'plot',.false.) + if (self % plotResults) then + ! Initialise a visualiser to be used when results are available + if (self % loud) print *, "Initialising results visualiser" + tempDict => dict % getDictPtr('viz') + call self % viz % init(geom, tempDict) + if (self % loud) print *, "Constructing geometry visualisation" + call self % viz % initVTK() + end if + + ! Store number of cells in geometry for convenience + self % nCells = self % geom % numberOfCells() + + ! Read fixed source dictionary + tempDict => dict % getDictPtr('source') + + ! Initialise RR arrays and nuclear data + call self % arrays % init(self % mgData, self % geom, & + self % pop * (self % termination - self % dead), self % rho, self % lin, & + .false., self % loud, tempDict) + + ! Zeros the prevFlux - makes for a better initial guess than 1's in eigenvalue! + call self % arrays % resetFluxes() + + end subroutine init + + !! + !! Run calculation + !! + !! See physicsPackage_inter for details + !! + subroutine run(self) + class(fixedSourceRRPhysicsPackage), intent(inout) :: self + + if (self % loud) call self % printSettings() + call self % cycles() + call self % printResults() + + end subroutine run + + !! + !! Perform cycles of The Random Ray Method. + !! + !! Randomly places the ray starting point and direction uniformly. + !! Rays are tracked until they reach some specified termination length. + !! During tracking, fluxes are attenuated (and adjusted according to BCs), + !! scoring to fluxes and volume estimates when the ray has surpassed its + !! specified dead length. + !! + !! Inactive and active iterations occur, terminating subject either to + !! given criteria or when a fixed number of iterations has been passed. + !! + subroutine cycles(self) + class(fixedSourceRRPhysicsPackage), target, intent(inout) :: self + type(ray), save :: r + type(RNG), target, save :: pRNG + real(defReal) :: hitRate + real(defReal) :: ONE_KEFF, elapsed_T, end_T, & + T_toEnd, transport_T + logical(defBool) :: keepRunning, isActive + integer(shortInt) :: i, itInac, itAct, it + integer(longInt), save :: ints + integer(longInt) :: intersections + class(arraysRR), pointer :: arrayPtr + !$omp threadprivate(pRNG, r, ints) + + ! Reset and start timer + call timerReset(self % timerMain) + call timerStart(self % timerMain) + + arrayPtr => self % arrays + + ! Stopping criterion is on number of convergence iterations. + ! TODO: Make this on, e.g., entropy during inactive, followed by stochastic noise during active! + itInac = 0 + itAct = 0 + isActive = .false. + keepRunning = .true. + + ! Keep a fixed keff + ONE_KEFF = ONE / self % keff + + ! Power iteration + do while( keepRunning ) + + if (isActive) then + itAct = itAct + 1 + else + itInac = itInac + 1 + end if + it = itInac + itAct + + call arrayPtr % updateSource(ONE_KEFF) + + ! Reset and start transport timer + call timerReset(self % timerTransport) + call timerStart(self % timerTransport) + intersections = 0 + + !$omp parallel do schedule(dynamic) reduction(+:intersections) + do i = 1, self % pop + + ! Set seed + pRNG = self % rand + call pRNG % stride(i) + r % pRNG => pRNG + + ! Set ray attributes + call initialiseRay(r, arrayPtr) + + ! Transport ray until termination criterion met + call transportSweep(r, ints, self % nG, self % cache, self % dead, & + self % termination, arrayPtr) + intersections = intersections + ints + + end do + !$omp end parallel do + + self % intersectionsTotal = self % intersectionsTotal + intersections + + call timerStop(self % timerTransport) + + ! Update RNG on master thread + call self % rand % stride(self % pop + 1) + + ! Normalise flux estimate and combines with source + call arrayPtr % normaliseFluxAndVolume(it) + + ! Accumulate flux scores + if (isActive) call arrayPtr % accumulateFluxScores() + + ! Calculate proportion of cells that were hit + hitRate = arrayPtr % getCellHitRate() + call arrayPtr % wipeCellHits() + + ! Evaluate stopping criterion for active or inactive iterations + if (isActive) then + keepRunning = (itAct < self % active) + else + isActive = (itInac >= self % inactive) + end if + + ! Set previous iteration flux to scalar flux + ! and zero scalar flux + call arrayPtr % resetFluxes() + + ! Calculate times + call timerStop(self % timerMain) + elapsed_T = timerTime(self % timerMain) + transport_T = timerTime(self % timerTransport) + self % time_transport = self % time_transport + transport_T + + ! Predict time to end + end_T = real(self % active + self % inactive, defReal) * elapsed_T / it + T_toEnd = max(ZERO, end_T - elapsed_T) + + ! Display progress + if (self % loud) then + call printFishLineR(it) + print * + print *, 'Iteration: ', numToChar(it), ' of ', numToChar(self % active + self % inactive) + if(isActive) then + print *,'Active iterations' + else + print *,'Inactive iterations' + end if + print *, 'Cell hit rate: ', trim(numToChar(real(hitRate,defReal))) + print *, 'Elapsed time: ', trim(secToChar(elapsed_T)) + print *, 'End time: ', trim(secToChar(end_T)) + print *, 'Time to end: ', trim(secToChar(T_toEnd)) + print *, 'Time per integration (ns): ', & + trim(numToChar(transport_T*10**9/(self % nG * intersections))) + end if + + end do + + ! Finalise flux and keff scores + call arrayPtr % finaliseFluxScores(itAct) + + end subroutine cycles + + !! + !! Output calculation results to a file + !! + !! Args: + !! None + !! + subroutine printResults(self) + class(fixedSourceRRPhysicsPackage), target, intent(inout) :: self + type(outputFile), target :: out + character(nameLen) :: name + class(outputFile), pointer :: outPtr + class(visualiser), pointer :: vizPtr + + call out % init(self % outputFormat, filename = self % outputFile) + + name = 'seed' + call out % printValue(self % rand % getSeed(),name) + + name = 'pop' + call out % printValue(self % pop,name) + + name = 'Inactive_Cycles' + call out % printValue(self % inactive,name) + + name = 'Active_Cycles' + call out % printValue(self % active,name) + + call cpu_time(self % CPU_time_end) + name = 'Total_CPU_Time' + call out % printValue((self % CPU_time_end - self % CPU_time_start),name) + + name = 'Total_Transport_Time' + call out % printValue(self % time_transport,name) + + name = 'Time_Per_Integration' + call out % printValue(self % time_transport/(self % intersectionsTotal * self % nG),name) + + name = 'Clock_Time' + call out % printValue(timerTime(self % timerMain),name) + + outPtr => out + + ! Send fluxes to map output + if (self % mapFlux) call self % arrays % outputMap(outPtr, self % fluxMap, .false.) + + ! Output fluxes at a point + if (allocated(self % samplePoints)) call self % arrays % outputPointFluxes(outPtr, self % samplePoints, self % sampleNames) + + ! Output material integral fluxes + if (allocated(self % intMatNames)) call self % arrays % outputMaterialIntegrals(outptr, self % intMatNames) + + outPtr => null() + + ! Send all fluxes and SDs to VTK + vizPtr => self % viz + if (self % plotResults) call self % arrays % outputToVTK(vizPtr) + + end subroutine printResults + + !! + !! Print settings of the random ray calculation + !! + !! Args: + !! None + !! + subroutine printSettings(self) + class(fixedSourceRRPhysicsPackage), intent(in) :: self + + print *, repeat("<>", MAX_COL/2) + print *, "/\/\ RANDOM RAY FIXED SOURCE CALCULATION /\/\" + if (self % lin) print *, "Using linear source" + print *, "Using "//numToChar(self % inactive)// " iterations for "& + //"the inactive cycles" + print *, "Using "//numToChar(self % active)// " iterations for "& + //"the active cycles" + print * + print *, "Rays per cycle: "// numToChar(self % pop) + print *, "Ray dead length: "//numToChar(self % dead) + print *, "Ray termination length: "//numToChar(self % termination) + print *, "Initial RNG Seed: "// numToChar(self % rand % getSeed()) + print * + print *, "Number of cells in the geometry: "// numToChar(self % nCells) + print *, "Number of energy groups: "// numToChar(self % nG) + if (self % cache) print *, "Accelerated with distance caching" + print *, repeat("<>", MAX_COL/2) + + end subroutine printSettings + + !! + !! Return to uninitialised state + !! + subroutine kill(self) + class(fixedSourceRRPhysicsPackage), intent(inout) :: self + + ! Clean Nuclear Data, Geometry and visualisation + call ndreg_kill() + call self % viz % kill() + + ! Clean contents + self % geom => null() + self % geomIdx = 0 + self % timerMain = 0 + self % timerTransport = 0 + self % mgData => null() + self % nG = 0 + self % nCells = 0 + self % termination = ZERO + self % dead = ZERO + self % pop = 0 + self % inactive = 0 + self % active = 0 + self % cache = .false. + self % lin = .false. + self % mapFlux = .false. + self % plotResults = .false. + self % keff = ONE + call self % arrays % kill() + call self % XSData % kill() + if(allocated(self % fluxMap)) then + call self % fluxMap % kill() + deallocate(self % fluxMap) + end if + if(allocated(self % samplePoints)) deallocate(self % samplePoints) + if(allocated(self % sampleNames)) deallocate(self % sampleNames) + if(allocated(self % intMatNames)) deallocate(self % intMatNames) + + end subroutine kill + +end module fixedSourceRRPhysicsPackage_class diff --git a/PhysicsPackages/physicsPackageFactory_func.f90 b/PhysicsPackages/physicsPackageFactory_func.f90 index b041bb77a..c793453e3 100644 --- a/PhysicsPackages/physicsPackageFactory_func.f90 +++ b/PhysicsPackages/physicsPackageFactory_func.f90 @@ -16,6 +16,7 @@ module physicsPackageFactory_func use vizPhysicsPackage_class, only : vizPhysicsPackage use rayVolPhysicsPackage_class, only : rayVolPhysicsPackage use randomRayPhysicsPackage_class, only : randomRayPhysicsPackage + use fixedSourceRRPhysicsPackage_class, only : fixedSourceRRPhysicsPackage ! use dynamPhysicsPackage_class, only : dynamPhysicsPackage implicit none @@ -29,6 +30,7 @@ module physicsPackageFactory_func 'fixedSourcePhysicsPackage ',& 'vizPhysicsPackage ',& 'randomRayPhysicsPackage ',& + 'fixedSourceRRPhysicsPackage ',& 'rayVolPhysicsPackage '] !! @@ -65,6 +67,9 @@ function new_physicsPackage(dict) result(new) case('randomRayPhysicsPackage') allocate( randomRayPhysicsPackage :: new) + case('fixedSourceRRPhysicsPackage') + allocate( fixedSourceRRPhysicsPackage :: new) + case('rayVolPhysicsPackage') allocate( rayVolPhysicsPackage :: new) diff --git a/PhysicsPackages/randomRayPhysicsPackage_class.f90 b/PhysicsPackages/randomRayPhysicsPackage_class.f90 index e59fa740d..04c19ad08 100644 --- a/PhysicsPackages/randomRayPhysicsPackage_class.f90 +++ b/PhysicsPackages/randomRayPhysicsPackage_class.f90 @@ -142,7 +142,6 @@ module randomRayPhysicsPackage_class logical(defBool) :: cache = .false. real(defReal) :: rho = ZERO logical(defBool) :: lin = .false. - integer(shortInt) :: ani = 0 character(pathLen) :: outputFile character(nameLen) :: outputFormat logical(defBool) :: plotResults = .false. @@ -230,9 +229,6 @@ subroutine init(self, dict, loud) ! Use linear sources? call dict % getOrDefault(self % lin, 'lin', .false.) - ! Use anisotropic scattering? - call dict % getOrDefault(self % ani, 'ani', 0) - ! Read outputfile path call dict % getOrDefault(self % outputFile,'outputFile','./output') @@ -248,7 +244,6 @@ subroutine init(self, dict, loud) if (self % dead < ZERO) call fatalError(Here, 'Dead length must be positive.') if (self % termination <= self % dead) call fatalError(Here,& 'Ray termination length must be greater than ray dead length') - if (self % ani < 0 .or. self % ani > 3) call fatalError(Here, 'Anisotropy order must be between 0 and 3') ! Check whether there is a map for outputting fission rates ! If so, read and initialise the map to be used @@ -355,7 +350,7 @@ subroutine init(self, dict, loud) ! Initialise RR arrays and nuclear data call self % arrays % init(self % mgData, self % geom, & - self % pop * (self % termination - self % dead), self % rho, self % lin, self % ani, .false., self % loud) + self % pop * (self % termination - self % dead), self % rho, self % lin, .false., self % loud) end subroutine init @@ -602,7 +597,6 @@ subroutine printSettings(self) print *, repeat("<>", MAX_COL/2) print *, "/\/\ RANDOM RAY EIGENVALUE CALCULATION /\/\" if (self % lin) print *, "Using linear source" - if (self % ani > 0) print *, "Using anisotropy order "//numToChar(self % ani) print *, "Using "//numToChar(self % inactive)// " iterations for "& //"the inactive cycles" print *, "Using "//numToChar(self % active)// " iterations for "& @@ -645,7 +639,6 @@ subroutine kill(self) self % active = 0 self % cache = .false. self % lin = .false. - self % ani = 0 self % mapFission = .false. self % mapFlux = .false. self % plotResults = .false. diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index cb2a7bf57..429ddd189 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -68,9 +68,9 @@ module arraysRR_class !! prevX -> Array of previous x-spatial moments of scalar flux [nG * nCells] !! prevY -> Array of previous y-spatial moments of scalar flux [nG * nCells] !! prevZ -> Array of previous z-spatial moments of scalar flux [nG * nCells] - !! sourceX -> Array of source x-spatial moments of scalar flux [nG * nCells] - !! sourceY -> Array of source y-spatial moments of scalar flux [nG * nCells] - !! sourceZ -> Array of source z-spatial moments of scalar flux [nG * nCells] + !! sourceX -> Array of source x-spatial gradients of scalar flux [nG * nCells] + !! sourceY -> Array of source y-spatial gradients of scalar flux [nG * nCells] + !! sourceZ -> Array of source z-spatial gradients of scalar flux [nG * nCells] !! momMat -> Array of symmetric spatial moment matrices [nCells * matSize] !! momTracks -> Array of weighted tracks used to computer spatial moment matrices [nCells * matSize] !! centroid -> Array of cell centroid values [nCells * nDim] @@ -81,14 +81,15 @@ module arraysRR_class type, public :: arraysRR private ! Components - class(geometryStd), pointer :: geom => null() - type(dataRR) :: XSData - integer(shortInt) :: nG = 0 - integer(shortInt) :: nCells = 0 - real(defReal) :: lengthPerIt = ZERO - real(defFlt) :: rho = 0.0_defFlt - integer(shortInt) :: ani = 0 - integer(shortInt) :: simulationType = 0 + class(geometryStd), pointer :: geom => null() + type(dataRR) :: XSData + integer(shortInt) :: nG = 0 + integer(shortInt) :: nCells = 0 + real(defReal) :: lengthPerIt = ZERO + real(defFlt) :: rho = 0.0_defFlt + integer(shortInt) :: ani = 0 + integer(shortInt) :: simulationType = 0 + real(defReal) :: totalVolume = ONE ! Flux arrays real(defFlt), dimension(:), allocatable :: scalarFlux @@ -123,6 +124,10 @@ module arraysRR_class real(defReal), dimension(:), allocatable :: centroid real(defReal), dimension(:), allocatable :: centroidTracks + real(defReal), dimension(:,:), allocatable :: xScores + real(defReal), dimension(:,:), allocatable :: yScores + real(defReal), dimension(:,:), allocatable :: zScores + ! OMP locks integer(kind=omp_lock_kind), dimension(:), allocatable :: locks @@ -138,20 +143,25 @@ module arraysRR_class procedure :: getFluxPointer procedure :: getSourcePointer procedure :: getSource + procedure :: getFixedSource procedure :: getPrevFlux procedure :: getFluxScore procedure :: getFluxSD procedure :: getNG + procedure :: getVolume procedure :: getCellPos procedure :: hasHit procedure :: getCellHitRate procedure :: getSimulationType procedure :: found + procedure :: getFluxAtAPoint procedure :: getFluxXYZPointers procedure :: getSourceXYZPointers procedure :: getCentroid - procedure :: getVolumePointers + procedure :: getMomentMatrix + procedure :: getFluxMoments + procedure :: getFluxMomentSDs ! Change individual elements of the type ! Predominantly for use in the transport sweep @@ -176,7 +186,9 @@ module arraysRR_class ! Output procedures procedure :: outputMap procedure :: outputToVTK - + procedure :: outputMaterialIntegrals + procedure :: outputPointFluxes + ! Private procedures procedure, private :: initialiseFixedSource @@ -195,10 +207,18 @@ module arraysRR_class procedure, private :: sourceUpdateKernelLIFA procedure, private :: sourceUpdateKernelFlatAni + procedure, private :: accumulateFluxScoresFlat + procedure, private :: accumulateFluxScoresLinear + + procedure, private :: finaliseFluxScoresFlat + procedure, private :: finaliseFluxScoresLinear + procedure, private :: calculateKeffKernel procedure, private :: invertMatrix + procedure, private :: materialIntegral + end type arraysRR contains @@ -209,29 +229,36 @@ module arraysRR_class !! The object is fed sizes and requirements by the physics package. !! This will allocate the necessary arrays !! - subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, dictFS) + subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) class(arraysRR), intent(inout) :: self class(baseMgNeutronDatabase), pointer, intent(in) :: db class(geometryStd), pointer, intent(in) :: geom real(defReal), intent(in) :: lengthPerIt real(defReal), intent(in) :: rho logical(defBool), intent(in) :: lin - integer(shortInt), intent(in) :: ani logical(defBool), intent(in) :: doKinetics logical(defBool), intent(in) :: loud class(dictionary), pointer, intent(inout), optional :: dictFS - integer(shortInt) :: i + integer(shortInt) :: ani, i + real(defReal), dimension(6) :: bb character(100), parameter :: Here = 'init (arraysRR_class.f90)' - call self % XSData % init(db, doKinetics, ani, loud) + call self % XSData % init(db, doKinetics, loud) self % nG = self % XSdata % getNG() self % geom => geom self % nCells = self % geom % numberOfCells() self % lengthPerIt = lengthPerIt self % rho = real(rho, defFlt) - + + ! Assume bounding box of the geometry is filled (and a box) + ! Can this be relaxed in future? + bb = self % geom % bounds() + self % totalVolume = (bb(4) - bb(1)) * (bb(5) - bb(2)) * (bb(6) - bb(3)) + ! Set simulation type + ! TODO: read ani from nuclear data + ani = 0 if (.not. lin .and. ani == 0) then self % simulationType = flatIso elseif (lin .and. ani == 0) then @@ -272,7 +299,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di call self % initialiseFixedSource(dictFS) end if - ! TODO: allocate linear and anisotropic components, if present + ! Allocate linear components, if present if (lin) then allocate(self % scalarX(self % nCells * self % nG)) @@ -288,6 +315,9 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di allocate(self % momTracks(self % nCells * matSize)) allocate(self % centroid(self % nCells * nDim)) allocate(self % centroidTracks(self % nCells * nDim)) + allocate(self % xScores(2, self % nG * self % nCells)) + allocate(self % yScores(2, self % nG * self % nCells)) + allocate(self % zScores(2, self % nG * self % nCells)) self % scalarX = 0.0_defFlt self % scalarY = 0.0_defFlt @@ -302,9 +332,13 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, ani, doKinetics, loud, di self % momTracks = ZERO self % centroid = ZERO self % centroidTracks = ZERO + self % xScores = ZERO + self % yScores = ZERO + self % zScores = ZERO end if + ! TODO: allocate anisotropic components, if present if (ani > 0) then end if @@ -325,7 +359,7 @@ end subroutine init !! source strengths in each energy group and places these in the appropriate !! elements of the fixed source vector. !! - !! Also sets source material identities for future use with uncollided calculations. + !! Also sets source material identities for future use with uncollided calculations. !! subroutine initialiseFixedSource(self, dict) class(arraysRR), intent(inout) :: self @@ -465,7 +499,7 @@ subroutine getSourcePointer(self, cIdx, sourceVec) end subroutine getSourcePointer !! - !! Return pointers to the source moment vectors for a given cell + !! Return pointers to the source gradient vectors for a given cell !! subroutine getSourceXYZPointers(self, cIdx, xVec, yVec, zVec) class(arraysRR), intent(in), target :: self @@ -483,7 +517,6 @@ subroutine getSourceXYZPointers(self, cIdx, xVec, yVec, zVec) end subroutine getSourceXYZPointers - !! !! Return source value given cell and group !! @@ -497,6 +530,24 @@ function getSource(self, cIdx, g) result(src) end function getSource + !! + !! Return fixed source value given cell and group + !! + function getFixedSource(self, cIdx, g) result(src) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defFlt) :: src + + if (allocated(self % fixedSource)) then + src = self % fixedSource(self % nG * (cIdx - 1) + g) + else + src = 0.0_defFlt + end if + + end function getFixedSource + + !! !! Return previous flux value given cell and group !! @@ -536,6 +587,53 @@ function getFluxSD(self, cIdx, g) result(flux) flux = self % fluxScores(2, self % nG * (cIdx - 1) + g) end function getFluxSD + + !! + !! Return final flux moment values given cell and group + !! + function getFluxMoments(self, cIdx, g) result(flux) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defReal), dimension(3) :: flux + integer(shortInt) :: idx + + idx = self % nG * (cIdx - 1) + g + flux(1) = self % xScores(1, idx) + flux(2) = self % yScores(1, idx) + flux(3) = self % zScores(1, idx) + + end function getFluxMoments + + !! + !! Return final flux moment standard deviations given cell and group + !! Will return square of moment scores if called before finaliseFluxScores + !! + function getFluxMomentSDs(self, cIdx, g) result(fluxSD) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + integer(shortInt), intent(in) :: g + real(defReal), dimension(3) :: fluxSD + integer(shortInt) :: idx + + idx = self % nG * (cIdx - 1) + g + fluxSD(1) = self % xScores(2, idx) + fluxSD(2) = self % yScores(2, idx) + fluxSD(3) = self % zScores(2, idx) + + end function getFluxMomentSDs + + !! + !! Return volume given cell ID + !! + function getVolume(self, cIdx) result(vol) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal) :: vol + + vol = self % volume(cIdx) + + end function getVolume !! !! Return cell position given cell ID @@ -559,11 +657,26 @@ function getCentroid(self, cIdx) result(cent) integer(shortInt) :: idx0, idx1 idx0 = nDim * (cIdx - 1) + 1 - idx1 = nDim * (cIdx - 1) + nDim + idx1 = nDim * cIdx cent = self % centroid(idx0:idx1) end function getCentroid + !! + !! Return moment matrix given cell ID + !! + function getMomentMatrix(self, cIdx) result(mat) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(matSize) :: mat + integer(shortInt) :: idx0, idx1 + + idx0 = matSize * (cIdx - 1) + 1 + idx1 = matSize * cIdx + mat = self % momMat(idx0:idx1) + + end function getMomentMatrix + !! !! Return the simulation type !! @@ -588,7 +701,6 @@ subroutine incrementVolume(self, cIdx, length) end subroutine incrementVolume - !! !! Increment the sum of length squared in cell cIdx. !! Assumes this is being called inside a lock for thread privacy. @@ -636,22 +748,6 @@ subroutine incrementMoments(self, cIdx, mat) end subroutine incrementMoments - !! - !! - !! - subroutine getVolumePointers(self, cIdx, volTracks, centroidTracks, momTracks) - class(arraysRR), intent(in), target :: self - integer(shortInt), intent(in) :: cIdx - real(defReal), dimension(:), pointer :: centroidTracks, momTracks - real(defReal), pointer :: volTracks - - volTracks => self % volumeTracks(cIdx) - centroidTracks => self % centroidTracks((nDim*(cIdx-1)+1):nDim*cIdx) - momTracks => self % momTracks((matSize*(cIdx-1)+1):matSize*cIdx) - - end subroutine getVolumePointers - - !! !! Check if a cell has been hit !! @@ -884,57 +980,43 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Save effort by skipping normalisation if volume is too small if (vol < volume_tolerance) then do g = 1, self % nG - idx = self % nG * (cIdx - 1) + g + idx = self % nG * (cIdx - 1) + g self % scalarFlux(idx) = 0.0_defFlt self % scalarX(idx) = 0.0_defFlt self % scalarY(idx) = 0.0_defFlt self % scalarZ(idx) = 0.0_defFlt end do + self % centroid((dIdx + x):(dIdx + z)) = ZERO + self % momMat((mIdx + xx):(mIdx + zz)) = ZERO cycle end if - if (self % volume(cIdx) > volume_tolerance) then - invVol = ONE / self % volumeTracks(cIdx) + invVol = ONE / self % volumeTracks(cIdx) - ! Update centroids - self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol - self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol - self % centroid(dIdx + z) = self % centroidTracks(dIdx + z) * invVol + ! Update centroids + self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol + self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol + self % centroid(dIdx + z) = self % centroidTracks(dIdx + z) * invVol - ! Update spatial moments - self % momMat(mIdx + xx) = self % momTracks(mIdx + xx) * invVol - self % momMat(mIdx + xy) = self % momTracks(mIdx + xy) * invVol - self % momMat(mIdx + xz) = self % momTracks(mIdx + xz) * invVol - self % momMat(mIdx + yy) = self % momTracks(mIdx + yy) * invVol - self % momMat(mIdx + yz) = self % momTracks(mIdx + yz) * invVol - self % momMat(mIdx + zz) = self % momTracks(mIdx + zz) * invVol - - else - self % centroid(dIdx + x) = ZERO - self % centroid(dIdx + y) = ZERO - self % centroid(dIdx + z) = ZERO + ! Update spatial moments + self % momMat(mIdx + xx) = self % momTracks(mIdx + xx) * invVol + self % momMat(mIdx + xy) = self % momTracks(mIdx + xy) * invVol + self % momMat(mIdx + xz) = self % momTracks(mIdx + xz) * invVol + self % momMat(mIdx + yy) = self % momTracks(mIdx + yy) * invVol + self % momMat(mIdx + yz) = self % momTracks(mIdx + yz) * invVol + self % momMat(mIdx + zz) = self % momTracks(mIdx + zz) * invVol - self % momMat(mIdx + xx) = ZERO - self % momMat(mIdx + xy) = ZERO - self % momMat(mIdx + xz) = ZERO - self % momMat(mIdx + yy) = ZERO - self % momMat(mIdx + yz) = ZERO - self % momMat(mIdx + zz) = ZERO - - end if - call self % XSData % getTotalPointer(matIdx, total) norm_V = real(norm / vol, defFlt) - + do g = 1, self % nG idx = self % nG * (cIdx - 1) + g - if (vol > volume_tolerance) then - self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - self % scalarX(idx) = self % scalarX(idx) * norm_V - self % scalarY(idx) = self % scalarY(idx) * norm_V - self % scalarZ(idx) = self % scalarZ(idx) * norm_V - end if + + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V + self % scalarX(idx) = self % scalarX(idx) * norm_V + self % scalarY(idx) = self % scalarY(idx) * norm_V + self % scalarZ(idx) = self % scalarZ(idx) * norm_V ! Apply the standard MoC post-sweep treatment and ! stabilisation for negative XSs @@ -944,9 +1026,6 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarX(idx) = self % scalarX(idx) / total(g) self % scalarY(idx) = self % scalarY(idx) / total(g) self % scalarZ(idx) = self % scalarZ(idx) / total(g) - !self % scalarX(idx) = 0.0_defFlt - !self % scalarY(idx) = 0.0_defFlt - !self % scalarZ(idx) = 0.0_defFlt ! Presumes non-zero total XS sigGG = self % XSData % getScatterXS(matIdx, g, g) @@ -1044,6 +1123,9 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) do g = 1, self % nG idx = baseIdx + g self % source(idx) = 0.0_defFlt + if (allocated(self % fixedSource)) then + self % source(idx) = self % source(idx) + self % fixedSource(idx) + end if end do return end if @@ -1100,22 +1182,38 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) real(defFlt) :: scatter, xScatter, yScatter, zScatter, & fission, xFission, yFission, zFission, & xSource, ySource, zSource - real(defFlt) :: invMxx, invMxy, invMxz, invMyy, invMyz, invMzz + real(defFlt), dimension(matSize) :: invM real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 real(defFlt), pointer, dimension(:) :: fluxVec, xFluxVec, yFluxVec, zFluxVec - ! invert moment matrices - call self % invertMatrix(cIdx, invMxx, invMxy, invMxz, invMyy, invMyz, invMzz) + ! Invert moment matrix + invM = self % invertMatrix(cIdx) ! Identify material matIdx = self % geom % geom % graph % getMatFromUID(cIdx) + + ! Guard against void cells + if (matIdx > self % XSData % getNMat()) then + baseIdx = self % nG * (cIdx - 1) + do g = 1, self % nG + idx = baseIdx + g + self % source(idx) = 0.0_defFlt + if (allocated(self % fixedSource)) then + self % source(idx) = self % source(idx) + self % fixedSource(idx) + end if + self % sourceX(idx) = 0.0_defFlt + self % sourceY(idx) = 0.0_defFlt + self % sourceZ(idx) = 0.0_defFlt + end do + return + end if ! Obtain XSs call self % XSData % getProdPointers(matIdx, nuFission, scatterXS, chi) baseIdx = self % nG * (cIdx - 1) - fluxVec => self % prevFlux((baseIdx+1):(baseIdx + self % nG)) + fluxVec => self % prevFlux((baseIdx + 1):(baseIdx + self % nG)) xFluxVec => self % prevX((baseIdx + 1):(baseIdx + self % nG)) yFluxVec => self % prevY((baseIdx + 1):(baseIdx + self % nG)) zFluxVec => self % prevZ((baseIdx + 1):(baseIdx + self % nG)) @@ -1126,7 +1224,7 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) yFission = 0.0_defFlt zFission = 0.0_defFlt - !$omp simd reduction(+:fission, xFission, yFission, zFission) aligned(fluxVec, xFluxVec, yFluxVec, zFluxVec, nuFission) + !$omp simd reduction(+:fission, xFission, yFission, zFission) do gIn = 1, self % nG fission = fission + fluxVec(gIn) * nuFission(gIn) xFission = xFission + xFluxVec(gIn) * nuFission(gIn) @@ -1163,17 +1261,20 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) idx = baseIdx + g self % source(idx) = chi(g) * fission + scatter + if (allocated(self % fixedSource)) then + self % source(idx) = self % source(idx) + self % fixedSource(idx) + end if xSource = chi(g) * xFission + xScatter ySource = chi(g) * yFission + yScatter zSource = chi(g) * zFission + zScatter ! Calculate source gradients by inverting the moment matrix - self % sourceX(baseIdx + g) = invMxx * xSource + & - invMxy * ySource + invMxz * zSource - self % sourceY(baseIdx + g) = invMxy * xSource + & - invMyy * ySource + invMyz * zSource - self % sourceZ(baseIdx + g) = invMxz * xSource + & - invMyz * ySource + invMzz * zSource + self % sourceX(idx) = invM(xx) * xSource + & + invM(xy) * ySource + invM(xz) * zSource + self % sourceY(idx) = invM(xy) * xSource + & + invM(yy) * ySource + invM(yz) * zSource + self % sourceZ(idx) = invM(xz) * xSource + & + invM(yz) * ySource + invM(zz) * zSource end do @@ -1204,12 +1305,13 @@ end subroutine sourceUpdateKernelLIFA !! !! Inverts the spatial moment matrix for use in linear source calculations. !! - subroutine invertMatrix(self, cIdx, invMxx, invMxy, invMxz, invMyy, invMyz, invMzz) + function invertMatrix(self, cIdx) result(invM) class(arraysRR), target, intent(in) :: self integer(shortInt), intent(in) :: cIdx - real(defFlt), intent(out) :: invMxx, invMxy, invMxz, invMyy, invMyz, invMzz + real(defFlt), dimension(matSize) :: invM integer(shortInt) :: condX, condY, condZ, inversionTest - real(defReal) :: det, one_det + real(defReal) :: det + real(defFlt) :: one_det associate(momVec => self % momMat(((cIdx - 1) * matSize + 1):(cIdx * matSize))) @@ -1226,103 +1328,64 @@ subroutine invertMatrix(self, cIdx, invMxx, invMxy, invMxz, invMyy, invMyz, invM ! Map conditions to test variable inversionTest = condX * 4 + condY * 2 + condZ + invM = 0.0_defFlt select case(inversionTest) case(invertXYZ) det = momVec(xx) * (momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz)) & - - momVec(yy) * momVec(xz) * momVec(xz) - momVec(zz) * momVec(xy) * momVec(xy) & + - momVec(yy) * momVec(xz) * momVec(xz) & + - momVec(zz) * momVec(xy) * momVec(xy) & + 2 * momVec(xy) * momVec(xz) * momVec(yz) - one_det = ONE/det - invMxx = real(one_det * (momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz)),defFlt) - invMxy = real(one_det * (momVec(xz) * momVec(yz) - momVec(xy) * momVec(zz)),defFlt) - invMxz = real(one_det * (momVec(xy) * momVec(yz) - momVec(yy) * momVec(xz)),defFlt) - invMyy = real(one_det * (momVec(xx) * momVec(zz) - momVec(xz) * momVec(xz)),defFlt) - invMyz = real(one_det * (momVec(xy) * momVec(xz) - momVec(xx) * momVec(yz)),defFlt) - invMzz = real(one_det * (momVec(xx) * momVec(yy) - momVec(xy) * momVec(xy)),defFlt) + invM(xx) = real(momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz),defFlt) + invM(xy) = real(momVec(xz) * momVec(yz) - momVec(xy) * momVec(zz),defFlt) + invM(xz) = real(momVec(xy) * momVec(yz) - momVec(yy) * momVec(xz),defFlt) + invM(yy) = real(momVec(xx) * momVec(zz) - momVec(xz) * momVec(xz),defFlt) + invM(yz) = real(momVec(xy) * momVec(xz) - momVec(xx) * momVec(yz),defFlt) + invM(zz) = real(momVec(xx) * momVec(yy) - momVec(xy) * momVec(xy),defFlt) case(invertYZ) det = momVec(yy) * momVec(zz) - momVec(yz) * momVec(yz) - one_det = ONE/det - invMxx = 0.0_defFlt - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = real(one_det * momVec(zz),defFlt) - invMyz = real(-one_det * momVec(yz),defFlt) - invMzz = real(one_det * momVec(yy),defFlt) + invM(yy) = real(momVec(zz),defFlt) + invM(yz) = real(-momVec(yz),defFlt) + invM(zz) = real(momVec(yy),defFlt) case(invertXY) det = momVec(xx) * momVec(yy) - momVec(xy) * momVec(xy) - one_det = ONE/det - invMxx = real(one_det * momVec(yy),defFlt) - invMxy = real(-one_det * momVec(xy),defFlt) - invMxz = 0.0_defFlt - invMyy = real(one_det * momVec(xx),defFlt) - invMyz = 0.0_defFlt - invMzz = 0.0_defFlt + invM(xx) = real(momVec(yy),defFlt) + invM(xy) = real(-momVec(xy),defFlt) + invM(yy) = real(momVec(xx),defFlt) case(invertXZ) det = momVec(xx) * momVec(zz) - momVec(xz) * momVec(xz) - one_det = ONE/det - invMxx = real(one_det * momVec(zz),defFlt) - invMxy = 0.0_defFlt - invMxz = real(-one_det * momVec(xz),defFlt) - invMyy = 0.0_defFlt - invMyz = 0.0_defFlt - invMzz = real(one_det * momVec(xx),defFlt) + invM(xx) = real(momVec(zz),defFlt) + invM(xz) = real(-momVec(xz),defFlt) + invM(zz) = real(momVec(xx),defFlt) case(invertX) det = momVec(xx) - one_det = ONE/det - invMxx = real(one_det,defFlt) - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = 0.0_defFlt - invMyz = 0.0_defFlt - invMzz = 0.0_defFLt + invM(xx) = 1.0_defFlt case(invertY) det = momVec(yy) - one_det = ONE/det - invMxx = 0.0_defFlt - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = real(one_det,defFlt) - invMyz = 0.0_defFlt - invMzz = 0.0_defFlt + invM(yy) = 1.0_defFlt case(invertZ) det = momVec(zz) - one_det = ONE/det - invMxx = 0.0_defFlt - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = 0.0_defFlt - invMyz = 0.0_defFlt - invMzz = real(one_det,defFlt) + invM(zz) = 1.0_defFlt case default - invMxx = 0.0_defFlt - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = 0.0_defFlt - invMyz = 0.0_defFlt - invMzz = 0.0_defFlt det = ONE end select + one_det = real(ONE/det, defFlt) + invM = invM * one_det + ! Check for zero determinant - if (abs(det) < det_tolerance) then - invMxx = 0.0_defFlt - invMxy = 0.0_defFlt - invMxz = 0.0_defFlt - invMyy = 0.0_defFlt - invMyz = 0.0_defFlt - invMzz = 0.0_defFlt - end if + if (abs(det) < det_tolerance) invM = 0.0_defFlt end associate - end subroutine invertMatrix + end function invertMatrix !! !! Calculate keff @@ -1431,7 +1494,7 @@ subroutine resetFluxesLinearIso(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do schedule(static) + !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = 0.0_defFlt @@ -1449,12 +1512,13 @@ end subroutine resetFluxesLinearIso !! !! Sets prevFlux to scalarFlux and zero's scalarFlux !! for flat sources with anisotropic scattering + !! TODO: add additional vectors of interest !! subroutine resetFluxesFlatAni(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do schedule(static) + !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = 0.0_defFlt @@ -1466,12 +1530,13 @@ end subroutine resetFluxesFlatAni !! !! Sets prevFlux to scalarFlux and zero's scalarFlux !! for linear sources with flat anisotropic scattering + !! TODO: add additional vectors of interest !! subroutine resetFluxesLIFA(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do schedule(static) + !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = 0.0_defFlt @@ -1480,11 +1545,28 @@ subroutine resetFluxesLIFA(self) end subroutine resetFluxesLIFA - !! !! Accumulate flux scores for stats !! subroutine accumulateFluxScores(self) + class(arraysRR), intent(inout) :: self + character(100), parameter :: Here = 'accumulateFLuxScores (arraysRR_class.f90)' + + select case(self % simulationType) + case(flatIso, flatAni) + call self % accumulateFluxScoresFlat() + case(linearIso, linearAni) + call self % accumulateFluxScoresLinear() + case default + call fatalError(Here,'Unsupported simulation type requested') + end select + + end subroutine accumulateFluxScores + + !! + !! Accumulate flux scores for stats + !! + subroutine accumulateFluxScoresFlat(self) class(arraysRR), intent(inout) :: self real(defReal), save :: flux integer(shortInt) :: idx @@ -1498,12 +1580,60 @@ subroutine accumulateFluxScores(self) end do !$omp end parallel do - end subroutine accumulateFluxScores + end subroutine accumulateFluxScoresFlat + + !! + !! Accumulate flux scores for stats + !! Includes linear components + !! + subroutine accumulateFluxScoresLinear(self) + class(arraysRR), intent(inout) :: self + real(defReal), save :: flux + integer(shortInt) :: idx + !$omp threadprivate(flux) + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + flux = real(self % scalarFlux(idx),defReal) + self % fluxScores(1, idx) = self % fluxScores(1, idx) + flux + self % fluxScores(2, idx) = self % fluxScores(2, idx) + flux * flux + flux = real(self % scalarX(idx),defReal) + self % xScores(1, idx) = self % xScores(1, idx) + flux + self % xScores(2, idx) = self % xScores(2, idx) + flux * flux + flux = real(self % scalarY(idx),defReal) + self % yScores(1, idx) = self % yScores(1, idx) + flux + self % yScores(2, idx) = self % yScores(2, idx) + flux * flux + flux = real(self % scalarZ(idx),defReal) + self % zScores(1, idx) = self % zScores(1, idx) + flux + self % zScores(2, idx) = self % zScores(2, idx) + flux * flux + end do + !$omp end parallel do + + end subroutine accumulateFluxScoresLinear + + !! + !! Finalise results + !! + subroutine finaliseFluxScores(self, it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + character(100), parameter :: Here = 'finaliseFLuxScores (arraysRR_class.f90)' + + select case(self % simulationType) + case(flatIso, flatAni) + call self % finaliseFluxScoresFlat(it) + case(linearIso, linearAni) + call self % finaliseFluxScoresLinear(it) + case default + call fatalError(Here,'Unsupported simulation type requested') + end select + + end subroutine finaliseFluxScores !! !! Finalise flux scores for stats !! - subroutine finaliseFluxScores(self,it) + subroutine finaliseFluxScoresFlat(self,it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it integer(shortInt) :: idx @@ -1530,7 +1660,70 @@ subroutine finaliseFluxScores(self,it) end do !$omp end parallel do - end subroutine finaliseFluxScores + end subroutine finaliseFluxScoresFlat + + !! + !! Finalise flux scores for stats + !! Includes linear components + !! + subroutine finaliseFluxScoresLinear(self,it) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + integer(shortInt) :: idx + real(defReal) :: N1, Nm1 + + if (it /= 1) then + Nm1 = 1.0_defReal/(it - 1) + else + Nm1 = 1.0_defReal + end if + N1 = 1.0_defReal/it + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) + self % fluxScores(1, idx) = self % fluxScores(1, idx) * N1 + self % fluxScores(2, idx) = self % fluxScores(2, idx) * N1 + self % fluxScores(2, idx) = Nm1 * (self % fluxScores(2, idx) - & + self % fluxScores(1, idx) * self % fluxScores(1, idx)) + if (self % fluxScores(2, idx) <= ZERO) then + self % fluxScores(2, idx) = ZERO + else + self % fluxScores(2, idx) = sqrt(self % fluxScores(2, idx)) + end if + + self % xScores(1, idx) = self % xScores(1, idx) * N1 + self % xScores(2, idx) = self % xScores(2, idx) * N1 + self % xScores(2, idx) = Nm1 * (self % xScores(2, idx) - & + self % xScores(1, idx) * self % xScores(1, idx)) + if (self % xScores(2, idx) <= ZERO) then + self % xScores(2, idx) = ZERO + else + self % xScores(2, idx) = sqrt(self % xScores(2, idx)) + end if + + self % yScores(1, idx) = self % yScores(1, idx) * N1 + self % yScores(2, idx) = self % yScores(2, idx) * N1 + self % yScores(2, idx) = Nm1 * (self % yScores(2, idx) - & + self % yScores(1, idx) * self % yScores(1, idx)) + if (self % yScores(2, idx) <= ZERO) then + self % yScores(2, idx) = ZERO + else + self % yScores(2, idx) = sqrt(self % yScores(2, idx)) + end if + + self % zScores(1, idx) = self % zScores(1, idx) * N1 + self % zScores(2, idx) = self % zScores(2, idx) * N1 + self % zScores(2, idx) = Nm1 * (self % zScores(2, idx) - & + self % zScores(1, idx) * self % zScores(1, idx)) + if (self % zScores(2, idx) <= ZERO) then + self % zScores(2, idx) = ZERO + else + self % zScores(2, idx) = sqrt(self % zScores(2, idx)) + end if + end do + !$omp end parallel do + + end subroutine finaliseFluxScoresLinear !! !! Outputs integral flux or fission rate when @@ -1561,7 +1754,7 @@ subroutine outputMap(self, out, map, doFission) !$omp parallel do reduction(+: res, resSD) do cIdx = 1, self % nCells - vol = self % volume(cIdx) + vol = self % volume(cIdx) * self % totalVolume if (vol < volume_tolerance) cycle ! Fudge a particle state to search tally map @@ -1656,13 +1849,33 @@ subroutine outputToVTK(self, viz) !$omp end parallel do call viz % addVTKData(resVec,name) end do + + if (allocated(self % fixedSource)) then + do g = 1, self % nG + name = 'fixedSource_'//numToChar(g) + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = real(self % getFixedSource(cIdx,g),defReal) + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + end do + end if ! Output final volume estimates - ! TODO: scale to be absolute, not relative name = 'volume' !$omp parallel do schedule(static) do cIdx = 1, self % nCells - resVec(cIdx) = self % volume(cIdx) + resVec(cIdx) = self % volume(cIdx) * self % totalVolume + end do + !$omp end parallel do + call viz % addVTKData(resVec,name) + + ! Output material IDs + name = 'material' + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + resVec(cIdx) = self % geom % geom % graph % getMatFromUID(cIdx) end do !$omp end parallel do call viz % addVTKData(resVec,name) @@ -1670,6 +1883,174 @@ subroutine outputToVTK(self, viz) call viz % finaliseVTK end subroutine outputToVTK + + !! + !! Output integrals over given materials + !! + subroutine outputMaterialIntegrals(self, out, matNames) + class(arraysRR), intent(in) :: self + class(outputFile), intent(inout) :: out + character(nameLen), dimension(:), intent(in) :: matNames + integer(shortInt) :: i, matIdx + character(nameLen) :: name + real(defReal) :: integral, intSD + + name = 'integral' + call out % startBlock(name) + + do i = 1, size(matNames) + + call out % startArray(matNames(i), [1]) + + ! Ensure name corresponds to a material present in the geometry + matIdx = self % XSData % getIdxFromName(matNames(i)) + + if (matIdx /= -1) then + call self % materialIntegral(matIdx, integral, intSD) + else + integral = ZERO + intSD = ZERO + print *,'WARNING: Material '//matNames(i)//' not found during integration.' + end if + + call out % addResult(integral, intSD) + call out % endArray() + + end do + call out % endBlock() + + end subroutine outputMaterialIntegrals + + !! + !! Perform an integral over a given material for all energies + !! + subroutine materialIntegral(self, matIdx, integral, intSD) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + real(defReal), intent(out) :: integral, intSD + integer(shortInt) :: cIdx + real(defReal), save :: vol + integer(shortInt), save :: mIdx, g + !$omp threadprivate(vol, mIdx, g) + + integral = ZERO + intSD = ZERO + + !$omp parallel do reduction(+: integral, intSD) + do cIdx = 1, self % nCells + + mIdx = self % geom % geom % graph % getMatFromUID(cIdx) + if (mIdx /= matIdx) cycle + + vol = self % volume(cIdx) * self % totalVolume + if (vol < volume_tolerance) cycle + + do g = 1, self % nG + integral = integral + self % getFluxScore(cIdx, g) * vol + + ! Neglects uncertainty in the volume estimate + intSD = intSD + self % getFluxSD(cIdx, g)**2 * vol * vol + end do + + end do + !$omp end parallel do + + if (intSD >= ZERO) intSD = sqrt(intSD) + if (abs(integral) > ZERO) intSD = intSD / abs(integral) + + + end subroutine materialIntegral + + !! + !! Output fluxes at given points + !! + subroutine outputPointFluxes(self, out, points, names) + class(arraysRR), intent(in) :: self + class(outputFile), intent(inout) :: out + real(defReal), dimension(:,:), intent(in) :: points + character(nameLen), dimension(:), intent(in) :: names + integer(shortInt) :: i + character(nameLen) :: name + real(defReal), dimension(self % nG) :: flux, fluxSD + character(100), parameter :: Here = 'outputPointFluxes (arraysRR_class.f90)' + + name = 'pointFlux' + call out % startBlock(name) + + ! Ensure points and names have the correction dimensions + if (size(points,1) /= 3) call fatalError(Here, 'Points are not 3D.') + if (size(points,2) /= size(names)) call fatalError(Here, & + 'Different numbers of sample points to sample names.') + + do i = 1, size(names) + + call out % startArray(names(i), [self % nG]) + call self % getFluxAtAPoint(points(:, i), flux, fluxSD) + call out % addResult(flux, fluxSD) + call out % endArray() + + end do + call out % endBlock() + + end subroutine outputPointFluxes + + !! + !! Returns the flux vector at a point in space + !! + subroutine getFluxAtAPoint(self, r, flux, fluxSD) + class(arraysRR), intent(in) :: self + real(defReal), dimension(3), intent(in) :: r + real(defReal), dimension(self % nG), intent(out) :: flux + real(defReal), dimension(self % nG), intent(out) :: fluxSD + integer(shortInt) :: g, matIdx, cIdx, i + real(defReal), dimension(3) :: mom, momSD, centroid, fluxGrad + real(defFlt), dimension(matSize) :: invM + + ! Identify cell at the given point + call self % geom % whatIsAt(matIdx, cIdx, r) + + if (cIdx > 0) then + do g = 1, self % nG + + flux(g) = self % getFluxScore(cIdx, g) + fluxSD(g) = self % getFluxSD(cIdx, g) + + ! Include linear moments if available + if ((self % simulationType == linearIso) .or. & + (self % simulationType == linearAni)) then + + fluxSD(g) = fluxSD(g) * fluxSD(g) + + mom = self % getFluxMoments(cIdx, g) + momSD = self % getFluxMomentSDs(cIdx, g) + centroid = self % getCentroid(cIdx) + invM = self % invertMatrix(cIdx) + + ! Get flux gradients + fluxGrad(x) = real(invM(xx) * mom(x) + invM(xy) * mom(y) + invM(xz) * mom(z), defReal) + fluxGrad(y) = real(invM(xy) * mom(x) + invM(yy) * mom(y) + invM(yz) * mom(z), defReal) + fluxGrad(z) = real(invM(xz) * mom(x) + invM(yz) * mom(y) + invM(zz) * mom(z), defReal) + + ! Note this will not correctly estimate uncertainty as moments are covariant + do i = 1, 3 + flux(g) = flux(g) + fluxGrad(i) * (r(i) - centroid(i)) + ! Not sure exactly how to propagate uncertainties - need to do some maths + fluxSD(g) = fluxSD(g) + momSD(i)**2 * (r(i) - centroid(i))**2 + end do + + if (fluxSD(g) > ZERO) fluxSD(g) = sqrt(fluxSD(g)) + + end if + + end do + + else + print *,'WARNING: No cell found at position '//numToChar(r) + flux = -ONE + fluxSD = -ONE + end if + + end subroutine getFluxAtAPoint !! !! Return to uninitialised state @@ -1706,6 +2087,9 @@ subroutine kill(self) if(allocated(self % momTracks)) deallocate(self % momTracks) if(allocated(self % centroid)) deallocate(self % centroid) if(allocated(self % centroidTracks)) deallocate(self % centroidTracks) + if(allocated(self % xScores)) deallocate(self % xScores) + if(allocated(self % yScores)) deallocate(self % yScores) + if(allocated(self % zScores)) deallocate(self % zScores) if(allocated(self % locks)) then do i = 1, self % nCells @@ -1724,6 +2108,7 @@ subroutine kill(self) self % rho = 0.0_defFlt self % simulationType = 0 self % ani = 0 + self % totalVolume = ZERO end subroutine kill diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index e19e94d5c..675401452 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -12,8 +12,8 @@ module constantsRR ! Parameter for when to ignore components of spatial moment matrices ! or when the matrix is poorly conditioned - real(defReal), parameter, public :: condition_tolerance = 1.0E-7, & - det_tolerance = 1.0E-10 + real(defReal), parameter, public :: condition_tolerance = 1.0E-10, & + det_tolerance = 1.0E-12 ! Parameters for indexing into matrices and spatial moments with linear sources integer(shortInt), parameter :: x = 1, y = 2, z = 3, nDim = 3, & diff --git a/RandomRayObjects/dataRR_class.f90 b/RandomRayObjects/dataRR_class.f90 index 7ec4ec101..1cb92d2b3 100644 --- a/RandomRayObjects/dataRR_class.f90 +++ b/RandomRayObjects/dataRR_class.f90 @@ -75,6 +75,7 @@ module dataRR_class procedure :: getNMat procedure :: getNPrec procedure :: getName + procedure :: getIdxFromName procedure :: isFissile ! Private procedures @@ -91,13 +92,12 @@ module dataRR_class !! Initialise necessary nuclear data. !! Can optionally include kinetic parameters. !! - subroutine init(self, db, doKinetics, aniOrder, loud) + subroutine init(self, db, doKinetics, loud) class(dataRR), intent(inout) :: self class(baseMgNeutronDatabase),pointer, intent(in) :: db logical(defBool), intent(in) :: doKinetics - integer(shortInt), intent(in) :: aniOrder logical(defBool), intent(in) :: loud - integer(shortInt) :: g, g1, m, matP1 + integer(shortInt) :: g, g1, m, matP1, aniOrder type(RNG) :: rand logical(defBool) :: fiss class(baseMgNeutronMaterial), pointer :: mat @@ -163,6 +163,8 @@ subroutine init(self, db, doKinetics, aniOrder, loud) end if ! Initialise higher-order scattering matrices + ! TODO: read anisotropy order from database + aniOrder = 0 if (aniOrder > 0) then print *,'Including anisotropic scattering data' call fatalError(Here,'Anisotropy not yet supported') @@ -255,12 +257,32 @@ end function getNPrec elemental function getName(self, matIdx) result(matName) class(dataRR), intent(in) :: self integer(shortInt), intent(in) :: matIdx + integer(shortInt) :: mIdx character(nameLen) :: matName - matName = self % names(matIdx) + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = matIdx + end if + matName = self % names(mIdx) end function getName + !! + !! Return the index of a material given its name + !! + elemental function getIdxFromName(self, matName) result(matIdx) + class(dataRR), intent(in) :: self + character(nameLen), intent(in) :: matName + integer(shortInt) :: matIdx + + do matIdx = 1, self % nMat + if (self % names(matIdx) == matName) return + end do + matIdx = -1 + + end function getIdxFromName !! !! Get scatter pointer diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 0c225da93..7eb831e4b 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -138,14 +138,14 @@ end subroutine checkRayLength !! Records the number of integrations/ray movements. !! subroutine transportSweep(r, ints, nG, doCache, dead, termination, arrays) - type(ray), intent(inout) :: r - integer(longInt), intent(out) :: ints - integer(shortInt), intent(in) :: nG - logical(defBool), intent(in) :: doCache - real(defReal), intent(in) :: dead - real(defReal), intent(in) :: termination - class(arraysRR), pointer, intent(inout) :: arrays - integer(shortInt) :: simType + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + integer(shortInt) :: simType character(100), parameter :: Here = 'transportSweep (rayHandling_func.f90)' simType = arrays % getSimulationType() @@ -169,22 +169,22 @@ end subroutine transportSweep !! Transport sweep for flat isotropic sources !! subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays) - type(ray), intent(inout) :: r - integer(longInt), intent(out) :: ints - integer(shortInt), intent(in) :: nG - logical(defBool), intent(in) :: doCache - real(defReal), intent(in) :: dead - real(defReal), intent(in) :: termination - class(arraysRR), pointer, intent(in) :: arrays - class(dataRR), pointer :: XSData - class(geometryStd), pointer :: geom - integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 - real(defReal) :: totalLength, length - logical(defBool) :: activeRay, hitVacuum - type(distCache) :: cache - real(defFlt) :: lenFlt - real(defFlt), dimension(nG) :: attenuate, delta, angular, tau - real(defFlt), pointer, dimension(:) :: scalar, source, total + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(in) :: arrays + class(dataRR), pointer :: XSData + class(geometryStd), pointer :: geom + integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 + real(defReal) :: totalLength, length + logical(defBool) :: activeRay, hitVacuum + type(distCache) :: cache + real(defFlt) :: lenFlt + real(defFlt), dimension(nG) :: attenuate, delta, angular, tau + real(defFlt), pointer, dimension(:) :: scalar, source, total XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -309,31 +309,29 @@ end subroutine transportSweepFlatIso !! Transport sweep for linear isotropic sources !! subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arrays) - type(ray), intent(inout) :: r - integer(longInt), intent(out) :: ints - integer(shortInt), intent(in) :: nG - logical(defBool), intent(in) :: doCache - real(defReal), intent(in) :: dead - real(defReal), intent(in) :: termination - class(arraysRR), pointer, intent(inout) :: arrays - class(dataRR), pointer :: XSData - class(geometryStd), pointer :: geom - integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 - real(defReal) :: totalLength, length, len2_12 - real(defReal), dimension(nDim) :: mid, r0, rC, mu0, rNorm - real(defReal), dimension(matSize) :: matScore - logical(defBool) :: activeRay, hitVacuum - type(distCache) :: cache - real(defFlt) :: lenFlt, lenFlt2_2 - real(defFlt), dimension(nDim) :: muFlt, r0NormFlt, rNormFlt - real(defFlt), dimension(nG) :: delta, angular, tau, flatQ, gradQ, & - F1, F2, angular0, G0, G1, G2, H, & - xInc, yInc, zInc - real(defFlt), pointer, dimension(:) :: scalar, source, total, & - scalarX, scalarY, scalarZ, & - sourceX, sourceY, sourceZ - !real(defReal), pointer, dimension(:) :: cPtr, mPtr - !real(defReal), pointer :: vPtr + type(ray), intent(inout) :: r + integer(longInt), intent(out) :: ints + integer(shortInt), intent(in) :: nG + logical(defBool), intent(in) :: doCache + real(defReal), intent(in) :: dead + real(defReal), intent(in) :: termination + class(arraysRR), pointer, intent(inout) :: arrays + class(dataRR), pointer :: XSData + class(geometryStd), pointer :: geom + integer(shortInt) :: matIdx, g, cIdx, event, matIdx0 + real(defReal) :: totalLength, length, len2_12 + real(defReal), dimension(nDim) :: mid, r0, rC, mu0, rNorm + real(defReal), dimension(matSize) :: matScore + logical(defBool) :: activeRay, hitVacuum + type(distCache) :: cache + real(defFlt) :: lenFlt, lenFlt2_2 + real(defFlt), dimension(nDim) :: muFlt, r0NormFlt, rNormFlt + real(defFlt), dimension(nG) :: delta, angular, tau, flatQ, gradQ, & + F1, F2, angular0, G0, G1, G2, H, & + xInc, yInc, zInc + real(defFlt), pointer, dimension(:) :: scalar, source, total, scalarX, & + scalarY, scalarZ, sourceX, sourceY, & + sourceZ XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -356,18 +354,16 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra end do end if - ! Obtain ray direction for LS calculations - mu0 = r % dirGlobal() - muFlt = real(mu0,defFlt) - ints = 0 matIdx0 = matIdx totalLength = ZERO activeRay = .false. do while (totalLength < termination) - ! Get ray entry position for LS calculations + ! Get ray entry position and direction for LS calculations r0 = r % rGlobal() + mu0 = r % dirGlobal() + muFlt = real(mu0,defFlt) ! Get material and cell the ray is moving through matIdx = r % coords % matIdx @@ -421,7 +417,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra lenFlt2_2 = lenFlt * lenFlt * one_two ! Compute exponentials necessary for angular flux update - !$omp simd aligned(total) + !$omp simd do g = 1, nG tau(g) = max(total(g) * lenFlt, 1.0E-8) end do @@ -455,7 +451,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra !$omp simd do g = 1, nG - angular(g) = angular(g) - delta(g) + angular(g) = angular(g) - delta(g) end do ! Accumulate to scalar flux @@ -524,17 +520,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra call arrays % incrementCentroid(cIdx, rC) call arrays % incrementMoments(cIdx, matScore) - !call arrays % getVolumePointers(cIdx, vPtr, cPtr, mPtr) - !vPtr = vPtr + length - !!$omp simd - !do g = 1,nDim - ! cPtr(g) = cPtr(g) + rC(g) - !end do - !!$omp simd - !do g = 1,nDim - ! mPtr(g) = mPtr(g) + matScore(g) - !end do - call arrays % unsetLock(cIdx) if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) @@ -546,10 +531,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra do g = 1, nG angular(g) = 0.0_defFlt end do - - ! Update ray direction on reflecting from boundary - mu0 = r % dirGlobal() - muFlt = real(mu0,defFlt) end if end do From b826d5048ff149a62c826be6675de17faba581cd Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sat, 27 Jul 2024 17:49:10 +0100 Subject: [PATCH 06/15] Added volume/miss policies for LS RR --- InputFiles/TRRM/dogleg_TRRM_scatter_coarse | 10 +- .../fixedSourceRRPhysicsPackage_class.f90 | 11 +- .../randomRayPhysicsPackage_class.f90 | 12 +- RandomRayObjects/arraysRR_class.f90 | 297 +++++++++++++----- RandomRayObjects/constantsRR.f90 | 4 + RandomRayObjects/rayHandling_func.f90 | 6 +- 6 files changed, 253 insertions(+), 87 deletions(-) diff --git a/InputFiles/TRRM/dogleg_TRRM_scatter_coarse b/InputFiles/TRRM/dogleg_TRRM_scatter_coarse index b281ea096..d58590659 100644 --- a/InputFiles/TRRM/dogleg_TRRM_scatter_coarse +++ b/InputFiles/TRRM/dogleg_TRRM_scatter_coarse @@ -2,16 +2,16 @@ type fixedSourceRRPhysicsPackage; lin 1; pop 2000; -active 2500; -inactive 500; -dead 120; -termination 1220; +pop 120; +active 4000; +inactive 1000; +dead 100; +termination 500; plot 1; cache 1; XSdata mg; dataType mg; outputFile dogleg_TRRM_scatter_coarse; -volume 360000; source { sourceMat ( 1.0 ); } integrate (sourceMat absorber); diff --git a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 index f3e7087e4..1c1cb60f8 100644 --- a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 @@ -187,7 +187,7 @@ subroutine init(self, dict, loud) class(fixedSourceRRPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict logical(defBool), intent(in), optional :: loud - integer(shortInt) :: seed_temp, n, nPoints + integer(shortInt) :: seed_temp, n, nPoints, volP, missP integer(longInt) :: seed character(10) :: time character(8) :: date @@ -218,6 +218,9 @@ subroutine init(self, dict, loud) call dict % get(self % inactive, 'inactive') call dict % getOrDefault(self % keff, 'keff', ONE) + call dict % getOrDefault(volP, 'volPolicy', 1) + call dict % getOrDefault(missP, 'missPolicy', 1) + ! Perform distance caching? call dict % getOrDefault(self % cache, 'cache', .false.) @@ -369,7 +372,7 @@ subroutine init(self, dict, loud) ! Initialise RR arrays and nuclear data call self % arrays % init(self % mgData, self % geom, & self % pop * (self % termination - self % dead), self % rho, self % lin, & - .false., self % loud, tempDict) + .false., self % loud, dictFS = tempDict, volPolicy = volP, missPolicy = missP) ! Zeros the prevFlux - makes for a better initial guess than 1's in eigenvalue! call self % arrays % resetFluxes() @@ -482,7 +485,7 @@ subroutine cycles(self) if (isActive) call arrayPtr % accumulateFluxScores() ! Calculate proportion of cells that were hit - hitRate = arrayPtr % getCellHitRate() + hitRate = arrayPtr % getCellHitRate(it) call arrayPtr % wipeCellHits() ! Evaluate stopping criterion for active or inactive iterations @@ -527,7 +530,7 @@ subroutine cycles(self) end do ! Finalise flux and keff scores - call arrayPtr % finaliseFluxScores(itAct) + call arrayPtr % finaliseFluxScores(itAct, it) end subroutine cycles diff --git a/PhysicsPackages/randomRayPhysicsPackage_class.f90 b/PhysicsPackages/randomRayPhysicsPackage_class.f90 index 04c19ad08..ae7abde16 100644 --- a/PhysicsPackages/randomRayPhysicsPackage_class.f90 +++ b/PhysicsPackages/randomRayPhysicsPackage_class.f90 @@ -191,7 +191,7 @@ subroutine init(self, dict, loud) class(randomRayPhysicsPackage), intent(inout) :: self class(dictionary), intent(inout) :: dict logical(defBool), intent(in), optional :: loud - integer(shortInt) :: seed_temp + integer(shortInt) :: seed_temp, volP, missP integer(longInt) :: seed character(10) :: time character(8) :: date @@ -220,6 +220,9 @@ subroutine init(self, dict, loud) call dict % get(self % inactive, 'inactive') call dict % getOrDefault(self % keff, 'keff', ONE) + call dict % getOrDefault(volP, 'volPolicy', 1) + call dict % getOrDefault(missP, 'missPolicy', 1) + ! Perform distance caching? call dict % getOrDefault(self % cache, 'cache', .false.) @@ -350,7 +353,8 @@ subroutine init(self, dict, loud) ! Initialise RR arrays and nuclear data call self % arrays % init(self % mgData, self % geom, & - self % pop * (self % termination - self % dead), self % rho, self % lin, .false., self % loud) + self % pop * (self % termination - self % dead), self % rho, self % lin, & + .false., self % loud, volPolicy = volP, missPolicy = missP) end subroutine init @@ -465,7 +469,7 @@ subroutine cycles(self) if (isActive) call arrayPtr % accumulateFluxScores() ! Calculate proportion of cells that were hit - hitRate = arrayPtr % getCellHitRate() + hitRate = arrayPtr % getCellHitRate(it) call arrayPtr % wipeCellHits() ! Evaluate stopping criterion for active or inactive iterations @@ -511,7 +515,7 @@ subroutine cycles(self) end do ! Finalise flux and keff scores - call arrayPtr % finaliseFluxScores(itAct) + call arrayPtr % finaliseFluxScores(itAct, it) if (itAct /= 1) then Nm1 = 1.0_defReal/(itAct - 1) else diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 429ddd189..645dfd149 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -25,7 +25,7 @@ module arraysRR_class implicit none private - + !! !! Object to store all arrays in random ray @@ -89,7 +89,9 @@ module arraysRR_class real(defFlt) :: rho = 0.0_defFlt integer(shortInt) :: ani = 0 integer(shortInt) :: simulationType = 0 - real(defReal) :: totalVolume = ONE + real(defReal) :: totalVolume = ONE + integer(shortInt) :: volPolicy = simAverage + integer(shortInt) :: missPolicy = srcPolicy ! Flux arrays real(defFlt), dimension(:), allocatable :: scalarFlux @@ -103,6 +105,7 @@ module arraysRR_class ! Geometry arrays real(defReal), dimension(:), allocatable :: volumeTracks + real(defReal), dimension(:), allocatable :: allVolumeTracks real(defReal), dimension(:), allocatable :: lengthSquared real(defReal), dimension(:), allocatable :: volume integer(shortInt), dimension(:), allocatable :: cellHit @@ -150,10 +153,11 @@ module arraysRR_class procedure :: getNG procedure :: getVolume procedure :: getCellPos - procedure :: hasHit + procedure :: wasHit procedure :: getCellHitRate procedure :: getSimulationType procedure :: found + procedure :: hasFixedSource procedure :: getFluxAtAPoint procedure :: getFluxXYZPointers @@ -214,9 +218,7 @@ module arraysRR_class procedure, private :: finaliseFluxScoresLinear procedure, private :: calculateKeffKernel - procedure, private :: invertMatrix - procedure, private :: materialIntegral end type arraysRR @@ -229,7 +231,8 @@ module arraysRR_class !! The object is fed sizes and requirements by the physics package. !! This will allocate the necessary arrays !! - subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) + subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & + dictFS, volPolicy, missPolicy) class(arraysRR), intent(inout) :: self class(baseMgNeutronDatabase), pointer, intent(in) :: db class(geometryStd), pointer, intent(in) :: geom @@ -239,6 +242,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) logical(defBool), intent(in) :: doKinetics logical(defBool), intent(in) :: loud class(dictionary), pointer, intent(inout), optional :: dictFS + integer(shortInt), intent(in), optional :: volPolicy, missPolicy integer(shortInt) :: ani, i real(defReal), dimension(6) :: bb character(100), parameter :: Here = 'init (arraysRR_class.f90)' @@ -246,11 +250,25 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) call self % XSData % init(db, doKinetics, loud) self % nG = self % XSdata % getNG() self % geom => geom - self % nCells = self % geom % numberOfCells() + self % nCells = self % geom % numberOfCells() self % lengthPerIt = lengthPerIt self % rho = real(rho, defFlt) + if (present(volPolicy)) then + self % volPolicy = volPolicy + else + self % volPolicy = simAverage + end if + if (present(missPolicy)) then + self % missPolicy = missPolicy + else + self % missPolicy = srcPolicy + end if + + print *, self % volPolicy + print *, self % missPolicy + ! Assume bounding box of the geometry is filled (and a box) ! Can this be relaxed in future? bb = self % geom % bounds() @@ -276,6 +294,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) allocate(self % fluxScores(2, self % nG * self % nCells)) allocate(self % source(self % nG * self % nCells)) allocate(self % volumeTracks(self % nCells)) + allocate(self % allVolumeTracks(self % nCells)) allocate(self % lengthSquared(self % nCells)) allocate(self % volume(self % nCells)) allocate(self % cellHit(self % nCells)) @@ -287,6 +306,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, dictFS) self % fluxScores = ZERO self % source = 0.0_defFlt self % volumeTracks = ZERO + self % allVolumeTracks = ZERO self % lengthSquared = ZERO self % volume = ZERO self % cellHit = 0 @@ -520,7 +540,7 @@ end subroutine getSourceXYZPointers !! !! Return source value given cell and group !! - function getSource(self, cIdx, g) result(src) + elemental function getSource(self, cIdx, g) result(src) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -533,7 +553,7 @@ end function getSource !! !! Return fixed source value given cell and group !! - function getFixedSource(self, cIdx, g) result(src) + elemental function getFixedSource(self, cIdx, g) result(src) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -551,7 +571,7 @@ end function getFixedSource !! !! Return previous flux value given cell and group !! - function getPrevFlux(self, cIdx, g) result(flux) + elemental function getPrevFlux(self, cIdx, g) result(flux) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -564,7 +584,7 @@ end function getPrevFlux !! !! Return final flux value given cell and group !! - function getFluxScore(self, cIdx, g) result(flux) + elemental function getFluxScore(self, cIdx, g) result(flux) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -578,7 +598,7 @@ end function getFluxScore !! Return final flux standard deviation given cell and group !! Will return square of flux scores if called before finaliseFluxScores !! - function getFluxSD(self, cIdx, g) result(flux) + elemental function getFluxSD(self, cIdx, g) result(flux) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -591,7 +611,7 @@ end function getFluxSD !! !! Return final flux moment values given cell and group !! - function getFluxMoments(self, cIdx, g) result(flux) + pure function getFluxMoments(self, cIdx, g) result(flux) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -609,7 +629,7 @@ end function getFluxMoments !! Return final flux moment standard deviations given cell and group !! Will return square of moment scores if called before finaliseFluxScores !! - function getFluxMomentSDs(self, cIdx, g) result(fluxSD) + pure function getFluxMomentSDs(self, cIdx, g) result(fluxSD) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g @@ -626,7 +646,7 @@ end function getFluxMomentSDs !! !! Return volume given cell ID !! - function getVolume(self, cIdx) result(vol) + elemental function getVolume(self, cIdx) result(vol) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx real(defReal) :: vol @@ -638,7 +658,7 @@ end function getVolume !! !! Return cell position given cell ID !! - function getCellPos(self, cIdx) result(pos) + pure function getCellPos(self, cIdx) result(pos) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx real(defReal), dimension(nDim) :: pos @@ -650,7 +670,7 @@ end function getCellPos !! !! Return cell centroid given cell ID !! - function getCentroid(self, cIdx) result(cent) + pure function getCentroid(self, cIdx) result(cent) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx real(defReal), dimension(nDim) :: cent @@ -665,7 +685,7 @@ end function getCentroid !! !! Return moment matrix given cell ID !! - function getMomentMatrix(self, cIdx) result(mat) + pure function getMomentMatrix(self, cIdx) result(mat) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx real(defReal), dimension(matSize) :: mat @@ -680,7 +700,7 @@ end function getMomentMatrix !! !! Return the simulation type !! - function getSimulationType(self) result(simType) + elemental function getSimulationType(self) result(simType) class(arraysRR), intent(in) :: self integer(shortInt) :: simType @@ -751,14 +771,14 @@ end subroutine incrementMoments !! !! Check if a cell has been hit !! - elemental function hasHit(self, cIdx) result (hit) + elemental function wasHit(self, cIdx) result (hit) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx - integer(shortInt) :: hit + logical(defBool) :: hit - hit = self % cellHit(cIdx) + hit = (self % cellHit(cIdx) == 1) - end function hasHit + end function wasHit !! !! Hit a cell @@ -774,13 +794,19 @@ end subroutine hitCell !! !! Return the cell hit rate for the given iteration !! - function getCellHitRate(self) result(hitRate) - class(arraysRR), intent(in) :: self - integer(shortInt) :: totalHit - real(defReal) :: hitRate + elemental function getCellHitRate(self, it) result(hitRate) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: it + integer(shortInt) :: totalHit, realCells + real(defReal) :: hitRate totalHit = sum(self % cellHit) - hitRate = real(totalHit, defReal) / self % nCells + if (it > 20) then + realCells = count(self % cellFound) + else + realCells = self % nCells + end if + hitRate = real(totalHit,defReal) / realCells end function getCellHitRate @@ -797,7 +823,7 @@ end subroutine wipeCellHits !! !! Has a cell ever been found? !! - function found(self, cIdx) result(wasFound) + elemental function found(self, cIdx) result(wasFound) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx logical(defBool) :: wasFound @@ -824,13 +850,32 @@ end subroutine newFound !! !! Return number of energy groups used !! - function getNG(self) result(nG) + elemental function getNG(self) result(nG) class(arraysRR), intent(in) :: self integer(shortInt) :: nG nG = self % nG end function getNG + + !! + !! Check if a cell has an inhomogeneous source + !! + elemental function hasFixedSource(self, cIdx) result (hasSrc) + class(arraysRR), intent(in) :: self + integer(shortInt), intent(in) :: cIdx + logical(defBool) :: hasSrc + integer(shortInt) :: idx1, idx2 + + if (allocated(self % fixedSource)) then + idx1 = self % nG * (cIdx - 1) + 1 + idx2 = self % nG * cIdx + hasSrc = any(self % fixedSource(idx1:idx2) > 0.0_defFlt) + else + hasSrc = .false. + end if + + end function hasFixedSource !! !! Set the OMP lock in a given cell @@ -890,7 +935,9 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) real(defFlt), dimension(:), pointer, save :: total integer(shortInt), save :: g, matIdx, idx integer(shortInt) :: cIdx - !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D) + logical(defBool), save :: hit, isSrc + character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' + !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D, hit, isSrc) norm = ONE / self % lengthPerIt normVol = ONE / (self % lengthPerIt * it) @@ -899,8 +946,27 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) do cIdx = 1, self % nCells matIdx = self % geom % geom % graph % getMatFromUID(cIdx) - ! Update volume due to additional rays - self % volume(cIdx) = self % volumeTracks(cIdx) * normVol + hit = self % wasHit(cIdx) + isSrc = self % hasFixedSource(cIdx) + self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & + self % volumeTracks(cIdx) + + ! Decide volume to use + select case(self % volPolicy) + case(simAverage) + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + case(naive) + self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + case(hybrid) + if (isSrc) then + self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + else + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + end if + case default + call fatalError(Here,'Unsupported volume handling requested') + end select + self % volumeTracks(cIdx) = ZERO vol = self % volume(cIdx) ! Save effort by skipping normalisation if volume is too small @@ -922,8 +988,9 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) ! Apply the standard MoC post-sweep treatment and ! stabilisation for negative XSs - if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + !if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + if (hit) then self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) ! Presumes non-zero total XS @@ -935,12 +1002,28 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) end if self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + D * self % prevFlux(idx) ) / (1 + D) - - ! Alternatively, handle unidentified/void regions else - self % scalarFlux(idx) = self % scalarFlux(idx) + & - real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + ! Decide flux treatment to use + select case(self % missPolicy) + case(srcPolicy) + self % scalarFlux(idx) = self % source(idx) / total(g) + case(prevPolicy) + self % scalarFlux(idx) = self % prevFlux(idx) + case(hybrid) + if (isSrc) then + self % scalarFlux(idx) = self % prevFlux(idx) + else + self % scalarFlux(idx) = self % source(idx) / total(g) + end if + case default + call fatalError(Here,'Unsupported miss handling requested') + end select end if + ! Alternatively, handle unidentified/void regions + !else + ! self % scalarFlux(idx) = self % scalarFlux(idx) + & + ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + !end if end do end do @@ -962,7 +1045,9 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) real(defFlt), dimension(:), pointer, save :: total integer(shortInt) :: cIdx integer(shortInt), save :: g, matIdx, idx, dIdx, mIdx - !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG) + logical(defBool), save :: hit, isSrc + character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' + !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG, hit, isSrc) norm = real(ONE / self % lengthPerIt, defFlt) normVol = ONE / (self % lengthPerIt * it) @@ -972,10 +1057,29 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) matIdx = self % geom % geom % graph % getMatFromUID(cIdx) dIdx = (cIdx - 1) * nDim mIdx = (cIdx - 1) * matSize - - ! Update volume - self % volume(cIdx) = self % volumeTracks(cIdx) * normVol - vol = real(self % volume(cIdx),defFlt) + + hit = self % wasHit(cIdx) + isSrc = self % hasFixedSource(cIdx) + self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & + self % volumeTracks(cIdx) + + ! Decide volume to use + select case(self % volPolicy) + case(simAverage) + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + case(naive) + self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + case(hybrid) + if (isSrc) then + self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + else + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + end if + case default + call fatalError(Here,'Unsupported volume handling requested') + end select + self % volumeTracks(cIdx) = ZERO + vol = real(self % volume(cIdx), defFlt) ! Save effort by skipping normalisation if volume is too small if (vol < volume_tolerance) then @@ -991,7 +1095,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) cycle end if - invVol = ONE / self % volumeTracks(cIdx) + invVol = ONE / self % allVolumeTracks(cIdx) ! Update centroids self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol @@ -1012,36 +1116,77 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) do g = 1, self % nG idx = self % nG * (cIdx - 1) + g + + if (hit) then + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V + self % scalarX(idx) = self % scalarX(idx) * norm_V + self % scalarY(idx) = self % scalarY(idx) * norm_V + self % scalarZ(idx) = self % scalarZ(idx) * norm_V + + ! Apply the standard MoC post-sweep treatment and + ! stabilisation for negative XSs + if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then - self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - self % scalarX(idx) = self % scalarX(idx) * norm_V - self % scalarY(idx) = self % scalarY(idx) * norm_V - self % scalarZ(idx) = self % scalarZ(idx) * norm_V - - ! Apply the standard MoC post-sweep treatment and - ! stabilisation for negative XSs - if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then - - self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) - self % scalarX(idx) = self % scalarX(idx) / total(g) - self % scalarY(idx) = self % scalarY(idx) / total(g) - self % scalarZ(idx) = self % scalarZ(idx) / total(g) + self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) + self % scalarX(idx) = self % scalarX(idx) / total(g) + self % scalarY(idx) = self % scalarY(idx) / total(g) + self % scalarZ(idx) = self % scalarZ(idx) / total(g) - ! Presumes non-zero total XS - sigGG = self % XSData % getScatterXS(matIdx, g, g) - if ((sigGG < 0) .and. (total(g) > 0)) then - D = -self % rho * sigGG / total(g) - else - D = 0.0_defFlt + ! Presumes non-zero total XS + sigGG = self % XSData % getScatterXS(matIdx, g, g) + if ((sigGG < 0) .and. (total(g) > 0)) then + D = -self % rho * sigGG / total(g) + else + D = 0.0_defFlt + end if + + self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + + D * self % prevFlux(idx) ) / (1 + D) end if - self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & - + D * self % prevFlux(idx) ) / (1 + D) - - ! Alternatively, handle unidentified/void regions else - self % scalarFlux(idx) = self % scalarFlux(idx) + & - real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + ! Decide flux treatment to use + associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) + select case(self % missPolicy) + case(srcPolicy) + self % scalarFlux(idx) = self % source(idx) / total(g) + ! Need to multiply source gradients by moment matrix + self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + case(prevPolicy) + self % scalarFlux(idx) = self % prevFlux(idx) + self % scalarX(idx) = self % prevX(idx) + self % scalarY(idx) = self % prevY(idx) + self % scalarZ(idx) = self % prevZ(idx) + case(hybrid) + if (isSrc) then + self % scalarFlux(idx) = self % prevFlux(idx) + self % scalarX(idx) = self % prevX(idx) + self % scalarY(idx) = self % prevY(idx) + self % scalarZ(idx) = self % prevZ(idx) + else + self % scalarFlux(idx) = self % source(idx) / total(g) + ! Need to multiply source gradients by moment matrix + self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + end if + case default + call fatalError(Here,'Unsupported miss handling requested') + end select + end associate end if + !! Alternatively, handle unidentified/void regions + !else + ! self % scalarFlux(idx) = self % scalarFlux(idx) + & + ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) + !end if end do @@ -1614,9 +1759,11 @@ end subroutine accumulateFluxScoresLinear !! !! Finalise results !! - subroutine finaliseFluxScores(self, it) + subroutine finaliseFluxScores(self, it, totalIt) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it + integer(shortInt), intent(in) :: totalIt + integer(shortInt) :: cIdx character(100), parameter :: Here = 'finaliseFLuxScores (arraysRR_class.f90)' select case(self % simulationType) @@ -1628,6 +1775,14 @@ subroutine finaliseFluxScores(self, it) call fatalError(Here,'Unsupported simulation type requested') end select + ! Also finalise volume scores + ! Ensures naive estimate is not used for post-processed results + !$omp parallel do schedule(static) + do cIdx = 1, self % nCells + self % volume(cIdx) = self % allVolumeTracks(cIdx) / (totalIt * self % lengthPerIt) + end do + !$omp end parallel do + end subroutine finaliseFluxScores !! @@ -1754,7 +1909,7 @@ subroutine outputMap(self, out, map, doFission) !$omp parallel do reduction(+: res, resSD) do cIdx = 1, self % nCells - vol = self % volume(cIdx) * self % totalVolume + vol = self % volume(cIdx) * self % totalVolume if (vol < volume_tolerance) cycle ! Fudge a particle state to search tally map diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index 675401452..a448e80ac 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -3,6 +3,10 @@ module constantsRR use numPrecision implicit none + + ! Parameters for volume/no-hit policy + integer(shortInt), parameter :: hybrid = 3, srcPolicy = 1, prevPolicy = 2, & + naive = 2, simAverage = 1 ! Parameters to identify the simulation type integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 7eb831e4b..13e81b781 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -263,7 +263,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays end do call arrays % incrementVolume(cIdx, length) call arrays % unsetLock(cIdx) - if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if @@ -282,7 +282,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays call arrays % incrementVolume(cIdx, length) call arrays % incrementLengthSquared(cIdx, length) call arrays % unsetLock(cIdx) - if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if @@ -521,7 +521,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra call arrays % incrementMoments(cIdx, matScore) call arrays % unsetLock(cIdx) - if (arrays % hasHit(cIdx) == 0) call arrays % hitCell(cIdx) + if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if From 9b775995136d7d60b61b1c77a89d997fa180ba1f Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sun, 28 Jul 2024 21:44:29 +0100 Subject: [PATCH 07/15] Added global VR CADIS calculation --- .../fixedSourceRRPhysicsPackage_class.f90 | 14 ++ RandomRayObjects/arraysRR_class.f90 | 121 +++++++++++++++++- RandomRayObjects/dataRR_class.f90 | 35 +++++ Visualisation/visualiser_class.f90 | 2 +- 4 files changed, 169 insertions(+), 3 deletions(-) diff --git a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 index 1c1cb60f8..e16fa083f 100644 --- a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 @@ -86,6 +86,7 @@ module fixedSourceRRPhysicsPackage_class !! #fluxMap {}# // Optionally output one-group fluxes according to a given map !! #plot 1;# // Optionally make VTK viewable plot of fluxes and uncertainties !! #rho 0;# // Optional stabilisation for negative in-group scattering XSs + !! #cadis 0;# // Optionally generate adjoints for global variance reduction !! !! geometry {} !! nuclearData {} @@ -152,6 +153,7 @@ module fixedSourceRRPhysicsPackage_class character(nameLen),dimension(:), allocatable :: intMatNames real(defReal), dimension(:,:), allocatable :: samplePoints character(nameLen),dimension(:), allocatable :: sampleNames + logical(defBool) :: doCADIS = .false. ! Results space integer(longInt) :: intersectionsTotal = 0 @@ -220,6 +222,8 @@ subroutine init(self, dict, loud) call dict % getOrDefault(volP, 'volPolicy', 1) call dict % getOrDefault(missP, 'missPolicy', 1) + + call dict % getOrDefault(self % doCadis, 'cadis', .false.) ! Perform distance caching? call dict % getOrDefault(self % cache, 'cache', .false.) @@ -390,6 +394,15 @@ subroutine run(self) if (self % loud) call self % printSettings() call self % cycles() call self % printResults() + if (self % doCadis) then + print *,'Performing adjoint calculation' + ! Reinitialise VTK + !if (self % plotResults) call self % viz % initVTK() + call self % arrays % initAdjoint() + call self % cycles() + self % outputFile = trim(self % outputFile)//'_adj' + call self % printResults() + end if end subroutine run @@ -604,6 +617,7 @@ subroutine printSettings(self) print *, repeat("<>", MAX_COL/2) print *, "/\/\ RANDOM RAY FIXED SOURCE CALCULATION /\/\" + if (self % doCadis) print *, "Will run a subsequent adjoint calculation" if (self % lin) print *, "Using linear source" print *, "Using "//numToChar(self % inactive)// " iterations for "& //"the inactive cycles" diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 645dfd149..9231913b6 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -122,6 +122,9 @@ module arraysRR_class real(defFlt), dimension(:), allocatable :: sourceX real(defFlt), dimension(:), allocatable :: sourceY real(defFlt), dimension(:), allocatable :: sourceZ + real(defFlt), dimension(:), allocatable :: fixedX + real(defFlt), dimension(:), allocatable :: fixedY + real(defFlt), dimension(:), allocatable :: fixedZ real(defReal), dimension(:), allocatable :: momMat real(defReal), dimension(:), allocatable :: momTracks real(defReal), dimension(:), allocatable :: centroid @@ -138,6 +141,7 @@ module arraysRR_class ! Public procedures procedure :: init + procedure :: initAdjoint procedure :: kill ! Access procedures @@ -373,6 +377,114 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & end subroutine init + !! + !! Initialise the adjoint source and update nuclear data. + !! For now, assumes the adjoint is for global variance reduction. + !! + subroutine initAdjoint(self) + class(arraysRR), intent(inout) :: self + integer(shortInt) :: cIdx + logical(defBool) :: doLinear + integer(shortInt), save :: i, g + real(defFlt), dimension(matSize), save :: invM + real(defFlt), save :: xMom, yMom, zMom + !$omp threadprivate(i, g, invM, xMom, yMom, zMom) + + doLinear = .false. + invM = 0.0_defFlt + + call self % xsData % setAdjointXS() + + if (.not. allocated(self % fixedSource)) then + allocate(self % fixedSource(size(self % scalarFlux))) + end if + self % fixedSource = 0.0_defFlt + + if (allocated(self % scalarX)) then + doLinear = .true. + if (.not. allocated(self % fixedX)) then + allocate(self % fixedX(size(self % scalarFlux))) + allocate(self % fixedY(size(self % scalarFlux))) + allocate(self % fixedZ(size(self % scalarFlux))) + end if + self % fixedX = 0.0_defFlt + self % fixedY = 0.0_defFlt + self % fixedZ = 0.0_defFlt + end if + + ! Create fixed source from the flux scores + ! Presently assumes the response of interest is global flux + !$omp parallel do + do cIdx = 1, self % nCells + + if (.not. self % found(cIdx)) cycle + if (doLinear) invM = self % invertMatrix(cIdx) + + do g = 1, self % nG + + i = (cIdx - 1) * self % nG + g + + ! Check for inordinately small flux values. + ! Note, these can have arbitrarily low magnitude. + ! Maybe should be something more robust. + if (self % fluxScores(1, i) == 0.0_defFlt) cycle + self % fixedSource(i) = real(ONE / self % fluxScores(1, i), defFlt) + + ! Linear source treatment relies on performing a Taylor expansion + ! of q' = 1/phi = 1/(phi_0 + grad phi * (r - r0)) + ! = 1/phi_0 - 1/phi^2_0 * gradPhi * (r - r0) + if (doLinear) then + xMom = real(self % xScores(1, i), defFlt) + yMom = real(self % yScores(1, i), defFlt) + zMom = real(self % zScores(1, i), defFlt) + self % fixedX(i) = invM(xx) * xMom + invM(xy) * yMom + invM(xz) * zMom + self % fixedY(i) = invM(xy) * xMom + invM(yy) * yMom + invM(yz) * zMom + self % fixedZ(i) = invM(xz) * xMom + invM(yz) * yMom + invM(zz) * zMom + + self % fixedX(i) = -self % fixedX(i) * self % fixedSource(i) ** 2 + self % fixedY(i) = -self % fixedY(i) * self % fixedSource(i) ** 2 + self % fixedZ(i) = -self % fixedZ(i) * self % fixedSource(i) ** 2 + end if + + end do + + end do + !$omp end parallel do + + ! Reinitialise arrays to be used during transport + self % scalarFlux = 0.0_defFlt + self % prevFlux = 0.0_defFlt + self % fluxScores = ZERO + self % source = 0.0_defFlt + + ! Ideally we would have a way of reusing the volume estimators + ! No compact ideas at the moment, so these will simply be reinitialised + self % volumeTracks = ZERO + self % allVolumeTracks = ZERO + self % lengthSquared = ZERO + self % volume = ZERO + + if (doLinear) then + self % scalarX = 0.0_defFlt + self % scalarY = 0.0_defFlt + self % scalarZ = 0.0_defFlt + self % prevX = 0.0_defFlt + self % prevY = 0.0_defFlt + self % prevZ = 0.0_defFlt + self % sourceX = 0.0_defFlt + self % sourceY = 0.0_defFlt + self % sourceZ = 0.0_defFlt + self % momMat = ZERO + self % momTracks = ZERO + self % centroid = ZERO + self % centroidTracks = ZERO + self % xScores = ZERO + self % yScores = ZERO + self % zScores = ZERO + end if + + end subroutine initAdjoint + !! !! Initialises fixed sources to be used in the simulation. !! Takes a dictionary containing names of materials in the geometry and @@ -914,7 +1026,7 @@ subroutine normaliseFluxAndVolume(self, it) select case(self % simulationType) case(flatIso) call self % normaliseFluxAndVolumeFlatIso(it) - case(LinearIso) + case(linearIso) call self % normaliseFluxAndVolumeLinearIso(it) case default call fatalError(Here,'Unsupported simulation type requested') @@ -1420,6 +1532,11 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) invM(yy) * ySource + invM(yz) * zSource self % sourceZ(idx) = invM(xz) * xSource + & invM(yz) * ySource + invM(zz) * zSource + if (allocated(self % fixedX)) then + self % sourceX(idx) = self % sourceX(idx) + self % fixedX(idx) + self % sourceY(idx) = self % sourceY(idx) + self % fixedY(idx) + self % sourceZ(idx) = self % sourceZ(idx) + self % fixedZ(idx) + end if end do @@ -2035,7 +2152,7 @@ subroutine outputToVTK(self, viz) !$omp end parallel do call viz % addVTKData(resVec,name) - call viz % finaliseVTK + call viz % finaliseVTK() end subroutine outputToVTK diff --git a/RandomRayObjects/dataRR_class.f90 b/RandomRayObjects/dataRR_class.f90 index 1cb92d2b3..03f2f8175 100644 --- a/RandomRayObjects/dataRR_class.f90 +++ b/RandomRayObjects/dataRR_class.f90 @@ -54,6 +54,7 @@ module dataRR_class contains procedure :: init + procedure :: setAdjointXS procedure :: kill ! TODO: add an XS update procedure, e.g., given multiphysics @@ -172,6 +173,40 @@ subroutine init(self, db, doKinetics, loud) end if end subroutine init + + !! + !! Change cross sections for adjoints simulations: + !! - swap chi and nuSigmaF + !! - transpose scattering matrices + !! + subroutine setAdjointXS(self) + class(dataRR), intent(inout) :: self + integer(shortInt) :: g, g1, m + real(defFlt), dimension(:), allocatable :: buffer + + ! Swap chi and nuSigmaF + allocate(buffer(self % nMat * self % nG)) + buffer = self % chi + self % chi = self % nuSigmaF + self % nuSigmaF = self % chi + deallocate(buffer) + + ! Transpose scattering matrix + allocate(buffer(self % nMat * self % nG * self % nG)) + buffer = self % sigmaS + + do m = 1, self % nMat + do g = 1, self % nG + do g1 = 1, self % nG + self % sigmaS(self % nG * self % nG * (m - 1) + self % nG * (g1 - 1) + g) = & + buffer(self % nG * self % nG * (m - 1) + self % nG * (g - 1) + g1) + end do + end do + end do + + ! TODO: apply the same treatment to anisotropic scattering matrices + + end subroutine setAdjointXS !! !! Calculate the lower and upper indices for accessing the XS array diff --git a/Visualisation/visualiser_class.f90 b/Visualisation/visualiser_class.f90 index dd9714a30..6b8ca8763 100644 --- a/Visualisation/visualiser_class.f90 +++ b/Visualisation/visualiser_class.f90 @@ -222,7 +222,7 @@ subroutine finaliseVTK(self) class(visualiser), intent(inout) :: self call self % vtk % output(self % name) - call self % vtk % kill() + !call self % vtk % kill() end subroutine finaliseVTK From 30e700558d600897392cd7c52c82d2e812e364da Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Tue, 6 Aug 2024 12:19:08 +0100 Subject: [PATCH 08/15] Tweaks --- RandomRayObjects/arraysRR_class.f90 | 21 +++++++++++++++------ RandomRayObjects/constantsRR.f90 | 6 +++--- RandomRayObjects/rayHandling_func.f90 | 21 +++++++++++++-------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 645dfd149..9b494c4c3 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -266,9 +266,6 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & self % missPolicy = srcPolicy end if - print *, self % volPolicy - print *, self % missPolicy - ! Assume bounding box of the geometry is filled (and a box) ! Can this be relaxed in future? bb = self % geom % bounds() @@ -1082,7 +1079,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) vol = real(self % volume(cIdx), defFlt) ! Save effort by skipping normalisation if volume is too small - if (vol < volume_tolerance) then + if (.not. self % found(cIdx)) then do g = 1, self % nG idx = self % nG * (cIdx - 1) + g self % scalarFlux(idx) = 0.0_defFlt @@ -1095,6 +1092,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) cycle end if + if (vol < volume_tolerance) cycle invVol = ONE / self % allVolumeTracks(cIdx) ! Update centroids @@ -1117,7 +1115,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) idx = self % nG * (cIdx - 1) + g - if (hit) then + if (hit .and. (vol > volume_tolerance)) then self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarX(idx) = self % scalarX(idx) * norm_V self % scalarY(idx) = self % scalarY(idx) * norm_V @@ -1134,7 +1132,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Presumes non-zero total XS sigGG = self % XSData % getScatterXS(matIdx, g, g) - if ((sigGG < 0) .and. (total(g) > 0)) then + if (sigGG < 0) then D = -self % rho * sigGG / total(g) else D = 0.0_defFlt @@ -1187,6 +1185,11 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! self % scalarFlux(idx) = self % scalarFlux(idx) + & ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) !end if + !if (it < 20) then + ! self % scalarX(idx) = 0.0_defFlt + ! self % scalarY(idx) = 0.0_defFlt + ! self % scalarZ(idx) = 0.0_defFlt + !end if end do @@ -1467,9 +1470,14 @@ function invertMatrix(self, cIdx) result(invM) condY = 0 condZ = 0 + ! Trying out simpler matrix test if (momVec(xx) > condition_tolerance) condX = 1 if (momVec(yy) > condition_tolerance) condY = 1 if (momVec(zz) > condition_tolerance) condZ = 1 + !condX = 1 + !condY = 1 + !DEFINITELY DO THIS FOR C5G7 WITH LOW POP + !condZ = 0 ! Map conditions to test variable inversionTest = condX * 4 + condY * 2 + condZ @@ -1579,6 +1587,7 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) ! Check whether to continue in this cell if (matIdx > self % XSData % getNMat()) return if (.not. self % XSData % isFissile(matIdx)) return + if (.not. self % found(cIdx)) return vol = self % volume(cIdx) if (vol < volume_tolerance) return diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index a448e80ac..c4d204610 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -12,12 +12,12 @@ module constantsRR integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 ! Parameter for when to skip a tiny volume - real(defReal), parameter, public :: volume_tolerance = 1.0E-12 + real(defReal), parameter, public :: volume_tolerance = 1.0E-10 ! Parameter for when to ignore components of spatial moment matrices ! or when the matrix is poorly conditioned - real(defReal), parameter, public :: condition_tolerance = 1.0E-10, & - det_tolerance = 1.0E-12 + real(defReal), parameter, public :: condition_tolerance = 1.0E-6, & + det_tolerance = 1.0E-10 ! Parameters for indexing into matrices and spatial moments with linear sources integer(shortInt), parameter :: x = 1, y = 2, z = 3, nDim = 3, & diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 13e81b781..0ebb6631d 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -385,20 +385,25 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra ! Calculate the track centre rC = r0 + length * HALF * mu0 - ! Set new cell's position - if (.not. arrays % found(cIdx)) then + ! Compute the track centroid and entry point in local co-ordinates + ! Convert to floats for speed + ! If region has not been visited, use ray's halfway point as centroid + if (arrays % found(cIdx)) then + mid = arrays % getCentroid(cIdx) + rNorm = rC - mid + rNormFlt = real(rNorm,defFlt) + r0NormFlt = real(r0 - mid,defFlt) + else + ! Set new cell's position call arrays % newFound(cIdx, rC) + rNorm = ZERO + rNormFlt = 0.0_defFlt + r0NormFlt = -real(HALF * mu0 * length,defFlt) end if call arrays % getSourcePointer(cIdx, source) call arrays % getSourceXYZPointers(cIdx, sourceX, sourceY, sourceZ) - mid = arrays % getCentroid(cIdx) - ! Compute the track centroid and entry point in local co-ordinates - ! Convert to floats for speed - rNorm = rC - mid - rNormFlt = real(rNorm,defFlt) - r0NormFlt = real(r0 - mid,defFlt) ! Calculate source terms !$omp simd aligned(sourceX, sourceY, sourceZ) From 2e44aee7447a71304669b65a43e07f5e5fe4157d Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sat, 10 Aug 2024 18:52:38 +0100 Subject: [PATCH 09/15] More tweaks to vol/miss policies --- RandomRayObjects/arraysRR_class.f90 | 66 +++++++++++++++------------ RandomRayObjects/constantsRR.f90 | 2 +- RandomRayObjects/rayHandling_func.f90 | 22 +++++---- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 9b494c4c3..beab934d4 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -283,7 +283,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & else self % simulationType = linearAni end if - if (ani >= 0) self % ani = ani + self % ani = ani ! Allocate and initialise arrays allocate(self % scalarFlux(self % nG * self % nCells)) @@ -837,6 +837,7 @@ subroutine newFound(self, cIdx, r) integer(shortInt), intent(in) :: cIdx real(defReal), dimension(3), intent(in) :: r + ! Remove critical if this is to go in the lock !$omp critical self % cellFound(cIdx) = .true. self % cellPos(:,cIdx) = r @@ -1062,10 +1063,10 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Decide volume to use select case(self % volPolicy) - case(simAverage) - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol case(naive) self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + case(simAverage) + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol case(hybrid) if (isSrc) then self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt @@ -1079,7 +1080,8 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) vol = real(self % volume(cIdx), defFlt) ! Save effort by skipping normalisation if volume is too small - if (.not. self % found(cIdx)) then + !if ((.not. self % found(cIdx)) .or. (vol < volume_tolerance)) then + if (vol < volume_tolerance) then do g = 1, self % nG idx = self % nG * (cIdx - 1) + g self % scalarFlux(idx) = 0.0_defFlt @@ -1092,7 +1094,6 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) cycle end if - if (vol < volume_tolerance) cycle invVol = ONE / self % allVolumeTracks(cIdx) ! Update centroids @@ -1115,7 +1116,8 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) idx = self % nG * (cIdx - 1) + g - if (hit .and. (vol > volume_tolerance)) then + !if (hit .and. (vol > volume_tolerance)) then + if (hit) then self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarX(idx) = self % scalarX(idx) * norm_V self % scalarY(idx) = self % scalarY(idx) * norm_V @@ -1145,15 +1147,20 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Decide flux treatment to use associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) select case(self % missPolicy) + ! Note: this is policy to use the source, not policy for hitting a fixed source case(srcPolicy) self % scalarFlux(idx) = self % source(idx) / total(g) + ! I THINK OPENMC SETS MOMENTS TO ZERO + self % scalarX(idx) = 0.0_defFlt + self % scalarY(idx) = 0.0_defFlt + self % scalarZ(idx) = 0.0_defFlt ! Need to multiply source gradients by moment matrix - self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + ! mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + ! mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + ! mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) case(prevPolicy) self % scalarFlux(idx) = self % prevFlux(idx) self % scalarX(idx) = self % prevX(idx) @@ -1167,29 +1174,29 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarZ(idx) = self % prevZ(idx) else self % scalarFlux(idx) = self % source(idx) / total(g) + ! I THINK OPENMC SETS MOMENTS TO ZERO + self % scalarX(idx) = 0.0_defFlt + self % scalarY(idx) = 0.0_defFlt + self % scalarZ(idx) = 0.0_defFlt ! Need to multiply source gradients by moment matrix - self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + ! mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + ! mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + !self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + ! mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) end if case default call fatalError(Here,'Unsupported miss handling requested') end select end associate end if - !! Alternatively, handle unidentified/void regions - !else - ! self % scalarFlux(idx) = self % scalarFlux(idx) + & - ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) - !end if - !if (it < 20) then - ! self % scalarX(idx) = 0.0_defFlt - ! self % scalarY(idx) = 0.0_defFlt - ! self % scalarZ(idx) = 0.0_defFlt - !end if + + if (it < 10) then + self % scalarX(idx) = 0.0_defFlt + self % scalarY(idx) = 0.0_defFlt + self % scalarZ(idx) = 0.0_defFlt + end if end do @@ -1564,6 +1571,7 @@ function calculateKeff(self, k0) result(k1) !$omp end parallel do k1 = k0 * fissTotal / prevFissTotal + if ((k1 <= 0) .or. (k1 > 5)) k1 = k0 end function calculateKeff @@ -1587,7 +1595,7 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) ! Check whether to continue in this cell if (matIdx > self % XSData % getNMat()) return if (.not. self % XSData % isFissile(matIdx)) return - if (.not. self % found(cIdx)) return + !if (.not. self % found(cIdx)) return vol = self % volume(cIdx) if (vol < volume_tolerance) return diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index c4d204610..45c7b7b46 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -17,7 +17,7 @@ module constantsRR ! Parameter for when to ignore components of spatial moment matrices ! or when the matrix is poorly conditioned real(defReal), parameter, public :: condition_tolerance = 1.0E-6, & - det_tolerance = 1.0E-10 + det_tolerance = 1.0E-8 ! Parameters for indexing into matrices and spatial moments with linear sources integer(shortInt), parameter :: x = 1, y = 2, z = 3, nDim = 3, & diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 0ebb6631d..bcfe27551 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -385,26 +385,27 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra ! Calculate the track centre rC = r0 + length * HALF * mu0 + ! Set new cell's position + if (.not. arrays % found(cIdx)) call arrays % newFound(cIdx, rC) + ! Compute the track centroid and entry point in local co-ordinates ! Convert to floats for speed - ! If region has not been visited, use ray's halfway point as centroid - if (arrays % found(cIdx)) then + ! If region is rarely visited, use ray's halfway point as centroid + ! Prevents numerical trouble + if (arrays % getVolume(cIdx) < volume_tolerance) then + rNorm = ZERO + rNormFlt = 0.0_defFlt + r0NormFlt = -real(HALF * mu0 * length,defFlt) + else mid = arrays % getCentroid(cIdx) rNorm = rC - mid rNormFlt = real(rNorm,defFlt) r0NormFlt = real(r0 - mid,defFlt) - else - ! Set new cell's position - call arrays % newFound(cIdx, rC) - rNorm = ZERO - rNormFlt = 0.0_defFlt - r0NormFlt = -real(HALF * mu0 * length,defFlt) end if call arrays % getSourcePointer(cIdx, source) call arrays % getSourceXYZPointers(cIdx, sourceX, sourceY, sourceZ) - ! Calculate source terms !$omp simd aligned(sourceX, sourceY, sourceZ) do g = 1, nG @@ -424,7 +425,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra ! Compute exponentials necessary for angular flux update !$omp simd do g = 1, nG - tau(g) = max(total(g) * lenFlt, 1.0E-8) + tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) end do !$omp simd @@ -524,6 +525,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra call arrays % incrementVolume(cIdx, length) call arrays % incrementCentroid(cIdx, rC) call arrays % incrementMoments(cIdx, matScore) + call arrays % unsetLock(cIdx) if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) From 88ed3c90223175ed573b23d50793a98f0455f093 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 14 Aug 2024 19:54:53 +0100 Subject: [PATCH 10/15] Fixes for stability --- RandomRayObjects/arraysRR_class.f90 | 169 ++++++++++++-------------- RandomRayObjects/rayHandling_func.f90 | 18 +-- 2 files changed, 89 insertions(+), 98 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index beab934d4..1eb0c4efa 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -156,7 +156,7 @@ module arraysRR_class procedure :: wasHit procedure :: getCellHitRate procedure :: getSimulationType - procedure :: found + procedure :: wasFound procedure :: hasFixedSource procedure :: getFluxAtAPoint @@ -820,14 +820,14 @@ end subroutine wipeCellHits !! !! Has a cell ever been found? !! - elemental function found(self, cIdx) result(wasFound) + elemental function wasFound(self, cIdx) result(found) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx - logical(defBool) :: wasFound + logical(defBool) :: found - wasFound = self % cellFound(cIdx) + found = self % cellFound(cIdx) - end function found + end function wasFound !! !! Note that a new cell has been found @@ -928,14 +928,14 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it real(defReal) :: norm, normVol - real(defReal), save :: vol + real(defReal), save :: vol, volAve, volNaive real(defFlt), save :: sigGG, D, norm_V real(defFlt), dimension(:), pointer, save :: total integer(shortInt), save :: g, matIdx, idx integer(shortInt) :: cIdx logical(defBool), save :: hit, isSrc character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' - !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D, hit, isSrc) + !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D, hit, isSrc, volAve, volNaive) norm = ONE / self % lengthPerIt normVol = ONE / (self % lengthPerIt * it) @@ -946,49 +946,48 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & self % volumeTracks(cIdx) + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + volAve = self % volume(cIdx) + volNaive = self % volumeTracks(cIdx) * norm + self % volumeTracks(cIdx) = ZERO ! Decide volume to use select case(self % volPolicy) case(simAverage) - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + vol = volAve case(naive) - self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + vol = volNaive case(hybrid) if (isSrc) then - self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + vol = volNaive else - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + vol = volAve end if case default call fatalError(Here,'Unsupported volume handling requested') end select - self % volumeTracks(cIdx) = ZERO - vol = self % volume(cIdx) - - ! Save effort by skipping normalisation if volume is too small + norm_V = real(norm / vol, defFlt) + if (vol < volume_tolerance) then do g = 1, self % nG - idx = self % nG * (cIdx - 1) + g + idx = self % nG * (cIdx - 1) + g self % scalarFlux(idx) = 0.0_defFlt end do - cycle + cycle end if - norm_V = real(norm / vol, defFlt) call self % XSData % getTotalPointer(matIdx, total) do g = 1, self % nG idx = self % nG * (cIdx - 1) + g - self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - ! Apply the standard MoC post-sweep treatment and - ! stabilisation for negative XSs - !if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then - if (hit) then + + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) ! Presumes non-zero total XS @@ -1016,9 +1015,11 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) case default call fatalError(Here,'Unsupported miss handling requested') end select + end if ! Alternatively, handle unidentified/void regions !else + ! self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V ! self % scalarFlux(idx) = self % scalarFlux(idx) + & ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) !end if @@ -1036,18 +1037,17 @@ end subroutine normaliseFluxAndVolumeFlatIso subroutine normaliseFluxAndVolumeLinearIso(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it - real(defFlt) :: norm - real(defReal) :: normVol - real(defReal), save :: invVol - real(defFlt), save :: vol, norm_V, D, sigGG + real(defReal) :: norm, normVol + real(defReal), save :: vol, invVol, volNaive, volAve + real(defFlt), save :: norm_V, D, sigGG real(defFlt), dimension(:), pointer, save :: total integer(shortInt) :: cIdx integer(shortInt), save :: g, matIdx, idx, dIdx, mIdx logical(defBool), save :: hit, isSrc character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' - !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG, hit, isSrc) + !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG, hit, isSrc, volNaive, volAve) - norm = real(ONE / self % lengthPerIt, defFlt) + norm = ONE / self % lengthPerIt normVol = ONE / (self % lengthPerIt * it) !$omp parallel do schedule(static) @@ -1058,29 +1058,48 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & self % volumeTracks(cIdx) + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + volAve = self % volume(cIdx) + volNaive = self % volumeTracks(cIdx) * norm + self % volumeTracks(cIdx) = ZERO ! Decide volume to use select case(self % volPolicy) case(naive) - self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + vol = volNaive case(simAverage) - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + vol = volAve case(hybrid) if (isSrc) then - self % volume(cIdx) = self % volumeTracks(cIdx) / self % lengthPerIt + vol = volNaive else - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + vol = volAve end if case default call fatalError(Here,'Unsupported volume handling requested') end select - self % volumeTracks(cIdx) = ZERO - vol = real(self % volume(cIdx), defFlt) + invVol = ONE / self % allVolumeTracks(cIdx) + + ! Update geometric information provided volume has been visited + if (self % allVolumeTracks(cIdx) > ZERO) then + ! Update centroids + self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol + self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol + self % centroid(dIdx + z) = self % centroidTracks(dIdx + z) * invVol - ! Save effort by skipping normalisation if volume is too small - !if ((.not. self % found(cIdx)) .or. (vol < volume_tolerance)) then + ! Update spatial moments + self % momMat(mIdx + xx) = self % momTracks(mIdx + xx) * invVol + self % momMat(mIdx + xy) = self % momTracks(mIdx + xy) * invVol + self % momMat(mIdx + xz) = self % momTracks(mIdx + xz) * invVol + self % momMat(mIdx + yy) = self % momTracks(mIdx + yy) * invVol + self % momMat(mIdx + yz) = self % momTracks(mIdx + yz) * invVol + self % momMat(mIdx + zz) = self % momTracks(mIdx + zz) * invVol + + end if + if (vol < volume_tolerance) then do g = 1, self % nG idx = self % nG * (cIdx - 1) + g @@ -1089,25 +1108,8 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarY(idx) = 0.0_defFlt self % scalarZ(idx) = 0.0_defFlt end do - self % centroid((dIdx + x):(dIdx + z)) = ZERO - self % momMat((mIdx + xx):(mIdx + zz)) = ZERO - cycle + cycle end if - - invVol = ONE / self % allVolumeTracks(cIdx) - - ! Update centroids - self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol - self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol - self % centroid(dIdx + z) = self % centroidTracks(dIdx + z) * invVol - - ! Update spatial moments - self % momMat(mIdx + xx) = self % momTracks(mIdx + xx) * invVol - self % momMat(mIdx + xy) = self % momTracks(mIdx + xy) * invVol - self % momMat(mIdx + xz) = self % momTracks(mIdx + xz) * invVol - self % momMat(mIdx + yy) = self % momTracks(mIdx + yy) * invVol - self % momMat(mIdx + yz) = self % momTracks(mIdx + yz) * invVol - self % momMat(mIdx + zz) = self % momTracks(mIdx + zz) * invVol call self % XSData % getTotalPointer(matIdx, total) norm_V = real(norm / vol, defFlt) @@ -1116,7 +1118,6 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) idx = self % nG * (cIdx - 1) + g - !if (hit .and. (vol > volume_tolerance)) then if (hit) then self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarX(idx) = self % scalarX(idx) * norm_V @@ -1125,7 +1126,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Apply the standard MoC post-sweep treatment and ! stabilisation for negative XSs - if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + !if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) self % scalarX(idx) = self % scalarX(idx) / total(g) @@ -1142,7 +1143,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + D * self % prevFlux(idx) ) / (1 + D) - end if + !end if else ! Decide flux treatment to use associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) @@ -1150,17 +1151,17 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) ! Note: this is policy to use the source, not policy for hitting a fixed source case(srcPolicy) self % scalarFlux(idx) = self % source(idx) / total(g) - ! I THINK OPENMC SETS MOMENTS TO ZERO - self % scalarX(idx) = 0.0_defFlt - self % scalarY(idx) = 0.0_defFlt - self % scalarZ(idx) = 0.0_defFlt + ! OPENMC SETS MOMENTS TO ZERO + !self % scalarX(idx) = 0.0_defFlt + !self % scalarY(idx) = 0.0_defFlt + !self % scalarZ(idx) = 0.0_defFlt ! Need to multiply source gradients by moment matrix - !self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - ! mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) - !self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - ! mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) - !self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - ! mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) case(prevPolicy) self % scalarFlux(idx) = self % prevFlux(idx) self % scalarX(idx) = self % prevX(idx) @@ -1174,17 +1175,17 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarZ(idx) = self % prevZ(idx) else self % scalarFlux(idx) = self % source(idx) / total(g) - ! I THINK OPENMC SETS MOMENTS TO ZERO - self % scalarX(idx) = 0.0_defFlt - self % scalarY(idx) = 0.0_defFlt - self % scalarZ(idx) = 0.0_defFlt + ! OPENMC SETS MOMENTS TO ZERO + !self % scalarX(idx) = 0.0_defFlt + !self % scalarY(idx) = 0.0_defFlt + !self % scalarZ(idx) = 0.0_defFlt ! Need to multiply source gradients by moment matrix - !self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - ! mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) - !self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - ! mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) - !self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - ! mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) end if case default call fatalError(Here,'Unsupported miss handling requested') @@ -1595,9 +1596,8 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) ! Check whether to continue in this cell if (matIdx > self % XSData % getNMat()) return if (.not. self % XSData % isFissile(matIdx)) return - !if (.not. self % found(cIdx)) return + if (.not. self % wasFound(cIdx)) return vol = self % volume(cIdx) - if (vol < volume_tolerance) return call self % XSData % getNuFissPointer(matIdx, nuSigmaF) flux => self % scalarFlux((self % nG * (cIdx - 1) + 1):(self % nG * cIdx)) @@ -1780,7 +1780,6 @@ subroutine finaliseFluxScores(self, it, totalIt) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it integer(shortInt), intent(in) :: totalIt - integer(shortInt) :: cIdx character(100), parameter :: Here = 'finaliseFLuxScores (arraysRR_class.f90)' select case(self % simulationType) @@ -1792,14 +1791,6 @@ subroutine finaliseFluxScores(self, it, totalIt) call fatalError(Here,'Unsupported simulation type requested') end select - ! Also finalise volume scores - ! Ensures naive estimate is not used for post-processed results - !$omp parallel do schedule(static) - do cIdx = 1, self % nCells - self % volume(cIdx) = self % allVolumeTracks(cIdx) / (totalIt * self % lengthPerIt) - end do - !$omp end parallel do - end subroutine finaliseFluxScores !! diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index bcfe27551..508155128 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -81,7 +81,7 @@ subroutine initialiseRay(r, arrays) call r % build(x, u, 1, ONE) call geom % placeCoord(r % coords) - if (.not. arrays % found(cIdx)) call arrays % newFound(cIdx, x) + if (.not. arrays % wasFound(cIdx)) call arrays % newFound(cIdx, x) end subroutine initialiseRay @@ -232,8 +232,8 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! Set new cell's position. Use half distance across cell ! to try and avoid FP error - if (.not. arrays % found(cIdx)) then - call arrays % newFound(cIdx, r % rGlobal() + length * HALF * r % dirGlobal()) + if (.not. arrays % wasFound(cIdx)) then + call arrays % newFound(cIdx, r % rGlobal() - length * HALF * r % dirGlobal()) end if lenFlt = real(length,defFlt) @@ -386,21 +386,21 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra rC = r0 + length * HALF * mu0 ! Set new cell's position - if (.not. arrays % found(cIdx)) call arrays % newFound(cIdx, rC) + if (.not. arrays % wasFound(cIdx)) call arrays % newFound(cIdx, rC) ! Compute the track centroid and entry point in local co-ordinates ! Convert to floats for speed ! If region is rarely visited, use ray's halfway point as centroid ! Prevents numerical trouble - if (arrays % getVolume(cIdx) < volume_tolerance) then - rNorm = ZERO - rNormFlt = 0.0_defFlt - r0NormFlt = -real(HALF * mu0 * length,defFlt) - else + if (arrays % getVolume(cIdx) > ZERO) then mid = arrays % getCentroid(cIdx) rNorm = rC - mid rNormFlt = real(rNorm,defFlt) r0NormFlt = real(r0 - mid,defFlt) + else + rNorm = ZERO + rNormFlt = 0.0_defFlt + r0NormFlt = -real(HALF * mu0 * length,defFlt) end if call arrays % getSourcePointer(cIdx, source) From 762ebececdaa18cb18610e8cc89b832c56cc0b4f Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Wed, 4 Sep 2024 17:12:34 +0100 Subject: [PATCH 11/15] Volume/miss policy tweaks --- RandomRayObjects/arraysRR_class.f90 | 61 +++++++++++++++------------ RandomRayObjects/rayHandling_func.f90 | 7 ++- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index fa5838f27..8687f2784 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -414,7 +414,7 @@ subroutine initAdjoint(self) !$omp parallel do do cIdx = 1, self % nCells - if (.not. self % found(cIdx)) cycle + if (.not. self % wasFound(cIdx)) cycle if (doLinear) invM = self % invertMatrix(cIdx) do g = 1, self % nG @@ -430,7 +430,8 @@ subroutine initAdjoint(self) ! Linear source treatment relies on performing a Taylor expansion ! of q' = 1/phi = 1/(phi_0 + grad phi * (r - r0)) ! = 1/phi_0 - 1/phi^2_0 * gradPhi * (r - r0) - if (doLinear) then + !if (doLinear) then + if (1 == 0) then xMom = real(self % xScores(1, i), defFlt) yMom = real(self % yScores(1, i), defFlt) zMom = real(self % zScores(1, i), defFlt) @@ -916,6 +917,7 @@ elemental function getCellHitRate(self, it) result(hitRate) realCells = self % nCells end if hitRate = real(totalHit,defReal) / realCells + !print *, realCells end function getCellHitRate @@ -980,7 +982,8 @@ elemental function hasFixedSource(self, cIdx) result (hasSrc) if (allocated(self % fixedSource)) then idx1 = self % nG * (cIdx - 1) + 1 idx2 = self % nG * cIdx - hasSrc = any(self % fixedSource(idx1:idx2) > 0.0_defFlt) + ! Take an absolute value in case of (possibly desirable?) negative sources + hasSrc = any(abs(self % fixedSource(idx1:idx2)) > 0.0_defFlt) else hasSrc = .false. end if @@ -1083,14 +1086,6 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) end select norm_V = real(norm / vol, defFlt) - if (vol < volume_tolerance) then - do g = 1, self % nG - idx = self % nG * (cIdx - 1) + g - self % scalarFlux(idx) = 0.0_defFlt - end do - cycle - end if - call self % XSData % getTotalPointer(matIdx, total) do g = 1, self % nG @@ -1098,6 +1093,14 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) idx = self % nG * (cIdx - 1) + g if (hit) then + + ! Can hit a cell but with a tiny volume, such that + ! things break a bit - would rather remove this arbitrary + ! check in future + if (vol < volume_tolerance) then + self % scalarFlux(idx) = 0.0_defFlt + cycle + end if self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) @@ -1212,17 +1215,6 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) end if - if (vol < volume_tolerance) then - do g = 1, self % nG - idx = self % nG * (cIdx - 1) + g - self % scalarFlux(idx) = 0.0_defFlt - self % scalarX(idx) = 0.0_defFlt - self % scalarY(idx) = 0.0_defFlt - self % scalarZ(idx) = 0.0_defFlt - end do - cycle - end if - call self % XSData % getTotalPointer(matIdx, total) norm_V = real(norm / vol, defFlt) @@ -1231,6 +1223,18 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) idx = self % nG * (cIdx - 1) + g if (hit) then + + ! Can hit a cell but with a tiny volume, such that + ! things break a bit - would rather remove this arbitrary + ! check in future + if (vol < volume_tolerance) then + self % scalarFlux(idx) = 0.0_defFlt + self % scalarX(idx) = 0.0_defFlt + self % scalarY(idx) = 0.0_defFlt + self % scalarZ(idx) = 0.0_defFlt + cycle + end if + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V self % scalarX(idx) = self % scalarX(idx) * norm_V self % scalarY(idx) = self % scalarY(idx) * norm_V @@ -1715,6 +1719,7 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) if (.not. self % XSData % isFissile(matIdx)) return if (.not. self % wasFound(cIdx)) return vol = self % volume(cIdx) + if (vol < volume_tolerance) return call self % XSData % getNuFissPointer(matIdx, nuSigmaF) flux => self % scalarFlux((self % nG * (cIdx - 1) + 1):(self % nG * cIdx)) @@ -2034,8 +2039,10 @@ subroutine outputMap(self, out, map, doFission) !$omp parallel do reduction(+: res, resSD) do cIdx = 1, self % nCells - vol = self % volume(cIdx) * self % totalVolume - if (vol < volume_tolerance) cycle + vol = self % volume(cIdx) + !if (vol < volume_tolerance) cycle + vol = vol * self % totalVolume + if (.not. self % wasFound(cIdx)) cycle ! Fudge a particle state to search tally map s % r = self % cellPos(:,cIdx) @@ -2222,8 +2229,10 @@ subroutine materialIntegral(self, matIdx, integral, intSD) mIdx = self % geom % geom % graph % getMatFromUID(cIdx) if (mIdx /= matIdx) cycle - vol = self % volume(cIdx) * self % totalVolume - if (vol < volume_tolerance) cycle + vol = self % volume(cIdx) + !if (vol < volume_tolerance) cycle + vol = vol * self % totalVolume + if (.not. self % wasFound(cIdx)) cycle do g = 1, self % nG integral = integral + self % getFluxScore(cIdx, g) * vol diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 508155128..6f9ecec5e 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -243,10 +243,15 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! TODO: Should use a better branching criterion. Maybe create it in data? ! Standard route if (matIdx <= XSData % getNMat()) then + + !$omp simd + do g = 1, nG + tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) + end do !$omp simd do g = 1, nG - tau(g) = total(g) * lenFlt + !tau(g) = total(g) * lenFlt attenuate(g) = lenFlt * expF1(tau(g)) delta(g) = (total(g) * angular(g) - source(g)) * attenuate(g) angular(g) = angular(g) - delta(g) From 8c78b3e130e5779ada62f0bbddfeb132fd704b48 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Sat, 14 Sep 2024 18:11:41 +0100 Subject: [PATCH 12/15] Temporary modification Forward solvers only use hybrid policies, while adjoint solvers differ. May delete or omdify yet in future. --- RandomRayObjects/arraysRR_class.f90 | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 8687f2784..eb696a681 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -90,8 +90,10 @@ module arraysRR_class integer(shortInt) :: ani = 0 integer(shortInt) :: simulationType = 0 real(defReal) :: totalVolume = ONE - integer(shortInt) :: volPolicy = simAverage - integer(shortInt) :: missPolicy = srcPolicy + integer(shortInt) :: volPolicy = hybrid !simAverage + integer(shortInt) :: missPolicy = hybrid !srcPolicy + integer(shortInt) :: tempVolPolicy = hybrid !simAverage + integer(shortInt) :: tempMissPolicy = hybrid !srcPolicy ! Flux arrays real(defFlt), dimension(:), allocatable :: scalarFlux @@ -260,14 +262,14 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & self % rho = real(rho, defFlt) if (present(volPolicy)) then - self % volPolicy = volPolicy + self % tempVolPolicy = volPolicy else - self % volPolicy = simAverage + self % tempVolPolicy = simAverage end if if (present(missPolicy)) then - self % missPolicy = missPolicy + self % tempMissPolicy = missPolicy else - self % missPolicy = srcPolicy + self % tempMissPolicy = srcPolicy end if ! Assume bounding box of the geometry is filled (and a box) @@ -390,6 +392,10 @@ subroutine initAdjoint(self) doLinear = .false. invM = 0.0_defFlt + ! Reset volume and miss policies - assume hybrid policy is used before + self % volPolicy = self % tempVolPolicy + self % missPolicy = self % tempMissPolicy + call self % xsData % setAdjointXS() if (.not. allocated(self % fixedSource)) then From b1ce4f2933ae2236b9cfeafe8ff6d2f72c37524b Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Mon, 8 Sep 2025 15:50:08 +0100 Subject: [PATCH 13/15] Random ray pre-tallies --- DataStructures/charMap_class.f90 | 2 +- DataStructures/intMap_class.f90 | 2 +- .../RandomRay/C5G7/C5G7_RoddedB_TRRM | 1131 +++++++++++++++++ .../Benchmarks/RandomRay/C5G7/C5G7_TRRM | 301 +++++ .../RandomRay/C5G7/C5G7_TRRM_coarse | 294 +++++ .../Benchmarks/RandomRay/C5G7/XS_C5G7/CR | 31 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/FC | 34 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/GT | 31 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/MOX43 | 36 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/MOX7 | 36 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/MOX87 | 34 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/UO2 | 34 + .../Benchmarks/RandomRay/C5G7/XS_C5G7/moder | 31 + .../RandomRay/DogLeg/XS_dog/absorberA | 16 + .../RandomRay/DogLeg/XS_dog/absorberS | 14 + .../Benchmarks/RandomRay/DogLeg/XS_dog/voidA | 16 + .../Benchmarks/RandomRay/DogLeg/XS_dog/voidS | 14 + .../RandomRay/DogLeg/dogleg_TRRM_absorb | 462 +++++++ .../RandomRay/DogLeg/dogleg_TRRM_scatter | 462 +++++++ .../Source/materialSource_class.f90 | 2 +- .../fixedSourcePhysicsPackage_class.f90 | 3 + .../fixedSourceRRPhysicsPackage_class.f90 | 12 +- .../randomRayPhysicsPackage_class.f90 | 18 +- RandomRayObjects/arraysRR_class.f90 | 614 +++++---- RandomRayObjects/constantsRR.f90 | 2 +- RandomRayObjects/dataRR_class.f90 | 78 +- RandomRayObjects/mathsRR_func.f90 | 36 +- RandomRayObjects/rayHandling_func.f90 | 219 ++-- 28 files changed, 3590 insertions(+), 375 deletions(-) create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/C5G7_RoddedB_TRRM create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM_coarse create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/CR create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/FC create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/GT create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX43 create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX7 create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX87 create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/UO2 create mode 100644 InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/moder create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberA create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberS create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidA create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidS create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_absorb create mode 100644 InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_scatter diff --git a/DataStructures/charMap_class.f90 b/DataStructures/charMap_class.f90 index b1e14f798..1d6f5d41a 100644 --- a/DataStructures/charMap_class.f90 +++ b/DataStructures/charMap_class.f90 @@ -193,7 +193,7 @@ end function length !! Errors: !! None !! - subroutine add(self, key, val) + recursive subroutine add(self, key, val) class(charMap), intent(inout) :: self character(nameLen), intent(in) :: key integer(shortInt), intent(in) :: val diff --git a/DataStructures/intMap_class.f90 b/DataStructures/intMap_class.f90 index d5863768f..59530ae6f 100644 --- a/DataStructures/intMap_class.f90 +++ b/DataStructures/intMap_class.f90 @@ -184,7 +184,7 @@ end function length !! Errors: !! None !! - subroutine add(self, key, val) + recursive subroutine add(self, key, val) class(intMap), intent(inout) :: self integer(shortInt), intent(in) :: key integer(shortInt), intent(in) :: val diff --git a/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_RoddedB_TRRM b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_RoddedB_TRRM new file mode 100644 index 000000000..4a64d3e05 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_RoddedB_TRRM @@ -0,0 +1,1131 @@ +type randomRayPhysicsPackage; + +pop 117000; +active 950; +inactive 1525; +dead 12.56; +termination 628.12; +plot 0; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_RoddedB_TRRM ; + + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 0 1 1 0); + 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 azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (UO2 UO2 UO2 water water water);} + pin2 { id 2; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (GT GT GT water water water);} + pin3 { id 3; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox43 mox43 mox43 water water water);} + pin4 { id 4; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox7 mox7 mox7 water water water);} + pin5 { id 5; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox87 mox87 mox87 water water water);} + pin6 { id 6; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (FC FC FC water water water);} + + // Control rod + pin7 { id 7; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0); rotation (22.5 0 0); fills (CR CR CR water water 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 +); +} + +latJustRods { + id 21; + type latUniverse; + origin (0.0 0.0 0.0); + pitch (1.26 1.26 0.0); + shape (17 17 0); + padMat water; + map ( + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 7 40 40 7 40 40 7 40 40 40 40 40 + 40 40 40 7 40 40 40 40 40 40 40 40 40 7 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 7 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 40 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 7 40 40 7 40 40 7 40 40 7 40 40 7 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 7 40 40 40 40 40 40 40 40 40 7 40 40 40 + 40 40 40 40 40 7 40 40 7 40 40 7 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 + 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.126 0.126 0.0); +shape (10 10 0); +padMat water; +map ( +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latUO2Rod{ + id 80; + 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 7 1 1 7 1 1 7 1 1 1 1 1 + 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 7 1 1 7 1 1 7 1 1 7 1 1 7 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 7 1 1 7 1 1 6 1 1 7 1 1 7 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 7 1 1 7 1 1 7 1 1 7 1 1 7 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 + 1 1 1 1 1 7 1 1 7 1 1 7 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 +); +} + +latMOXRod{ + id 90; + 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 7 4 4 7 4 4 7 4 4 4 4 3 + 3 4 4 7 4 5 5 5 5 5 5 5 4 7 4 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 7 5 5 2 5 5 7 5 5 7 5 5 7 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 7 5 5 7 5 5 6 5 5 7 5 5 7 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 7 5 5 7 5 5 7 5 5 7 5 5 7 4 3 + 3 4 4 4 5 5 5 5 5 5 5 5 5 4 4 4 3 + 3 4 4 7 4 5 5 5 5 5 5 5 4 7 4 4 3 + 3 4 4 4 4 7 4 4 7 4 4 7 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.357); + shape (3 3 180); + padMat water; + map ( + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +21 21 60 +21 21 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 90 60 +90 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +80 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +10 20 60 +20 10 60 +50 50 70 + +); +} + +} + +} + +viz { +// bmp1 { +// type bmp; +// output material_yz; +// what material; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } +// bmp2 { +// type bmp; +// output material_xy; +// what material; +// centre (0.0 0.0 31.0); +// axis z; +// res (2000 2000); } +// bmp3 { +// type bmp; +// output ID_yz; +// what uniqueID; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } +// myVTK { +// type vtk; +// what uniqueID; +// centre (-21.42 0.0 0.0); +// axis x; +// res (2000 2000); } + myVTK { + type vtk; + what uniqueID; + corner (-21.42 -32.13 -32.13); + width (0.1 64.26 64.26); + vox (1 2000 2000); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + numberOfGroups 7; + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + + // Control rod + CR { + temp 300; + xsFile ../XS_C5G7/CR; + composition { } + } +} +} + + diff --git a/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM new file mode 100644 index 000000000..eecb6305e --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM @@ -0,0 +1,301 @@ +type randomRayPhysicsPackage; +lin 0; +pop 1750; +active 1200; +inactive 1000; +dead 20; +termination 220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_TRRM; + +fissionMap {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;} +} +fluxMap {type multiMap; + maps (xax yax); + xax { type spaceMap; axis x; grid lin; min -32.13; max 32.13; N 51;} + yax { type spaceMap; axis y; grid lin; min -32.13; max 32.13; N 51;} +} + +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 azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (UO2 UO2 UO2 water water water);} + pin2 { id 2; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (GT GT GT water water water);} + pin3 { id 3; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox43 mox43 mox43 water water water);} + pin4 { id 4; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox7 mox7 mox7 water water water);} + pin5 { id 5; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (mox87 mox87 mox87 water water water);} + pin6 { id 6; type azimPinUniverse; naz 8; radii (0.311769 0.440908 0.5400 0.63 0.72 0.0 ); rotation (22.5 0 0); fills (FC FC FC water water 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 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.126 0.126 0.0); +shape (10 10 0); +padMat water; +map ( +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +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 60 +20 10 60 +50 50 70 +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner (-32.13 -32.13 -1.0); + width (64.26 64.26 2.0); + vox (2000 2000 1); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + +} +} + + diff --git a/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM_coarse b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM_coarse new file mode 100644 index 000000000..40313a1b0 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/C5G7_TRRM_coarse @@ -0,0 +1,294 @@ +type randomRayPhysicsPackage; + +lin 1; +pop 1750; +active 1200; +inactive 1000; +dead 20; +termination 220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile C5G7_TRRM_coarse; + +fissionMap {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;} +} +fluxMap {type multiMap; + maps (xax yax); + xax { type spaceMap; axis x; grid lin; min -32.13; max 32.13; N 51;} + yax { type spaceMap; axis y; grid lin; min -32.13; max 32.13; N 51;} +} + +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 azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (UO2 water);} + pin2 { id 2; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (GT water);} + pin3 { id 3; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox43 water);} + pin4 { id 4; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox7 water);} + pin5 { id 5; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 0 0); fills (mox87 water);} + pin6 { id 6; type azimPinUniverse; nazR (4 8); radii (0.5400 0.0); rotation (0 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 +); +} + +latFineModer +{ +id 40; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (0.63 0.63 0.0); +shape (2 2 0); +padMat water; +map ( +30 30 +30 30 +); +} + +latModUp +{ +id 50; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +latModLeft +{ +id 60; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +); +} + +latModCorner +{ +id 70; +type latUniverse; +origin (0.0 0.0 0.0); +pitch (1.26 1.26 0.0); +shape (17 17 0); +padMat water; +map ( +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 +); +} + +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 60 +20 10 60 +50 50 70 +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner (-32.13 -32.13 -1.0); + width (64.26 64.26 2.0); + vox (2000 2000 1); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + water { + temp 300; + xsFile ../XS_C5G7/moder; + composition { } + } + + 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 { } + } + +} +} + + diff --git a/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/CR b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/CR new file mode 100644 index 000000000..e4dbeae5b --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/FC b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/FC new file mode 100644 index 000000000..441cd9895 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/GT b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/GT new file mode 100644 index 000000000..77ed9f30f --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/MOX43 b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX43 new file mode 100644 index 000000000..46054ba02 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/MOX7 b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX7 new file mode 100644 index 000000000..3db4c6cb1 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/MOX87 b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/MOX87 new file mode 100644 index 000000000..6d47c4a11 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/UO2 b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/UO2 new file mode 100644 index 000000000..ffb187b5d --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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/RandomRay/C5G7/XS_C5G7/moder b/InputFiles/Benchmarks/RandomRay/C5G7/XS_C5G7/moder new file mode 100644 index 000000000..029b934f1 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/C5G7/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 +); + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberA b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberA new file mode 100644 index 000000000..2494eb505 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberA @@ -0,0 +1,16 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +//0.05 //scatter case +0.10 // absorber case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + //0.05 // scatter case + 0.0 // absorber case +); + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberS b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberS new file mode 100644 index 000000000..5f4b0c316 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/absorberS @@ -0,0 +1,14 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +0.05 //scatter case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.05 // scatter case +); + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidA b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidA new file mode 100644 index 000000000..adfd286ba --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidA @@ -0,0 +1,16 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +//0.5E-4 // scatter case +1.0E-4 // absorber case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + //0.5E-4 // scatter case + 0.0 // absorber case +); + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidS b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidS new file mode 100644 index 000000000..5945ee09a --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/XS_dog/voidS @@ -0,0 +1,14 @@ +// This XS corresponds to the Case 2 for the Kobayashi dogleg benchmark + +numberOfGroups 1; + +capture ( +0.5E-4 // scatter case +); + +scatteringMultiplicity ( 1.0 ); + +P0 ( + 0.5E-4 // scatter case +); + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_absorb b/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_absorb new file mode 100644 index 000000000..cbddd28f0 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_absorb @@ -0,0 +1,462 @@ +type fixedSourceRRPhysicsPackage; + +pop 10000; +active 2100; +inactive 0; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_absorb; + +integrate (sourceMat); +source { sourceMat ( 1.0 ); } + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.1111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.11111111111111111 1.111111111111111111); + shape ( 9 9 9 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.11111111111111 1.111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat sourceMat; + 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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidA; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberA; + composition { } + } + + +} +} + + diff --git a/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_scatter b/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_scatter new file mode 100644 index 000000000..8a9c18ef3 --- /dev/null +++ b/InputFiles/Benchmarks/RandomRay/DogLeg/dogleg_TRRM_scatter @@ -0,0 +1,462 @@ +type fixedSourceRRPhysicsPackage; +lin 0; +!pop 10000; +pop 3000; +active 2000; +inactive 100; +dead 120; +termination 1220; +plot 1; +cache 1; +XSdata mg; +dataType mg; +outputFile dogleg_TRRM_scatter; + +source { sourceMat ( 1.0 ); } +integrate (sourceMat absorber); + +samplePoints { +A3_1 ( 5.0 5.0 5.0 ); +A3_2 ( 5.0 15.0 5.0 ); +A3_3 ( 5.0 25.0 5.0 ); +A3_4 ( 5.0 35.0 5.0 ); +A3_5 ( 5.0 45.0 5.0 ); +A3_6 ( 5.0 55.0 5.0 ); +A3_7 ( 5.0 65.0 5.0 ); +A3_8 ( 5.0 75.0 5.0 ); +A3_9 ( 5.0 85.0 5.0 ); +A3_10 ( 5.0 95.0 5.0 ); +B3_1 (5.0 55.0 5.0); +B3_2 (15.0 55.0 5.0); +B3_3 (25.0 55.0 5.0); +B3_4 (35.0 55.0 5.0); +B3_5 (45.0 55.0 5.0); +B3_6 (55.0 55.0 5.0); +C3_1 (5.0 95.0 35.0); +C3_2 (15.0 95.0 35.0); +C3_3 (25.0 95.0 35.0); +C3_4 (35.0 95.0 35.0); +C3_5 (45.0 95.0 35.0); +C3_6 (55.0 95.0 35.0); + +} + +geometry { + type geometryStd; + // ( -x, +x, -y, +y, -z, +z) + boundary ( 1 0 1 0 1 0 ); + graph { type extended; } + + surfaces { + Domain { id 3; type box; origin ( 30.0 50.0 30.0 ); halfwidth ( 30.0 50.0 30.0 ); } + } + + cells { } + + universes { + root { id 1000; type rootUniverse; border 3; fill u<100>; } + + // Pin universes + pin1 { type pinUniverse; id 1; radii ( 0.0 ); fills ( absorber ); } + pin2 { type pinUniverse; id 2; radii ( 0.0 ); fills ( voidMat ); } + pin3 { type pinUniverse; id 3; radii ( 0.0 ); fills ( sourceMat ); } + +// Lattices +latAbsCentred { + id 15; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.1111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 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 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 + 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 +); +} + +latVoidCentred { + id 25; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.1111111111111111 1.11111111111111111 1.111111111111111111); + shape ( 9 9 9 ); + padMat voidMat; + map ( +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 +); +} + +latSourceCentred { + id 35; + type latUniverse; + origin ( 0.0 0.0 0.0 ); + pitch ( 1.11111111111111 1.111111111111111 1.11111111111111 ); + shape ( 9 9 9 ); + padMat absorber; + 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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 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 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 +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 +); +} + +latGeom +{ + id 100; + type latUniverse; + origin ( 30.0 50.0 30.0 ); + pitch ( 10.0 10.0 10.0 ); + shape ( 6 10 6 ); + padMat absorber; + map ( + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 25 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 + +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +15 15 15 15 15 15 +25 25 25 25 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +25 15 15 15 15 15 +35 15 15 15 15 15 + +); +} + +} + +} + +viz { + myVTK { + type vtk; + what uniqueID; + corner ( 0.0 0.0 0.0 ); + width ( 60.0 100.0 60.0 ); + vox ( 60 100 60 ); + } +} + + +nuclearData { + handles { + mg { type baseMgNeutronDatabase; PN P0;} + } + materials { + + absorber { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + + voidMat { + temp 300; + xsFile ./XS_dog/voidS; + composition { } + } + + sourceMat { + temp 300; + xsFile ./XS_dog/absorberS; + composition { } + } + +} +} + + diff --git a/ParticleObjects/Source/materialSource_class.f90 b/ParticleObjects/Source/materialSource_class.f90 index 3f508f5aa..a66899c73 100644 --- a/ParticleObjects/Source/materialSource_class.f90 +++ b/ParticleObjects/Source/materialSource_class.f90 @@ -152,7 +152,7 @@ function sampleParticle(self, rand) result(p) rejection : do ! Protect against infinite loop i = i +1 - if ( i > 200) then + if ( i > 5000) then call fatalError(Here, 'Infinite loop in sampling source. Please check that'//& ' defined volume contains source material.') end if diff --git a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 index 01957d9fd..f6ce413c8 100644 --- a/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourcePhysicsPackage_class.f90 @@ -172,6 +172,9 @@ subroutine cycles(self, tally, N_cycles) call self % thisCycle % printToFile(trim(self % outputFile)//'_source'//numToChar(i)) end if + ! Update RNG after source generation + call self % pRNG % stride(self % pop) + call tally % reportCycleStart(self % thisCycle) !$omp parallel do schedule(dynamic) diff --git a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 index e16fa083f..7026dbc92 100644 --- a/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 +++ b/PhysicsPackages/fixedSourceRRPhysicsPackage_class.f90 @@ -86,8 +86,13 @@ module fixedSourceRRPhysicsPackage_class !! #fluxMap {}# // Optionally output one-group fluxes according to a given map !! #plot 1;# // Optionally make VTK viewable plot of fluxes and uncertainties !! #rho 0;# // Optional stabilisation for negative in-group scattering XSs + !! #lin 0;# // Optionally use linear (rather than flat) sources + !! #2d 0;# // Optional input to stablise linear sources in 2D problems + !! #volPolicy 1;# // Optional input to specify how volumes should be handled + !! #missPolicy 1;# // Optional input to specify how misses should be handled !! #cadis 0;# // Optionally generate adjoints for global variance reduction !! + !! tally {} !! geometry {} !! nuclearData {} !! } @@ -100,6 +105,7 @@ module fixedSourceRRPhysicsPackage_class !! mgData -> MG database. Calculation obviously cannot be run in CE. !! nG -> Number of energy groups, kept for convenience. !! nCells -> Number of unique cells in the geometry, kept for convenience. + !! doCADIS -> Logical to check whether to do adjoint calculations !! !! termination -> Distance a ray can travel before it is terminated !! dead -> Distance a ray must travel before it becomes active @@ -437,6 +443,7 @@ subroutine cycles(self) call timerStart(self % timerMain) arrayPtr => self % arrays + call arrayPtr % zeroPrevFlux() ! Stopping criterion is on number of convergence iterations. ! TODO: Make this on, e.g., entropy during inactive, followed by stochastic noise during active! @@ -543,7 +550,7 @@ subroutine cycles(self) end do ! Finalise flux and keff scores - call arrayPtr % finaliseFluxScores(itAct, it) + call arrayPtr % finaliseFluxScores(itAct) end subroutine cycles @@ -587,6 +594,9 @@ subroutine printResults(self) name = 'Clock_Time' call out % printValue(timerTime(self % timerMain),name) + name = 'Hit_rate' + call out % printValue(self % arrays % getAverageHitRate(),name) + outPtr => out ! Send fluxes to map output diff --git a/PhysicsPackages/randomRayPhysicsPackage_class.f90 b/PhysicsPackages/randomRayPhysicsPackage_class.f90 index ae7abde16..7f2228857 100644 --- a/PhysicsPackages/randomRayPhysicsPackage_class.f90 +++ b/PhysicsPackages/randomRayPhysicsPackage_class.f90 @@ -84,9 +84,14 @@ module randomRayPhysicsPackage_class !! #fluxMap {}# // Optionally output one-group fluxes according to a given map !! #plot 1;# // Optionally make VTK viewable plot of fluxes and uncertainties !! #rho 0;# // Optional stabilisation for negative in-group scattering XSs + !! #lin 0;# // Optionally use linear (rather than flat) sources + !! #2d 0;# // Optional input to stablise linear sources in 2D problems + !! #volPolicy 1;# // Optional input to specify how volumes should be handled + !! #missPolicy 1;# // Optional input to specify how misses should be handled !! !! geometry {} !! nuclearData {} + !! tally {} !! } !! !! Private Members @@ -116,6 +121,8 @@ module randomRayPhysicsPackage_class !! keff -> Estimated value of keff !! keffScore -> Vector holding cumulative keff score and keff^2 score !! + !! tally -> Tally admin to output results + !! !! intersectionsTotal -> Total number of ray traces for the calculation !! !! Interface: @@ -201,6 +208,7 @@ subroutine init(self, dict, loud) character(nameLen) :: geomName, graphType, nucData class(geometry), pointer :: geom type(outputFile) :: test_out + logical(defBool) :: set2D character(100), parameter :: Here = 'init (randomRayPhysicsPackage_class.f90)' call cpu_time(self % CPU_time_start) @@ -231,6 +239,9 @@ subroutine init(self, dict, loud) ! Use linear sources? call dict % getOrDefault(self % lin, 'lin', .false.) + + ! Is the problem 2D? + call dict % getOrDefault(set2D, '2d', .false.) ! Read outputfile path call dict % getOrDefault(self % outputFile,'outputFile','./output') @@ -354,7 +365,7 @@ subroutine init(self, dict, loud) ! Initialise RR arrays and nuclear data call self % arrays % init(self % mgData, self % geom, & self % pop * (self % termination - self % dead), self % rho, self % lin, & - .false., self % loud, volPolicy = volP, missPolicy = missP) + .false., self % loud, volPolicy = volP, missPolicy = missP, set2D = set2D) end subroutine init @@ -515,7 +526,7 @@ subroutine cycles(self) end do ! Finalise flux and keff scores - call arrayPtr % finaliseFluxScores(itAct, it) + call arrayPtr % finaliseFluxScores(itAct) if (itAct /= 1) then Nm1 = 1.0_defReal/(itAct - 1) else @@ -568,6 +579,9 @@ subroutine printResults(self) name = 'Clock_Time' call out % printValue(timerTime(self % timerMain),name) + + name = 'Hit_rate' + call out % printValue(self % arrays % getAverageHitRate(),name) ! Print keff name = 'keff' diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index eb696a681..b7bb64c56 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -44,6 +44,7 @@ module arraysRR_class !! rho -> Stabilisation factor: 0 is no stabilisation, 1 is aggressive stabilisation !! ani -> Order of anisotropic flux moments to be stored !! simulationType -> Identifies which simulation to perform: flat/linear, isotropic/anisotropic + !! set2D -> Stabilises LS in 2D problems if true (zeros Z moment) !! !! scalarFlux -> Array of scalar flux values of length [nG * nCells] !! prevFlux -> Array of previous scalar flux values of length [nG * nCells] @@ -55,7 +56,6 @@ module arraysRR_class !! sourceIdx -> Array of material indices containing fixed sources !! !! volumeTracks -> Array of sum of track lengths for computing volumes [nCells] - !! lengthSquared -> Array of sum of lengths^2 for use in cells with zero XS [nCells] !! volume -> Array of dimensionless cell volumes [nCells] !! !! cellHit -> Array of ints whether a cell was visited this iteration [nCells] @@ -92,13 +92,12 @@ module arraysRR_class real(defReal) :: totalVolume = ONE integer(shortInt) :: volPolicy = hybrid !simAverage integer(shortInt) :: missPolicy = hybrid !srcPolicy - integer(shortInt) :: tempVolPolicy = hybrid !simAverage - integer(shortInt) :: tempMissPolicy = hybrid !srcPolicy + logical(defBool) :: set2D = .false. ! Stabilises LS in 2D problems ! Flux arrays - real(defFlt), dimension(:), allocatable :: scalarFlux - real(defFlt), dimension(:), allocatable :: prevFlux - real(defReal), dimension(:,:), allocatable :: fluxScores + real(defReal), dimension(:), allocatable :: scalarFlux + real(defReal), dimension(:), allocatable :: prevFlux + real(defReal), dimension(:,:), allocatable :: fluxScores ! Source arrays real(defFlt), dimension(:), allocatable :: source @@ -108,19 +107,18 @@ module arraysRR_class ! Geometry arrays real(defReal), dimension(:), allocatable :: volumeTracks real(defReal), dimension(:), allocatable :: allVolumeTracks - real(defReal), dimension(:), allocatable :: lengthSquared real(defReal), dimension(:), allocatable :: volume integer(shortInt), dimension(:), allocatable :: cellHit logical(defBool), dimension(:), allocatable :: cellFound real(defReal), dimension(:,:), allocatable :: cellPos ! Linear source arrays - real(defFlt), dimension(:), allocatable :: scalarX - real(defFlt), dimension(:), allocatable :: scalarY - real(defFlt), dimension(:), allocatable :: scalarZ - real(defFlt), dimension(:), allocatable :: prevX - real(defFlt), dimension(:), allocatable :: prevY - real(defFlt), dimension(:), allocatable :: prevZ + real(defReal), dimension(:), allocatable :: scalarX + real(defReal), dimension(:), allocatable :: scalarY + real(defReal), dimension(:), allocatable :: scalarZ + real(defReal), dimension(:), allocatable :: prevX + real(defReal), dimension(:), allocatable :: prevY + real(defReal), dimension(:), allocatable :: prevZ real(defFlt), dimension(:), allocatable :: sourceX real(defFlt), dimension(:), allocatable :: sourceY real(defFlt), dimension(:), allocatable :: sourceZ @@ -138,6 +136,10 @@ module arraysRR_class ! OMP locks integer(kind=omp_lock_kind), dimension(:), allocatable :: locks + + ! Other data + real(defReal) :: averageHit = ZERO + integer(shortInt) :: iterations = 0 contains @@ -176,14 +178,15 @@ module arraysRR_class ! Change individual elements of the type ! Predominantly for use in the transport sweep procedure :: incrementVolume - procedure :: incrementLengthSquared procedure :: incrementCentroid procedure :: incrementMoments procedure :: hitCell + procedure :: getAverageHitRate procedure :: wipeCellHits procedure :: newFound procedure :: setLock procedure :: unsetLock + procedure :: setActiveLength ! Basic RR procedures procedure :: resetFluxes @@ -192,6 +195,7 @@ module arraysRR_class procedure :: accumulateFluxScores procedure :: finaliseFluxScores procedure :: calculateKeff + procedure :: zeroPrevFlux ! Output procedures procedure :: outputMap @@ -238,7 +242,7 @@ module arraysRR_class !! This will allocate the necessary arrays !! subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & - dictFS, volPolicy, missPolicy) + dictFS, volPolicy, missPolicy, set2D) class(arraysRR), intent(inout) :: self class(baseMgNeutronDatabase), pointer, intent(in) :: db class(geometryStd), pointer, intent(in) :: geom @@ -249,6 +253,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & logical(defBool), intent(in) :: loud class(dictionary), pointer, intent(inout), optional :: dictFS integer(shortInt), intent(in), optional :: volPolicy, missPolicy + logical(defBool), intent(in), optional :: set2D integer(shortInt) :: ani, i real(defReal), dimension(6) :: bb character(100), parameter :: Here = 'init (arraysRR_class.f90)' @@ -262,14 +267,20 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & self % rho = real(rho, defFlt) if (present(volPolicy)) then - self % tempVolPolicy = volPolicy + self % volPolicy = volPolicy else - self % tempVolPolicy = simAverage + self % volPolicy = simAverage end if if (present(missPolicy)) then - self % tempMissPolicy = missPolicy + self % missPolicy = missPolicy else - self % tempMissPolicy = srcPolicy + self % missPolicy = srcPolicy + end if + + if (present(set2D)) then + self % set2D = set2D + else + self % set2D = .false. end if ! Assume bounding box of the geometry is filled (and a box) @@ -298,19 +309,17 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & allocate(self % source(self % nG * self % nCells)) allocate(self % volumeTracks(self % nCells)) allocate(self % allVolumeTracks(self % nCells)) - allocate(self % lengthSquared(self % nCells)) allocate(self % volume(self % nCells)) allocate(self % cellHit(self % nCells)) allocate(self % cellFound(self % nCells)) allocate(self % cellPos(nDim, self % nCells)) - self % scalarFlux = 0.0_defFlt - self % prevFlux = 1.0_defFlt + self % scalarFlux = ZERO + self % prevFlux = ONE self % fluxScores = ZERO self % source = 0.0_defFlt self % volumeTracks = ZERO self % allVolumeTracks = ZERO - self % lengthSquared = ZERO self % volume = ZERO self % cellHit = 0 self % cellFound = .false. @@ -319,6 +328,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & ! Initialise the fixed source if present if (present(dictFS)) then allocate(self % fixedSource(self % nG * self % nCells)) + self % fixedSource = 0.0_defFlt call self % initialiseFixedSource(dictFS) end if @@ -342,12 +352,12 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & allocate(self % yScores(2, self % nG * self % nCells)) allocate(self % zScores(2, self % nG * self % nCells)) - self % scalarX = 0.0_defFlt - self % scalarY = 0.0_defFlt - self % scalarZ = 0.0_defFlt - self % prevX = 0.0_defFlt - self % prevY = 0.0_defFlt - self % prevZ = 0.0_defFlt + self % scalarX = ZERO + self % scalarY = ZERO + self % scalarZ = ZERO + self % prevX = ZERO + self % prevY = ZERO + self % prevZ = ZERO self % sourceX = 0.0_defFlt self % sourceY = 0.0_defFlt self % sourceZ = 0.0_defFlt @@ -376,6 +386,17 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & end subroutine init + !! + !! Overwrite the active length + !! + subroutine setActiveLength(self, lengthPerIt) + class(arraysRR), intent(inout) :: self + real(defReal), intent(in) :: lengthPerIt + + self % lengthPerIt = lengthPerIt + + end subroutine setActiveLength + !! !! Initialise the adjoint source and update nuclear data. !! For now, assumes the adjoint is for global variance reduction. @@ -392,10 +413,6 @@ subroutine initAdjoint(self) doLinear = .false. invM = 0.0_defFlt - ! Reset volume and miss policies - assume hybrid policy is used before - self % volPolicy = self % tempVolPolicy - self % missPolicy = self % tempMissPolicy - call self % xsData % setAdjointXS() if (.not. allocated(self % fixedSource)) then @@ -403,7 +420,8 @@ subroutine initAdjoint(self) end if self % fixedSource = 0.0_defFlt - if (allocated(self % scalarX)) then + if ((self % simulationType == linearIso) .or. & + (self % simulationType == linearAni)) then doLinear = .true. if (.not. allocated(self % fixedX)) then allocate(self % fixedX(size(self % scalarFlux))) @@ -430,17 +448,13 @@ subroutine initAdjoint(self) ! Check for inordinately small flux values. ! Note, these can have arbitrarily low magnitude. ! Maybe should be something more robust. - if (self % fluxScores(1, i) == 0.0_defFlt) cycle + if (self % fluxScores(1, i) == ZERO) cycle self % fixedSource(i) = real(ONE / self % fluxScores(1, i), defFlt) ! Linear source treatment relies on performing a Taylor expansion - ! of q' = 1/phi = 1/(phi_0 + grad phi * (r - r0)) - ! = 1/phi_0 - 1/phi^2_0 * gradPhi * (r - r0) - !if (doLinear) then - if (1 == 0) then - xMom = real(self % xScores(1, i), defFlt) - yMom = real(self % yScores(1, i), defFlt) - zMom = real(self % zScores(1, i), defFlt) + ! of q' = 1/phi = 1/(phi_0 + ) + ! = 1/phi_0 - 1/phi^2_0 * + if (doLinear .and. (self % fixedSource(i) > 0)) then self % fixedX(i) = invM(xx) * xMom + invM(xy) * yMom + invM(xz) * zMom self % fixedY(i) = invM(xy) * xMom + invM(yy) * yMom + invM(yz) * zMom self % fixedZ(i) = invM(xz) * xMom + invM(yz) * yMom + invM(zz) * zMom @@ -448,6 +462,7 @@ subroutine initAdjoint(self) self % fixedX(i) = -self % fixedX(i) * self % fixedSource(i) ** 2 self % fixedY(i) = -self % fixedY(i) * self % fixedSource(i) ** 2 self % fixedZ(i) = -self % fixedZ(i) * self % fixedSource(i) ** 2 + end if end do @@ -456,8 +471,8 @@ subroutine initAdjoint(self) !$omp end parallel do ! Reinitialise arrays to be used during transport - self % scalarFlux = 0.0_defFlt - self % prevFlux = 0.0_defFlt + self % scalarFlux = ZERO + self % prevFlux = ZERO self % fluxScores = ZERO self % source = 0.0_defFlt @@ -465,16 +480,15 @@ subroutine initAdjoint(self) ! No compact ideas at the moment, so these will simply be reinitialised self % volumeTracks = ZERO self % allVolumeTracks = ZERO - self % lengthSquared = ZERO self % volume = ZERO if (doLinear) then - self % scalarX = 0.0_defFlt - self % scalarY = 0.0_defFlt - self % scalarZ = 0.0_defFlt - self % prevX = 0.0_defFlt - self % prevY = 0.0_defFlt - self % prevZ = 0.0_defFlt + self % scalarX = ZERO + self % scalarY = ZERO + self % scalarZ = ZERO + self % prevX = ZERO + self % prevY = ZERO + self % prevZ = ZERO self % sourceX = 0.0_defFlt self % sourceY = 0.0_defFlt self % sourceZ = 0.0_defFlt @@ -562,15 +576,14 @@ subroutine initialiseFixedSource(self, dict) end subroutine initialiseFixedSource - !! !! Return a pointer to the flux vector for a given cell !! subroutine getFluxPointer(self, cIdx, fluxVec) - class(arraysRR), intent(in), target :: self - integer(shortInt), intent(in) :: cIdx - real(defFlt), dimension(:), pointer, intent(out) :: fluxVec - integer(shortInt) :: baseIdx1, baseIdx2 + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(:), pointer, intent(out) :: fluxVec + integer(shortInt) :: baseIdx1, baseIdx2 baseIdx1 = self % nG * (cIdx - 1) + 1 baseIdx2 = self % nG * cIdx @@ -582,12 +595,12 @@ end subroutine getFluxPointer !! Return a pointer to the flux spatial moment vectors for a given cell !! subroutine getFluxXYZPointers(self, cIdx, xVec, yVec, zVec) - class(arraysRR), intent(in), target :: self - integer(shortInt), intent(in) :: cIdx - real(defFlt), dimension(:), pointer, intent(out) :: xVec - real(defFlt), dimension(:), pointer, intent(out) :: yVec - real(defFlt), dimension(:), pointer, intent(out) :: zVec - integer(shortInt) :: baseIdx1, baseIdx2 + class(arraysRR), intent(in), target :: self + integer(shortInt), intent(in) :: cIdx + real(defReal), dimension(:), pointer, intent(out) :: xVec + real(defReal), dimension(:), pointer, intent(out) :: yVec + real(defReal), dimension(:), pointer, intent(out) :: zVec + integer(shortInt) :: baseIdx1, baseIdx2 baseIdx1 = self % nG * (cIdx - 1) + 1 baseIdx2 = self % nG * cIdx @@ -683,7 +696,6 @@ elemental function getFixedSource(self, cIdx, g) result(src) end function getFixedSource - !! !! Return previous flux value given cell and group !! @@ -691,7 +703,7 @@ elemental function getPrevFlux(self, cIdx, g) result(flux) class(arraysRR), intent(in) :: self integer(shortInt), intent(in) :: cIdx integer(shortInt), intent(in) :: g - real(defFlt) :: flux + real(defReal) :: flux flux = self % prevFlux(self % nG * (cIdx - 1) + g) @@ -837,19 +849,6 @@ subroutine incrementVolume(self, cIdx, length) end subroutine incrementVolume - !! - !! Increment the sum of length squared in cell cIdx. - !! Assumes this is being called inside a lock for thread privacy. - !! - subroutine incrementLengthSquared(self, cIdx, length) - class(arraysRR), intent(inout) :: self - integer(shortInt), intent(in) :: cIdx - real(defReal), intent(in) :: length - - self % lengthSquared(cIdx) = self % lengthSquared(cIdx) + length * length - - end subroutine incrementLengthSquared - !! !! Increment the local centroid estimate in cell cIdx. !! rL is the tracklength-weighted centroid @@ -909,12 +908,23 @@ end subroutine hitCell !! !! Return the cell hit rate for the given iteration + !! Also accumulate to average hit rate. !! - elemental function getCellHitRate(self, it) result(hitRate) - class(arraysRR), intent(in) :: self - integer(shortInt), intent(in) :: it - integer(shortInt) :: totalHit, realCells - real(defReal) :: hitRate + !! Only averages after 20 iterations to account for + !! requiring several iterations to determine which cells + !! are present in the geometry. + !! + function getCellHitRate(self, it) result(hitRate) + class(arraysRR), intent(inout) :: self + integer(shortInt), intent(in) :: it + integer(shortInt) :: totalHit, realCells + real(defReal) :: hitRate + + ! Reset averages after iteration 20 + if (it == 21) then + self % averageHit = ZERO + self % iterations = 0 + end if totalHit = sum(self % cellHit) if (it > 20) then @@ -922,11 +932,24 @@ elemental function getCellHitRate(self, it) result(hitRate) else realCells = self % nCells end if - hitRate = real(totalHit,defReal) / realCells - !print *, realCells + hitRate = real(totalHit,defReal) / realCells + + self % averageHit = self % averageHit + hitRate + self % iterations = self % iterations + 1 end function getCellHitRate + !! + !! Return the simulation average cell hit rate + !! + function getAverageHitRate(self) result(hitRate) + class(arraysRR), intent(in) :: self + real(defReal) :: hitRate + + hitRate = self % averageHit / self % iterations + + end function getAverageHitRate + !! !! Wipe cell hits !! @@ -1038,7 +1061,7 @@ subroutine normaliseFluxAndVolume(self, it) case default call fatalError(Here,'Unsupported simulation type requested') end select - + end subroutine normaliseFluxAndVolume !! @@ -1048,32 +1071,34 @@ end subroutine normaliseFluxAndVolume subroutine normaliseFluxAndVolumeFlatIso(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it - real(defReal) :: norm, normVol - real(defReal), save :: vol, volAve, volNaive - real(defFlt), save :: sigGG, D, norm_V + real(defReal) :: norm, normIt + real(defReal), save :: vol, volAve, volNaive, D + real(defFlt), save :: sigGG real(defFlt), dimension(:), pointer, save :: total integer(shortInt), save :: g, matIdx, idx integer(shortInt) :: cIdx logical(defBool), save :: hit, isSrc - character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' - !$omp threadprivate(total, vol, norm_V, idx, g, matIdx, sigGG, D, hit, isSrc, volAve, volNaive) + character(100), parameter :: Here = 'normaliseFluxAndVolumeFlatIso (arraysRR_class.f90)' + !$omp threadprivate(total, vol, idx, g, matIdx, sigGG, D, hit, isSrc, volAve, volNaive) norm = ONE / self % lengthPerIt - normVol = ONE / (self % lengthPerIt * it) - + normIt = ONE / (self % lengthPerIt * it) + !$omp parallel do - do cIdx = 1, self % nCells + cellLoop: do cIdx = 1, self % nCells matIdx = self % geom % geom % graph % getMatFromUID(cIdx) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + !! Compute various volume types + ! Actual integral volume self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & self % volumeTracks(cIdx) - self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol + self % volume(cIdx) = self % allVolumeTracks(cIdx) * normIt volAve = self % volume(cIdx) + ! Cycle-wise volume volNaive = self % volumeTracks(cIdx) * norm - self % volumeTracks(cIdx) = ZERO ! Decide volume to use select case(self % volPolicy) @@ -1090,63 +1115,93 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) case default call fatalError(Here,'Unsupported volume handling requested') end select - norm_V = real(norm / vol, defFlt) + ! Reset cycle-wise estimator + self % volumeTracks(cIdx) = ZERO + call self % XSData % getTotalPointer(matIdx, total) + + groupLoop: do g = 1, self % nG - do g = 1, self % nG + idx = self % nG * (cIdx - 1) + g - idx = self % nG * (cIdx - 1) + g + ! Route for non-void materials + if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + if (hit) then + + ! Can hit a cell but with a tiny volume, such that + ! things break a bit - would rather remove this arbitrary + ! check in future + if (vol < volume_tolerance) then + !self % scalarFlux(idx) = ZERO + self % scalarFlux(idx) = self % source(idx) / total(g) + cycle groupLoop + end if - if (hit) then - ! Can hit a cell but with a tiny volume, such that - ! things break a bit - would rather remove this arbitrary - ! check in future - if (vol < volume_tolerance) then - self % scalarFlux(idx) = 0.0_defFlt - cycle - end if - - self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) - - ! Presumes non-zero total XS - sigGG = self % XSData % getScatterXS(matIdx, g, g) - if ((sigGG < 0) .and. (total(g) > 0)) then - D = -self % rho * sigGG / total(g) + self % scalarFlux(idx) = self % scalarFlux(idx) * norm + self % scalarFlux(idx) = self % scalarFlux(idx) / (vol * total(g)) + + !scalar0 = self % scalarFlux(idx) + + ! Presumes non-zero total XS + sigGG = self % XSData % getScatterXS(matIdx, g, g) + if ((sigGG < 0) .and. (total(g) > 0)) then + D = -real(self % rho * sigGG / total(g), defReal) + else + D = ZERO + end if + + self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / total(g) & + + D * self % prevFlux(idx) ) / (1 + D) + + ! If scalar flux is negative, do it again with naive + ! This can severely affect particle conservation. + !if (self % scalarFlux(idx) < ZERO) then + ! self % scalarFlux(idx) = ZERO + ! !self % scalarFlux(idx) = scalar0 * vol/volNaive + ! !self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / total(g) & + ! ! + D * self % prevFlux(idx) ) / (1 + D) + !end if + else - D = 0.0_defFlt + + ! Decide flux treatment to use on missing a cell + select case(self % missPolicy) + case(srcPolicy) + self % scalarFlux(idx) = self % source(idx) / total(g) + case(prevPolicy) + self % scalarFlux(idx) = self % prevFlux(idx) + case(hybrid) + if (isSrc) then + self % scalarFlux(idx) = self % prevFlux(idx) + else + self % scalarFlux(idx) = self % source(idx) / total(g) + end if + case default + call fatalError(Here,'Unsupported miss handling requested') + end select + end if - self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & - + D * self % prevFlux(idx) ) / (1 + D) + + ! Alternatively, handle unidentified/void regions else - ! Decide flux treatment to use - select case(self % missPolicy) - case(srcPolicy) - self % scalarFlux(idx) = self % source(idx) / total(g) - case(prevPolicy) - self % scalarFlux(idx) = self % prevFlux(idx) - case(hybrid) - if (isSrc) then - self % scalarFlux(idx) = self % prevFlux(idx) - else - self % scalarFlux(idx) = self % source(idx) / total(g) - end if - case default - call fatalError(Here,'Unsupported miss handling requested') - end select + + if (vol < volume_tolerance) then + self % scalarFlux(idx) = ZERO + cycle groupLoop + end if + if (hit) then + self % scalarFlux(idx) = self % scalarFlux(idx) * norm / vol + else + self % scalarFlux(idx) = self % prevFlux(idx) + end if end if - ! Alternatively, handle unidentified/void regions - !else - ! self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - ! self % scalarFlux(idx) = self % scalarFlux(idx) + & - ! real(self % source(idx) * self % lengthSquared(cIdx) * norm / (2 * vol), defFlt) - !end if - end do - end do + end do groupLoop + + end do cellLoop !$omp end parallel do end subroutine normaliseFluxAndVolumeFlatIso @@ -1159,8 +1214,8 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it real(defReal) :: norm, normVol - real(defReal), save :: vol, invVol, volNaive, volAve - real(defFlt), save :: norm_V, D, sigGG + real(defReal), save :: vol, invVol, volNaive, volAve, norm_V + real(defFlt), save :: D, sigGG real(defFlt), dimension(:), pointer, save :: total integer(shortInt) :: cIdx integer(shortInt), save :: g, matIdx, idx, dIdx, mIdx @@ -1171,6 +1226,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) norm = ONE / self % lengthPerIt normVol = ONE / (self % lengthPerIt * it) + !$omp parallel do schedule(static) do cIdx = 1, self % nCells matIdx = self % geom % geom % graph % getMatFromUID(cIdx) @@ -1180,32 +1236,43 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + ! Compute various volume types + ! Actual integral volume self % allVolumeTracks(cIdx) = self % allVolumeTracks(cIdx) + & self % volumeTracks(cIdx) self % volume(cIdx) = self % allVolumeTracks(cIdx) * normVol volAve = self % volume(cIdx) + ! Iteration-wise volume volNaive = self % volumeTracks(cIdx) * norm - self % volumeTracks(cIdx) = ZERO - + ! Decide volume to use select case(self % volPolicy) case(naive) vol = volNaive + norm_V = ONE / self % volumeTracks(cIdx) case(simAverage) vol = volAve + norm_V = it / self % allVolumeTracks(cIdx) case(hybrid) if (isSrc) then vol = volNaive + norm_V = ONE / self % volumeTracks(cIdx) else vol = volAve + norm_V = it / self % allVolumeTracks(cIdx) end if case default call fatalError(Here,'Unsupported volume handling requested') end select - invVol = ONE / self % allVolumeTracks(cIdx) + + ! Reset cycle-wise estimator + self % volumeTracks(cIdx) = ZERO ! Update geometric information provided volume has been visited if (self % allVolumeTracks(cIdx) > ZERO) then + + invVol = ONE / self % allVolumeTracks(cIdx) + ! Update centroids self % centroid(dIdx + x) = self % centroidTracks(dIdx + x) * invVol self % centroid(dIdx + y) = self % centroidTracks(dIdx + y) * invVol @@ -1222,39 +1289,33 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) end if call self % XSData % getTotalPointer(matIdx, total) - norm_V = real(norm / vol, defFlt) - do g = 1, self % nG + groupLoop: do g = 1, self % nG idx = self % nG * (cIdx - 1) + g + + + if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + if (hit) then - if (hit) then + ! Can hit a cell but with a tiny volume, such that + ! things break a bit - would rather remove this arbitrary + ! check in future + if (vol < volume_tolerance) then + self % scalarFlux(idx) = ZERO + self % scalarX(idx) = ZERO + self % scalarY(idx) = ZERO + self % scalarZ(idx) = ZERO + cycle groupLoop + end if - ! Can hit a cell but with a tiny volume, such that - ! things break a bit - would rather remove this arbitrary - ! check in future - if (vol < volume_tolerance) then - self % scalarFlux(idx) = 0.0_defFlt - self % scalarX(idx) = 0.0_defFlt - self % scalarY(idx) = 0.0_defFlt - self % scalarZ(idx) = 0.0_defFlt - cycle - end if - - self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V - self % scalarX(idx) = self % scalarX(idx) * norm_V - self % scalarY(idx) = self % scalarY(idx) * norm_V - self % scalarZ(idx) = self % scalarZ(idx) * norm_V - - ! Apply the standard MoC post-sweep treatment and - ! stabilisation for negative XSs - !if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then - - self % scalarFlux(idx) = self % scalarFlux(idx) / total(g) - self % scalarX(idx) = self % scalarX(idx) / total(g) - self % scalarY(idx) = self % scalarY(idx) / total(g) - self % scalarZ(idx) = self % scalarZ(idx) / total(g) + self % scalarFlux(idx) = self % scalarFlux(idx) * norm_V / total(g) + self % scalarX(idx) = self % scalarX(idx) * norm_V / total(g) + self % scalarY(idx) = self % scalarY(idx) * norm_V / total(g) + self % scalarZ(idx) = self % scalarZ(idx) * norm_V / total(g) + ! Apply the standard MoC post-sweep treatment and + ! stabilisation for negative XSs ! Presumes non-zero total XS sigGG = self % XSData % getScatterXS(matIdx, g, g) if (sigGG < 0) then @@ -1265,37 +1326,12 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + D * self % prevFlux(idx) ) / (1 + D) - !end if - else - ! Decide flux treatment to use - associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) - select case(self % missPolicy) - ! Note: this is policy to use the source, not policy for hitting a fixed source - case(srcPolicy) - self % scalarFlux(idx) = self % source(idx) / total(g) - ! OPENMC SETS MOMENTS TO ZERO - !self % scalarX(idx) = 0.0_defFlt - !self % scalarY(idx) = 0.0_defFlt - !self % scalarZ(idx) = 0.0_defFlt - ! Need to multiply source gradients by moment matrix - self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) - self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) - case(prevPolicy) - self % scalarFlux(idx) = self % prevFlux(idx) - self % scalarX(idx) = self % prevX(idx) - self % scalarY(idx) = self % prevY(idx) - self % scalarZ(idx) = self % prevZ(idx) - case(hybrid) - if (isSrc) then - self % scalarFlux(idx) = self % prevFlux(idx) - self % scalarX(idx) = self % prevX(idx) - self % scalarY(idx) = self % prevY(idx) - self % scalarZ(idx) = self % prevZ(idx) - else + else + ! Decide flux treatment to use + associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) + select case(self % missPolicy) + ! Note: this is policy to use the source, not policy for hitting a fixed source + case(srcPolicy) self % scalarFlux(idx) = self % source(idx) / total(g) ! OPENMC SETS MOMENTS TO ZERO !self % scalarX(idx) = 0.0_defFlt @@ -1303,25 +1339,57 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) !self % scalarZ(idx) = 0.0_defFlt ! Need to multiply source gradients by moment matrix self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & - mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & - mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & - mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) - end if - case default - call fatalError(Here,'Unsupported miss handling requested') - end select - end associate + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + case(prevPolicy) + self % scalarFlux(idx) = self % prevFlux(idx) + self % scalarX(idx) = self % prevX(idx) + self % scalarY(idx) = self % prevY(idx) + self % scalarZ(idx) = self % prevZ(idx) + case(hybrid) + if (isSrc) then + self % scalarFlux(idx) = self % prevFlux(idx) + self % scalarX(idx) = self % prevX(idx) + self % scalarY(idx) = self % prevY(idx) + self % scalarZ(idx) = self % prevZ(idx) + else + self % scalarFlux(idx) = self % source(idx) / total(g) + ! OPENMC SETS MOMENTS TO ZERO + !self % scalarX(idx) = 0.0_defFlt + !self % scalarY(idx) = 0.0_defFlt + !self % scalarZ(idx) = 0.0_defFlt + ! Need to multiply source gradients by moment matrix + self % scalarX(idx) = real(mat(xx) *self % sourceX(idx) + & + mat(xy) * self % sourceY(idx) + mat(xz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarY(idx) = real(mat(xy) *self % sourceX(idx) + & + mat(yy) * self % sourceY(idx) + mat(yz) * self % sourceZ(idx),defFlt)/ total(g) + self % scalarZ(idx) = real(mat(xz) *self % sourceX(idx) + & + mat(yz) * self % sourceY(idx) + mat(zz) * self % sourceZ(idx),defFlt)/ total(g) + end if + case default + call fatalError(Here,'Unsupported miss handling requested') + end select + end associate + end if + + else + + ! Apply void treatment + + end if + ! For stability while still accumulating geometric info if (it < 10) then - self % scalarX(idx) = 0.0_defFlt - self % scalarY(idx) = 0.0_defFlt - self % scalarZ(idx) = 0.0_defFlt + self % scalarX(idx) = ZERO + self % scalarY(idx) = ZERO + self % scalarZ(idx) = ZERO end if - end do + end do groupLoop end do !$omp end parallel do @@ -1389,7 +1457,8 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) integer(shortInt), intent(in) :: cIdx real(defFlt), intent(in) :: ONE_KEFF real(defFlt) :: scatter, fission - real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS, fluxVec + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS + real(defReal), dimension(:), pointer :: fluxVec integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 ! Identify material @@ -1418,7 +1487,7 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) fission = 0.0_defFlt !$omp simd reduction(+:fission) do gIn = 1, self % nG - fission = fission + fluxVec(gIn) * nuFission(gIn) + fission = fission + real(fluxVec(gIn) * nuFission(gIn), defFlt) end do fission = fission * ONE_KEFF @@ -1432,7 +1501,7 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) scatter = 0.0_defFlt !$omp simd reduction(+:scatter) do gIn = 1, self % nG - scatter = scatter + fluxVec(gIn) * scatterVec(gIn) + scatter = scatter + real(fluxVec(gIn) * scatterVec(gIn), defFlt) end do end associate @@ -1454,16 +1523,16 @@ end subroutine sourceUpdateKernelFlatIso !! with isotropic scattering !! subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) - class(arraysRR), target, intent(inout) :: self - integer(shortInt), intent(in) :: cIdx - real(defFlt), intent(in) :: ONE_KEFF - real(defFlt) :: scatter, xScatter, yScatter, zScatter, & - fission, xFission, yFission, zFission, & - xSource, ySource, zSource - real(defFlt), dimension(matSize) :: invM - real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS - integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 - real(defFlt), pointer, dimension(:) :: fluxVec, xFluxVec, yFluxVec, zFluxVec + class(arraysRR), target, intent(inout) :: self + integer(shortInt), intent(in) :: cIdx + real(defFlt), intent(in) :: ONE_KEFF + real(defFlt) :: scatter, xScatter, yScatter, zScatter, & + fission, xFission, yFission, zFission, & + xSource, ySource, zSource + real(defFlt), dimension(matSize) :: invM + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS + integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 + real(defReal), pointer, dimension(:) :: fluxVec, xFluxVec, yFluxVec, zFluxVec ! Invert moment matrix invM = self % invertMatrix(cIdx) @@ -1504,16 +1573,17 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) !$omp simd reduction(+:fission, xFission, yFission, zFission) do gIn = 1, self % nG - fission = fission + fluxVec(gIn) * nuFission(gIn) - xFission = xFission + xFluxVec(gIn) * nuFission(gIn) - yFission = yFission + yFluxVec(gIn) * nuFission(gIn) - zFission = zFission + zFluxVec(gIn) * nuFission(gIn) + fission = fission + real(fluxVec(gIn) * nuFission(gIn), defFlt) + xFission = xFission + real(xFluxVec(gIn) * nuFission(gIn), defFlt) + yFission = yFission + real(yFluxVec(gIn) * nuFission(gIn), defFlt) + zFission = zFission + real(zFluxVec(gIn) * nuFission(gIn), defFlt) end do fission = fission * ONE_KEFF xFission = xFission * ONE_KEFF yFission = yFission * ONE_KEFF zFission = zFission * ONE_KEFF + !call self % XSData % getTotalPointer(matIdx, total) do g = 1, self % nG sIdx1 = self % nG * (g - 1) + 1 @@ -1527,10 +1597,10 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) zScatter = 0.0_defFlt !$omp simd reduction(+:scatter, xScatter, yScatter, zScatter) do gIn = 1, self % nG - scatter = scatter + fluxVec(gIn) * scatterVec(gIn) - xScatter = xScatter + xFluxVec(gIn) * scatterVec(gIn) - yScatter = yScatter + yFluxVec(gIn) * scatterVec(gIn) - zScatter = zScatter + zFluxVec(gIn) * scatterVec(gIn) + scatter = scatter + real(fluxVec(gIn) * scatterVec(gIn), defFlt) + xScatter = xScatter + real(xFluxVec(gIn) * scatterVec(gIn), defFlt) + yScatter = yScatter + real(yFluxVec(gIn) * scatterVec(gIn), defFlt) + zScatter = zScatter + real(zFluxVec(gIn) * scatterVec(gIn), defFlt) end do end associate @@ -1542,10 +1612,17 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) if (allocated(self % fixedSource)) then self % source(idx) = self % source(idx) + self % fixedSource(idx) end if + xSource = chi(g) * xFission + xScatter ySource = chi(g) * yFission + yScatter zSource = chi(g) * zFission + zScatter - + + if (allocated(self % fixedX)) then + xSource = xSource + self % fixedX(idx) + ySource = ySource + self % fixedY(idx) + zSource = zSource + self % fixedZ(idx) + end if + ! Calculate source gradients by inverting the moment matrix self % sourceX(idx) = invM(xx) * xSource + & invM(xy) * ySource + invM(xz) * zSource @@ -1553,12 +1630,7 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) invM(yy) * ySource + invM(yz) * zSource self % sourceZ(idx) = invM(xz) * xSource + & invM(yz) * ySource + invM(zz) * zSource - if (allocated(self % fixedX)) then - self % sourceX(idx) = self % sourceX(idx) + self % fixedX(idx) - self % sourceY(idx) = self % sourceY(idx) + self % fixedY(idx) - self % sourceZ(idx) = self % sourceZ(idx) + self % fixedZ(idx) - end if - + end do end subroutine sourceUpdateKernelLinearIso @@ -1609,10 +1681,8 @@ function invertMatrix(self, cIdx) result(invM) if (momVec(xx) > condition_tolerance) condX = 1 if (momVec(yy) > condition_tolerance) condY = 1 if (momVec(zz) > condition_tolerance) condZ = 1 - !condX = 1 - !condY = 1 - !DEFINITELY DO THIS FOR C5G7 WITH LOW POP - !condZ = 0 + ! Significantly stabilises 2D linear source problems. Z moments can vary wildly. + if (self % set2D) condZ = 0 ! Map conditions to test variable inversionTest = condX * 4 + condY * 2 + condZ @@ -1686,6 +1756,7 @@ function calculateKeff(self, k0) result(k1) integer(shortInt) :: cIdx real(defReal) :: fissTotal, prevFissTotal real(defReal), save :: fissLocal, prevFissLocal + character(100), parameter :: Here = 'calculateKeff (arraysRR_class.f90)' !$omp threadprivate (fissLocal, prevFissLocal) fissTotal = ZERO @@ -1699,7 +1770,8 @@ function calculateKeff(self, k0) result(k1) !$omp end parallel do k1 = k0 * fissTotal / prevFissTotal - if ((k1 <= 0) .or. (k1 > 5)) k1 = k0 + if ((k1 <= 0) .or. (k1 > 5)) call fatalError(Here, 'Unphysical keff: '//numToChar(k1)) + if (k1 /= k1) call fatalError(Here, 'NaN keff') end function calculateKeff @@ -1712,7 +1784,8 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) real(defReal), intent(out) :: fissionRate, prevFissionRate real(defReal) :: vol integer(shortInt) :: g, matIdx - real(defFlt), dimension(:), pointer :: nuSigmaF, flux, prevFlux + real(defFlt), dimension(:), pointer :: nuSigmaF + real(defReal), dimension(:), pointer :: flux, prevFlux fissionRate = ZERO prevFissionRate = ZERO @@ -1742,6 +1815,21 @@ subroutine calculateKeffKernel(self, cIdx, fissionRate, prevFissionRate) end subroutine calculateKeffKernel + !! + !! Zero the previous-step flux + !! + subroutine zeroPrevFlux(self) + class(arraysRR), intent(inout) :: self + character(100), parameter :: Here = 'zeroPrevFlux (arraysRR_class.f90)' + + if (allocated(self % prevFlux)) then + self % prevFlux = ZERO + else + call fatalError(Here,'prevFlux has not been initialised') + end if + + end subroutine zeroPrevFlux + !! !! Reset fluxes !! @@ -1770,7 +1858,7 @@ subroutine resetFluxesFlatIso(self) !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) - self % scalarFlux(idx) = 0.0_defFlt + self % scalarFlux(idx) = ZERO end do !$omp end parallel do @@ -1787,13 +1875,13 @@ subroutine resetFluxesLinearIso(self) !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) - self % scalarFlux(idx) = 0.0_defFlt + self % scalarFlux(idx) = ZERO self % prevX(idx) = self % scalarX(idx) - self % scalarX(idx) = 0.0_defFlt + self % scalarX(idx) = ZERO self % prevY(idx) = self % scalarY(idx) - self % scalarY(idx) = 0.0_defFlt + self % scalarY(idx) = ZERO self % prevZ(idx) = self % scalarZ(idx) - self % scalarZ(idx) = 0.0_defFlt + self % scalarZ(idx) = ZERO end do !$omp end parallel do @@ -1811,7 +1899,7 @@ subroutine resetFluxesFlatAni(self) !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) - self % scalarFlux(idx) = 0.0_defFlt + self % scalarFlux(idx) = ZERO end do !$omp end parallel do @@ -1829,7 +1917,7 @@ subroutine resetFluxesLIFA(self) !$omp parallel do do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) - self % scalarFlux(idx) = 0.0_defFlt + self % scalarFlux(idx) = ZERO end do !$omp end parallel do @@ -1904,11 +1992,10 @@ end subroutine accumulateFluxScoresLinear !! !! Finalise results !! - subroutine finaliseFluxScores(self, it, totalIt) + subroutine finaliseFluxScores(self, it) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: it - integer(shortInt), intent(in) :: totalIt - character(100), parameter :: Here = 'finaliseFLuxScores (arraysRR_class.f90)' + character(100), parameter :: Here = 'finaliseFluxScores (arraysRR_class.f90)' select case(self % simulationType) case(flatIso, flatAni) @@ -2041,6 +2128,7 @@ subroutine outputMap(self, out, map, doFission) res = ZERO resSD = ZERO + ! Find whether cells are in map and sum their contributions !$omp parallel do reduction(+: res, resSD) do cIdx = 1, self % nCells @@ -2362,7 +2450,6 @@ subroutine kill(self) if(allocated(self % fixedSource)) deallocate(self % fixedSource) if(allocated(self % sourceIdx)) deallocate(self % sourceIdx) if(allocated(self % volumeTracks)) deallocate(self % volumeTracks) - if(allocated(self % lengthSquared)) deallocate(self % lengthSquared) if(allocated(self % volume)) deallocate(self % volume) if(allocated(self % cellHit)) deallocate(self % cellHit) if(allocated(self % cellFound)) deallocate(self % cellFound) @@ -2403,7 +2490,12 @@ subroutine kill(self) self % rho = 0.0_defFlt self % simulationType = 0 self % ani = 0 - self % totalVolume = ZERO + self % totalVolume = ONE + self % averageHit = ZERO + self % iterations = 0 + self % volPolicy = hybrid + self % missPolicy = hybrid + self % set2D = .false. end subroutine kill diff --git a/RandomRayObjects/constantsRR.f90 b/RandomRayObjects/constantsRR.f90 index 45c7b7b46..195302a20 100644 --- a/RandomRayObjects/constantsRR.f90 +++ b/RandomRayObjects/constantsRR.f90 @@ -12,7 +12,7 @@ module constantsRR integer(shortInt), parameter, public :: flatIso = 1, linearIso = 2, flatAni = 3, linearAni = 4 ! Parameter for when to skip a tiny volume - real(defReal), parameter, public :: volume_tolerance = 1.0E-10 + real(defReal), parameter, public :: volume_tolerance = 1.0E-12 ! Parameter for when to ignore components of spatial moment matrices ! or when the matrix is poorly conditioned diff --git a/RandomRayObjects/dataRR_class.f90 b/RandomRayObjects/dataRR_class.f90 index 03f2f8175..6a7bffa9c 100644 --- a/RandomRayObjects/dataRR_class.f90 +++ b/RandomRayObjects/dataRR_class.f90 @@ -3,7 +3,7 @@ module dataRR_class use numPrecision use universalVariables use rng_class, only : RNG - use genericProcedures, only : fatalError + use genericProcedures, only : fatalError, numToChar ! Nuclear Data use materialMenu_mod, only : mm_nMat => nMat, mm_matName => matName @@ -55,6 +55,8 @@ module dataRR_class procedure :: init procedure :: setAdjointXS + procedure :: display + procedure :: materialName procedure :: kill ! TODO: add an XS update procedure, e.g., given multiphysics @@ -100,9 +102,10 @@ subroutine init(self, db, doKinetics, loud) logical(defBool), intent(in) :: loud integer(shortInt) :: g, g1, m, matP1, aniOrder type(RNG) :: rand - logical(defBool) :: fiss + logical(defBool) :: fiss, negScat class(baseMgNeutronMaterial), pointer :: mat class(materialHandle), pointer :: matPtr + real(defFlt) :: sig character(100), parameter :: Here = 'init (dataRR_class.f90)' self % doKinetics = doKinetics @@ -112,7 +115,7 @@ subroutine init(self, db, doKinetics, loud) self % nG2 = self % nG * self % nG ! Initialise local nuclear data - ! Allocate nMat + 1 materials to catch any undefined materials + ! Allocate nMat + 1 materials to catch void and undefined materials ! TODO: clean nuclear database afterwards! It is no longer used ! and takes up memory. self % nMat = mm_nMat() @@ -149,13 +152,33 @@ subroutine init(self, db, doKinetics, loud) ! Include scattering multiplicity do g1 = 1, self % nG self % sigmaS(self % nG * self % nG * (m - 1) + self % nG * (g - 1) + g1) = & - real(mat % getScatterXS(g1, g, rand) * mat % scatter % prod(g1, g) , defFlt) + real(mat % getScatterXS(g1, g, rand) * mat % scatter % prod(g, g1) , defFlt) end do end do self % fissile(m) = fiss self % names(m) = mm_matName(m) end do + ! Check whethere any sigmaT's are zero or negative. + ! Also check whether any negative scattering matrix diagonals occur. + print *,'Checking cross sections' + negScat = .false. + do m = 1, self % nMat + do g = 1, self % nG + sig = self % sigmaT(self % nG * (m - 1) + g) + if (sig <= 0.0_defFlt) then + call fatalError(Here, 'Dubious cross section in material '// self % names(m)//& + ' in group '//numToChar(g)//': '//numToChar(real(sig,defReal))) + end if + sig = self % sigmaS(self % nG * self % nG * (m - 1) + self % nG * (g - 1) + g) + if (sig < 0.0_defFlt) negScat = .true. + end do + end do + + if (negScat) then + print *,'Warning: some scattering cross sections are negative. Consider diagonal stabilisation' + end if + ! Initialise data necessary for kinetic/noise calculations if (self % doKinetics) then print *,'Including kinetic data' @@ -208,6 +231,44 @@ subroutine setAdjointXS(self) end subroutine setAdjointXS + !! + !! Display contents of the class + !! + subroutine display(self) + class(dataRR), intent(in) :: self + + print *,'Number of group: '//numToChar(self % nG) + print *,'Number of materials: '//numToChar(self % nMat) + if (allocated(self % names)) then + print *,'Material names: '//self % names + else + print *,'Material names not allocated' + end if + if (allocated(self % sigmaT)) print *,'Total XS: '//numToChar(real(self % sigmaT,defReal)) + if (allocated(self % nuSigmaF)) print *,'NuSigmaF XS: '//numToChar(real(self % nuSigmaF,defReal)) + if (allocated(self % sigmaF)) print *,'SigmaF XS: '//numToChar(real(self % sigmaF,defReal)) + if (allocated(self % sigmaS)) print *,'SigmaS XS: '//numToChar(real(self % sigmaS,defReal)) + if (allocated(self % chi)) print *,'Chi: '//numToChar(real(self % chi,defReal)) + + end subroutine display + + !! + !! Return the name of a given material + !! + function materialName(self, matIdx) result(matName) + class(dataRR), intent(in) :: self + integer(shortInt), intent(in) :: matIdx + character(nameLen) :: matName + character(100), parameter :: Here = 'materialName (dataRR_class.f90)' + + if ((matIdx > 0) .and. (matIdx <= self % nMat + 1)) then + matName = self % names(matIdx) + else + call fatalError(Here, 'Invalid material index: '//numToChar(matIdx)) + end if + + end function materialName + !! !! Calculate the lower and upper indices for accessing the XS array !! (excluding scattering and kinetic data) @@ -216,7 +277,7 @@ pure subroutine getIdxs(self, matIdx, idx1, idx2) class(dataRR), intent(in) :: self integer(shortInt), intent(in) :: matIdx integer(shortInt), intent(out) :: idx1, idx2 - + idx1 = (matIdx - 1) * self % nG + 1 idx2 = matIdx * self % nG @@ -229,7 +290,14 @@ pure subroutine getScatterIdxs(self, matIdx, idx1, idx2) class(dataRR), intent(in) :: self integer(shortInt), intent(in) :: matIdx integer(shortInt), intent(out) :: idx1, idx2 + integer(shortInt) :: mIdx + if (matIdx > self % nMat) then + mIdx = self % nMat + 1 + else + mIdx = self % nMat + end if + idx1 = (matIdx - 1) * self % nG2 + 1 idx2 = matIdx * self % nG2 diff --git a/RandomRayObjects/mathsRR_func.f90 b/RandomRayObjects/mathsRR_func.f90 index 7819940bf..ca6f4b6b2 100644 --- a/RandomRayObjects/mathsRR_func.f90 +++ b/RandomRayObjects/mathsRR_func.f90 @@ -16,7 +16,7 @@ module mathsRR_func implicit none private - public :: expF1, expG, expG2 + public :: expF1, expF1Tau, expG, expG2 ! Numerator coefficients in F1 rational approximation real(defFlt), parameter :: c1n = -1.0000013559236386308, c2n = 0.23151368626911062025,& @@ -24,7 +24,7 @@ module mathsRR_func c6n = 0.00010360973791574984608, c7n = -0.000013276571933735820960 ! Denominator coefficients in F1 rational approximation - real(defFlt), parameter :: c0d = ONE, c1d = -0.73151337729389001396, c2d = 0.26058381273536471371, & + real(defFlt), parameter :: c0d = 1.0_defFlt, c1d = -0.73151337729389001396, c2d = 0.26058381273536471371, & c3d = -0.059892419041316836940, c4d = 0.0099070188241094279067, c5d = -0.0012623388962473160860, & c6d = 0.00010361277635498731388, c7d = -0.000013276569500666698498 @@ -80,6 +80,38 @@ elemental function expF1(tau) result(x) x = -num / den end function expF1 + + !! + !! Computes x = [1 - exp(-tau)] = F1*tau for use in MoC calcs + !! Tau is the optical distance. + !! F1 is a common name in MoC literature + !! + elemental function expF1Tau(tau) result(x) + real(defFlt), intent(in) :: tau + real(defFlt) :: x + real(defFlt) :: den, num + + x = -tau + den = c7d + den = den * x + c6d + den = den * x + c5d + den = den * x + c4d + den = den * x + c3d + den = den * x + c2d + den = den * x + c1d + den = den * x + c0d + + num = c7n + num = num * x + c6n + num = num * x + c5n + num = num * x + c4n + num = num * x + c3n + num = num * x + c2n + num = num * x + c1n + num = num * x + x = num / den + + end function expF1Tau !! !! Computes y = 1/x-(1-exp(-x))/x**2 using a 5/6th order rational approximation. diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 6f9ecec5e..fa7861cad 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -15,7 +15,7 @@ module rayHandling_func ! Random ray modules use arraysRR_class, only : arraysRR use dataRR_class, only : dataRR - use mathsRR_func, only : expF1, expG, expG2 + use mathsRR_func, only : expF1, expF1Tau, expG, expG2 ! Random ray - or a standard particle use particle_class, only : ray => particle @@ -182,9 +182,10 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays real(defReal) :: totalLength, length logical(defBool) :: activeRay, hitVacuum type(distCache) :: cache - real(defFlt) :: lenFlt - real(defFlt), dimension(nG) :: attenuate, delta, angular, tau - real(defFlt), pointer, dimension(:) :: scalar, source, total + real(defFlt) :: lenFlt, len_2 + real(defFlt), dimension(nG) :: attenuate, delta, angular, tau, inc + real(defFlt), pointer, dimension(:) :: source, total + real(defReal), pointer, dimension(:) :: scalar XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -197,13 +198,14 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! Catch for regions with voids ! Assumes these are defined as 'void' ! TODO: Use a more robust criterion, as for branching later - if (matIdx <= XSData % getNMat()) then + if (matIdx <= XSData % getNMat() .and. all(total > 0)) then do g = 1, nG angular(g) = arrays % getSource(cIdx,g) / total(g) end do else do g = 1, nG - angular(g) = arrays % getPrevFlux(cIdx,g) + angular(g) = real(arrays % getPrevFlux(cIdx, g), defFlt) + !angular(g) = 0.0_defFlt end do end if @@ -246,17 +248,17 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays !$omp simd do g = 1, nG - tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) + !tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) ! Not sure whether this does much for stability + tau(g) = total(g) * lenFlt end do !$omp simd do g = 1, nG - !tau(g) = total(g) * lenFlt attenuate(g) = lenFlt * expF1(tau(g)) delta(g) = (total(g) * angular(g) - source(g)) * attenuate(g) angular(g) = angular(g) - delta(g) end do - + ! Accumulate to scalar flux if (activeRay) then @@ -264,7 +266,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays call arrays % getFluxPointer(cIdx, scalar) !$omp simd do g = 1, nG - scalar(g) = scalar(g) + delta(g) + scalar(g) = scalar(g) + delta(g) end do call arrays % incrementVolume(cIdx, length) call arrays % unsetLock(cIdx) @@ -278,14 +280,19 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! Accumulate to scalar flux if (activeRay) then + len_2 = lenFlt * one_two + !$omp simd + do g = 1, nG + inc(g) = lenFlt * (angular(g) + source(g) * len_2) + end do + call arrays % setLock(cIdx) call arrays % getFluxPointer(cIdx, scalar) !$omp simd do g = 1, nG - scalar(g) = scalar(g) + angular(g) * lenFlt + scalar(g) = scalar(g) + inc(g) end do call arrays % incrementVolume(cIdx, length) - call arrays % incrementLengthSquared(cIdx, length) call arrays % unsetLock(cIdx) if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) @@ -334,9 +341,9 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra real(defFlt), dimension(nG) :: delta, angular, tau, flatQ, gradQ, & F1, F2, angular0, G0, G1, G2, H, & xInc, yInc, zInc - real(defFlt), pointer, dimension(:) :: scalar, source, total, scalarX, & - scalarY, scalarZ, sourceX, sourceY, & - sourceZ + real(defFlt), pointer, dimension(:) :: source, total, sourceX, sourceY, sourceZ + real(defReal), pointer, dimension(:) :: scalar, scalarX, scalarY, scalarZ + character(100), parameter :: Here = 'transportSweepLinearIso (rayHandling_func.f90)' XSData => arrays % getDataPointer() geom => arrays % getGeomPointer() @@ -355,7 +362,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra end do else do g = 1, nG - angular(g) = arrays % getPrevFlux(cIdx,g) + angular(g) = real(arrays % getPrevFlux(cIdx,g), defFlt) end do end if @@ -427,114 +434,126 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra lenFlt = real(length,defFlt) lenFlt2_2 = lenFlt * lenFlt * one_two - ! Compute exponentials necessary for angular flux update - !$omp simd - do g = 1, nG - tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) - end do - - !$omp simd - do g = 1, nG - G0(g) = expG(tau(g)) - end do - - !$omp simd - do g = 1, nG - F1(g) = 1.0_defFlt - tau(g) * G0(g) - end do - - !$omp simd - do g = 1, nG - F2(g) = 2.0_defFlt * G0(g) - F1(g) - end do - - !$omp simd - do g = 1, nG - delta(g) = (tau(g) * angular(g) - lenFlt * flatQ(g)) * F1(g) & - - gradQ(g) * F2(g) * lenFlt2_2 - end do + ! Branch for voids etc + ! TODO: Should use a better branching criterion. Maybe create it in data? + ! Standard route + if (matIdx <= XSData % getNMat()) then - ! Create an intermediate flux variable for use in LS scores - !$omp simd - do g = 1, nG - angular0(g) = angular(g) - end do + ! Compute exponentials necessary for angular flux update + !$omp simd + do g = 1, nG + !tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) ! This line worsens stability + tau(g) = total(g) * lenFlt + end do - !$omp simd - do g = 1, nG - angular(g) = angular(g) - delta(g) - end do - - ! Accumulate to scalar flux - if (activeRay) then + !$omp simd + do g = 1, nG + G0(g) = expG(tau(g)) + end do - ! Precompute geometric info to keep it out of the lock - len2_12 = length * length * one_twelve - matScore(xx) = length * (rNorm(x) * rNorm(x) + mu0(x) * mu0(x) * len2_12) - matScore(xy) = length * (rNorm(x) * rNorm(y) + mu0(x) * mu0(y) * len2_12) - matScore(xz) = length * (rNorm(x) * rNorm(z) + mu0(x) * mu0(z) * len2_12) - matScore(yy) = length * (rNorm(y) * rNorm(y) + mu0(y) * mu0(y) * len2_12) - matScore(yz) = length * (rNorm(y) * rNorm(z) + mu0(y) * mu0(z) * len2_12) - matScore(zz) = length * (rNorm(z) * rNorm(z) + mu0(z) * mu0(z) * len2_12) - rC = rC * length - - ! Compute necessary exponentials outside of the lock - ! Follows those in Gunow - !$omp simd do g = 1, nG - H(g) = F1(g) - G0(g) + F1(g) = 1.0_defFlt - tau(g) * G0(g) end do - + !$omp simd do g = 1, nG - G1(g) = one_two - H(g) + F2(g) = 2.0_defFlt * G0(g) - F1(g) end do - + !$omp simd do g = 1, nG - G2(g) = expG2(tau(g)) + delta(g) = (tau(g) * angular(g) - lenFlt * flatQ(g)) * F1(g) & + - gradQ(g) * F2(g) * lenFlt2_2 end do - - ! Make some more condensed variables to help vectorisation - !$omp simd + + ! Create an intermediate flux variable for use in LS scores + !$omp simd do g = 1, nG - G1(g) = G1(g) * flatQ(g) * lenFlt - G2(g) = G2(g) * gradQ(g) * lenFlt2_2 - H(g) = H(g) * angular0(g) * tau(g) - H(g) = (G1(g) + G2(g) + H(g)) * lenFlt - flatQ(g) = flatQ(g) * lenFlt + delta(g) + angular0(g) = angular(g) end do - + !$omp simd do g = 1, nG - xInc(g) = r0NormFlt(x) * flatQ(g) + muFlt(x) * H(g) - yInc(g) = r0NormFlt(y) * flatQ(g) + muFlt(y) * H(g) - zInc(g) = r0NormFlt(z) * flatQ(g) + muFlt(z) * H(g) + angular(g) = angular(g) - delta(g) end do - call arrays % setLock(cIdx) - - call arrays % getFluxPointer(cIdx, scalar) - call arrays % getFluxXYZPointers(cIdx, scalarX, scalarY, scalarZ) - - ! Update flux moments - !$omp simd aligned(scalar, scalarX, scalarY, scalarZ) + ! Accumulate to scalar flux + if (activeRay) then + + ! Precompute geometric info to keep it out of the lock + len2_12 = length * length * one_twelve + matScore(xx) = length * (rNorm(x) * rNorm(x) + mu0(x) * mu0(x) * len2_12) + matScore(xy) = length * (rNorm(x) * rNorm(y) + mu0(x) * mu0(y) * len2_12) + matScore(xz) = length * (rNorm(x) * rNorm(z) + mu0(x) * mu0(z) * len2_12) + matScore(yy) = length * (rNorm(y) * rNorm(y) + mu0(y) * mu0(y) * len2_12) + matScore(yz) = length * (rNorm(y) * rNorm(z) + mu0(y) * mu0(z) * len2_12) + matScore(zz) = length * (rNorm(z) * rNorm(z) + mu0(z) * mu0(z) * len2_12) + rC = rC * length + + ! Compute necessary exponentials outside of the lock + ! Follows those in Gunow + + !$omp simd + do g = 1, nG + H(g) = F1(g) - G0(g) + end do + + !$omp simd + do g = 1, nG + G1(g) = one_two - H(g) + end do + + !$omp simd + do g = 1, nG + G2(g) = expG2(tau(g)) + end do + + ! Make some more condensed variables to help vectorisation + !$omp simd + do g = 1, nG + G1(g) = G1(g) * flatQ(g) * lenFlt + G2(g) = G2(g) * gradQ(g) * lenFlt2_2 + H(g) = H(g) * angular0(g) * tau(g) + H(g) = (G1(g) + G2(g) + H(g)) * lenFlt + flatQ(g) = flatQ(g) * lenFlt + delta(g) + end do + + !$omp simd do g = 1, nG - scalar(g) = scalar(g) + delta(g) - scalarX(g) = scalarX(g) + xInc(g) - scalarY(g) = scalarY(g) + yInc(g) - scalarZ(g) = scalarZ(g) + zInc(g) + xInc(g) = r0NormFlt(x) * flatQ(g) + muFlt(x) * H(g) + yInc(g) = r0NormFlt(y) * flatQ(g) + muFlt(y) * H(g) + zInc(g) = r0NormFlt(z) * flatQ(g) + muFlt(z) * H(g) end do + + call arrays % setLock(cIdx) + + call arrays % getFluxPointer(cIdx, scalar) + call arrays % getFluxXYZPointers(cIdx, scalarX, scalarY, scalarZ) + + ! Update flux moments + !$omp simd aligned(scalar, scalarX, scalarY, scalarZ) + do g = 1, nG + scalar(g) = scalar(g) + delta(g) + scalarX(g) = scalarX(g) + xInc(g) + scalarY(g) = scalarY(g) + yInc(g) + scalarZ(g) = scalarZ(g) + zInc(g) + end do - call arrays % incrementVolume(cIdx, length) - call arrays % incrementCentroid(cIdx, rC) - call arrays % incrementMoments(cIdx, matScore) + call arrays % incrementVolume(cIdx, length) + call arrays % incrementCentroid(cIdx, rC) + call arrays % incrementMoments(cIdx, matScore) - call arrays % unsetLock(cIdx) - if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) + call arrays % unsetLock(cIdx) + if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) + end if + + ! TODO: handle void cells + else + call fatalError(Here,'Void treatment has not been implemented for linear isotopic') + end if ! Check for a vacuum hit From fa1d5e608417663f79b8a271de0765dad64e9816 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Thu, 11 Sep 2025 14:28:29 +0100 Subject: [PATCH 14/15] Check for small cells --- RandomRayObjects/arraysRR_class.f90 | 165 ++++++++++---------------- RandomRayObjects/rayHandling_func.f90 | 55 +++++++-- 2 files changed, 102 insertions(+), 118 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 8e628d320..114bf2be2 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -61,9 +61,9 @@ module arraysRR_class !! volumeTracks -> Array of sum of track lengths for computing volumes [nCells] !! volume -> Array of dimensionless cell volumes [nCells] !! - !! cellHit -> Array of ints whether a cell was visited this iteration [nCells] - !! cellFound -> Array of logicals whether a cell was ever visited [nCells] - !! cellPos -> Array of cell positions [3 * nCells] + !! cellHit -> Array of ints whether a cell was visited this iteration [nCells] + !! cellTotalHit -> Array of total number of hits for a cell over all iterations [nCells] + !! cellPos -> Array of cell positions [3 * nCells] !! !! scalarX -> Array of x-spatial moments of scalar flux [nG * nCells] !! scalarY -> Array of y-spatial moments of scalar flux [nG * nCells] @@ -112,6 +112,7 @@ module arraysRR_class real(defReal), dimension(:), allocatable :: allVolumeTracks real(defReal), dimension(:), allocatable :: volume integer(shortInt), dimension(:), allocatable :: cellHit + integer(longInt), dimension(:), allocatable :: cellTotalHit logical(defBool), dimension(:), allocatable :: cellFound real(defReal), dimension(:,:), allocatable :: cellPos @@ -206,7 +207,6 @@ module arraysRR_class ! Output procedures procedure :: outputMap procedure :: outputToVTK - procedure :: outputMaterialIntegrals procedure :: outputPointFluxes ! Private procedures @@ -235,7 +235,6 @@ module arraysRR_class procedure, private :: calculateKeffKernel procedure, private :: invertMatrix - procedure, private :: materialIntegral end type arraysRR @@ -317,7 +316,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & allocate(self % allVolumeTracks(self % nCells)) allocate(self % volume(self % nCells)) allocate(self % cellHit(self % nCells)) - allocate(self % cellFound(self % nCells)) + allocate(self % cellTotalHit(self % nCells)) allocate(self % cellPos(nDim, self % nCells)) self % scalarFlux = ZERO @@ -328,7 +327,7 @@ subroutine init(self, db, geom, lengthPerIt, rho, lin, doKinetics, loud, & self % allVolumeTracks = ZERO self % volume = ZERO self % cellHit = 0 - self % cellFound = .false. + self % cellTotalHit = 0 self % cellPos = -INFINITY ! Initialise the fixed source if present @@ -902,13 +901,15 @@ elemental function wasHit(self, cIdx) result (hit) end function wasHit !! - !! Hit a cell + !! Hit a cell. + !! Should only be called in a lock. !! subroutine hitCell(self, cIdx) class(arraysRR), intent(inout) :: self integer(shortInt), intent(in) :: cIdx self % cellHit(cIdx) = 1 + self % cellTotalHit(cIdx) = self % cellTotalHit(cIdx) + 1 end subroutine hitCell @@ -934,7 +935,7 @@ function getCellHitRate(self, it) result(hitRate) totalHit = sum(self % cellHit) if (it > 20) then - realCells = count(self % cellFound) + realCells = count(self % cellTotalHit > 0) else realCells = self % nCells end if @@ -974,7 +975,7 @@ elemental function wasFound(self, cIdx) result(found) integer(shortInt), intent(in) :: cIdx logical(defBool) :: found - found = self % cellFound(cIdx) + found = (self % cellTotalHit(cIdx) > 0) end function wasFound @@ -988,7 +989,6 @@ subroutine newFound(self, cIdx, r) ! Remove critical if this is to go in the lock !$omp critical - self % cellFound(cIdx) = .true. self % cellPos(:,cIdx) = r !$omp end critical @@ -1079,13 +1079,13 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) integer(shortInt), intent(in) :: it real(defReal) :: norm, normIt real(defReal), save :: vol, volAve, volNaive, D - real(defFlt), save :: sigGG + real(defFlt), save :: sigGG, tot real(defFlt), dimension(:), pointer, save :: total integer(shortInt), save :: g, matIdx, idx integer(shortInt) :: cIdx - logical(defBool), save :: hit, isSrc + logical(defBool), save :: hit, isSrc, smallCell character(100), parameter :: Here = 'normaliseFluxAndVolumeFlatIso (arraysRR_class.f90)' - !$omp threadprivate(total, vol, idx, g, matIdx, sigGG, D, hit, isSrc, volAve, volNaive) + !$omp threadprivate(total, vol, idx, g, matIdx, sigGG, D, hit, isSrc, volAve, volNaive, tot, smallCell) norm = ONE / self % lengthPerIt normIt = ONE / (self % lengthPerIt * it) @@ -1096,6 +1096,9 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + + ! Is the cell hit frequently? + smallCell = (real(self % cellTotalHit(cIdx) / it, defReal) < 1.5) !! Compute various volume types ! Actual integral volume @@ -1121,6 +1124,8 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) case default call fatalError(Here,'Unsupported volume handling requested') end select + + if (smallCell) vol = volNaive ! Reset cycle-wise estimator self % volumeTracks(cIdx) = ZERO @@ -1130,35 +1135,35 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) groupLoop: do g = 1, self % nG idx = self % nG * (cIdx - 1) + g + tot = total(g) ! Route for non-void materials - if (matIdx <= self % XSData % getNMat() .and. total(g) > 0) then + if (matIdx <= self % XSData % getNMat() .and. tot > 0) then if (hit) then ! Can hit a cell but with a tiny volume, such that ! things break a bit - would rather remove this arbitrary ! check in future if (vol < volume_tolerance) then - !self % scalarFlux(idx) = ZERO - self % scalarFlux(idx) = self % source(idx) / total(g) + self % scalarFlux(idx) = ZERO cycle groupLoop end if self % scalarFlux(idx) = self % scalarFlux(idx) * norm - self % scalarFlux(idx) = self % scalarFlux(idx) / (vol * total(g)) + self % scalarFlux(idx) = self % scalarFlux(idx) / (vol * tot) !scalar0 = self % scalarFlux(idx) ! Presumes non-zero total XS sigGG = self % XSData % getScatterXS(matIdx, g, g) if ((sigGG < 0) .and. (total(g) > 0)) then - D = -real(self % rho * sigGG / total(g), defReal) + D = -real(self % rho * sigGG / tot, defReal) else D = ZERO end if - self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / total(g) & + self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / tot & + D * self % prevFlux(idx) ) / (1 + D) ! If scalar flux is negative, do it again with naive @@ -1169,20 +1174,23 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) ! !self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / total(g) & ! ! + D * self % prevFlux(idx) ) / (1 + D) !end if + !if (self % scalarFlux(idx) < ZERO .and. tot < 1.0E-7_defFlt) then + ! self % scalarFlux(idx) = self % prevFlux(idx) + !end if else ! Decide flux treatment to use on missing a cell select case(self % missPolicy) case(srcPolicy) - self % scalarFlux(idx) = self % source(idx) / total(g) + self % scalarFlux(idx) = self % source(idx) / tot case(prevPolicy) self % scalarFlux(idx) = self % prevFlux(idx) case(hybrid) if (isSrc) then self % scalarFlux(idx) = self % prevFlux(idx) else - self % scalarFlux(idx) = self % source(idx) / total(g) + self % scalarFlux(idx) = self % source(idx) / tot end if case default call fatalError(Here,'Unsupported miss handling requested') @@ -1225,9 +1233,9 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) real(defFlt), dimension(:), pointer, save :: total integer(shortInt) :: cIdx integer(shortInt), save :: g, matIdx, idx, dIdx, mIdx - logical(defBool), save :: hit, isSrc + logical(defBool), save :: hit, isSrc, smallCell character(100), parameter :: Here = 'normaliseFluxAndVolumeLinearIso (arraysRR_class.f90)' - !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG, hit, isSrc, volNaive, volAve) + !$omp threadprivate(total, vol, idx, mIdx, dIdx, g, matIdx, invVol, norm_V, D, sigGG, hit, isSrc, volNaive, volAve, smallCell) norm = ONE / self % lengthPerIt normVol = ONE / (self % lengthPerIt * it) @@ -1241,6 +1249,8 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) hit = self % wasHit(cIdx) isSrc = self % hasFixedSource(cIdx) + ! Is the cell hit frequently? + smallCell = (real(self % cellTotalHit(cIdx) / it, defReal) < 1.5) ! Compute various volume types ! Actual integral volume @@ -1270,6 +1280,11 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) case default call fatalError(Here,'Unsupported volume handling requested') end select + + if (smallCell) then + vol = volNaive + norm_V = ONE / self % volumeTracks(cIdx) + end if ! Reset cycle-wise estimator self % volumeTracks(cIdx) = ZERO @@ -1332,6 +1347,7 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx)/total(g) & + D * self % prevFlux(idx) ) / (1 + D) + else ! Decide flux treatment to use associate(mat => self % momMat((mIdx + 1):(mIdx + matSize))) @@ -1384,7 +1400,25 @@ subroutine normaliseFluxAndVolumeLinearIso(self, it) else ! Apply void treatment + if (vol < volume_tolerance) then + self % scalarFlux(idx) = ZERO + self % scalarX(idx) = ZERO + self % scalarY(idx) = ZERO + self % scalarZ(idx) = ZERO + cycle groupLoop + end if + if (hit) then + self % scalarFlux(idx) = self % scalarFlux(idx) * norm / vol + self % scalarX(idx) = ZERO + self % scalarY(idx) = ZERO + self % scalarZ(idx) = ZERO + else + self % scalarFlux(idx) = self % prevFlux(idx) + self % scalarX(idx) = ZERO + self % scalarY(idx) = ZERO + self % scalarZ(idx) = ZERO + end if end if @@ -2016,7 +2050,7 @@ subroutine tallyResults(self, tally) !$omp threadprivate(p, vol, pos, g, matIdx, fluxVec) !$omp parallel - call p % build([-INF, -INF, -INF], [ONE, ZERO, ZERO], 1, ZERO, ZERO) + call p % build([-INFINITY, -INFINITY, -INFINITY], [ONE, ZERO, ZERO], 1, ZERO, ZERO) !$omp end parallel !$omp parallel do @@ -2322,85 +2356,6 @@ subroutine outputToVTK(self, viz) end subroutine outputToVTK - !! - !! Output integrals over given materials - !! - subroutine outputMaterialIntegrals(self, out, matNames) - class(arraysRR), intent(in) :: self - class(outputFile), intent(inout) :: out - character(nameLen), dimension(:), intent(in) :: matNames - integer(shortInt) :: i, matIdx - character(nameLen) :: name - real(defReal) :: integral, intSD - - name = 'integral' - call out % startBlock(name) - - do i = 1, size(matNames) - - call out % startArray(matNames(i), [1]) - - ! Ensure name corresponds to a material present in the geometry - matIdx = self % XSData % getIdxFromName(matNames(i)) - - if (matIdx /= -1) then - call self % materialIntegral(matIdx, integral, intSD) - else - integral = ZERO - intSD = ZERO - print *,'WARNING: Material '//matNames(i)//' not found during integration.' - end if - - call out % addResult(integral, intSD) - call out % endArray() - - end do - call out % endBlock() - - end subroutine outputMaterialIntegrals - - !! - !! Perform an integral over a given material for all energies - !! - subroutine materialIntegral(self, matIdx, integral, intSD) - class(arraysRR), intent(in) :: self - integer(shortInt), intent(in) :: matIdx - real(defReal), intent(out) :: integral, intSD - integer(shortInt) :: cIdx - real(defReal), save :: vol - integer(shortInt), save :: mIdx, g - !$omp threadprivate(vol, mIdx, g) - - integral = ZERO - intSD = ZERO - - !$omp parallel do reduction(+: integral, intSD) - do cIdx = 1, self % nCells - - mIdx = self % geom % geom % graph % getMatFromUID(cIdx) - if (mIdx /= matIdx) cycle - - vol = self % volume(cIdx) - !if (vol < volume_tolerance) cycle - vol = vol * self % totalVolume - if (.not. self % wasFound(cIdx)) cycle - - do g = 1, self % nG - integral = integral + self % getFluxScore(cIdx, g) * vol - - ! Neglects uncertainty in the volume estimate - intSD = intSD + self % getFluxSD(cIdx, g)**2 * vol * vol - end do - - end do - !$omp end parallel do - - if (intSD >= ZERO) intSD = sqrt(intSD) - if (abs(integral) > ZERO) intSD = intSD / abs(integral) - - - end subroutine materialIntegral - !! !! Output fluxes at given points !! @@ -2509,7 +2464,7 @@ subroutine kill(self) if(allocated(self % volumeTracks)) deallocate(self % volumeTracks) if(allocated(self % volume)) deallocate(self % volume) if(allocated(self % cellHit)) deallocate(self % cellHit) - if(allocated(self % cellFound)) deallocate(self % cellFound) + if(allocated(self % cellTotalHit)) deallocate(self % cellTotalHit) if(allocated(self % cellPos)) deallocate(self % cellPos) ! Clean LS contents diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index fa7861cad..058c6bcea 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -198,9 +198,13 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays ! Catch for regions with voids ! Assumes these are defined as 'void' ! TODO: Use a more robust criterion, as for branching later - if (matIdx <= XSData % getNMat() .and. all(total > 0)) then + if (matIdx <= XSData % getNMat()) then do g = 1, nG - angular(g) = arrays % getSource(cIdx,g) / total(g) + if (total(g) > 1.0E-6_defFlt) then + angular(g) = arrays % getSource(cIdx,g) / total(g) + else + angular(g) = real(arrays % getPrevFlux(cIdx, g), defFlt) + end if end do else do g = 1, nG @@ -237,7 +241,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays if (.not. arrays % wasFound(cIdx)) then call arrays % newFound(cIdx, r % rGlobal() - length * HALF * r % dirGlobal()) end if - + lenFlt = real(length,defFlt) call arrays % getSourcePointer(cIdx, source) @@ -248,7 +252,7 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays !$omp simd do g = 1, nG - !tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) ! Not sure whether this does much for stability + !tau(g) = max(total(g) * lenFlt, 1.0e-6_defFlt) ! Not sure whether this does much for stability tau(g) = total(g) * lenFlt end do @@ -269,8 +273,8 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays scalar(g) = scalar(g) + delta(g) end do call arrays % incrementVolume(cIdx, length) + call arrays % hitCell(cIdx) call arrays % unsetLock(cIdx) - if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if @@ -293,8 +297,8 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays scalar(g) = scalar(g) + inc(g) end do call arrays % incrementVolume(cIdx, length) + call arrays % hitCell(cIdx) call arrays % unsetLock(cIdx) - if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if @@ -336,11 +340,11 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra real(defReal), dimension(matSize) :: matScore logical(defBool) :: activeRay, hitVacuum type(distCache) :: cache - real(defFlt) :: lenFlt, lenFlt2_2 + real(defFlt) :: lenFlt, lenFlt2_2, len_2 real(defFlt), dimension(nDim) :: muFlt, r0NormFlt, rNormFlt real(defFlt), dimension(nG) :: delta, angular, tau, flatQ, gradQ, & F1, F2, angular0, G0, G1, G2, H, & - xInc, yInc, zInc + xInc, yInc, zInc, inc real(defFlt), pointer, dimension(:) :: source, total, sourceX, sourceY, sourceZ real(defReal), pointer, dimension(:) :: scalar, scalarX, scalarY, scalarZ character(100), parameter :: Here = 'transportSweepLinearIso (rayHandling_func.f90)' @@ -414,7 +418,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra rNormFlt = 0.0_defFlt r0NormFlt = -real(HALF * mu0 * length,defFlt) end if - + call arrays % getSourcePointer(cIdx, source) call arrays % getSourceXYZPointers(cIdx, sourceX, sourceY, sourceZ) @@ -543,16 +547,41 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra call arrays % incrementVolume(cIdx, length) call arrays % incrementCentroid(cIdx, rC) call arrays % incrementMoments(cIdx, matScore) - + call arrays % hitCell(cIdx) call arrays % unsetLock(cIdx) - if (.not. arrays % wasHit(cIdx)) call arrays % hitCell(cIdx) end if - ! TODO: handle void cells + ! Handle void cells. Assume flat source. + ! Does not accumulate geometric info. else - call fatalError(Here,'Void treatment has not been implemented for linear isotopic') + + ! Accumulate to scalar flux + if (activeRay) then + + len_2 = lenFlt * one_two + !$omp simd + do g = 1, nG + inc(g) = lenFlt * (angular(g) + source(g) * len_2) + end do + + call arrays % setLock(cIdx) + call arrays % getFluxPointer(cIdx, scalar) + !$omp simd + do g = 1, nG + scalar(g) = scalar(g) + inc(g) + end do + call arrays % incrementVolume(cIdx, length) + call arrays % hitCell(cIdx) + call arrays % unsetLock(cIdx) + + end if + + !$omp simd + do g = 1, nG + angular(g) = angular(g) + source(g) * lenFlt + end do end if From 45ac2be1c2751b19fce68df2a2e7f9832e726fb8 Mon Sep 17 00:00:00 2001 From: ChasingNeutrons Date: Fri, 19 Sep 2025 23:14:03 +0100 Subject: [PATCH 15/15] Speed fixes to source update --- RandomRayObjects/arraysRR_class.f90 | 213 +++++++++----------------- RandomRayObjects/rayHandling_func.f90 | 8 +- 2 files changed, 73 insertions(+), 148 deletions(-) diff --git a/RandomRayObjects/arraysRR_class.f90 b/RandomRayObjects/arraysRR_class.f90 index 114bf2be2..1cc9e4651 100644 --- a/RandomRayObjects/arraysRR_class.f90 +++ b/RandomRayObjects/arraysRR_class.f90 @@ -205,7 +205,6 @@ module arraysRR_class procedure :: tallyResults ! Output procedures - procedure :: outputMap procedure :: outputToVTK procedure :: outputPointFluxes @@ -833,7 +832,7 @@ end function getMomentMatrix !! !! Return the simulation type !! - elemental function getSimulationType(self) result(simType) + function getSimulationType(self) result(simType) class(arraysRR), intent(in) :: self integer(shortInt) :: simType @@ -1149,12 +1148,9 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) cycle groupLoop end if - self % scalarFlux(idx) = self % scalarFlux(idx) * norm self % scalarFlux(idx) = self % scalarFlux(idx) / (vol * tot) - !scalar0 = self % scalarFlux(idx) - ! Presumes non-zero total XS sigGG = self % XSData % getScatterXS(matIdx, g, g) if ((sigGG < 0) .and. (total(g) > 0)) then @@ -1166,18 +1162,6 @@ subroutine normaliseFluxAndVolumeFlatIso(self, it) self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / tot & + D * self % prevFlux(idx) ) / (1 + D) - ! If scalar flux is negative, do it again with naive - ! This can severely affect particle conservation. - !if (self % scalarFlux(idx) < ZERO) then - ! self % scalarFlux(idx) = ZERO - ! !self % scalarFlux(idx) = scalar0 * vol/volNaive - ! !self % scalarFlux(idx) = (self % scalarFlux(idx) + self % source(idx) / total(g) & - ! ! + D * self % prevFlux(idx) ) / (1 + D) - !end if - !if (self % scalarFlux(idx) < ZERO .and. tot < 1.0E-7_defFlt) then - ! self % scalarFlux(idx) = self % prevFlux(idx) - !end if - else ! Decide flux treatment to use on missing a cell @@ -1497,8 +1481,8 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) integer(shortInt), intent(in) :: cIdx real(defFlt), intent(in) :: ONE_KEFF real(defFlt) :: scatter, fission - real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS - real(defReal), dimension(:), pointer :: fluxVec + real(defFlt), dimension(self % nG) :: fluxFlt + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS, scatterVec integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 ! Identify material @@ -1521,13 +1505,13 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) call self % XSData % getProdPointers(matIdx, nuFission, scatterXS, chi) baseIdx = self % nG * (cIdx - 1) - fluxVec => self % prevFlux((baseIdx + 1):(baseIdx + self % nG)) + fluxFlt = real(self % prevFlux((baseIdx + 1):(baseIdx + self % nG)), defFlt) ! Calculate fission source fission = 0.0_defFlt !$omp simd reduction(+:fission) do gIn = 1, self % nG - fission = fission + real(fluxVec(gIn) * nuFission(gIn), defFlt) + fission = fission + fluxFlt(gIn) * nuFission(gIn) end do fission = fission * ONE_KEFF @@ -1535,16 +1519,14 @@ subroutine sourceUpdateKernelFlatIso(self, cIdx, ONE_KEFF) sIdx1 = self % nG * (g - 1) + 1 sIdx2 = self % nG * g - associate(scatterVec => scatterXS(sIdx1:sIdx2)) - - ! Calculate scattering source - scatter = 0.0_defFlt - !$omp simd reduction(+:scatter) - do gIn = 1, self % nG - scatter = scatter + real(fluxVec(gIn) * scatterVec(gIn), defFlt) - end do + scatterVec => scatterXS(sIdx1:sIdx2) - end associate + ! Calculate scattering source + scatter = 0.0_defFlt + !$omp simd reduction(+:scatter) + do gIn = 1, self % nG + scatter = scatter + fluxFlt(gIn) * scatterVec(gIn) + end do ! Output index idx = baseIdx + g @@ -1570,9 +1552,9 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) fission, xFission, yFission, zFission, & xSource, ySource, zSource real(defFlt), dimension(matSize) :: invM - real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS + real(defFlt), dimension(self % nG) :: fluxFlt, xFlt, yFlt, zFlt + real(defFlt), dimension(:), pointer :: nuFission, chi, scatterXS, scatterVec integer(shortInt) :: matIdx, g, gIn, baseIdx, idx, sIdx1, sIdx2 - real(defReal), pointer, dimension(:) :: fluxVec, xFluxVec, yFluxVec, zFluxVec ! Invert moment matrix invM = self % invertMatrix(cIdx) @@ -1600,10 +1582,10 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) call self % XSData % getProdPointers(matIdx, nuFission, scatterXS, chi) baseIdx = self % nG * (cIdx - 1) - fluxVec => self % prevFlux((baseIdx + 1):(baseIdx + self % nG)) - xFluxVec => self % prevX((baseIdx + 1):(baseIdx + self % nG)) - yFluxVec => self % prevY((baseIdx + 1):(baseIdx + self % nG)) - zFluxVec => self % prevZ((baseIdx + 1):(baseIdx + self % nG)) + fluxFlt = real(self % prevFlux((baseIdx + 1):(baseIdx + self % nG)), defFlt) + xFlt = real(self % prevX((baseIdx + 1):(baseIdx + self % nG)), defFlt) + yFlt = real(self % prevY((baseIdx + 1):(baseIdx + self % nG)), defFlt) + zFlt = real(self % prevZ((baseIdx + 1):(baseIdx + self % nG)), defFlt) ! Calculate fission source fission = 0.0_defFlt @@ -1613,10 +1595,10 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) !$omp simd reduction(+:fission, xFission, yFission, zFission) do gIn = 1, self % nG - fission = fission + real(fluxVec(gIn) * nuFission(gIn), defFlt) - xFission = xFission + real(xFluxVec(gIn) * nuFission(gIn), defFlt) - yFission = yFission + real(yFluxVec(gIn) * nuFission(gIn), defFlt) - zFission = zFission + real(zFluxVec(gIn) * nuFission(gIn), defFlt) + fission = fission + fluxFlt(gIn) * nuFission(gIn) + xFission = xFission + xFlt(gIn) * nuFission(gIn) + yFission = yFission + yFlt(gIn) * nuFission(gIn) + zFission = zFission + zFlt(gIn) * nuFission(gIn) end do fission = fission * ONE_KEFF xFission = xFission * ONE_KEFF @@ -1628,22 +1610,20 @@ subroutine sourceUpdateKernelLinearIso(self, cIdx, ONE_KEFF) sIdx1 = self % nG * (g - 1) + 1 sIdx2 = self % nG * g - associate(scatterVec => scatterXS(sIdx1:sIdx2)) - - ! Calculate scattering source - scatter = 0.0_defFlt - xScatter = 0.0_defFlt - yScatter = 0.0_defFlt - zScatter = 0.0_defFlt - !$omp simd reduction(+:scatter, xScatter, yScatter, zScatter) - do gIn = 1, self % nG - scatter = scatter + real(fluxVec(gIn) * scatterVec(gIn), defFlt) - xScatter = xScatter + real(xFluxVec(gIn) * scatterVec(gIn), defFlt) - yScatter = yScatter + real(yFluxVec(gIn) * scatterVec(gIn), defFlt) - zScatter = zScatter + real(zFluxVec(gIn) * scatterVec(gIn), defFlt) - end do - - end associate + scatterVec => scatterXS(sIdx1:sIdx2) + + ! Calculate scattering source + scatter = 0.0_defFlt + xScatter = 0.0_defFlt + yScatter = 0.0_defFlt + zScatter = 0.0_defFlt + !$omp simd reduction(+:scatter, xScatter, yScatter, zScatter) + do gIn = 1, self % nG + scatter = scatter + fluxFlt(gIn) * scatterVec(gIn) + xScatter = xScatter + xFlt(gIn) * scatterVec(gIn) + yScatter = yScatter + yFlt(gIn) * scatterVec(gIn) + zScatter = zScatter + zFlt(gIn) * scatterVec(gIn) + end do ! Output index idx = baseIdx + g @@ -1895,7 +1875,7 @@ subroutine resetFluxesFlatIso(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do + !$omp parallel do schedule(static) do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = ZERO @@ -1912,14 +1892,29 @@ subroutine resetFluxesLinearIso(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do + !$omp parallel do schedule(static) do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = ZERO + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) self % prevX(idx) = self % scalarX(idx) self % scalarX(idx) = ZERO + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) self % prevY(idx) = self % scalarY(idx) self % scalarY(idx) = ZERO + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) self % prevZ(idx) = self % scalarZ(idx) self % scalarZ(idx) = ZERO end do @@ -1936,7 +1931,7 @@ subroutine resetFluxesFlatAni(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do + !$omp parallel do schedule(static) do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = ZERO @@ -1954,7 +1949,7 @@ subroutine resetFluxesLIFA(self) class(arraysRR), intent(inout) :: self integer(shortInt) :: idx - !$omp parallel do + !$omp parallel do schedule(static) do idx = 1, size(self % scalarFlux) self % prevFlux(idx) = self % scalarFlux(idx) self % scalarFlux(idx) = ZERO @@ -2015,12 +2010,27 @@ subroutine accumulateFluxScoresLinear(self) flux = self % scalarFlux(idx) self % fluxScores(1, idx) = self % fluxScores(1, idx) + flux self % fluxScores(2, idx) = self % fluxScores(2, idx) + flux * flux + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) flux = self % scalarX(idx) self % xScores(1, idx) = self % xScores(1, idx) + flux self % xScores(2, idx) = self % xScores(2, idx) + flux * flux + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) flux = self % scalarY(idx) self % yScores(1, idx) = self % yScores(1, idx) + flux self % yScores(2, idx) = self % yScores(2, idx) + flux * flux + end do + !$omp end parallel do + + !$omp parallel do schedule(static) + do idx = 1, size(self % scalarFlux) flux = self % scalarZ(idx) self % zScores(1, idx) = self % zScores(1, idx) + flux self % zScores(2, idx) = self % zScores(2, idx) + flux * flux @@ -2194,89 +2204,6 @@ subroutine finaliseFluxScoresLinear(self,it) end subroutine finaliseFluxScoresLinear - !! - !! Outputs integral flux or fission rate when - !! given a tally map - !! - subroutine outputMap(self, out, map, doFission) - class(arraysRR), intent(in) :: self - class(outputFile), intent(inout) :: out - class(tallyMap), pointer, intent(in) :: map - logical(defBool), intent(in) :: doFission - character(nameLen) :: name - integer(shortInt) :: cIdx - integer(shortInt),dimension(:),allocatable :: resArrayShape - type(particleState), save :: s - real(defReal), save :: vol - real(defFlt), save :: sig - integer(shortInt), save :: i, matIdx, g - real(defReal), dimension(:), allocatable :: res, resSD - !$omp threadprivate(s, vol, sig, i, matIdx, g) - - resArrayShape = [map % binArrayShape()] - allocate(res(map % bins(0))) - allocate(resSD(map % bins(0))) - res = ZERO - resSD = ZERO - - - ! Find whether cells are in map and sum their contributions - !$omp parallel do reduction(+: res, resSD) - do cIdx = 1, self % nCells - - vol = self % volume(cIdx) - !if (vol < volume_tolerance) cycle - vol = vol * self % totalVolume - if (.not. self % wasFound(cIdx)) cycle - - ! Fudge a particle state to search tally map - s % r = self % cellPos(:,cIdx) - i = map % map(s) - - if (i > 0) then - matIdx = self % geom % geom % graph % getMatFromUID(cIdx) - do g = 1, self % nG - if (doFission) then - sig = self % XSData % getFissionXS(matIdx, g) - else - sig = 1.0_defFlt - end if - res(i) = res(i) + vol * self % getFluxScore(cIdx,g) * sig - ! Neglects uncertainty in volume - assumed small. - resSD(i) = resSD(i) + & - self % getFluxSD(cIdx,g)**2 * vol * vol * sig * sig - end do - end if - - end do - !$omp end parallel do - - do i = 1,size(resSD) - resSD(i) = sqrt(resSD(i)) - if (res(i) > 0) resSD(i) = resSD(i) / res(i) - end do - - if (doFission) then - name = 'fiss1G' - else - name = 'flux1G' - end if - call out % startBlock(name) - call out % startArray(name, resArrayShape) - ! Add all map elements to results - do i = 1, map % bins(0) - call out % addResult(res(i), resSD(i)) - end do - call out % endArray() - ! Output tally map - call map % print(out) - call out % endBlock() - - deallocate(res) - deallocate(resSD) - - end subroutine outputMap - !! !! Send all arrays of interest to VTK output !! diff --git a/RandomRayObjects/rayHandling_func.f90 b/RandomRayObjects/rayHandling_func.f90 index 058c6bcea..2940a8d4e 100644 --- a/RandomRayObjects/rayHandling_func.f90 +++ b/RandomRayObjects/rayHandling_func.f90 @@ -208,8 +208,8 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays end do else do g = 1, nG - angular(g) = real(arrays % getPrevFlux(cIdx, g), defFlt) - !angular(g) = 0.0_defFlt + !angular(g) = real(arrays % getPrevFlux(cIdx, g), defFlt) + angular(g) = 0.0_defFlt end do end if @@ -252,7 +252,6 @@ subroutine transportSweepFlatIso(r, ints, nG, doCache, dead, termination, arrays !$omp simd do g = 1, nG - !tau(g) = max(total(g) * lenFlt, 1.0e-6_defFlt) ! Not sure whether this does much for stability tau(g) = total(g) * lenFlt end do @@ -366,7 +365,7 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra end do else do g = 1, nG - angular(g) = real(arrays % getPrevFlux(cIdx,g), defFlt) + angular(g) = 0.0_defFlt end do end if @@ -446,7 +445,6 @@ subroutine transportSweepLinearIso(r, ints, nG, doCache, dead, termination, arra ! Compute exponentials necessary for angular flux update !$omp simd do g = 1, nG - !tau(g) = max(total(g) * lenFlt, 1.0e-8_defFlt) ! This line worsens stability tau(g) = total(g) * lenFlt end do