Improved performance of cross section reading. Only one pass is made through each ACE library now.

This commit is contained in:
Paul Romano 2011-11-08 13:12:50 -05:00
parent cbb23472f3
commit c63ae4755b
2 changed files with 198 additions and 251 deletions

View file

@ -3,8 +3,8 @@ module cross_section
use constants
use cross_section_header, only: Nuclide, Reaction, SAB_Table, XsListing
use datatypes, only: dict_create, dict_add_key, dict_get_key, &
dict_has_key, dict_delete
use datatypes_header, only: DictionaryCI
dict_has_key, dict_delete, dict_keys
use datatypes_header, only: DictionaryCI, ListKeyValueCI
use endf, only: reaction_name
use error, only: fatal_error
use fileio, only: read_line, skip_lines
@ -34,16 +34,24 @@ contains
subroutine read_xs()
integer :: i ! index in materials array
integer :: j ! index over nuclides in material
integer :: index ! index in xs_listings array
integer :: index_nuclides ! index in nuclides
integer :: index_sab ! index in sab_tables
character(10) :: key ! name of isotope, e.g. 92235.03c
type(Material), pointer :: mat => null()
type(Nuclide), pointer :: nuc => null()
type(SAB_Table), pointer :: sab => null()
type(DictionaryCI), pointer :: temp_dict => null()
integer :: i ! index in materials array
integer :: j ! index over nuclides in material
integer :: index ! index in xs_listings array
integer :: index_nuclides ! index in nuclides
integer :: index_sab ! index in sab_tables
character(10) :: name ! name of isotope, e.g. 92235.03c
character(10) :: alias ! alias of nuclide, e.g. U-235.03c
character(MAX_FILE_LEN) :: path ! path to ACE cross section library
type(Material), pointer :: mat => null()
type(Nuclide), pointer :: nuc => null()
type(SAB_Table), pointer :: sab => null()
type(DictionaryCI), pointer :: library_dict => null()
type(ListKeyValueCI), pointer :: list => null()
call dict_create(library_dict)
! ==========================================================================
! COUNT NUMBER OF TABLES AND CREATE DICTIONARIES
! First we need to determine how many continuous-energy tables and how many
! S(a,b) thermal scattering tables there are -- this loop doesn't actually
@ -58,89 +66,109 @@ contains
! materials -- if not, then increment the count for the number of
! nuclides and add to dictionary
do j = 1, mat % n_nuclides
key = mat % names(j)
call lower_case(key)
if (.not. dict_has_key(nuclide_dict, key)) then
index_nuclides = index_nuclides + 1
call dict_add_key(nuclide_dict, key, index_nuclides)
name = mat % names(j)
! First check that this nuclide is listed in the cross_sections.xml
! file
if (.not. dict_has_key(xs_listing_dict, name)) then
message = "Could not find nuclide " // trim(name) // &
" in cross_sections.xml file!"
call fatal_error()
end if
! Find index in xs_listing and set the name and alias according to the
! listing
index = dict_get_key(xs_listing_dict, name)
name = xs_listings(index) % name
alias = xs_listings(index) % alias
! If this nuclide hasn't been encountered yet, we need to add its name
! and alias to the nuclide_dict
if (.not. dict_has_key(nuclide_dict, name)) then
index_nuclides = index_nuclides + 1
mat % nuclide(j) = index_nuclides
call dict_add_key(nuclide_dict, name, index_nuclides)
call dict_add_key(nuclide_dict, alias, index_nuclides)
else
mat % nuclide(j) = dict_get_key(nuclide_dict, key)
mat % nuclide(j) = dict_get_key(nuclide_dict, name)
end if
! Determine the set of ACE files which contain cross-sections used
! in this problem
path = xs_listings(index) % path
if (.not. dict_has_key(library_dict, path)) then
call dict_add_key(library_dict, path, 0)
end if
end do
! Check if S(a,b) exists on other materials
if (mat % has_sab_table) then
key = mat % sab_name
call lower_case(key)
if (.not. dict_has_key(sab_dict, key)) then
index_sab = index_sab + 1
call dict_add_key(sab_dict, key, index_sab)
mat % sab_table = index_sab
else
mat % sab_table = dict_get_key(sab_dict, key)
name = mat % sab_name
! First check that this nuclide is listed in the cross_sections.xml
! file
if (.not. dict_has_key(xs_listing_dict, name)) then
message = "Could not find S(a,b) table " // trim(name) // &
" in cross_sections.xml file!"
call fatal_error()
end if
! Find index in xs_listing and set the name and alias according to the
! listing
index = dict_get_key(xs_listing_dict, name)
name = xs_listings(index) % name
alias = xs_listings(index) % alias
! If this sab hasn't been encountered yet, we need to add its name
! and alias to the sab_dict
if (.not. dict_has_key(sab_dict, name)) then
index_sab = index_sab + 1
mat % sab_table = index_sab
call dict_add_key(sab_dict, name, index_sab)
call dict_add_key(sab_dict, alias, index_sab)
else
mat % sab_table = dict_get_key(sab_dict, name)
end if
! Determine the set of ACE files which contain cross-sections used
! in this problem
path = xs_listings(index) % path
if (.not. dict_has_key(library_dict, path)) then
call dict_add_key(library_dict, path, 0)
end if
else
mat % sab_table = 0
end if
end do
n_nuclides_total = index_nuclides
n_sab_tables = index_sab
! allocate arrays for ACE table storage
! allocate arrays for ACE table storage and cross section cache
allocate(nuclides(n_nuclides_total))
allocate(sab_tables(n_sab_tables))
! allocate array for microscopic cross section cache
allocate(micro_xs(n_nuclides_total))
call dict_create(temp_dict)
! ==========================================================================
! READ ALL ACE CROSS SECTION TABLES
! Get list to list of nuclides
list => dict_keys(library_dict)
! Loop over all files
do while (associated(list))
! Read all cross sections from this file
path = list % data % key
call read_ace_tables(path)
! Move pointer to next item
list => list % next
end do
! Now that the nuclides and sab_tables arrays have been allocated, we can
! repeat the same loop through each table in each material and read the
! cross sections
index_nuclides = 0
index_sab = 0
do i = 1, n_materials
mat => materials(i)
do j = 1, mat % n_nuclides
! Get index in xs_listings array for this nuclide
index = mat % xs_listing(j)
! Get name of nuclide
key = mat % names(j)
call lower_case(key)
if (.not. dict_has_key(temp_dict, key)) then
index_nuclides = index_nuclides + 1
call read_ACE_continuous(index_nuclides, index)
call dict_add_key(temp_dict, key, index_nuclides)
end if
end do
! Read S(a,b) table if this material has one and it hasn't been read
! already
if (mat % has_sab_table) then
! Get name of S(a,b) table
key = mat % sab_name
if (.not. dict_has_key(temp_dict, key)) then
! Find the entry in xs_listings for this table
if (dict_has_key(xs_listing_dict, key)) then
index = dict_get_key(xs_listing_dict, key)
else
message = "Cannot find cross-section " // trim(key) // &
" in specified cross_sections.xml file."
call fatal_error()
end if
! Read the table and add entry to dictionary
index_sab = index_sab + 1
call read_ACE_thermal(index_sab, index)
call dict_add_key(temp_dict, key, index_sab)
end if
! In order to know which nuclide the S(a,b) table applies to, we need
! to search through the list of nuclides for one which has a matching
! zaid
@ -162,51 +190,35 @@ contains
end if
end do
! delete dictionary
call dict_delete(temp_dict)
call dict_delete(library_dict)
end subroutine read_xs
!===============================================================================
! READ_ACE_CONTINUOUS reads in a single ACE continuous-energy neutron cross
! section table. This routine reads the header data and then calls appropriate
! subroutines to parse the actual data.
! READ_ACE_TABLES reads in all nuclides and S(a,b) tables that are present in
! the problem from a single ACE library. This routine reads the header data for
! each table and then calls appropriate subroutines to parse the actual data.
!===============================================================================
subroutine read_ACE_continuous(index_table, index)
subroutine read_ace_tables(filename)
integer, intent(in) :: index_table ! index in nuclides array
integer, intent(in) :: index ! index in xs_listings array
character(*) :: filename ! name of ACE library file
integer :: in = 7 ! unit to read from
integer :: ioError ! error status for file access
integer :: lines ! number of lines (data
integer :: n ! number of data values
real(8) :: kT ! ACE table temperature
logical :: file_exists ! does ACE library exist?
logical :: found_xs ! did we find table in library?
integer :: index_nuclides ! index in nuclides array
integer :: index_sab ! index in sab_tables array
integer :: in = 7 ! unit to read from
integer :: ioError ! error status for file access
integer :: lines ! number of lines (data
integer :: n ! number of data values
real(8) :: kT ! ACE table temperature
logical :: file_exists ! does ACE library exist?
logical :: found_nuclide ! did we find nuclide in library?
logical :: found_sab ! did we find S(a,b) table in library?
character(7) :: readable ! is ACE library readable?
character(MAX_LINE_LEN) :: line ! single line to read
character(MAX_WORD_LEN) :: words(MAX_WORDS) ! words on a line
character(MAX_FILE_LEN) :: filename ! name of ACE library file
character(10) :: tablename ! name of cross section table
type(Nuclide), pointer :: nuc => null()
! Check to make sure index in nuclides array and xs_listings arrays are
! valid
if (index_table > size(nuclides)) then
message = "Index of table to read is greater than length of nuclides."
call fatal_error()
elseif (index > size(xs_listings)) then
message = "Index of xs_listing entry is greater than length of " // &
"xs_listings."
call fatal_error()
end if
filename = xs_listings(index) % path
tablename = xs_listings(index) % name
nuc => nuclides(index_table)
type(Nuclide), pointer :: nuc => null()
type(SAB_Table), pointer :: sab => null()
! Check if input file exists and is readable
inquire(FILE=filename, EXIST=file_exists, READ=readable)
@ -219,37 +231,73 @@ contains
call fatal_error()
end if
! display message
message = "Loading ACE cross section table: " // tablename
call write_message(6)
! open file
open(file=filename, unit=in, status='old', &
& action='read', iostat=ioError)
open(FILE=filename, UNIT=in, STATUS='old', &
& ACTION='read', IOSTAT=ioError)
if (ioError /= 0) then
message = "Error while opening file: " // filename
call fatal_error()
end if
found_xs = .false.
do while (.not. found_xs)
do
! Reset flags for finding table to read
found_nuclide = .false.
found_sab = .false.
! Read next line and tokenize it into strings. If we have reached the end
! of the file, then the loop is exited
call read_line(in, line, ioError)
if (ioError < 0) then
message = "Could not find ACE table " // tablename // "."
call fatal_error()
end if
if (ioError < 0) exit
call split_string(line, words, n)
if (trim(words(1)) == trim(tablename)) then
found_xs = .true.
if (dict_has_key(nuclide_dict, words(1))) then
found_nuclide = .true.
index_nuclides = dict_get_key(nuclide_dict, words(1))
nuc => nuclides(index_nuclides)
! Copy header data
nuc % name = words(1)
nuc % awr = str_to_real(words(2))
kT = str_to_real(words(3))
kT = str_to_real(words(3))
nuc % temp = kT / K_BOLTZMANN
! display message
message = "Loading ACE cross section table: " // nuc % name
call write_message(6)
! Skip 5 lines
call skip_lines(in, 5, ioError)
elseif (dict_has_key(sab_dict, words(1))) then
found_sab = .true.
index_sab = dict_get_key(sab_dict, words(1))
sab => sab_tables(index_sab)
! Copy header data
sab % name = words(1)
sab % awr = str_to_real(words(2))
kT = str_to_real(words(3))
sab % temp = kT / K_BOLTZMANN
! display message
message = "Loading ACE cross section table: " // sab % name
call write_message(6)
! Skip 1 line
call skip_lines(in, 1, ioError)
! Read corresponding ZAID
call read_line(in, line, ioError)
call split_string(line, words, n)
sab % zaid = str_to_int(words(1))
! Skip remaining 3 lines
call skip_lines(in, 3, ioError)
else
call skip_lines(in, 5, ioError)
end if
! Skip 5 lines
call skip_lines(in, 5, ioError)
! Read NXS and JXS data
read(UNIT=in, FMT=*) NXS
read(UNIT=in, FMT=*) JXS
@ -258,7 +306,7 @@ contains
n = NXS(1)
lines = (n + 3)/4
if (found_xs) then
if (found_nuclide) then
! Set ZAID of nuclide
nuc % zaid = NXS(2)
@ -267,26 +315,38 @@ contains
! Read XSS
read(UNIT=in, FMT=*) XSS
call read_esz(nuc)
call read_nu_data(nuc)
call read_reactions(nuc)
call read_angular_dist(nuc)
call read_energy_dist(nuc)
call read_unr_res(nuc)
! Free memory from XSS array
deallocate(XSS)
elseif (found_sab) then
! allocate storage for XSS array
allocate(XSS(n))
! Read XSS
read(UNIT=in, FMT=*) XSS
call read_thermal_data(sab)
! Free memory from XSS array
deallocate(XSS)
else
call skip_lines(in, lines, ioError)
end if
end do
call read_esz(nuc)
call read_nu_data(nuc)
call read_reactions(nuc)
call read_angular_dist(nuc)
call read_energy_dist(nuc)
call read_unr_res(nuc)
! Free memory from XSS array
if(allocated(XSS)) deallocate(XSS)
if(associated(nuc)) nullify(nuc)
if(associated(sab)) nullify(sab)
close(unit=in)
close(UNIT=in)
end subroutine read_ACE_continuous
end subroutine read_ace_tables
!===============================================================================
! READ_ESZ - reads through the ESZ block. This block contains the energy grid,
@ -1057,119 +1117,6 @@ contains
end subroutine read_unr_res
!===============================================================================
! READ_ACE_THERMAL reads in a single ACE thermal scattering S(a,b) table. This
! routine in particular reads the header data and then calls read_thermal_data
! to parse the actual data blocks.
!===============================================================================
subroutine read_ACE_thermal(index_table, index)
integer, intent(in) :: index_table ! index in sab_tables array
integer, intent(in) :: index ! index in xs_listings array
integer :: in = 7 ! unit to read from
integer :: ioError ! error status for file access
integer :: lines ! number of lines (data
integer :: n ! number of data values
real(8) :: kT ! ACE table temperature
logical :: file_exists ! does ACE library exist?
logical :: found_xs ! did we find table in library?
character(7) :: readable ! is ACE library readable?
character(MAX_LINE_LEN) :: line ! single line to read
character(MAX_WORD_LEN) :: words(MAX_WORDS) ! words on a line
character(MAX_WORD_LEN) :: filename ! name of ACE library file
character(10) :: tablename ! name of cross section table
type(SAB_Table), pointer :: table => null()
filename = xs_listings(index) % path
tablename = xs_listings(index) % name
table => sab_tables(index_table)
! Check if input file exists and is readable
inquire(FILE=filename, EXIST=file_exists, READ=readable)
if (.not. file_exists) then
message = "ACE library '" // trim(filename) // "' does not exist!"
call fatal_error()
elseif (readable(1:3) == 'NO') then
message = "ACE library '" // trim(filename) // "' is not readable! &
&Change file permissions with chmod command."
call fatal_error()
end if
! display message
message = "Loading ACE cross section table: " // tablename
call write_message(6)
! open file
open(file=filename, unit=in, status='old', &
& action='read', iostat=ioError)
if (ioError /= 0) then
message = "Error while opening file: " // filename
call fatal_error()
end if
found_xs = .false.
do while (.not. found_xs)
call read_line(in, line, ioError)
if (ioError < 0) then
message = "Could not find ACE table " // tablename // "."
call fatal_error()
end if
call split_string(line, words, n)
if (trim(words(1)) == trim(tablename)) then
found_xs = .true.
table%name = words(1)
table%awr = str_to_real(words(2))
kT = str_to_real(words(3))
table%temp = kT / K_BOLTZMANN
! Skip 1 line
call skip_lines(in, 1, ioError)
! Read corresponding ZAID
call read_line(in, line, ioError)
call split_string(line, words, n)
table % zaid = str_to_int(words(1))
! Skip remaining 3 lines
call skip_lines(in, 3, ioError)
else
! Skip 5 lines
call skip_lines(in, 5, ioError)
end if
! Read NXS and JXS data
read(UNIT=in, FMT=*) NXS
read(UNIT=in, FMT=*) JXS
! Calculate how many data points and lines in the XSS array
n = NXS(1)
lines = (n + 3)/4
if (found_xs) then
! allocate storage for XSS array
allocate(XSS(n))
! Read XSS
read(UNIT=in, FMT=*) XSS
else
call skip_lines(in, lines, ioError)
end if
end do
call read_thermal_data(table)
! Free memory from XSS array
if(allocated(XSS)) deallocate(XSS)
if(associated(table)) nullify(table)
close(unit=in)
end subroutine read_ACE_thermal
!===============================================================================
! READ_THERMAL_DATA reads elastic and inelastic cross sections and corresponding
! secondary energy/angle distributions derived from experimental S(a,b)

View file

@ -17,7 +17,7 @@ module datatypes_header
!===============================================================================
! Key length for dictionary
integer, parameter :: DICT_KEY_LENGTH = 20
integer, parameter :: DICT_KEY_LENGTH = 255
type KeyValueCI
character(len=DICT_KEY_LENGTH) :: key