From 19fb9ea598a236bffad758c879d9040ea22aabc2 Mon Sep 17 00:00:00 2001 From: g_giud Date: Sat, 27 May 2017 21:15:31 -0400 Subject: [PATCH 001/229] partial currents in python interface Added cell_from and cell_to tallies --- openmc/filter.py | 73 +++++++++++++++++++++++++++++++++++++++++++++-- openmc/tallies.py | 21 +++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index 676bc66e1..063961d81 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -15,7 +15,7 @@ import openmc.checkvalue as cv _FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', - 'distribcell', 'delayedgroup', 'energyfunction'] + 'distribcell', 'delayedgroup', 'energyfunction', 'celltocell', 'cellfrom', 'cellto'] _CURRENT_NAMES = {1: 'x-min out', 2: 'x-min in', 3: 'x-max out', 4: 'x-max in', @@ -335,6 +335,9 @@ class Filter(object): """ if filter_bin not in self.bins: + print('Failed to find') + print(filter_bin) + print(self.bins) msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) raise ValueError(msg) @@ -533,7 +536,66 @@ class CellFilter(IntegralFilter): """ +class CellToCellFilter(IntegralFilter): + """Bins tally on which couple of cells the neutrons went from and to. /CHANGE/ + Parameters + ---------- + bins : Iterable of Integral + openmc.Cell IDs. + + Attributes + ---------- + bins : Iterable of Integral + openmc.Cell IDs. + num_bins : Integral + The number of filter bins + stride : Integral + The number of filter, nuclide and score bins within each of this + filter's bins. + + """ + +class CellFromFilter(IntegralFilter): + """Bins tally on which couple of cells the neutrons came from. /CHANGE/ + + Parameters + ---------- + bins : Integral or Iterable of Integral + openmc.Cell IDs. + + Attributes + ---------- + bins : Integral or Iterable of Integral + openmc.Cell IDs. + num_bins : Integral + The number of filter bins + stride : Integral + The number of filter, nuclide and score bins within each of this + filter's bins. + + """ + +class CellToFilter(IntegralFilter): + """Bins tally on which couple of cells the neutrons went to. /CHANGE/ + + Parameters + ---------- + bins : Integral or Iterable of Integral + openmc.Cell IDs. + + Attributes + ---------- + bins : Integral or Iterable of Integral + openmc.Cell IDs. + num_bins : Integral + The number of filter bins + stride : Integral + The number of filter, nuclide and score bins within each of this + filter's bins. + + """ + class CellbornFilter(IntegralFilter): """Bins tally events based on the cell that the particle was born in. @@ -901,8 +963,12 @@ class RealFilter(Filter): return np.allclose(self.bins, other.bins) def get_bin_index(self, filter_bin): - i = np.where(self.bins == filter_bin[1])[0] + i = np.where(abs(self.bins -filter_bin[1]) < 1e-10)[0] if len(i) == 0: + print('Tally bins', self.bins) + print('Bins searched for:', filter_bin) + print('Search result', i) + print(self.bins - filter_bin[1]) msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) raise ValueError(msg) @@ -940,6 +1006,9 @@ class EnergyFilter(RealFilter): def get_bin_index(self, filter_bin): # Use lower energy bound to find index for RealFilters + + #print(self.bins, filter_bin) + deltas = np.abs(self.bins - filter_bin[1]) / filter_bin[1] min_delta = np.min(deltas) if min_delta < 1E-3: diff --git a/openmc/tallies.py b/openmc/tallies.py index 0bf87de10..f3af788a6 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -239,6 +239,9 @@ class Tally(object): num_bins = 1 for self_filter in self.filters: + + #print("Looping through filters, num_bin", self_filter.num_bins, num_bins) + num_bins *= self_filter.num_bins return num_bins @@ -1215,6 +1218,7 @@ class Tally(object): # Find the equivalent Filter in this Tally's list of Filters filter_found = self.find_filter(filter_type) + #print('searched for filter', filter_type, 'and found', filter_found) # Get the index for the requested bin from the Filter and return it filter_index = filter_found.get_bin_index(filter_bin) @@ -1376,6 +1380,12 @@ class Tally(object): else: bins = self_filter.bins + #print('in get_filter_indices') + #print('arguments', filters, filter_bins) + #print('params') + #print(bins) + #print(type(self_filter), self_filter) + # Initialize a NumPy array for the Filter bin indices filter_indices.append(np.zeros(len(bins), dtype=np.int)) @@ -1520,6 +1530,8 @@ class Tally(object): e.g., if the score(s) do not match those in the Tally. """ + #print("\n In get_values") + #print("Tally shape", self.shape) # Ensure that the tally has data if (value == 'mean' and self.mean is None) or \ @@ -1529,6 +1541,13 @@ class Tally(object): (value == 'sum_sq' and self.sum_sq is None): msg = 'The Tally ID="{0}" has no data to return'.format(self.id) raise ValueError(msg) + + #print('\n arguments') + #print(filters) + #print(filter_bins) + #print('\n Tally characteristics') + #print(self) + #print(self.name, self.filters, self.scores,self.num_filter_bins) # Get filter, nuclide and score indices filter_indices = self.get_filter_indices(filters, filter_bins) @@ -1537,7 +1556,7 @@ class Tally(object): # Construct outer product of all three index types with each other indices = np.ix_(filter_indices, nuclide_indices, score_indices) - + # Return the desired result from Tally if value == 'mean': data = self.mean[indices] From ff6f05c4b7431e484bedf63b897fec3ecfeca46d Mon Sep 17 00:00:00 2001 From: g_giud Date: Sat, 27 May 2017 21:18:03 -0400 Subject: [PATCH 002/229] partial current tallies in fortran src coded when they should be triggered, when doing surface crossings, and in which form , as cell_from and cell_to filters --- src/constants.F90 | 13 +- src/geometry.F90 | 19 ++- src/global.F90 | 4 +- src/input_xml.F90 | 67 ++++++++- src/particle_header.F90 | 13 +- src/tally.F90 | 141 +++++++++++++++++- src/tally_filter.F90 | 315 +++++++++++++++++++++++++++++++++++++++ src/tally_initialize.F90 | 1 + src/tracking.F90 | 11 ++ 9 files changed, 573 insertions(+), 11 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index c44896b31..b5ae55796 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -288,7 +288,8 @@ module constants ! Tally type integer, parameter :: & TALLY_VOLUME = 1, & - TALLY_SURFACE_CURRENT = 2 + TALLY_SURFACE_CURRENT = 2, & + TALLY_CELL_TO_CELL = 3 ! Tally estimator types integer, parameter :: & @@ -304,7 +305,7 @@ module constants EVENT_ABSORB = 2 ! Tally score type - integer, parameter :: N_SCORE_TYPES = 24 + integer, parameter :: N_SCORE_TYPES = 25 integer, parameter :: & SCORE_FLUX = -1, & ! flux SCORE_TOTAL = -2, & ! total reaction rate @@ -329,7 +330,8 @@ module constants SCORE_INVERSE_VELOCITY = -21, & ! flux-weighted inverse velocity SCORE_FISS_Q_PROMPT = -22, & ! prompt fission Q-value SCORE_FISS_Q_RECOV = -23, & ! recoverable fission Q-value - SCORE_DECAY_RATE = -24 ! delayed neutron precursor decay rate + SCORE_DECAY_RATE = -24, & ! delayed neutron precursor decay rate + SCORE_CELL_TO_CELL_TYPE = -25 ! cell to cell partial current ! Maximum scattering order supported integer, parameter :: MAX_ANG_ORDER = 10 @@ -352,7 +354,7 @@ module constants integer, parameter :: NO_BIN_FOUND = -1 ! Tally filter and map types - integer, parameter :: N_FILTER_TYPES = 14 + integer, parameter :: N_FILTER_TYPES = 15 integer, parameter :: & FILTER_UNIVERSE = 1, & FILTER_MATERIAL = 2, & @@ -367,7 +369,8 @@ module constants FILTER_POLAR = 11, & FILTER_AZIMUTHAL = 12, & FILTER_DELAYEDGROUP = 13, & - FILTER_ENERGYFUNCTION = 14 + FILTER_ENERGYFUNCTION = 14, & + FILTER_CELL_TO_CELL = 15 ! Mesh types integer, parameter :: & diff --git a/src/geometry.F90 b/src/geometry.F90 index 485615991..cb9236ba2 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -11,7 +11,8 @@ module geometry use surface_header use stl_vector, only: VectorInt use string, only: to_str - use tally, only: score_surface_current + use tally, only: score_surface_current, & + &score_cell_to_cell implicit none @@ -396,6 +397,8 @@ contains integer :: i_surface ! index in surfaces logical :: found ! particle found in universe? class(Surface), pointer :: surf + + !print *, "cross surface called" i_surface = abs(p % surface) surf => surfaces(i_surface)%obj @@ -565,6 +568,11 @@ contains ! cells on the positive side call find_cell(p, found, surf%neighbor_pos) + + ! /CHANGE/ Score cell_to_cell +! print *, "Positive side, calling score_cell_to_cell" + call score_cell_to_cell(p, last_cell) + if (found) return elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then @@ -572,6 +580,11 @@ contains ! cells on the negative side call find_cell(p, found, surf%neighbor_neg) + + ! /CHANGE/ Score cell_to_cell +! print *, "Negative side, calling score_cell_to_cell" + call score_cell_to_cell(p, last_cell) + if (found) return end if @@ -604,6 +617,10 @@ contains return end if end if + + ! /CHANGE/ Score cell_to_cell +! print *, "Searched all cells then calling score_cell_to_cell" + call score_cell_to_cell(p, last_cell) end subroutine cross_surface diff --git a/src/global.F90 b/src/global.F90 index 780f323f3..7b13dc4be 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -155,10 +155,11 @@ module global type(SetInt) :: active_tracklength_tallies type(SetInt) :: active_current_tallies type(SetInt) :: active_collision_tallies + type(SetInt) :: active_cell_to_cell_tallies type(SetInt) :: active_tallies !$omp threadprivate(active_analog_tallies, active_tracklength_tallies, & !$omp& active_current_tallies, active_collision_tallies, & -!$omp& active_tallies) +!$omp& active_tallies, active_cell_to_cell_tallies) ! Global tallies ! 1) collision estimate of k-eff @@ -515,6 +516,7 @@ contains call active_tracklength_tallies % clear() call active_current_tallies % clear() call active_collision_tallies % clear() + call active_cell_to_cell_tallies % clear() call active_tallies % clear() ! Deallocate track_identifiers diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a5c894d10..03e7abc5a 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2989,6 +2989,8 @@ contains ! Get pointer list to XML and get number of filters call get_node_list(node_tal, "filter", node_filt_list) n_filters = size(node_filt_list) + +! print *, "Number of filters", n_filters ! Allocate filters array allocate(t % filters(n_filters)) @@ -3012,8 +3014,9 @@ contains end if n_words = node_word_count(node_filt, "bins") case ("mesh", "universe", "material", "cell", "distribcell", & - "cellborn", "surface", "delayedgroup") - if (.not. check_for_node(node_filt, "bins")) then + "cellborn", "surface", "delayedgroup", "celltocell",& + "cellfrom","cellto") ! /CHANGE/ + if (.not. check_for_node(node_filt, "bins")) then call fatal_error("Bins not set in filter on tally " & // trim(to_str(t % id))) end if @@ -3048,6 +3051,63 @@ contains end select ! Set the filter index in the tally find_filter array t % find_filter(FILTER_CELL) = j + + case ('celltocell') ! /CHANGE/ + ! Allocate and declare the filter type + allocate(CellToCellFilter::t % filters(j) % obj) + select type (filt => t % filters(j) % obj) + type is (CellToCellFilter) + ! Allocate and store bins + filt % n_bins = n_words / 2 ! 2 cells in each bin +! print *, "Filter n bins", n_words / 2 + allocate(filt % cells(n_words)) ! cell storage OR tally storage ??? + call get_node_array(node_filt, "bins", filt % cells) + ! node_filt is a pointer to filter + ! + end select + ! Set the filter index in the tally find_filter array + t % find_filter(FILTER_CELL_TO_CELL) = j + + ! Set estimator + t % estimator = ESTIMATOR_ANALOG + + case ('cellfrom') ! /CHANGE/ + ! Allocate and declare the filter type + allocate(CellFromFilter::t % filters(j) % obj) + select type (filt => t % filters(j) % obj) + type is (CellFromFilter) + ! Allocate and store bins + filt % n_bins = n_words +! print *, "Filter n bins", n_words + allocate(filt % cells(n_words)) + call get_node_array(node_filt, "bins", filt % cells) + ! node_filt is a pointer to filter + ! + end select + ! Set the filter index in the tally find_filter array + t % find_filter(FILTER_CELL_TO_CELL) = j + + ! Set estimator + t % estimator = ESTIMATOR_ANALOG + + case ('cellto') ! /CHANGE/ + ! Allocate and declare the filter type + allocate(CellToFilter::t % filters(j) % obj) + select type (filt => t % filters(j) % obj) + type is (CellToFilter) + ! Allocate and store bins + filt % n_bins = n_words +! print *, "Filter n bins", n_words + allocate(filt % cells(n_words)) + call get_node_array(node_filt, "bins", filt % cells) + ! node_filt is a pointer to filter + ! + end select + ! Set the filter index in the tally find_filter array + t % find_filter(FILTER_CELL_TO_CELL) = j + + ! Set estimator + t % estimator = ESTIMATOR_ANALOG case ('cellborn') ! Allocate and declare the filter type @@ -3783,6 +3843,9 @@ contains case ('events') t % score_bins(j) = SCORE_EVENTS + case ('partial_current') ! /CHANGE/ + t % type = TALLY_CELL_TO_CELL + t % score_bins(j) = SCORE_CELL_TO_CELL_TYPE case ('elastic', '(n,elastic)') t % score_bins(j) = ELASTIC diff --git a/src/particle_header.F90 b/src/particle_header.F90 index a7309393b..c6d478540 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -15,6 +15,9 @@ module particle_header !=============================================================================== type LocalCoord + + integer :: last_cell = NONE + ! Indices in various arrays for this level integer :: cell = NONE integer :: universe = NONE @@ -57,7 +60,13 @@ module particle_header real(8) :: wgt ! particle weight real(8) :: mu ! angle of scatter logical :: alive ! is particle alive? - + + ! Previous cell before crossing surface + integer :: last_cell + ! Particle coordinates + integer :: last_n_coord ! number of current coordinates +! type(LocalCoord) :: last_coord(MAX_COORD) ! coordinates for all levels + ! Pre-collision physical data real(8) :: last_xyz_current(3) ! coordinates of the last collision or ! reflective/periodic surface crossing @@ -172,6 +181,8 @@ contains elemental subroutine reset_coord(this) class(LocalCoord), intent(inout) :: this + this % last_cell = NONE + this % cell = NONE this % universe = NONE this % lattice = NONE diff --git a/src/tally.F90 b/src/tally.F90 index 248fb1664..dffd798f2 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -116,9 +116,12 @@ contains !######################################################################### ! Determine appropirate scoring value. + +! print *, "Score bin", score_bin select case(score_bin) - + + ! use default case for cell_to_from tallies, with t % estimator == ESTIMATOR_ANALOG case (SCORE_FLUX, SCORE_FLUX_YN) if (t % estimator == ESTIMATOR_ANALOG) then @@ -1177,7 +1180,16 @@ contains end if end if + case(SCORE_CELL_TO_CELL_TYPE) + ! Not using default because score_bin and event_MT thing + ! score_bin is -25, and event_MT seems to match the cell id + ! print*, p % event_MT, score_bin +! print *, "Scoring", p % last_wgt, flux + score = p % last_wgt * flux + case default + !print *, "Found right score type" + !print * , t % estimator if (t % estimator == ESTIMATOR_ANALOG) then ! Any other score is assumed to be a MT number. Thus, we just need ! to check if it matches the MT number of the event @@ -2079,6 +2091,13 @@ contains case (SCORE_EVENTS) ! Simply count number of scoring events score = ONE + + case(SCORE_CELL_TO_CELL_TYPE) + ! Not using default because score_bin and event_MT thing + ! score_bin is -25, and event_MT seems to match the cell id + ! print*, p % event_MT, score_bin +! print *, "Scoring", p % last_wgt, flux + score = p % last_wgt * flux end select @@ -2111,6 +2130,8 @@ contains integer :: num_nm ! Number of N,M orders in harmonic integer :: n ! Moment loop index real(8) :: uvw(3) + +! print *, "Expand and score, score bin", score_bin, "score", score, "filter_index", filter_index select case(score_bin) case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N) @@ -2194,6 +2215,7 @@ contains case default +! print *, "Adding to total in expand-and-score", score !$omp atomic t % results(RESULT_VALUE, score_index, filter_index) = & t % results(RESULT_VALUE, score_index, filter_index) + score @@ -3019,6 +3041,120 @@ contains end subroutine score_collision_tally +!=============================================================================== +! SCORE_CELL_TO_CELL tallies partial currents from cell_to to cell_from +!=============================================================================== + + subroutine score_cell_to_cell(p, last_cell) + + type(Particle), intent(in) :: p + integer, intent(in) :: last_cell + + ! if particle has leaked + ! DF could preserve leakage aiight + !if p % alive = .false. then + +!end if + integer :: i + integer :: i_tally + integer :: i_filt + integer :: k ! loop index for nuclide bins + ! position during the loop + integer :: filter_index ! single index for single bin + integer :: i_nuclide ! index in nuclides array + real(8) :: filter_weight ! combined weight of all filters + real(8) :: dummy_real8 + type(TallyObject), pointer :: t + + ! A loop over all tallies is necessary because we need to simultaneously + ! determine different filter bins for the same tally in order to score to it + + TALLY_LOOP: do i = 1, active_cell_to_cell_tallies % size() + ! Get index of tally and pointer to tally + i_tally = active_cell_to_cell_tallies % get_item(i) + t => tallies(i_tally) + + ! Find the first bin in each filter. There may be more than one matching + ! bin per filter, but we'll deal with those later. + do i_filt = 1, size(t % filters) +! print *, "1st bin Matching bins before", matching_bins(i_filt) + call t % filters(i_filt) % obj % get_next_bin(p, t % estimator, & + NO_BIN_FOUND, matching_bins(i_filt), filter_weights(i_filt)) +! print *, "1st Matching bins after", matching_bins(i_filt) + ! If there are no valid bins for this filter, then there is nothing to + ! score and we can move on to the next tally. + if (matching_bins(i_filt) == NO_BIN_FOUND) cycle TALLY_LOOP + end do + + ! ======================================================================== + ! Loop until we've covered all valid bins on each of the filters. + + FILTER_LOOP: do + + ! Determine scoring index and weight for this filter combination + filter_index = sum((matching_bins(1:size(t % filters)) - 1) & + * t % stride) + 1 + filter_weight = product(filter_weights(:size(t % filters))) +! print *, "SCORE_CELL_TO_CELL", filter_index + + ! Determine score for each bin + call score_general(p, t, 0, filter_index, & + 0, dummy_real8, filter_weight) +! call score_general(p, t, (k-1)*t % n_score_bins, filter_index, & +! i_nuclide, atom_density, flux * filter_weight) +! 0 for nuclides, atom_density and flux is set to 1 + + ! ====================================================================== + ! Filter logic + + ! If there are no filters, then we are done. + if (size(t % filters) == 0) exit FILTER_LOOP + + ! Increment the filter bins, starting with the last filter. If we get a + ! NO_BIN_FOUND for the last filter, it means we finished all valid bins + ! for that filter, but next-to-last filter might have more than one + ! valid bin so we need to increment that one as well, and so on. + do i_filt = size(t % filters), 1, -1 +! print *, "2nd bin Matching bins before", matching_bins(i_filt) + + call t % filters(i_filt) % obj % get_next_bin(p, t % estimator, & + matching_bins(i_filt), matching_bins(i_filt), & + filter_weights(i_filt)) +! print *, "2nd bin Matching bins after", matching_bins(i_filt) + + if (matching_bins(i_filt) /= NO_BIN_FOUND) exit + end do + + ! If we got all NO_BIN_FOUNDs, then we have finished all valid bins for + ! each of the filters. Exit the loop. + if (all(matching_bins(:size(t % filters)) == NO_BIN_FOUND)) & + exit FILTER_LOOP + + ! Reset all the filters with NO_BIN_FOUND. This will set them back to + ! their first valid bin. + do i_filt = 1, size(t % filters) + if (matching_bins(i_filt) == NO_BIN_FOUND) then + call t % filters(i_filt) % obj % get_next_bin(p, t % estimator, & + matching_bins(i_filt), matching_bins(i_filt), & + filter_weights(i_filt)) + end if + end do + end do FILTER_LOOP + + ! If the user has specified that we can assume all tallies are spatially + ! separate, this implies that once a tally has been scored to, we needn't + ! check the others. This cuts down on overhead when there are many + ! tallies specified + + if (assume_separate) exit TALLY_LOOP + + end do TALLY_LOOP + + ! Reset tally map positioning + position = 0 + + end subroutine score_cell_to_cell + !=============================================================================== ! SCORE_SURFACE_CURRENT tallies surface crossings in a mesh tally by manually ! determining which mesh surfaces were crossed @@ -4284,7 +4420,10 @@ contains end if elseif (user_tallies(i) % type == TALLY_SURFACE_CURRENT) then call active_current_tallies % add(i_user_tallies + i) + elseif (user_tallies(i) % type == TALLY_CELL_TO_CELL) then + call active_cell_to_cell_tallies % add(i_user_tallies + i) end if + end do end subroutine setup_active_usertallies diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index efa944d90..77dff5899 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -70,6 +70,45 @@ module tally_filter procedure :: text_label => text_label_cell procedure :: initialize => initialize_cell end type CellFilter + +!=============================================================================== +! CELLFROMTOFILTER specifies which geometric cells particles exit. +!=============================================================================== + type, extends(TallyFilter) :: CellToCellFilter + integer, allocatable :: cells(:) + type(DictIntInt) :: map + contains + procedure :: get_next_bin => get_next_bin_cell_to_cell + procedure :: to_statepoint => to_statepoint_cell_to_cell + procedure :: text_label => text_label_cell_to_cell + procedure :: initialize => initialize_cell_to_cell + end type CellToCellFilter + +!=============================================================================== +! CELLFROMFILTER specifies which geometric cells particles exit. +!=============================================================================== + type, extends(TallyFilter) :: CellFromFilter + integer, allocatable :: cells(:) + type(DictIntInt) :: map + contains + procedure :: get_next_bin => get_next_bin_cell_from + procedure :: to_statepoint => to_statepoint_cell_from + procedure :: text_label => text_label_cell_from + procedure :: initialize => initialize_cell_from + end type CellFromFilter + +!=============================================================================== +! CELLTOFILTER specifies which geometric cells particles enter. +!=============================================================================== + type, extends(TallyFilter) :: CellToFilter + integer, allocatable :: cells(:) + type(DictIntInt) :: map + contains + procedure :: get_next_bin => get_next_bin_cell_to + procedure :: to_statepoint => to_statepoint_cell_to + procedure :: text_label => text_label_cell_to + procedure :: initialize => initialize_cell_to + end type CellToFilter !=============================================================================== ! DISTRIBCELLFILTER specifies which distributed geometric cells tally events @@ -714,6 +753,282 @@ contains label = "Cell " // to_str(cells(this % cells(bin)) % id) end function text_label_cell +!=============================================================================== +! Cell_to_cell_Filter methods +!=============================================================================== + subroutine get_next_bin_cell_to_cell(this, p, estimator, current_bin, & + next_bin, weight) + + class(CellToCellFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + integer, value, intent(in) :: current_bin + integer, intent(out) :: next_bin + real(8), intent(out) :: weight + + integer :: i, start + + ! Find the coordinate level of the last bin we found. + if (current_bin == NO_BIN_FOUND) then + start = 1 + else + do i = 1, p % n_coord + if (p % coord(i) % cell == this % cells(current_bin)) then + start = i + 1 + exit + end if + end do + end if + + ! Starting one coordinate level deeper, find the next bin. !!!!!!!!!!!!!!!!!! OLD !!!!!!!!!!!!!!!!!!!!!!!!!! + next_bin = NO_BIN_FOUND + weight = ERROR_REAL + do i = start, p % n_coord + if (this % map % has_key(p % coord(i) % cell) .and. & + this % map % has_key(p % last_cell)) then + next_bin = this % map % get_key(p % coord(i) % cell) + weight = ONE + exit + end if + end do + end subroutine get_next_bin_cell_to_cell + + subroutine to_statepoint_cell_to_cell(this, filter_group) + class(CellToCellFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cell_to_cell + + subroutine initialize_cell_to_cell(this) + class(CellToCellFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % cells(i) +! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) + if (cell_dict % has_key(id)) then + this % cells(i) = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + + ! Generate mapping from cell indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % cells(i), i) + end do + end subroutine initialize_cell_to_cell + + function text_label_cell_to_cell(this, bin) result(label) + class(CellToCellFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Cell to from" // to_str(cells(this % cells(bin)) % id) + end function text_label_cell_to_cell + +!=============================================================================== +! Cell_From_Filter methods +!=============================================================================== + subroutine get_next_bin_cell_from(this, p, estimator, current_bin, & + next_bin, weight) + + class(CellFromFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + integer, value, intent(in) :: current_bin + integer, intent(out) :: next_bin + real(8), intent(out) :: weight + + integer :: i, start + + ! Find the coordinate level of the last bin we found. +! if (current_bin == NO_BIN_FOUND) then +! start = 1 +! else +! do i = 1, p % last_n_coord !shouldnt be done this way, modify later!! +! ! print *, p % last_cell, this % cells(current_bin) +! if (p % last_cell == this % cells(current_bin)) then +! start = i + 1 +! exit +! end if +! end do +! end if + + ! Starting one coordinate level deeper, find the next bin. + next_bin = NO_BIN_FOUND + weight = ERROR_REAL + weight = ONE + if (current_bin == NO_BIN_FOUND) then +! print *, "Looking in map for cell at", p % last_cell," :",this % map % get_key(p % last_cell) + if (this % map % has_key(p % last_cell)) then +! print *, "Found in map for cell at", p % last_cell," :",this % map % get_key(p % last_cell) + next_bin = this % map % get_key(p % last_cell) + end if + else + next_bin = NO_BIN_FOUND + end if + +! do i = start, p % last_n_coord +! if (this % map % has_key(p % last_cell)) then +! next_bin = this % map % get_key(p % coord(i) % last_cell) !need to use coord(i) to dig one level deeper +! weight = ONE +! exit +! end if +! end do + end subroutine get_next_bin_cell_from + + subroutine to_statepoint_cell_from(this, filter_group) + class(CellFromFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cell_from + + subroutine initialize_cell_from(this) + class(CellFromFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % cells(i) +! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) + if (cell_dict % has_key(id)) then + this % cells(i) = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + + ! Generate mapping from cell indices to filter bins. + do i = 1, this % n_bins +! print *, "Filling bin/cell map : cell",this % cells(i), "bin", i + call this % map % add_key(this % cells(i), i) + end do + end subroutine initialize_cell_from + + function text_label_cell_from(this, bin) result(label) + class(CellFromFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Cell to from" // to_str(cells(this % cells(bin)) % id) + end function text_label_cell_from + +!=============================================================================== +! Cell_To_Filter methods +!=============================================================================== + subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & + next_bin, weight) + + class(CellToFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + integer, value, intent(in) :: current_bin + integer, intent(out) :: next_bin + real(8), intent(out) :: weight + + integer :: i, start + + ! Find the coordinate level of the last bin we found. + if (current_bin == NO_BIN_FOUND) then + start = 1 + else + do i = 1, p % n_coord + if (p % coord(i) % cell == this % cells(current_bin)) then + start = i + 1 + exit + end if + end do + end if + + ! Starting one coordinate level deeper, find the next bin. + next_bin = NO_BIN_FOUND + weight = ERROR_REAL + do i = start, p % n_coord + if (this % map % has_key(p % coord(i) % cell)) then + next_bin = this % map % get_key(p % coord(i) % cell) + weight = ONE + exit + end if + end do + end subroutine get_next_bin_cell_to + + subroutine to_statepoint_cell_to(this, filter_group) + class(CellToFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cell_to + + subroutine initialize_cell_to(this) + class(CellToFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % cells(i) +! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) + if (cell_dict % has_key(id)) then + this % cells(i) = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + + ! Generate mapping from cell indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % cells(i), i) + end do + end subroutine initialize_cell_to + + function text_label_cell_to(this, bin) result(label) + class(CellToFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Cell to to" // to_str(cells(this % cells(bin)) % id) + end function text_label_cell_to + + !=============================================================================== ! DistribcellFilter methods !=============================================================================== diff --git a/src/tally_initialize.F90 b/src/tally_initialize.F90 index 0e7a50a9c..4c2c6406c 100644 --- a/src/tally_initialize.F90 +++ b/src/tally_initialize.F90 @@ -63,6 +63,7 @@ contains t % total_score_bins = t % n_score_bins * t % n_nuclide_bins ! Allocate results array + print *, "Allocating", t % total_score_bins, t % total_filter_bins allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) t % results(:,:,:) = ZERO diff --git a/src/tracking.F90 b/src/tracking.F90 index 7650f598a..e9fbc8662 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -37,6 +37,7 @@ contains integer :: surface_crossed ! surface which particle is on integer :: lattice_translation(3) ! in-lattice translation vector integer :: last_cell ! most recent cell particle was in + integer :: last_n_coord ! most recent number of levels for last_cell integer :: n_event ! number of collisions/crossings real(8) :: d_boundary ! distance to nearest boundary real(8) :: d_collision ! sampled distance to collision @@ -148,7 +149,11 @@ contains ! PARTICLE CROSSES SURFACE if (next_level > 0) p % n_coord = next_level + + ! Saving previous cell data last_cell = p % coord(p % n_coord) % cell + last_n_coord = p % n_coord + p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary @@ -158,6 +163,12 @@ contains else ! Particle crosses surface p % surface = surface_crossed + + ! /CHANGE/ Saving stuff on particle + p % last_cell = last_cell + p % last_n_coord = last_n_coord + p % coord(next_level) % last_cell = last_cell + call cross_surface(p, last_cell) p % event = EVENT_SURFACE end if From 21c3d6083cb87d3833ae8bd4023ebd9c27f80555 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Fri, 16 Jun 2017 23:03:27 -0400 Subject: [PATCH 003/229] added projection on normal scores, minor fixes, code clean up --- src/constants.F90 | 5 +- src/endf.F90 | 4 + src/geometry.F90 | 41 +++++---- src/input_xml.F90 | 26 +++--- src/output.F90 | 3 + src/particle_header.F90 | 20 ++--- src/tally.F90 | 79 ++++++++--------- src/tally_filter.F90 | 183 ++++++---------------------------------- src/tracking.F90 | 11 +-- 9 files changed, 120 insertions(+), 252 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index 9c52572db..77d2dcb22 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -305,7 +305,7 @@ module constants EVENT_ABSORB = 2 ! Tally score type - integer, parameter :: N_SCORE_TYPES = 25 + integer, parameter :: N_SCORE_TYPES = 26 integer, parameter :: & SCORE_FLUX = -1, & ! flux SCORE_TOTAL = -2, & ! total reaction rate @@ -331,7 +331,8 @@ module constants SCORE_FISS_Q_PROMPT = -22, & ! prompt fission Q-value SCORE_FISS_Q_RECOV = -23, & ! recoverable fission Q-value SCORE_DECAY_RATE = -24, & ! delayed neutron precursor decay rate - SCORE_CELL_TO_CELL_TYPE = -25 ! cell to cell partial current + SCORE_CELL_TO_CELL = -25, & ! cell to cell partial current + SCORE_CELL_TO_CELL_NORMAL_PROJECTION = -26 ! cell to cell partial current projected on surface normal ! Maximum scattering order supported integer, parameter :: MAX_ANG_ORDER = 10 diff --git a/src/endf.F90 b/src/endf.F90 index 0ba2db388..f672776a9 100644 --- a/src/endf.F90 +++ b/src/endf.F90 @@ -66,6 +66,10 @@ contains string = "fission-q-prompt" case (SCORE_FISS_Q_RECOV) string = "fission-q-recoverable" + case (SCORE_CELL_TO_CELL) + string = "cell-to-cell-partial-current" + case (SCORE_CELL_TO_CELL_NORMAL_PROJECTION) + string = "cell-to-cell-partial-current-projection-on-normal" ! Normal ENDF-based reactions case (TOTAL_XS) diff --git a/src/geometry.F90 b/src/geometry.F90 index 7283748a0..03a7de788 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -12,7 +12,7 @@ module geometry use stl_vector, only: VectorInt use string, only: to_str use tally, only: score_surface_current, & - &score_cell_to_cell + &score_partial_current implicit none @@ -399,8 +399,6 @@ contains logical :: rotational ! if rotational periodic BC applied logical :: found ! particle found in universe? class(Surface), pointer :: surf - - !print *, "cross surface called" i_surface = abs(p % surface) surf => surfaces(i_surface)%obj @@ -613,23 +611,33 @@ contains ! cells on the positive side call find_cell(p, found, surf%neighbor_pos) - - ! /CHANGE/ Score cell_to_cell -! print *, "Positive side, calling score_cell_to_cell" - call score_cell_to_cell(p, last_cell) - + + ! Save cosine of angle between surface normal and particle direction + p % normal_proj = dot_product(p % coord(1) % uvw, & + & surf % normal(p % coord(1) % xyz)) / & + & sqrt(dot_product(surf % normal(p % coord(1) % xyz)& + &, surf % normal(p % coord(1) % xyz))) + + ! Score cell to cell partial currents + call score_partial_current(p) + if (found) return elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then ! If coming from positive side of surface, search all the neighboring ! cells on the negative side + ! Save cosine of angle between surface normal and particle direction + p % normal_proj = dot_product(p % coord(1) % uvw, & + & surf % normal(p % coord(1) % xyz)) / & + & sqrt(dot_product(surf % normal(p % coord(1) % xyz)& + &, surf % normal(p % coord(1) % xyz))) + call find_cell(p, found, surf%neighbor_neg) - - ! /CHANGE/ Score cell_to_cell -! print *, "Negative side, calling score_cell_to_cell" - call score_cell_to_cell(p, last_cell) - + + ! Score cell to cell partial currents + call score_partial_current(p) + if (found) return end if @@ -662,10 +670,9 @@ contains return end if end if - - ! /CHANGE/ Score cell_to_cell -! print *, "Searched all cells then calling score_cell_to_cell" - call score_cell_to_cell(p, last_cell) + + ! Score cell to cell partial currents + call score_partial_current(p) end subroutine cross_surface diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7ded1060c..e74824e1d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3004,7 +3004,7 @@ contains end if n_words = node_word_count(node_filt, "bins") case ("mesh", "universe", "material", "cell", "distribcell", & - "cellborn", "surface", "delayedgroup") + "cellborn", "cellto", "cellfrom", "surface", "delayedgroup") if (.not. check_for_node(node_filt, "bins")) then call fatal_error("Bins not set in filter " // trim(to_str(filter_id))) end if @@ -3035,7 +3035,7 @@ contains allocate(filt % cells(n_words)) call get_node_array(node_filt, "bins", filt % cells) end select - + case ('cellfrom') ! Allocate and declare the filter type allocate(CellFromFilter :: f % obj) @@ -3046,7 +3046,7 @@ contains allocate(filt % cells(n_words)) call get_node_array(node_filt, "bins", filt % cells) end select - + case ('cellto') ! Allocate and declare the filter type allocate(CellToFilter :: f % obj) @@ -3057,7 +3057,7 @@ contains allocate(filt % cells(n_words)) call get_node_array(node_filt, "bins", filt % cells) end select - + case ('cellborn') ! Allocate and declare the filter type allocate(CellbornFilter :: f % obj) @@ -3414,17 +3414,10 @@ contains t % find_filter(FILTER_DISTRIBCELL) = j type is (CellFilter) t % find_filter(FILTER_CELL) = j - type is (CellFromFilter) t % find_filter(FILTER_CELL_TO_CELL) = j - - t % estimator = ESTIMATOR_ANALOG - type is (CellToFilter) t % find_filter(FILTER_CELL_TO_CELL) = j - - t % estimator = ESTIMATOR_ANALOG - type is (CellbornFilter) t % find_filter(FILTER_CELLBORN) = j type is (MaterialFilter) @@ -3927,13 +3920,14 @@ contains t % find_filter(FILTER_SURFACE) = n_filter t % filter(n_filter) = i_filt - case ('events') - t % score_bins(j) = SCORE_EVENTS - case ('partial_current') t % type = TALLY_CELL_TO_CELL - t % score_bins(j) = SCORE_CELL_TO_CELL_TYPE - + t % score_bins(j) = SCORE_CELL_TO_CELL + case ('projected_partial_current') + t % type = TALLY_CELL_TO_CELL + t % score_bins(j) = SCORE_CELL_TO_CELL_NORMAL_PROJECTION + case ('events') + t % score_bins(j) = SCORE_EVENTS case ('elastic', '(n,elastic)') t % score_bins(j) = ELASTIC case ('(n,2nd)') diff --git a/src/output.F90 b/src/output.F90 index 10d4f0511..46e882756 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -733,6 +733,9 @@ contains score_names(abs(SCORE_INVERSE_VELOCITY)) = "Flux-Weighted Inverse Velocity" score_names(abs(SCORE_FISS_Q_PROMPT)) = "Prompt fission power" score_names(abs(SCORE_FISS_Q_RECOV)) = "Recoverable fission power" + score_names(abs(SCORE_CELL_TO_CELL)) = "Partial current" + score_names(abs(SCORE_CELL_TO_CELL_NORMAL_PROJECTION)) = "Partial & + ¤t projected on normal of surface" ! Create filename for tally output filename = trim(path_output) // "tallies.out" diff --git a/src/particle_header.F90 b/src/particle_header.F90 index c6d478540..bf22a2c6a 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -15,9 +15,7 @@ module particle_header !=============================================================================== type LocalCoord - - integer :: last_cell = NONE - + ! Indices in various arrays for this level integer :: cell = NONE integer :: universe = NONE @@ -60,13 +58,11 @@ module particle_header real(8) :: wgt ! particle weight real(8) :: mu ! angle of scatter logical :: alive ! is particle alive? - - ! Previous cell before crossing surface - integer :: last_cell - ! Particle coordinates - integer :: last_n_coord ! number of current coordinates -! type(LocalCoord) :: last_coord(MAX_COORD) ! coordinates for all levels - + + ! Crossing surface data + integer :: last_cell ! last cell the particle was in before crossing + real(8) :: normal_proj ! cos of angle to surface normal when crossing + ! Pre-collision physical data real(8) :: last_xyz_current(3) ! coordinates of the last collision or ! reflective/periodic surface crossing @@ -136,6 +132,7 @@ contains ! clear attributes this % surface = NONE + this % last_cell = NONE this % cell_born = NONE this % material = NONE this % last_material = NONE @@ -143,6 +140,7 @@ contains this % wgt = ONE this % last_wgt = ONE this % absorb_wgt = ZERO + this % normal_proj = 1 this % n_bank = 0 this % wgt_bank = ZERO this % sqrtkT = ERROR_REAL @@ -181,8 +179,6 @@ contains elemental subroutine reset_coord(this) class(LocalCoord), intent(inout) :: this - this % last_cell = NONE - this % cell = NONE this % universe = NONE this % lattice = NONE diff --git a/src/tally.F90 b/src/tally.F90 index 3d18d162f..ccfd828f1 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -116,12 +116,8 @@ contains !######################################################################### ! Determine appropirate scoring value. - -! print *, "Score bin", score_bin select case(score_bin) - - ! use default case for cell_to_from tallies, with t % estimator == ESTIMATOR_ANALOG case (SCORE_FLUX, SCORE_FLUX_YN) if (t % estimator == ESTIMATOR_ANALOG) then @@ -1180,16 +1176,13 @@ contains end if end if - case(SCORE_CELL_TO_CELL_TYPE) - ! Not using default because score_bin and event_MT thing - ! score_bin is -25, and event_MT seems to match the cell id - ! print*, p % event_MT, score_bin -! print *, "Scoring", p % last_wgt, flux + case(SCORE_CELL_TO_CELL) score = p % last_wgt * flux - + + case(SCORE_CELL_TO_CELL_NORMAL_PROJECTION) + score = p % last_wgt * flux * p % normal_proj + case default - !print *, "Found right score type" - !print * , t % estimator if (t % estimator == ESTIMATOR_ANALOG) then ! Any other score is assumed to be a MT number. Thus, we just need ! to check if it matches the MT number of the event @@ -2091,14 +2084,13 @@ contains case (SCORE_EVENTS) ! Simply count number of scoring events score = ONE - - case(SCORE_CELL_TO_CELL_TYPE) - ! Not using default because score_bin and event_MT thing - ! score_bin is -25, and event_MT seems to match the cell id - ! print*, p % event_MT, score_bin -! print *, "Scoring", p % last_wgt, flux + + case(SCORE_CELL_TO_CELL) score = p % last_wgt * flux + case(SCORE_CELL_TO_CELL_NORMAL_PROJECTION) + score = p % last_wgt * flux * p % normal_proj + end select !######################################################################### @@ -2130,8 +2122,6 @@ contains integer :: num_nm ! Number of N,M orders in harmonic integer :: n ! Moment loop index real(8) :: uvw(3) - -! print *, "Expand and score, score bin", score_bin, "score", score, "filter_index", filter_index select case(score_bin) case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N) @@ -2215,7 +2205,6 @@ contains case default -! print *, "Adding to total in expand-and-score", score !$omp atomic t % results(RESULT_VALUE, score_index, filter_index) = & t % results(RESULT_VALUE, score_index, filter_index) + score @@ -3160,18 +3149,17 @@ contains end subroutine score_collision_tally !=============================================================================== -! SCORE_CELL_TO_CELL tallies partial currents from cell_to to cell_from +! score_partial_current tallies partial currents from cell_to to cell_from !=============================================================================== - subroutine score_cell_to_cell(p, last_cell) + subroutine score_partial_current(p) type(Particle), intent(in) :: p - integer, intent(in) :: last_cell - + ! if particle has leaked - ! DF could preserve leakage aiight - !if p % alive = .false. then - + ! DF could preserve leakage + ! if p % alive = .false. then + !end if integer :: i integer :: i_tally @@ -3183,9 +3171,8 @@ contains real(8) :: flux ! collision estimate of flux real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations - real(8) :: dummy_real8 type(TallyObject), pointer :: t - + ! Determine collision estimate of flux if (survival_biasing) then ! We need to account for the fact that some weight was already absorbed @@ -3193,13 +3180,15 @@ contains else flux = p % last_wgt end if - + ! A loop over all tallies is necessary because we need to simultaneously ! determine different filter bins for the same tally in order to score to it + ! However, we can restrict the list to cell_to_cell tallies since we know we + ! are crossing a surface - TALLY_LOOP: do i = 1, active_collision_tallies % size() + TALLY_LOOP: do i = 1, active_cell_to_cell_tallies % size() ! Get index of tally and pointer to tally - i_tally = active_collision_tallies % data(i) + i_tally = active_cell_to_cell_tallies % data(i) t => tallies(i_tally) ! Find all valid bins in each filter if they have not already been found @@ -3245,11 +3234,10 @@ contains filter_weight = filter_weight * filter_matches(i_filt) % weights % & data(i_bin) end do - - + call score_general(p, t, 0, filter_index, & - 0, dummy_real8, filter_weight) - + 0, 0d0, flux * filter_weight) + ! ====================================================================== ! Filter logic @@ -3282,15 +3270,15 @@ contains if (assume_separate) exit TALLY_LOOP end do TALLY_LOOP - + ! Reset filter matches flag filter_matches(:) % bins_present = .false. ! Reset tally map positioning position = 0 - - end subroutine score_cell_to_cell - + + end subroutine score_partial_current + !=============================================================================== ! SCORE_SURFACE_CURRENT tallies surface crossings in a mesh tally by manually ! determining which mesh surfaces were crossed @@ -4584,9 +4572,8 @@ contains call active_current_tallies % push_back(i_user_tallies + i) elseif (user_tallies(i) % type == TALLY_CELL_TO_CELL) then call active_cell_to_cell_tallies % push_back(i_user_tallies + i) - call active_current_tallies % push_back(i_user_tallies + i) end if - + end do call active_tallies % shrink_to_fit() @@ -4594,6 +4581,7 @@ contains call active_tracklength_tallies % shrink_to_fit() call active_collision_tallies % shrink_to_fit() call active_current_tallies % shrink_to_fit() + call active_cell_to_cell_tallies % shrink_to_fit() end subroutine setup_active_usertallies @@ -4617,6 +4605,9 @@ contains else if (active_current_tallies % size() > 0) then call fatal_error("Active current tallies should not exist before CMFD & &tallies!") + else if (active_cell_to_cell_tallies % size() > 0) then + call fatal_error("Active cell to cell tallies should not exist before & + &CMFD tallies!") end if do i = 1, n_cmfd_tallies @@ -4627,6 +4618,7 @@ contains if (cmfd_tallies(i) % type == TALLY_VOLUME) then if (cmfd_tallies(i) % estimator == ESTIMATOR_ANALOG) then call active_analog_tallies % push_back(i_cmfd_tallies + i) + call active_cell_to_cell_tallies % push_back(i_cmfd_tallies + 1) elseif (cmfd_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then call active_tracklength_tallies % push_back(i_cmfd_tallies + i) end if @@ -4640,6 +4632,7 @@ contains call active_tracklength_tallies % shrink_to_fit() call active_collision_tallies % shrink_to_fit() call active_current_tallies % shrink_to_fit() + call active_cell_to_cell_tallies % shrink_to_fit() end subroutine setup_active_cmfdtallies diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 341e44deb..b70528bf4 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -70,20 +70,7 @@ module tally_filter procedure :: text_label => text_label_cell procedure :: initialize => initialize_cell end type CellFilter - -!=============================================================================== -! CELLFROMTOFILTER specifies which geometric cells particles exit. -!=============================================================================== - type, extends(TallyFilter) :: CellToCellFilter - integer, allocatable :: cells(:) - type(DictIntInt) :: map - contains - procedure :: get_next_bin => get_next_bin_cell_to_cell - procedure :: to_statepoint => to_statepoint_cell_to_cell - procedure :: text_label => text_label_cell_to_cell - procedure :: initialize => initialize_cell_to_cell - end type CellToCellFilter - + !=============================================================================== ! CELLFROMFILTER specifies which geometric cells particles exit. !=============================================================================== @@ -96,7 +83,7 @@ module tally_filter procedure :: text_label => text_label_cell_from procedure :: initialize => initialize_cell_from end type CellFromFilter - + !=============================================================================== ! CELLTOFILTER specifies which geometric cells particles enter. !=============================================================================== @@ -757,99 +744,10 @@ contains end function text_label_cell !=============================================================================== -! Cell_to_cell_Filter methods +! CellFromFilter methods !=============================================================================== - subroutine get_next_bin_cell_to_cell(this, p, estimator, current_bin, & + subroutine get_next_bin_cell_from(this, p, estimator, current_bin, & next_bin, weight) - - class(CellToCellFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight - - integer :: i, start - - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % cell == this % cells(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. !!!!!!!!!!!!!!!!!! OLD !!!!!!!!!!!!!!!!!!!!!!!!!! - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord - if (this % map % has_key(p % coord(i) % cell) .and. & - this % map % has_key(p % last_cell)) then - next_bin = this % map % get_key(p % coord(i) % cell) - weight = ONE - exit - end if - end do - end subroutine get_next_bin_cell_to_cell - - subroutine to_statepoint_cell_to_cell(this, filter_group) - class(CellToCellFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: cell_ids(:) - - call write_dataset(filter_group, "type", "cell") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(cell_ids(size(this % cells))) - do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id - end do - call write_dataset(filter_group, "bins", cell_ids) - end subroutine to_statepoint_cell_to_cell - - subroutine initialize_cell_to_cell(this) - class(CellToCellFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % cells(i) -! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - - ! Generate mapping from cell indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) - end do - end subroutine initialize_cell_to_cell - - function text_label_cell_to_cell(this, bin) result(label) - class(CellToCellFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Cell to from" // to_str(cells(this % cells(bin)) % id) - end function text_label_cell_to_cell - -!=============================================================================== -! Cell_From_Filter methods -!=============================================================================== - subroutine get_next_bin_cell_from(this, p, estimator, current_bin, & - next_bin, weight) - class(CellFromFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator @@ -859,45 +757,24 @@ contains integer :: i, start - ! Find the coordinate level of the last bin we found. -! if (current_bin == NO_BIN_FOUND) then -! start = 1 -! else -! do i = 1, p % last_n_coord !shouldnt be done this way, modify later!! -! ! print *, p % last_cell, this % cells(current_bin) -! if (p % last_cell == this % cells(current_bin)) then -! start = i + 1 -! exit -! end if -! end do -! end if - - ! Starting one coordinate level deeper, find the next bin. + ! Particle can only have one cell_from + ! If current_bin is already a bin, then no need to look for another bin next_bin = NO_BIN_FOUND weight = ERROR_REAL - weight = ONE if (current_bin == NO_BIN_FOUND) then -! print *, "Looking in map for cell at", p % last_cell," :",this % map % get_key(p % last_cell) if (this % map % has_key(p % last_cell)) then -! print *, "Found in map for cell at", p % last_cell," :",this % map % get_key(p % last_cell) next_bin = this % map % get_key(p % last_cell) + weight = ONE end if else next_bin = NO_BIN_FOUND end if - -! do i = start, p % last_n_coord -! if (this % map % has_key(p % last_cell)) then -! next_bin = this % map % get_key(p % coord(i) % last_cell) !need to use coord(i) to dig one level deeper -! weight = ONE -! exit -! end if -! end do + end subroutine get_next_bin_cell_from subroutine to_statepoint_cell_from(this, filter_group) class(CellFromFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group + integer(HID_T), intent(in) :: filter_group integer :: i integer, allocatable :: cell_ids(:) @@ -920,7 +797,6 @@ contains ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) -! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) if (cell_dict % has_key(id)) then this % cells(i) = cell_dict % get_key(id) else @@ -931,31 +807,29 @@ contains ! Generate mapping from cell indices to filter bins. do i = 1, this % n_bins -! print *, "Filling bin/cell map : cell",this % cells(i), "bin", i call this % map % add_key(this % cells(i), i) end do end subroutine initialize_cell_from - + function text_label_cell_from(this, bin) result(label) class(CellFromFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label - label = "Cell to from" // to_str(cells(this % cells(bin)) % id) + label = "Cell from " // to_str(cells(this % cells(bin)) % id) end function text_label_cell_from - + !=============================================================================== -! Cell_To_Filter methods +! CellToFilter methods !=============================================================================== - subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & + subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & next_bin, weight) - class(CellToFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + integer, value, intent(in) :: current_bin + integer, intent(out) :: next_bin + real(8), intent(out) :: weight integer :: i, start @@ -985,7 +859,7 @@ contains subroutine to_statepoint_cell_to(this, filter_group) class(CellToFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group + integer(HID_T), intent(in) :: filter_group integer :: i integer, allocatable :: cell_ids(:) @@ -1008,7 +882,7 @@ contains ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) -! print *,this % n_bins, this % cells(i), cell_dict % get_key(id) + if (cell_dict % has_key(id)) then this % cells(i) = cell_dict % get_key(id) else @@ -1022,16 +896,15 @@ contains call this % map % add_key(this % cells(i), i) end do end subroutine initialize_cell_to - + function text_label_cell_to(this, bin) result(label) class(CellToFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label - label = "Cell to to" // to_str(cells(this % cells(bin)) % id) + label = "Cell to " // to_str(cells(this % cells(bin)) % id) end function text_label_cell_to - - + !=============================================================================== ! DistribcellFilter methods !=============================================================================== diff --git a/src/tracking.F90 b/src/tracking.F90 index e9fbc8662..4a87b4ffa 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -149,11 +149,10 @@ contains ! PARTICLE CROSSES SURFACE if (next_level > 0) p % n_coord = next_level - + ! Saving previous cell data last_cell = p % coord(p % n_coord) % cell - last_n_coord = p % n_coord - + p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary @@ -163,12 +162,10 @@ contains else ! Particle crosses surface p % surface = surface_crossed - + ! /CHANGE/ Saving stuff on particle p % last_cell = last_cell - p % last_n_coord = last_n_coord - p % coord(next_level) % last_cell = last_cell - + call cross_surface(p, last_cell) p % event = EVENT_SURFACE end if From 51c698635193aed9a282055d3dd9ded32cb93b7f Mon Sep 17 00:00:00 2001 From: Guillaume Date: Fri, 16 Jun 2017 23:07:59 -0400 Subject: [PATCH 004/229] added filters to python API --- openmc/filter.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index 303687e2f..449141d77 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -375,9 +375,7 @@ class Filter(object): """ if filter_bin not in self.bins: - print('Failed to find') - print(filter_bin) - print(self.bins) + msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) raise ValueError(msg) @@ -506,7 +504,6 @@ class WithIDFilter(Filter): self._bins = bins - class UniverseFilter(WithIDFilter): """Bins tally event locations based on the Universe they occured in. @@ -600,6 +597,10 @@ class CellFilter(WithIDFilter): @property def bins(self): return self._bins + + @bins.setter + def bins(self, bins): + self._smart_set_bins(bins, openmc.Cell) class CellFromFilter(WithIDFilter): """Bins tally on which couple of cells the neutrons came from. @@ -616,6 +617,8 @@ class CellFromFilter(WithIDFilter): ---------- bins : Integral or Iterable of Integral openmc.Cell IDs. + id : int + Unique identifier for the filter num_bins : Integral The number of filter bins stride : Integral @@ -623,6 +626,13 @@ class CellFromFilter(WithIDFilter): filter's bins. """ + @property + def bins(self): + return self._bins + + @bins.setter + def bins(self, bins): + self._smart_set_bins(bins, openmc.Cell) class CellToFilter(WithIDFilter): """Bins tally on which couple of cells the neutrons went to. @@ -639,6 +649,8 @@ class CellToFilter(WithIDFilter): ---------- bins : Integral or Iterable of Integral openmc.Cell IDs. + id : int + Unique identifier for the filter num_bins : Integral The number of filter bins stride : Integral @@ -646,6 +658,13 @@ class CellToFilter(WithIDFilter): filter's bins. """ + @property + def bins(self): + return self._bins + + @bins.setter + def bins(self, bins): + self._smart_set_bins(bins, openmc.Cell) class CellbornFilter(WithIDFilter): """Bins tally events based on which Cell the neutron was born in. @@ -1066,10 +1085,6 @@ class RealFilter(Filter): def get_bin_index(self, filter_bin): i = np.where(abs(self.bins -filter_bin[1]) < 1e-10)[0] if len(i) == 0: - print('Tally bins', self.bins) - print('Bins searched for:', filter_bin) - print('Search result', i) - print(self.bins - filter_bin[1]) msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) raise ValueError(msg) @@ -1111,9 +1126,7 @@ class EnergyFilter(RealFilter): def get_bin_index(self, filter_bin): # Use lower energy bound to find index for RealFilters - - #print(self.bins, filter_bin) - + deltas = np.abs(self.bins - filter_bin[1]) / filter_bin[1] min_delta = np.min(deltas) if min_delta < 1E-3: From fdd5eff2e8ee8572c3e6cbac66f6ce6e3486d0d0 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Fri, 16 Jun 2017 23:28:21 -0400 Subject: [PATCH 005/229] white spaces issues --- src/tally.F90 | 2 +- src/tally_filter.F90 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index ccfd828f1..6cda8d627 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2090,7 +2090,7 @@ contains case(SCORE_CELL_TO_CELL_NORMAL_PROJECTION) score = p % last_wgt * flux * p % normal_proj - + end select !######################################################################### diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index b70528bf4..194f0422d 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -746,8 +746,8 @@ contains !=============================================================================== ! CellFromFilter methods !=============================================================================== - subroutine get_next_bin_cell_from(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_next_bin_cell_from(this, p, estimator, current_bin, & + next_bin, weight) class(CellFromFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator @@ -822,8 +822,8 @@ contains !=============================================================================== ! CellToFilter methods !=============================================================================== - subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & + next_bin, weight) class(CellToFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator From ab9e589174fc30684c6dd93d355cd466503151ed Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 15:26:54 -0400 Subject: [PATCH 006/229] deleted some debug prints --- openmc/tallies.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 88e996192..61dbd4d32 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -238,10 +238,7 @@ class Tally(object): def num_filter_bins(self): num_bins = 1 - for self_filter in self.filters: - - #print("Looping through filters, num_bin", self_filter.num_bins, num_bins) - + for self_filter in self.filters: num_bins *= self_filter.num_bins return num_bins @@ -1219,7 +1216,6 @@ class Tally(object): # Find the equivalent Filter in this Tally's list of Filters filter_found = self.find_filter(filter_type) - #print('searched for filter', filter_type, 'and found', filter_found) # Get the index for the requested bin from the Filter and return it filter_index = filter_found.get_bin_index(filter_bin) @@ -1381,12 +1377,6 @@ class Tally(object): else: bins = self_filter.bins - #print('in get_filter_indices') - #print('arguments', filters, filter_bins) - #print('params') - #print(bins) - #print(type(self_filter), self_filter) - # Initialize a NumPy array for the Filter bin indices filter_indices.append(np.zeros(len(bins), dtype=np.int)) @@ -1531,8 +1521,6 @@ class Tally(object): e.g., if the score(s) do not match those in the Tally. """ - #print("\n In get_values") - #print("Tally shape", self.shape) # Ensure that the tally has data if (value == 'mean' and self.mean is None) or \ @@ -1542,13 +1530,6 @@ class Tally(object): (value == 'sum_sq' and self.sum_sq is None): msg = 'The Tally ID="{0}" has no data to return'.format(self.id) raise ValueError(msg) - - #print('\n arguments') - #print(filters) - #print(filter_bins) - #print('\n Tally characteristics') - #print(self) - #print(self.name, self.filters, self.scores,self.num_filter_bins) # Get filter, nuclide and score indices filter_indices = self.get_filter_indices(filters, filter_bins) @@ -1557,7 +1538,7 @@ class Tally(object): # Construct outer product of all three index types with each other indices = np.ix_(filter_indices, nuclide_indices, score_indices) - + # Return the desired result from Tally if value == 'mean': data = self.mean[indices] From 3b46ebdd8915cdd90a019dfcc8d8b31341083a01 Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 16:56:11 -0400 Subject: [PATCH 007/229] Deleted extra comments --- src/tally.F90 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 6cda8d627..a40e0b80f 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3156,10 +3156,6 @@ contains type(Particle), intent(in) :: p - ! if particle has leaked - ! DF could preserve leakage - ! if p % alive = .false. then - !end if integer :: i integer :: i_tally @@ -3181,11 +3177,6 @@ contains flux = p % last_wgt end if - ! A loop over all tallies is necessary because we need to simultaneously - ! determine different filter bins for the same tally in order to score to it - ! However, we can restrict the list to cell_to_cell tallies since we know we - ! are crossing a surface - TALLY_LOOP: do i = 1, active_cell_to_cell_tallies % size() ! Get index of tally and pointer to tally i_tally = active_cell_to_cell_tallies % data(i) From 691173886c0c50da8e00d3949d7dfcdc8bb19e7f Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 17:37:48 -0400 Subject: [PATCH 008/229] Update tallies.py --- openmc/tallies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 61dbd4d32..1641d6164 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -238,7 +238,7 @@ class Tally(object): def num_filter_bins(self): num_bins = 1 - for self_filter in self.filters: + for self_filter in self.filters: num_bins *= self_filter.num_bins return num_bins From 3ab762f617f548039e0ed554271cc3140141835d Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 17:40:05 -0400 Subject: [PATCH 009/229] Update filter.py --- openmc/filter.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index 449141d77..6c059d66e 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -375,7 +375,6 @@ class Filter(object): """ if filter_bin not in self.bins: - msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) raise ValueError(msg) @@ -504,6 +503,7 @@ class WithIDFilter(Filter): self._bins = bins + class UniverseFilter(WithIDFilter): """Bins tally event locations based on the Universe they occured in. @@ -1083,7 +1083,7 @@ class RealFilter(Filter): return np.allclose(self.bins, other.bins) def get_bin_index(self, filter_bin): - i = np.where(abs(self.bins -filter_bin[1]) < 1e-10)[0] + i = np.where(i = np.where(self.bins == filter_bin[1])[0] if len(i) == 0: msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) @@ -1126,7 +1126,6 @@ class EnergyFilter(RealFilter): def get_bin_index(self, filter_bin): # Use lower energy bound to find index for RealFilters - deltas = np.abs(self.bins - filter_bin[1]) / filter_bin[1] min_delta = np.min(deltas) if min_delta < 1E-3: From 974db1ca5718ae7e3cd155e0d91b0e771e48930d Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 17:53:05 -0400 Subject: [PATCH 010/229] Update filter.py --- openmc/filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/filter.py b/openmc/filter.py index 6c059d66e..bc6b0bd35 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -1083,7 +1083,7 @@ class RealFilter(Filter): return np.allclose(self.bins, other.bins) def get_bin_index(self, filter_bin): - i = np.where(i = np.where(self.bins == filter_bin[1])[0] + i = np.where(self.bins == filter_bin[1])[0] if len(i) == 0: msg = 'Unable to get the bin index for Filter since "{0}" ' \ 'is not one of the bins'.format(filter_bin) From 76ab40293b993e348c8ec0c38baa39f7460a4d96 Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 17:54:28 -0400 Subject: [PATCH 011/229] deleted extra print --- src/tally_initialize.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tally_initialize.F90 b/src/tally_initialize.F90 index 2182053c3..46c028364 100644 --- a/src/tally_initialize.F90 +++ b/src/tally_initialize.F90 @@ -62,7 +62,6 @@ contains t % total_score_bins = t % n_score_bins * t % n_nuclide_bins ! Allocate results array - print *, "Allocating", t % total_score_bins, t % total_filter_bins allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) t % results(:,:,:) = ZERO From 81d122657a4d39b8d371e6af551616cf5e5edf96 Mon Sep 17 00:00:00 2001 From: Giud Date: Sun, 18 Jun 2017 17:56:14 -0400 Subject: [PATCH 012/229] Reworded comment --- src/tracking.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracking.F90 b/src/tracking.F90 index 4a87b4ffa..ef0c06371 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -163,7 +163,7 @@ contains ! Particle crosses surface p % surface = surface_crossed - ! /CHANGE/ Saving stuff on particle + ! Saving last cell for tallying purposes p % last_cell = last_cell call cross_surface(p, last_cell) From e584ade6848b822f541bde6d89299125ffe73758 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Mon, 19 Jun 2017 20:07:24 -0400 Subject: [PATCH 013/229] implemented half of Sterling s corrections (inheriting cellfilter, moved partial current scoring)+ bug fix on energy filter --- src/constants.F90 | 5 +- src/endf.F90 | 2 - src/geometry.F90 | 23 -------- src/input_xml.F90 | 3 - src/output.F90 | 2 - src/tally.F90 | 35 +++++++----- src/tally_filter.F90 | 128 +++++++++++++++++++++---------------------- src/tracking.F90 | 10 +++- 8 files changed, 95 insertions(+), 113 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index 77d2dcb22..4e9fe9865 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -305,7 +305,7 @@ module constants EVENT_ABSORB = 2 ! Tally score type - integer, parameter :: N_SCORE_TYPES = 26 + integer, parameter :: N_SCORE_TYPES = 25 integer, parameter :: & SCORE_FLUX = -1, & ! flux SCORE_TOTAL = -2, & ! total reaction rate @@ -331,8 +331,7 @@ module constants SCORE_FISS_Q_PROMPT = -22, & ! prompt fission Q-value SCORE_FISS_Q_RECOV = -23, & ! recoverable fission Q-value SCORE_DECAY_RATE = -24, & ! delayed neutron precursor decay rate - SCORE_CELL_TO_CELL = -25, & ! cell to cell partial current - SCORE_CELL_TO_CELL_NORMAL_PROJECTION = -26 ! cell to cell partial current projected on surface normal + SCORE_CELL_TO_CELL = -25 ! cell to cell partial current ! Maximum scattering order supported integer, parameter :: MAX_ANG_ORDER = 10 diff --git a/src/endf.F90 b/src/endf.F90 index f672776a9..7f3de44f5 100644 --- a/src/endf.F90 +++ b/src/endf.F90 @@ -68,8 +68,6 @@ contains string = "fission-q-recoverable" case (SCORE_CELL_TO_CELL) string = "cell-to-cell-partial-current" - case (SCORE_CELL_TO_CELL_NORMAL_PROJECTION) - string = "cell-to-cell-partial-current-projection-on-normal" ! Normal ENDF-based reactions case (TOTAL_XS) diff --git a/src/geometry.F90 b/src/geometry.F90 index 03a7de788..d6c6bff3b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -611,33 +611,13 @@ contains ! cells on the positive side call find_cell(p, found, surf%neighbor_pos) - - ! Save cosine of angle between surface normal and particle direction - p % normal_proj = dot_product(p % coord(1) % uvw, & - & surf % normal(p % coord(1) % xyz)) / & - & sqrt(dot_product(surf % normal(p % coord(1) % xyz)& - &, surf % normal(p % coord(1) % xyz))) - - ! Score cell to cell partial currents - call score_partial_current(p) - if (found) return elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then ! If coming from positive side of surface, search all the neighboring ! cells on the negative side - ! Save cosine of angle between surface normal and particle direction - p % normal_proj = dot_product(p % coord(1) % uvw, & - & surf % normal(p % coord(1) % xyz)) / & - & sqrt(dot_product(surf % normal(p % coord(1) % xyz)& - &, surf % normal(p % coord(1) % xyz))) - call find_cell(p, found, surf%neighbor_neg) - - ! Score cell to cell partial currents - call score_partial_current(p) - if (found) return end if @@ -671,9 +651,6 @@ contains end if end if - ! Score cell to cell partial currents - call score_partial_current(p) - end subroutine cross_surface !=============================================================================== diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e74824e1d..ab111dcc5 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3923,9 +3923,6 @@ contains case ('partial_current') t % type = TALLY_CELL_TO_CELL t % score_bins(j) = SCORE_CELL_TO_CELL - case ('projected_partial_current') - t % type = TALLY_CELL_TO_CELL - t % score_bins(j) = SCORE_CELL_TO_CELL_NORMAL_PROJECTION case ('events') t % score_bins(j) = SCORE_EVENTS case ('elastic', '(n,elastic)') diff --git a/src/output.F90 b/src/output.F90 index 46e882756..bfd501407 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -734,8 +734,6 @@ contains score_names(abs(SCORE_FISS_Q_PROMPT)) = "Prompt fission power" score_names(abs(SCORE_FISS_Q_RECOV)) = "Recoverable fission power" score_names(abs(SCORE_CELL_TO_CELL)) = "Partial current" - score_names(abs(SCORE_CELL_TO_CELL_NORMAL_PROJECTION)) = "Partial & - ¤t projected on normal of surface" ! Create filename for tally output filename = trim(path_output) // "tallies.out" diff --git a/src/tally.F90 b/src/tally.F90 index a40e0b80f..d0f504b4e 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -119,6 +119,7 @@ contains select case(score_bin) + case (SCORE_FLUX, SCORE_FLUX_YN) if (t % estimator == ESTIMATOR_ANALOG) then ! All events score to a flux bin. We actually use a collision @@ -1176,12 +1177,6 @@ contains end if end if - case(SCORE_CELL_TO_CELL) - score = p % last_wgt * flux - - case(SCORE_CELL_TO_CELL_NORMAL_PROJECTION) - score = p % last_wgt * flux * p % normal_proj - case default if (t % estimator == ESTIMATOR_ANALOG) then ! Any other score is assumed to be a MT number. Thus, we just need @@ -2085,12 +2080,6 @@ contains ! Simply count number of scoring events score = ONE - case(SCORE_CELL_TO_CELL) - score = p % last_wgt * flux - - case(SCORE_CELL_TO_CELL_NORMAL_PROJECTION) - score = p % last_wgt * flux * p % normal_proj - end select !######################################################################### @@ -3161,11 +3150,15 @@ contains integer :: i_tally integer :: i_filt integer :: i_bin + integer :: q ! loop index for scoring bins + integer :: score_bin ! scoring bin, e.g. SCORE_FLUX + integer :: score_index ! scoring bin index integer :: j ! loop index for scoring bins integer :: filter_index ! single index for single bin integer :: matching_bin ! next valid filter bin real(8) :: flux ! collision estimate of flux real(8) :: filter_weight ! combined weight of all filters + real(8) :: score ! analog tally score logical :: finished ! found all valid bin combinations type(TallyObject), pointer :: t @@ -3226,8 +3219,22 @@ contains data(i_bin) end do - call score_general(p, t, 0, filter_index, & - 0, 0d0, flux * filter_weight) + ! Determine score + score = flux * filter_weight + + ! Currently only one score type + SCORE_LOOP: do q = 1, t % n_user_score_bins + + ! determine what type of score bin + score_bin = t % score_bins(q) + + ! determine scoring bin index, no offset from nuclide bins + score_index = q + + ! Expand score if necessary and add to tally results. + call expand_and_score(p, t, score_index, filter_index, score_bin, & + score, q) + end do SCORE_LOOP ! ====================================================================== ! Filter logic diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 194f0422d..eb36e8c9f 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -87,14 +87,12 @@ module tally_filter !=============================================================================== ! CELLTOFILTER specifies which geometric cells particles enter. !=============================================================================== - type, extends(TallyFilter) :: CellToFilter - integer, allocatable :: cells(:) - type(DictIntInt) :: map + type, extends(CellFilter) :: CellToFilter +! integer, allocatable :: cells(:) +! type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_cell_to - procedure :: to_statepoint => to_statepoint_cell_to - procedure :: text_label => text_label_cell_to - procedure :: initialize => initialize_cell_to + procedure :: to_statepoint_cell => to_statepoint_cell_to + procedure :: text_label_cell => text_label_cell_to end type CellToFilter !=============================================================================== @@ -779,7 +777,7 @@ contains integer :: i integer, allocatable :: cell_ids(:) - call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "type", "cell from") call write_dataset(filter_group, "n_bins", this % n_bins) allocate(cell_ids(size(this % cells))) @@ -822,40 +820,40 @@ contains !=============================================================================== ! CellToFilter methods !=============================================================================== - subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & - next_bin, weight) - class(CellToFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight - - integer :: i, start - - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % cell == this % cells(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord - if (this % map % has_key(p % coord(i) % cell)) then - next_bin = this % map % get_key(p % coord(i) % cell) - weight = ONE - exit - end if - end do - end subroutine get_next_bin_cell_to +! subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & +! next_bin, weight) +! class(CellToFilter), intent(in) :: this +! type(Particle), intent(in) :: p +! integer, intent(in) :: estimator +! integer, value, intent(in) :: current_bin +! integer, intent(out) :: next_bin +! real(8), intent(out) :: weight +! +! integer :: i, start +! +! ! Find the coordinate level of the last bin we found. +! if (current_bin == NO_BIN_FOUND) then +! start = 1 +! else +! do i = 1, p % n_coord +! if (p % coord(i) % cell == this % cells(current_bin)) then +! start = i + 1 +! exit +! end if +! end do +! end if +! +! ! Starting one coordinate level deeper, find the next bin. +! next_bin = NO_BIN_FOUND +! weight = ERROR_REAL +! do i = start, p % n_coord +! if (this % map % has_key(p % coord(i) % cell)) then +! next_bin = this % map % get_key(p % coord(i) % cell) +! weight = ONE +! exit +! end if +! end do +! end subroutine get_next_bin_cell_to subroutine to_statepoint_cell_to(this, filter_group) class(CellToFilter), intent(in) :: this @@ -864,7 +862,7 @@ contains integer :: i integer, allocatable :: cell_ids(:) - call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "type", "cell to") call write_dataset(filter_group, "n_bins", this % n_bins) allocate(cell_ids(size(this % cells))) @@ -874,28 +872,28 @@ contains call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cell_to - subroutine initialize_cell_to(this) - class(CellToFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % cells(i) - - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - - ! Generate mapping from cell indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) - end do - end subroutine initialize_cell_to +! subroutine initialize_cell_to(this) +! class(CellToFilter), intent(inout) :: this +! +! integer :: i, id +! +! ! Convert ids to indices. +! do i = 1, this % n_bins +! id = this % cells(i) +! +! if (cell_dict % has_key(id)) then +! this % cells(i) = cell_dict % get_key(id) +! else +! call fatal_error("Could not find cell " // trim(to_str(id)) & +! &// " specified on tally filter.") +! end if +! end do +! +! ! Generate mapping from cell indices to filter bins. +! do i = 1, this % n_bins +! call this % map % add_key(this % cells(i), i) +! end do +! end subroutine initialize_cell_to function text_label_cell_to(this, bin) result(label) class(CellToFilter), intent(in) :: this diff --git a/src/tracking.F90 b/src/tracking.F90 index ef0c06371..d8d0f8a7a 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -15,7 +15,7 @@ module tracking use string, only: to_str use tally, only: score_analog_tally, score_tracklength_tally, & score_collision_tally, score_surface_current, & - score_track_derivative, & + score_track_derivative, score_partial_current, & score_collision_derivative, zero_flux_derivs use track_output, only: initialize_particle_track, write_particle_track, & add_particle_track, finalize_particle_track @@ -166,8 +166,16 @@ contains ! Saving last cell for tallying purposes p % last_cell = last_cell + ! Update last_ information. This is needed to use the same filters as + ! the ones implemented for regular tallies + p % last_uvw = p % coord(p % n_coord) % uvw + p % last_E = p % E + call cross_surface(p, last_cell) p % event = EVENT_SURFACE + + ! Score cell to cell partial currents + call score_partial_current(p) end if else ! ==================================================================== From d952d67fe545ba1d26a1a85fdcfa6206cfbfc9ae Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 08:39:16 -0400 Subject: [PATCH 014/229] made cell_from filter more general --- openmc/filter.py | 3 ++- src/geometry.F90 | 3 +-- src/particle_header.F90 | 55 ++++++++++++++++++++++++++++++++++++----- src/tally_filter.F90 | 49 ++++++++++++++++++++---------------- src/tracking.F90 | 10 +++----- 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index bc6b0bd35..9382c333b 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -18,7 +18,8 @@ AUTO_FILTER_ID = 10000 _FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', - 'distribcell', 'delayedgroup', 'energyfunction', 'celltocell', 'cellfrom', 'cellto'] + 'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom', + 'cellto'] _CURRENT_NAMES = {1: 'x-min out', 2: 'x-min in', 3: 'x-max out', 4: 'x-max in', diff --git a/src/geometry.F90 b/src/geometry.F90 index d6c6bff3b..f80bd7eb7 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -11,8 +11,7 @@ module geometry use surface_header use stl_vector, only: VectorInt use string, only: to_str - use tally, only: score_surface_current, & - &score_partial_current + use tally, only: score_surface_current implicit none diff --git a/src/particle_header.F90 b/src/particle_header.F90 index bf22a2c6a..4f9aa2559 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -32,6 +32,7 @@ module particle_header logical :: rotated = .false. contains procedure :: reset => reset_coord + procedure :: copy_coord end type LocalCoord !=============================================================================== @@ -48,6 +49,10 @@ module particle_header integer :: n_coord ! number of current coordinates type(LocalCoord) :: coord(MAX_COORD) ! coordinates for all levels + ! Particle coordinates before crossing a surface + integer :: last_n_coord ! number of current coordinates + type(LocalCoord) :: last_coord(MAX_COORD) ! coordinates for all levels + ! Energy Data real(8) :: E ! post-collision energy real(8) :: last_E ! pre-collision energy @@ -59,10 +64,6 @@ module particle_header real(8) :: mu ! angle of scatter logical :: alive ! is particle alive? - ! Crossing surface data - integer :: last_cell ! last cell the particle was in before crossing - real(8) :: normal_proj ! cos of angle to surface normal when crossing - ! Pre-collision physical data real(8) :: last_xyz_current(3) ! coordinates of the last collision or ! reflective/periodic surface crossing @@ -110,6 +111,7 @@ module particle_header procedure :: clear => clear_particle procedure :: initialize_from_source procedure :: create_secondary + procedure :: set_last_coord end type Particle contains @@ -132,7 +134,6 @@ contains ! clear attributes this % surface = NONE - this % last_cell = NONE this % cell_born = NONE this % material = NONE this % last_material = NONE @@ -140,7 +141,6 @@ contains this % wgt = ONE this % last_wgt = ONE this % absorb_wgt = ZERO - this % normal_proj = 1 this % n_bank = 0 this % wgt_bank = ZERO this % sqrtkT = ERROR_REAL @@ -153,6 +153,8 @@ contains ! Set up base level coordinates this % coord(1) % universe = root_universe this % n_coord = 1 + this % last_coord(1) % universe = root_universe + this % last_n_coord = 1 end subroutine initialize_particle @@ -223,6 +225,47 @@ contains end subroutine initialize_from_source +!=============================================================================== +! SET_LAST_COORD copies all coordinate levels from coord to last_coord. This is +! meant to have information about the last cell in the cell_from filter +!=============================================================================== + + subroutine set_last_coord(this) + class(Particle), intent(inout) :: this + integer :: i + + this % last_n_coord = this % n_coord + + ! copy all information at all coordinate levels + do i = 1, this % n_coord + call this % last_coord(i) % copy_coord(this % coord(i)) + end do + + ! reset the rest of former last_coord + do i = this % n_coord + 1, MAX_COORD + call this % last_coord(i) % reset() + end do + + end subroutine set_last_coord + +!=============================================================================== +! COPY_COORD copies one coordinate levels from coord to last_coord. +!=============================================================================== + + elemental subroutine copy_coord(this, coord) + class(LocalCoord), intent(inout) :: this + class(LocalCoord), intent(in) :: coord + + this % cell = coord % cell + this % universe = coord % universe + this % lattice = coord % lattice + this % lattice_x = coord % lattice_x + this % lattice_y = coord % lattice_y + this % lattice_z = coord % lattice_z + this % rotated = coord % rotated + + end subroutine copy_coord + !=============================================================================== ! CREATE_SECONDARY stores the current phase space attributes of the particle in ! the secondary bank and increments the number of sites in the secondary bank. diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index eb36e8c9f..c4e72eba5 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -72,24 +72,21 @@ module tally_filter end type CellFilter !=============================================================================== -! CELLFROMFILTER specifies which geometric cells particles exit. +! CELLFROMFILTER specifies which geometric cells particles exit when crossing a +! surface. !=============================================================================== - type, extends(TallyFilter) :: CellFromFilter - integer, allocatable :: cells(:) - type(DictIntInt) :: map + type, extends(CellFilter) :: CellFromFilter contains - procedure :: get_next_bin => get_next_bin_cell_from - procedure :: to_statepoint => to_statepoint_cell_from - procedure :: text_label => text_label_cell_from - procedure :: initialize => initialize_cell_from + procedure :: get_next_bin_cell => get_next_bin_cell_from + procedure :: to_statepoint_cell => to_statepoint_cell_from + procedure :: text_label_cell => text_label_cell_from end type CellFromFilter !=============================================================================== -! CELLTOFILTER specifies which geometric cells particles enter. +! CELLTOFILTER specifies which geometric cells particles enter when crossing a +! surface. !=============================================================================== type, extends(CellFilter) :: CellToFilter -! integer, allocatable :: cells(:) -! type(DictIntInt) :: map contains procedure :: to_statepoint_cell => to_statepoint_cell_to procedure :: text_label_cell => text_label_cell_to @@ -755,18 +752,28 @@ contains integer :: i, start - ! Particle can only have one cell_from - ! If current_bin is already a bin, then no need to look for another bin + ! Find the coordinate level of the last bin we found. + if (current_bin == NO_BIN_FOUND) then + start = 1 + else + do i = 1, p % last_n_coord + if (p % last_coord(i) % cell == this % cells(current_bin)) then + start = i + 1 + exit + end if + end do + end if + + ! Starting one coordinate level deeper, find the next bin. next_bin = NO_BIN_FOUND weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then - if (this % map % has_key(p % last_cell)) then - next_bin = this % map % get_key(p % last_cell) + do i = start, p % last_n_coord + if (this % map % has_key(p % last_coord(i) % cell)) then + next_bin = this % map % get_key(p % last_coord(i) % cell) weight = ONE + exit end if - else - next_bin = NO_BIN_FOUND - end if + end do end subroutine get_next_bin_cell_from @@ -777,7 +784,7 @@ contains integer :: i integer, allocatable :: cell_ids(:) - call write_dataset(filter_group, "type", "cell from") + call write_dataset(filter_group, "type", "cellfrom") call write_dataset(filter_group, "n_bins", this % n_bins) allocate(cell_ids(size(this % cells))) @@ -862,7 +869,7 @@ contains integer :: i integer, allocatable :: cell_ids(:) - call write_dataset(filter_group, "type", "cell to") + call write_dataset(filter_group, "type", "cellto") call write_dataset(filter_group, "n_bins", this % n_bins) allocate(cell_ids(size(this % cells))) diff --git a/src/tracking.F90 b/src/tracking.F90 index d8d0f8a7a..c05cdf54f 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -37,7 +37,6 @@ contains integer :: surface_crossed ! surface which particle is on integer :: lattice_translation(3) ! in-lattice translation vector integer :: last_cell ! most recent cell particle was in - integer :: last_n_coord ! most recent number of levels for last_cell integer :: n_event ! number of collisions/crossings real(8) :: d_boundary ! distance to nearest boundary real(8) :: d_collision ! sampled distance to collision @@ -152,6 +151,7 @@ contains ! Saving previous cell data last_cell = p % coord(p % n_coord) % cell +! p % set_last_coord() p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then @@ -163,9 +163,6 @@ contains ! Particle crosses surface p % surface = surface_crossed - ! Saving last cell for tallying purposes - p % last_cell = last_cell - ! Update last_ information. This is needed to use the same filters as ! the ones implemented for regular tallies p % last_uvw = p % coord(p % n_coord) % uvw @@ -173,10 +170,9 @@ contains call cross_surface(p, last_cell) p % event = EVENT_SURFACE - - ! Score cell to cell partial currents - call score_partial_current(p) end if + ! Score cell to cell partial currents + if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) else ! ==================================================================== ! PARTICLE HAS COLLISION From 7edc49bd2b366ff33213bef6f78c950528d6be15 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 08:41:37 -0400 Subject: [PATCH 015/229] deleted commented code in filter --- src/tally_filter.F90 | 80 -------------------------------------------- 1 file changed, 80 deletions(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index c4e72eba5..e19bd1bb4 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -794,28 +794,6 @@ contains call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cell_from - subroutine initialize_cell_from(this) - class(CellFromFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % cells(i) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - - ! Generate mapping from cell indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) - end do - end subroutine initialize_cell_from - function text_label_cell_from(this, bin) result(label) class(CellFromFilter), intent(in) :: this integer, intent(in) :: bin @@ -827,41 +805,6 @@ contains !=============================================================================== ! CellToFilter methods !=============================================================================== -! subroutine get_next_bin_cell_to(this, p, estimator, current_bin, & -! next_bin, weight) -! class(CellToFilter), intent(in) :: this -! type(Particle), intent(in) :: p -! integer, intent(in) :: estimator -! integer, value, intent(in) :: current_bin -! integer, intent(out) :: next_bin -! real(8), intent(out) :: weight -! -! integer :: i, start -! -! ! Find the coordinate level of the last bin we found. -! if (current_bin == NO_BIN_FOUND) then -! start = 1 -! else -! do i = 1, p % n_coord -! if (p % coord(i) % cell == this % cells(current_bin)) then -! start = i + 1 -! exit -! end if -! end do -! end if -! -! ! Starting one coordinate level deeper, find the next bin. -! next_bin = NO_BIN_FOUND -! weight = ERROR_REAL -! do i = start, p % n_coord -! if (this % map % has_key(p % coord(i) % cell)) then -! next_bin = this % map % get_key(p % coord(i) % cell) -! weight = ONE -! exit -! end if -! end do -! end subroutine get_next_bin_cell_to - subroutine to_statepoint_cell_to(this, filter_group) class(CellToFilter), intent(in) :: this integer(HID_T), intent(in) :: filter_group @@ -879,29 +822,6 @@ contains call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cell_to -! subroutine initialize_cell_to(this) -! class(CellToFilter), intent(inout) :: this -! -! integer :: i, id -! -! ! Convert ids to indices. -! do i = 1, this % n_bins -! id = this % cells(i) -! -! if (cell_dict % has_key(id)) then -! this % cells(i) = cell_dict % get_key(id) -! else -! call fatal_error("Could not find cell " // trim(to_str(id)) & -! &// " specified on tally filter.") -! end if -! end do -! -! ! Generate mapping from cell indices to filter bins. -! do i = 1, this % n_bins -! call this % map % add_key(this % cells(i), i) -! end do -! end subroutine initialize_cell_to - function text_label_cell_to(this, bin) result(label) class(CellToFilter), intent(in) :: this integer, intent(in) :: bin From a56bbcdbfbbd4ecee3c30a34ee9fefd6a73c9080 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 08:55:30 -0400 Subject: [PATCH 016/229] white spaces --- src/tally.F90 | 2 +- src/tracking.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index d0f504b4e..80a392c15 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3230,7 +3230,7 @@ contains ! determine scoring bin index, no offset from nuclide bins score_index = q - + ! Expand score if necessary and add to tally results. call expand_and_score(p, t, score_index, filter_index, score_bin, & score, q) diff --git a/src/tracking.F90 b/src/tracking.F90 index c05cdf54f..f70a9e115 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -172,7 +172,7 @@ contains p % event = EVENT_SURFACE end if ! Score cell to cell partial currents - if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) + if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) else ! ==================================================================== ! PARTICLE HAS COLLISION From 397d5c4ec8d85bf4b417729d419463fb111a9da0 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 09:22:43 -0400 Subject: [PATCH 017/229] forgot a call --- src/particle_header.F90 | 1 + src/tracking.F90 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/particle_header.F90 b/src/particle_header.F90 index 4f9aa2559..903b96bd4 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -231,6 +231,7 @@ contains !=============================================================================== subroutine set_last_coord(this) + class(Particle), intent(inout) :: this integer :: i diff --git a/src/tracking.F90 b/src/tracking.F90 index f70a9e115..2bb352acc 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -151,7 +151,7 @@ contains ! Saving previous cell data last_cell = p % coord(p % n_coord) % cell -! p % set_last_coord() + call p % set_last_coord() p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then From 0b20d11a377a3b2d92efe2b8be6c3973246b82aa Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 11:52:02 -0400 Subject: [PATCH 018/229] modified inheriting filter in tally filter --- src/tally_filter.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index e19bd1bb4..2ceb31284 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -77,9 +77,9 @@ module tally_filter !=============================================================================== type, extends(CellFilter) :: CellFromFilter contains - procedure :: get_next_bin_cell => get_next_bin_cell_from - procedure :: to_statepoint_cell => to_statepoint_cell_from - procedure :: text_label_cell => text_label_cell_from + procedure :: get_next_bin => get_next_bin_cell_from + procedure :: to_statepoint => to_statepoint_cell_from + procedure :: text_label => text_label_cell_from end type CellFromFilter !=============================================================================== @@ -88,8 +88,8 @@ module tally_filter !=============================================================================== type, extends(CellFilter) :: CellToFilter contains - procedure :: to_statepoint_cell => to_statepoint_cell_to - procedure :: text_label_cell => text_label_cell_to + procedure :: to_statepoint => to_statepoint_cell_to + procedure :: text_label => text_label_cell_to end type CellToFilter !=============================================================================== From 42d741b46389809f87f293c79db4e1cfaae7791d Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 15:04:04 -0400 Subject: [PATCH 019/229] small fix on whether to look for cell to cell tallies --- src/tracking.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracking.F90 b/src/tracking.F90 index 2bb352acc..7935eb3d4 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -172,7 +172,7 @@ contains p % event = EVENT_SURFACE end if ! Score cell to cell partial currents - if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) + if(active_cell_to_cell_tallies%size()>2) call score_partial_current(p) else ! ==================================================================== ! PARTICLE HAS COLLISION From 593cca09b3dc7a086fdf6a46b1277f8f15a9e10b Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 15:04:49 -0400 Subject: [PATCH 020/229] save previous data earlier --- src/tracking.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tracking.F90 b/src/tracking.F90 index 7935eb3d4..a34b5a28b 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -153,6 +153,11 @@ contains last_cell = p % coord(p % n_coord) % cell call p % set_last_coord() + ! Update last_ information. This is needed to use the same filters as + ! the ones implemented for regular tallies + p % last_uvw = p % coord(p % n_coord) % uvw + p % last_E = p % E + p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary @@ -163,11 +168,6 @@ contains ! Particle crosses surface p % surface = surface_crossed - ! Update last_ information. This is needed to use the same filters as - ! the ones implemented for regular tallies - p % last_uvw = p % coord(p % n_coord) % uvw - p % last_E = p % E - call cross_surface(p, last_cell) p % event = EVENT_SURFACE end if From 6ecc40676ee41e8f1b42bfbb1197b66315a5a381 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 20 Jun 2017 18:06:13 -0400 Subject: [PATCH 021/229] deleted action on cell_to_cell tallies in cmfd tally setup --- src/tally.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 80a392c15..3ac7e3165 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4616,7 +4616,6 @@ contains if (cmfd_tallies(i) % type == TALLY_VOLUME) then if (cmfd_tallies(i) % estimator == ESTIMATOR_ANALOG) then call active_analog_tallies % push_back(i_cmfd_tallies + i) - call active_cell_to_cell_tallies % push_back(i_cmfd_tallies + 1) elseif (cmfd_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then call active_tracklength_tallies % push_back(i_cmfd_tallies + i) end if @@ -4630,7 +4629,6 @@ contains call active_tracklength_tallies % shrink_to_fit() call active_collision_tallies % shrink_to_fit() call active_current_tallies % shrink_to_fit() - call active_cell_to_cell_tallies % shrink_to_fit() end subroutine setup_active_cmfdtallies From e61a04ee91cf9ac2c53d1ec0f7adafcc7d3eac56 Mon Sep 17 00:00:00 2001 From: Giud Date: Fri, 23 Jun 2017 19:55:28 -0400 Subject: [PATCH 022/229] Update tracking.F90 --- src/tracking.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracking.F90 b/src/tracking.F90 index a34b5a28b..13c05cff0 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -172,7 +172,7 @@ contains p % event = EVENT_SURFACE end if ! Score cell to cell partial currents - if(active_cell_to_cell_tallies%size()>2) call score_partial_current(p) + if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) else ! ==================================================================== ! PARTICLE HAS COLLISION From 345f84b42836ded0a0f9481e204505e643bc2ef2 Mon Sep 17 00:00:00 2001 From: guillaume Date: Mon, 26 Jun 2017 22:01:58 -0400 Subject: [PATCH 023/229] Implemented Paul Romano suggestions, changed score and tally names, used associate, and copied all coord to last%coord --- src/constants.F90 | 9 ++++----- src/endf.F90 | 2 -- src/global.F90 | 4 ++-- src/input_xml.F90 | 19 +++---------------- src/output.F90 | 2 +- src/particle_header.F90 | 25 +------------------------ src/tally.F90 | 27 ++++++++++++++------------- src/tally_filter.F90 | 38 -------------------------------------- src/tracking.F90 | 8 ++++---- 9 files changed, 29 insertions(+), 105 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index 4e9fe9865..5684e8c3b 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -289,7 +289,7 @@ module constants integer, parameter :: & TALLY_VOLUME = 1, & TALLY_SURFACE_CURRENT = 2, & - TALLY_CELL_TO_CELL = 3 + TALLY_SURFACE = 3 ! Tally estimator types integer, parameter :: & @@ -305,7 +305,7 @@ module constants EVENT_ABSORB = 2 ! Tally score type - integer, parameter :: N_SCORE_TYPES = 25 + integer, parameter :: N_SCORE_TYPES = 24 integer, parameter :: & SCORE_FLUX = -1, & ! flux SCORE_TOTAL = -2, & ! total reaction rate @@ -330,8 +330,7 @@ module constants SCORE_INVERSE_VELOCITY = -21, & ! flux-weighted inverse velocity SCORE_FISS_Q_PROMPT = -22, & ! prompt fission Q-value SCORE_FISS_Q_RECOV = -23, & ! recoverable fission Q-value - SCORE_DECAY_RATE = -24, & ! delayed neutron precursor decay rate - SCORE_CELL_TO_CELL = -25 ! cell to cell partial current + SCORE_DECAY_RATE = -24 ! delayed neutron precursor decay rate ! Maximum scattering order supported integer, parameter :: MAX_ANG_ORDER = 10 @@ -370,7 +369,7 @@ module constants FILTER_AZIMUTHAL = 12, & FILTER_DELAYEDGROUP = 13, & FILTER_ENERGYFUNCTION = 14, & - FILTER_CELL_TO_CELL = 15 + FILTER_CELLFROM = 15 ! Mesh types integer, parameter :: & diff --git a/src/endf.F90 b/src/endf.F90 index 7f3de44f5..0ba2db388 100644 --- a/src/endf.F90 +++ b/src/endf.F90 @@ -66,8 +66,6 @@ contains string = "fission-q-prompt" case (SCORE_FISS_Q_RECOV) string = "fission-q-recoverable" - case (SCORE_CELL_TO_CELL) - string = "cell-to-cell-partial-current" ! Normal ENDF-based reactions case (TOTAL_XS) diff --git a/src/global.F90 b/src/global.F90 index 8fefc11c6..e48480481 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -159,7 +159,7 @@ module global type(VectorInt) :: active_current_tallies type(VectorInt) :: active_collision_tallies type(VectorInt) :: active_tallies - type(VectorInt) :: active_cell_to_cell_tallies + type(VectorInt) :: active_surface_tallies ! Global tallies ! 1) collision estimate of k-eff @@ -518,7 +518,7 @@ contains call active_tracklength_tallies % clear() call active_current_tallies % clear() call active_collision_tallies % clear() - call active_cell_to_cell_tallies % clear() + call active_surface_tallies % clear() call active_tallies % clear() ! Deallocate track_identifiers diff --git a/src/input_xml.F90 b/src/input_xml.F90 index ab111dcc5..cef1bd865 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3047,17 +3047,6 @@ contains call get_node_array(node_filt, "bins", filt % cells) end select - case ('cellto') - ! Allocate and declare the filter type - allocate(CellToFilter :: f % obj) - select type (filt => f % obj) - type is (CellToFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % cells(n_words)) - call get_node_array(node_filt, "bins", filt % cells) - end select - case ('cellborn') ! Allocate and declare the filter type allocate(CellbornFilter :: f % obj) @@ -3415,9 +3404,7 @@ contains type is (CellFilter) t % find_filter(FILTER_CELL) = j type is (CellFromFilter) - t % find_filter(FILTER_CELL_TO_CELL) = j - type is (CellToFilter) - t % find_filter(FILTER_CELL_TO_CELL) = j + t % find_filter(FILTER_CELLFROM) = j type is (CellbornFilter) t % find_filter(FILTER_CELLBORN) = j type is (MaterialFilter) @@ -3921,8 +3908,8 @@ contains t % filter(n_filter) = i_filt case ('partial_current') - t % type = TALLY_CELL_TO_CELL - t % score_bins(j) = SCORE_CELL_TO_CELL + t % type = TALLY_SURFACE + t % score_bins(j) = SCORE_CURRENT case ('events') t % score_bins(j) = SCORE_EVENTS case ('elastic', '(n,elastic)') diff --git a/src/output.F90 b/src/output.F90 index bfd501407..a260cbe03 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -733,7 +733,7 @@ contains score_names(abs(SCORE_INVERSE_VELOCITY)) = "Flux-Weighted Inverse Velocity" score_names(abs(SCORE_FISS_Q_PROMPT)) = "Prompt fission power" score_names(abs(SCORE_FISS_Q_RECOV)) = "Recoverable fission power" - score_names(abs(SCORE_CELL_TO_CELL)) = "Partial current" + score_names(abs(SCORE_CURRENT)) = "Partial current" ! Create filename for tally output filename = trim(path_output) // "tallies.out" diff --git a/src/particle_header.F90 b/src/particle_header.F90 index 903b96bd4..7fcdf5668 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -32,7 +32,6 @@ module particle_header logical :: rotated = .false. contains procedure :: reset => reset_coord - procedure :: copy_coord end type LocalCoord !=============================================================================== @@ -236,11 +235,7 @@ contains integer :: i this % last_n_coord = this % n_coord - - ! copy all information at all coordinate levels - do i = 1, this % n_coord - call this % last_coord(i) % copy_coord(this % coord(i)) - end do + this % last_coord = this % coord ! reset the rest of former last_coord do i = this % n_coord + 1, MAX_COORD @@ -249,24 +244,6 @@ contains end subroutine set_last_coord -!=============================================================================== -! COPY_COORD copies one coordinate levels from coord to last_coord. -!=============================================================================== - - elemental subroutine copy_coord(this, coord) - class(LocalCoord), intent(inout) :: this - class(LocalCoord), intent(in) :: coord - - this % cell = coord % cell - this % universe = coord % universe - this % lattice = coord % lattice - this % lattice_x = coord % lattice_x - this % lattice_y = coord % lattice_y - this % lattice_z = coord % lattice_z - this % rotated = coord % rotated - - end subroutine copy_coord - !=============================================================================== ! CREATE_SECONDARY stores the current phase space attributes of the particle in ! the secondary bank and increments the number of sites in the secondary bank. diff --git a/src/tally.F90 b/src/tally.F90 index 3ac7e3165..29bf35b70 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3138,14 +3138,14 @@ contains end subroutine score_collision_tally !=============================================================================== -! score_partial_current tallies partial currents from cell_to to cell_from +! score_surface_tally is called at every surface crossing and can be used to +! tally partial currents between two cells !=============================================================================== - subroutine score_partial_current(p) + subroutine score_surface_tally(p) type(Particle), intent(in) :: p - !end if integer :: i integer :: i_tally integer :: i_filt @@ -3160,7 +3160,6 @@ contains real(8) :: filter_weight ! combined weight of all filters real(8) :: score ! analog tally score logical :: finished ! found all valid bin combinations - type(TallyObject), pointer :: t ! Determine collision estimate of flux if (survival_biasing) then @@ -3170,10 +3169,10 @@ contains flux = p % last_wgt end if - TALLY_LOOP: do i = 1, active_cell_to_cell_tallies % size() + TALLY_LOOP: do i = 1, active_surface_tallies % size() ! Get index of tally and pointer to tally - i_tally = active_cell_to_cell_tallies % data(i) - t => tallies(i_tally) + i_tally = active_surface_tallies % data(i) + associate (t => tallies(i_tally)) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. @@ -3233,7 +3232,7 @@ contains ! Expand score if necessary and add to tally results. call expand_and_score(p, t, score_index, filter_index, score_bin, & - score, q) + score, score_index) end do SCORE_LOOP ! ====================================================================== @@ -3260,6 +3259,8 @@ contains end do FILTER_LOOP + end associate + ! If the user has specified that we can assume all tallies are spatially ! separate, this implies that once a tally has been scored to, we needn't ! check the others. This cuts down on overhead when there are many @@ -3275,7 +3276,7 @@ contains ! Reset tally map positioning position = 0 - end subroutine score_partial_current + end subroutine score_surface_tally !=============================================================================== ! SCORE_SURFACE_CURRENT tallies surface crossings in a mesh tally by manually @@ -4568,8 +4569,8 @@ contains end if elseif (user_tallies(i) % type == TALLY_SURFACE_CURRENT) then call active_current_tallies % push_back(i_user_tallies + i) - elseif (user_tallies(i) % type == TALLY_CELL_TO_CELL) then - call active_cell_to_cell_tallies % push_back(i_user_tallies + i) + elseif (user_tallies(i) % type == TALLY_SURFACE) then + call active_surface_tallies % push_back(i_user_tallies + i) end if end do @@ -4579,7 +4580,7 @@ contains call active_tracklength_tallies % shrink_to_fit() call active_collision_tallies % shrink_to_fit() call active_current_tallies % shrink_to_fit() - call active_cell_to_cell_tallies % shrink_to_fit() + call active_surface_tallies % shrink_to_fit() end subroutine setup_active_usertallies @@ -4603,7 +4604,7 @@ contains else if (active_current_tallies % size() > 0) then call fatal_error("Active current tallies should not exist before CMFD & &tallies!") - else if (active_cell_to_cell_tallies % size() > 0) then + else if (active_surface_tallies % size() > 0) then call fatal_error("Active cell to cell tallies should not exist before & &CMFD tallies!") end if diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 2ceb31284..0e6518737 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -82,16 +82,6 @@ module tally_filter procedure :: text_label => text_label_cell_from end type CellFromFilter -!=============================================================================== -! CELLTOFILTER specifies which geometric cells particles enter when crossing a -! surface. -!=============================================================================== - type, extends(CellFilter) :: CellToFilter - contains - procedure :: to_statepoint => to_statepoint_cell_to - procedure :: text_label => text_label_cell_to - end type CellToFilter - !=============================================================================== ! DISTRIBCELLFILTER specifies which distributed geometric cells tally events ! reside in. @@ -802,34 +792,6 @@ contains label = "Cell from " // to_str(cells(this % cells(bin)) % id) end function text_label_cell_from -!=============================================================================== -! CellToFilter methods -!=============================================================================== - subroutine to_statepoint_cell_to(this, filter_group) - class(CellToFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: cell_ids(:) - - call write_dataset(filter_group, "type", "cellto") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(cell_ids(size(this % cells))) - do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id - end do - call write_dataset(filter_group, "bins", cell_ids) - end subroutine to_statepoint_cell_to - - function text_label_cell_to(this, bin) result(label) - class(CellToFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Cell to " // to_str(cells(this % cells(bin)) % id) - end function text_label_cell_to - !=============================================================================== ! DistribcellFilter methods !=============================================================================== diff --git a/src/tracking.F90 b/src/tracking.F90 index 13c05cff0..8e67843e8 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -15,7 +15,7 @@ module tracking use string, only: to_str use tally, only: score_analog_tally, score_tracklength_tally, & score_collision_tally, score_surface_current, & - score_track_derivative, score_partial_current, & + score_track_derivative, score_surface_tally, & score_collision_derivative, zero_flux_derivs use track_output, only: initialize_particle_track, write_particle_track, & add_particle_track, finalize_particle_track @@ -153,8 +153,8 @@ contains last_cell = p % coord(p % n_coord) % cell call p % set_last_coord() - ! Update last_ information. This is needed to use the same filters as - ! the ones implemented for regular tallies + ! Update last_ data. This is needed to use the same filters in + ! surface tallies as the ones implemented for regular tallies p % last_uvw = p % coord(p % n_coord) % uvw p % last_E = p % E @@ -172,7 +172,7 @@ contains p % event = EVENT_SURFACE end if ! Score cell to cell partial currents - if(active_cell_to_cell_tallies%size()>0) call score_partial_current(p) + if(active_surface_tallies % size() > 0) call score_surface_tally(p) else ! ==================================================================== ! PARTICLE HAS COLLISION From ca9fbb0c8fe6bbfd1fbe7f05ae8ac37b44d8293c Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 28 Jun 2017 18:58:28 -0400 Subject: [PATCH 024/229] changes for documentation in base.rst and tallies.rst --- docs/source/pythonapi/base.rst | 1 + docs/source/usersguide/tallies.rst | 10 ++++++++- openmc/filter.py | 36 +++--------------------------- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index dde1c9119..e6cf1e1cc 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -117,6 +117,7 @@ Constructing Tallies openmc.UniverseFilter openmc.MaterialFilter openmc.CellFilter + openmc.CellFromFilter openmc.CellbornFilter openmc.SurfaceFilter openmc.MeshFilter diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 3ee2e99d7..46ad97721 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -266,7 +266,15 @@ The following tables show all valid scores: | |particle. Note that this score can only be used if | | |a mesh filter has been specified. Furthermore, it | | |may not be used in conjunction with any other | - | |score. | + | |score. Only energy and mesh filters may be used. | + +----------------------+---------------------------------------------------+ + |partial_current |Partial currents on any surface previously defined | + | |in the geometry. Units are particles per source | + | |particle. Note that this score cannot be used with | + | |a current score or a surface or mesh filter. | + | |It may be used in conjunction with any other score.| + | |Surfaces can be defined with cell_from and cell | + | |(to) filters. | +----------------------+---------------------------------------------------+ |events |Number of scoring events. Units are events per | | |source particle. | diff --git a/openmc/filter.py b/openmc/filter.py index 9382c333b..e822b9553 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -603,13 +603,14 @@ class CellFilter(WithIDFilter): def bins(self, bins): self._smart_set_bins(bins, openmc.Cell) + class CellFromFilter(WithIDFilter): - """Bins tally on which couple of cells the neutrons came from. + """Bins tally on which Cell the neutron came from. Parameters ---------- bins : openmc.Cell, Integral, or iterable thereof - The Cells to tally. Either openmc.Cell objects or their + The Cell(s) to tally. Either openmc.Cell objects or their Integral ID numbers can be used. filter_id : int Unique identifier for the filter @@ -634,38 +635,7 @@ class CellFromFilter(WithIDFilter): @bins.setter def bins(self, bins): self._smart_set_bins(bins, openmc.Cell) - -class CellToFilter(WithIDFilter): - """Bins tally on which couple of cells the neutrons went to. - Parameters - ---------- - bins : openmc.Cell, Integral, or iterable thereof - The Cells to tally. Either openmc.Cell objects or their - Integral ID numbers can be used. - filter_id : int - Unique identifier for the filter - - Attributes - ---------- - bins : Integral or Iterable of Integral - openmc.Cell IDs. - id : int - Unique identifier for the filter - num_bins : Integral - The number of filter bins - stride : Integral - The number of filter, nuclide and score bins within each of this - filter's bins. - - """ - @property - def bins(self): - return self._bins - - @bins.setter - def bins(self, bins): - self._smart_set_bins(bins, openmc.Cell) class CellbornFilter(WithIDFilter): """Bins tally events based on which Cell the neutron was born in. From aba768d9fdc960305329d3101011395086b6b97d Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 28 Jun 2017 20:42:25 -0400 Subject: [PATCH 025/229] changes to documentation --- docs/source/io_formats/tallies.rst | 20 +++++++++++++++----- src/relaxng/tallies.rnc | 14 ++++++++------ src/relaxng/tallies.rng | 2 ++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 9c0a2515e..25f40c370 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -123,8 +123,8 @@ to the scored values. The ``filter`` element has the following attributes/sub-elements: :type: - The type of the filter. Accepted options are "cell", "cellborn", - "material", "universe", "energy", "energyout", "mu", "polar", + The type of the filter. Accepted options are "cell", "cellfrom", + "cellborn", "material", "universe", "energy", "energyout", "mu", "polar", "azimuthal", "mesh", "distribcell", "delayedgroup", and "energyfunction". @@ -154,14 +154,24 @@ For each filter type, the following table describes what the ``bins`` attribute should be set to: :cell: - A list of unique IDs for cells in which the tally should be accumulated. + A list of cells or unique IDs for cells in which the tally should be + accumulated. + +:cellfrom: + This filter allows the tally to be scored when crossing a surface and the + particle came from a specified cell. A list of cell or cell IDs should be + given. + To tally a partial current from a cell to another, this filter should be + used in combination with a cell filter. + This filter should not be used in combination with a surface or meshfilter. :cellborn: This filter allows the tally to be scored to only when particles were - originally born in a specified cell. A list of cell IDs should be given. + originally born in a specified cell. A list of cell or cell IDs should be + given. :material: - A list of unique IDs for matreials in which the tally should be accumulated. + A list of unique IDs for materials in which the tally should be accumulated. :universe: A list of unique IDs for universes in which the tally should be accumulated. diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc index 4674fd4c0..5ab8971e6 100644 --- a/src/relaxng/tallies.rnc +++ b/src/relaxng/tallies.rnc @@ -35,12 +35,14 @@ element tallies { element filter { (element id { xsd:int } | attribute id { xsd:int }) & ( - ( (element type { ( "cell" | "cellborn" | "material" | "universe" | - "surface" | "distribcell" | "mesh" | "energy" | "energyout" | "mu" | - "polar" | "azimuthal" | "delayedgroup" | "energyfunction") } | - attribute type { ( "cell" | "cellborn" | "material" | "universe" | - "surface" | "distribcell" | "mesh" | "energy" | "energyout" | "mu" | - "polar" | "azimuthal" | "delayedgroup" | "energyfunction") }) & + ( (element type { ( "cell" | "cellfrom" | "cellborn" | "material" | + "universe" | "surface" | "distribcell" | "mesh" | "energy" | + "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | + "energyfunction") } | + attribute type { ( "cell" | "cellfrom" | "cellborn" | "material" | + "universe" | "surface" | "distribcell" | "mesh" | "energy" | + "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | + "energyfunction") }) & (element bins { list { xsd:double+ } } | attribute bins { list { xsd:double+ } }) ) | diff --git a/src/relaxng/tallies.rng b/src/relaxng/tallies.rng index 1c68e57e8..bad2fdce9 100644 --- a/src/relaxng/tallies.rng +++ b/src/relaxng/tallies.rng @@ -168,6 +168,7 @@ cell + cellfrom cellborn material universe @@ -186,6 +187,7 @@ cell + cellfrom cellborn material universe From 6c247fe28408263cdab8ad33d9cec9ff41a5c0fe Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 28 Jun 2017 21:51:50 -0400 Subject: [PATCH 026/229] added test suite for surface tally, with partial currents both ways (fuel to water and water to fuel) and couple of filters relevant to crossing surfaces --- src/tally.F90 | 2 +- tests/test_surface_tally/geometry.xml | 11 ++++++ tests/test_surface_tally/materials.xml | 21 +++++++++++ tests/test_surface_tally/results_true.dat | 36 +++++++++++++++++++ tests/test_surface_tally/settings.xml | 12 +++++++ tests/test_surface_tally/tallies.xml | 34 ++++++++++++++++++ .../test_surface_tally/test_surface_tally.py | 11 ++++++ 7 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tests/test_surface_tally/geometry.xml create mode 100644 tests/test_surface_tally/materials.xml create mode 100644 tests/test_surface_tally/results_true.dat create mode 100644 tests/test_surface_tally/settings.xml create mode 100644 tests/test_surface_tally/tallies.xml create mode 100644 tests/test_surface_tally/test_surface_tally.py diff --git a/src/tally.F90 b/src/tally.F90 index 29bf35b70..3e96b9193 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3138,7 +3138,7 @@ contains end subroutine score_collision_tally !=============================================================================== -! score_surface_tally is called at every surface crossing and can be used to +! score_surface_tally is called at every surface crossing and can be used to ! tally partial currents between two cells !=============================================================================== diff --git a/tests/test_surface_tally/geometry.xml b/tests/test_surface_tally/geometry.xml new file mode 100644 index 000000000..26f4175c6 --- /dev/null +++ b/tests/test_surface_tally/geometry.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/test_surface_tally/materials.xml b/tests/test_surface_tally/materials.xml new file mode 100644 index 000000000..506f5f74a --- /dev/null +++ b/tests/test_surface_tally/materials.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat new file mode 100644 index 000000000..256619452 --- /dev/null +++ b/tests/test_surface_tally/results_true.dat @@ -0,0 +1,36 @@ +k-combined: +1.177844E+00 1.713522E-02 +tally 1: +9.400000E-01 +1.778300E-01 +2.561000E+00 +1.315759E+00 +8.618000E+00 +1.487929E+01 +2.559600E+01 +1.311144E+02 +4.700000E-02 +4.870000E-04 +1.010000E-01 +2.207000E-03 +3.780000E-01 +2.889000E-02 +1.089000E+00 +2.432570E-01 +tally 2: +9.070000E-01 +1.648450E-01 +2.495000E+00 +1.247251E+00 +8.515000E+00 +1.452994E+01 +2.539500E+01 +1.290580E+02 +3.800000E-02 +3.220000E-04 +8.400000E-02 +1.480000E-03 +3.540000E-01 +2.528400E-02 +9.770000E-01 +1.957910E-01 diff --git a/tests/test_surface_tally/settings.xml b/tests/test_surface_tally/settings.xml new file mode 100644 index 000000000..d97ee454a --- /dev/null +++ b/tests/test_surface_tally/settings.xml @@ -0,0 +1,12 @@ + + + eigenvalue + 1000 + 10 + 5 + + + -0.62992 -0.62992 -1 0.62992 0.62992 1 + + + diff --git a/tests/test_surface_tally/tallies.xml b/tests/test_surface_tally/tallies.xml new file mode 100644 index 000000000..1b6901634 --- /dev/null +++ b/tests/test_surface_tally/tallies.xml @@ -0,0 +1,34 @@ + + + + 10000 + + + 10001 + + + 0.0 4000000.0 20000000.0 + + + 0.0 0.785398163397 3.14159265359 + + + 0.0 0.785398163397 3.14159265359 + + + 10001 + + + 10000 + + + 10003 10004 10000 10001 10002 + partial_current + analog + + + 10005 10006 10000 10001 10002 + partial_current + analog + + diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py new file mode 100644 index 000000000..b04fcc6eb --- /dev/null +++ b/tests/test_surface_tally/test_surface_tally.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +import os +import sys +sys.path.insert(0, os.pardir) +from testing_harness import TestHarness + + +if __name__ == '__main__': + harness = TestHarness('statepoint.10.h5') + harness.main() From 9f0f001a688d9899f88e845a074eed7851b66e58 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 29 Jun 2017 18:03:35 -0400 Subject: [PATCH 027/229] enabling surface tallies in input --- src/input_xml.F90 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index cef1bd865..af759fd4e 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3081,7 +3081,6 @@ contains end select case ('surface') - call fatal_error("Surface filter is not yet supported!") ! Allocate and declare the filter type allocate(SurfaceFilter :: f % obj) select type (filt => f % obj) @@ -3442,13 +3441,6 @@ contains ! Store the filter indices call move_alloc(FROM=temp_filter, TO=t % filter) - ! Check that both cell and surface weren't specified - if (t % find_filter(FILTER_CELL) > 0 .and. & - t % find_filter(FILTER_SURFACE) > 0) then - call fatal_error("Cannot specify both cell and surface filters for & - &tally " // trim(to_str(t % id))) - end if - ! ======================================================================= ! READ DATA FOR NUCLIDES From 096d4551c7df5d8538028751b5db8f3781358d52 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 14:16:36 -0400 Subject: [PATCH 028/229] fixed survival biasing in score_surface_tally --- src/tally.F90 | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 3e96b9193..7c3ab7020 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3161,13 +3161,8 @@ contains real(8) :: score ! analog tally score logical :: finished ! found all valid bin combinations - ! Determine collision estimate of flux - if (survival_biasing) then - ! We need to account for the fact that some weight was already absorbed - flux = (p % last_wgt + p % absorb_wgt) - else - flux = p % last_wgt - end if + ! No collision, so no weight change when survival biasing + flux = p % wgt TALLY_LOOP: do i = 1, active_surface_tallies % size() ! Get index of tally and pointer to tally From db5b05b5d818a56b69fa7177c74cb8ae86e8f089 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 14:19:12 -0400 Subject: [PATCH 029/229] fixed pointer issue in calling expand and score from score_surface_tally --- src/tally.F90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tally.F90 b/src/tally.F90 index 7c3ab7020..a5c42e6ac 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3151,6 +3151,7 @@ contains integer :: i_filt integer :: i_bin integer :: q ! loop index for scoring bins + integer :: k ! working index for expand and score integer :: score_bin ! scoring bin, e.g. SCORE_FLUX integer :: score_index ! scoring bin index integer :: j ! loop index for scoring bins @@ -3217,7 +3218,9 @@ contains score = flux * filter_weight ! Currently only one score type + k = 0 SCORE_LOOP: do q = 1, t % n_user_score_bins + k = k + 1 ! determine what type of score bin score_bin = t % score_bins(q) @@ -3227,7 +3230,7 @@ contains ! Expand score if necessary and add to tally results. call expand_and_score(p, t, score_index, filter_index, score_bin, & - score, score_index) + score, k) end do SCORE_LOOP ! ====================================================================== From 81c2f51839704eaa8c912f659acbc09b5228d35a Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 16:37:31 -0400 Subject: [PATCH 030/229] changed from ABS to abs to debug travis? --- src/tally_filter.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 0e6518737..62f5afe0e 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -962,7 +962,7 @@ contains weight = ERROR_REAL if (current_bin == NO_BIN_FOUND) then do i = 1, this % n_bins - if (p % surface == this % surfaces(i)) then + if (abs(p % surface) == this % surfaces(i)) then next_bin = i weight = ONE exit From f7a85dda546a6813fedd15ccc1771611a9a218ec Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 19:38:53 -0400 Subject: [PATCH 031/229] Updated docs with surface tallies --- docs/source/io_formats/tallies.rst | 14 ++++++++++---- docs/source/usersguide/tallies.rst | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 25f40c370..93c58c348 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -124,8 +124,8 @@ attributes/sub-elements: :type: The type of the filter. Accepted options are "cell", "cellfrom", - "cellborn", "material", "universe", "energy", "energyout", "mu", "polar", - "azimuthal", "mesh", "distribcell", "delayedgroup", and + "cellborn", "surface", "material", "universe", "energy", "energyout", "mu", + "polar", "azimuthal", "mesh", "distribcell", "delayedgroup", and "energyfunction". :bins: @@ -157,13 +157,19 @@ should be set to: A list of cells or unique IDs for cells in which the tally should be accumulated. +:surface: + This filter allows the tally to be scored when crossing a surface. A list of + surface IDs should be given.It does not specify in which direction the + surface is crossed, and a cellfrom or a cell filter may be used to tally + partial currents. + :cellfrom: This filter allows the tally to be scored when crossing a surface and the particle came from a specified cell. A list of cell or cell IDs should be given. To tally a partial current from a cell to another, this filter should be - used in combination with a cell filter. - This filter should not be used in combination with a surface or meshfilter. + used in combination with a cell filter, to define the other cell. + This filter should not be used in combination with a meshfilter. :cellborn: This filter allows the tally to be scored to only when particles were diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 46ad97721..521735a83 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -271,10 +271,10 @@ The following tables show all valid scores: |partial_current |Partial currents on any surface previously defined | | |in the geometry. Units are particles per source | | |particle. Note that this score cannot be used with | - | |a current score or a surface or mesh filter. | + | |a current score or a mesh filter. | | |It may be used in conjunction with any other score.| | |Surfaces can be defined with cell_from and cell | - | |(to) filters. | + | |(to) filters or surface filters. | +----------------------+---------------------------------------------------+ |events |Number of scoring events. Units are events per | | |source particle. | From 06a99dde5e5a04413c3d53eca171bdf840492ebc Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 19:59:58 -0400 Subject: [PATCH 032/229] Changed score name from partial current to total current because of surface_filter behavior --- docs/source/io_formats/tallies.rst | 2 +- docs/source/usersguide/tallies.rst | 2 +- src/constants.F90 | 2 +- src/input_xml.F90 | 2 +- src/tally.F90 | 2 +- src/tally_filter.F90 | 3 +-- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 93c58c348..b0de8b6e6 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -159,7 +159,7 @@ should be set to: :surface: This filter allows the tally to be scored when crossing a surface. A list of - surface IDs should be given.It does not specify in which direction the + surface IDs should be given. It does not specify in which direction the surface is crossed, and a cellfrom or a cell filter may be used to tally partial currents. diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 521735a83..f92826384 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -268,7 +268,7 @@ The following tables show all valid scores: | |may not be used in conjunction with any other | | |score. Only energy and mesh filters may be used. | +----------------------+---------------------------------------------------+ - |partial_current |Partial currents on any surface previously defined | + |total-current |Total currents on any surface previously defined | | |in the geometry. Units are particles per source | | |particle. Note that this score cannot be used with | | |a current score or a mesh filter. | diff --git a/src/constants.F90 b/src/constants.F90 index 5684e8c3b..b2c34be04 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -319,7 +319,7 @@ module constants SCORE_FISSION = -10, & ! fission rate SCORE_NU_FISSION = -11, & ! neutron production rate SCORE_KAPPA_FISSION = -12, & ! fission energy production rate - SCORE_CURRENT = -13, & ! partial current + SCORE_CURRENT = -13, & ! current SCORE_FLUX_YN = -14, & ! angular moment of flux SCORE_TOTAL_YN = -15, & ! angular moment of total reaction rate SCORE_SCATTER_YN = -16, & ! angular flux-weighted scattering moment (0:N) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index af759fd4e..8b8367ca7 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3899,7 +3899,7 @@ contains t % find_filter(FILTER_SURFACE) = n_filter t % filter(n_filter) = i_filt - case ('partial_current') + case ('total-current') t % type = TALLY_SURFACE t % score_bins(j) = SCORE_CURRENT case ('events') diff --git a/src/tally.F90 b/src/tally.F90 index a5c42e6ac..2c0f7de06 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3139,7 +3139,7 @@ contains !=============================================================================== ! score_surface_tally is called at every surface crossing and can be used to -! tally partial currents between two cells +! tally total or partial currents between two cells !=============================================================================== subroutine score_surface_tally(p) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 62f5afe0e..6dc331001 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -109,8 +109,7 @@ module tally_filter end type CellbornFilter !=============================================================================== -! SURFACEFILTER is currently not implemented for usual geometric surfaces, but -! it is used as a placeholder for mesh surfaces used in current tallies. +! SURFACEFILTER specifies which surface particles are crossing !=============================================================================== type, extends(TallyFilter) :: SurfaceFilter integer, allocatable :: surfaces(:) From e4c5304f5597f18b8684896cd938cea85ffca55a Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 20:07:30 -0400 Subject: [PATCH 033/229] Added how to get partial currents in total current description --- docs/source/usersguide/tallies.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index f92826384..35b2ff9ac 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -272,9 +272,10 @@ The following tables show all valid scores: | |in the geometry. Units are particles per source | | |particle. Note that this score cannot be used with | | |a current score or a mesh filter. | - | |It may be used in conjunction with any other score.| + | |It may be used along with any other filter. | | |Surfaces can be defined with cell_from and cell | - | |(to) filters or surface filters. | + | |(to) filters or surface filters, partial currents | + | |can be obtained with cell_from and cell filters. | +----------------------+---------------------------------------------------+ |events |Number of scoring events. Units are events per | | |source particle. | From 15bbffc6781b14acaf686939a9ceaf4819382c4e Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 6 Jul 2017 20:27:58 -0400 Subject: [PATCH 034/229] Added surface_filter, standalone and with cell_from in test_surface_tally --- tests/test_surface_tally/geometry.xml | 16 +++---- tests/test_surface_tally/results_true.dat | 51 +++++++++++++++++++++++ tests/test_surface_tally/tallies.xml | 30 ++++++++++--- 3 files changed, 83 insertions(+), 14 deletions(-) diff --git a/tests/test_surface_tally/geometry.xml b/tests/test_surface_tally/geometry.xml index 26f4175c6..19eae6333 100644 --- a/tests/test_surface_tally/geometry.xml +++ b/tests/test_surface_tally/geometry.xml @@ -1,11 +1,11 @@ - - - - - - - - + + + + + + + + diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index 256619452..f9f473b19 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -18,6 +18,23 @@ tally 1: 1.089000E+00 2.432570E-01 tally 2: +9.400000E-01 +1.778300E-01 +2.561000E+00 +1.315759E+00 +8.618000E+00 +1.487929E+01 +2.559600E+01 +1.311144E+02 +4.700000E-02 +4.870000E-04 +1.010000E-01 +2.207000E-03 +3.780000E-01 +2.889000E-02 +1.089000E+00 +2.432570E-01 +tally 3: 9.070000E-01 1.648450E-01 2.495000E+00 @@ -34,3 +51,37 @@ tally 2: 2.528400E-02 9.770000E-01 1.957910E-01 +tally 4: +9.070000E-01 +1.648450E-01 +2.495000E+00 +1.247251E+00 +8.515000E+00 +1.452994E+01 +2.539500E+01 +1.290580E+02 +3.800000E-02 +3.220000E-04 +8.400000E-02 +1.480000E-03 +3.540000E-01 +2.528400E-02 +9.770000E-01 +1.957910E-01 +tally 5: +1.847000E+00 +6.843910E-01 +5.056000E+00 +5.124718E+00 +1.713300E+01 +5.881492E+01 +5.099100E+01 +5.203348E+02 +8.500000E-02 +1.595000E-03 +1.850000E-01 +7.259000E-03 +7.320000E-01 +1.080440E-01 +2.066000E+00 +8.753660E-01 diff --git a/tests/test_surface_tally/tallies.xml b/tests/test_surface_tally/tallies.xml index 1b6901634..fd76a84d2 100644 --- a/tests/test_surface_tally/tallies.xml +++ b/tests/test_surface_tally/tallies.xml @@ -15,20 +15,38 @@ 0.0 0.785398163397 3.14159265359 - + + 1 + + 10001 - + 10000 10003 10004 10000 10001 10002 - partial_current + total-current analog - - 10005 10006 10000 10001 10002 - partial_current + + 10003 10005 10000 10001 10002 + total-current + analog + + + 10006 10007 10000 10001 10002 + total-current + analog + + + 10006 10005 10000 10001 10002 + total-current + analog + + + 10005 10000 10001 10002 + total-current analog From f445f3db6dedff8024ab71654b8d664465722a2a Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 13 Jul 2017 22:59:17 -0400 Subject: [PATCH 035/229] correction on documentation --- docs/source/io_formats/tallies.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index b0de8b6e6..62075be93 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -154,18 +154,18 @@ For each filter type, the following table describes what the ``bins`` attribute should be set to: :cell: - A list of cells or unique IDs for cells in which the tally should be + A list of unique IDs for cells in which the tally should be accumulated. :surface: This filter allows the tally to be scored when crossing a surface. A list of - surface IDs should be given. It does not specify in which direction the - surface is crossed, and a cellfrom or a cell filter may be used to tally - partial currents. + surface IDs should be given. By default, net currents are tallied, and to + tally a partial current from one cell to another, this should be used in + combination with a cell or cell_from filter that defines the other cell. :cellfrom: This filter allows the tally to be scored when crossing a surface and the - particle came from a specified cell. A list of cell or cell IDs should be + particle came from a specified cell. A list of cell IDs should be given. To tally a partial current from a cell to another, this filter should be used in combination with a cell filter, to define the other cell. @@ -173,7 +173,7 @@ should be set to: :cellborn: This filter allows the tally to be scored to only when particles were - originally born in a specified cell. A list of cell or cell IDs should be + originally born in a specified cell. A list of cell IDs should be given. :material: From 53875b703424971c818606229599c11d28fa516f Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 13 Jul 2017 23:09:27 -0400 Subject: [PATCH 036/229] made surface tally default to net current, and changed tally_surface_current to tally_mesh_current --- src/constants.F90 | 4 ++-- src/input_xml.F90 | 2 +- src/tally.F90 | 4 ++-- src/tally_filter.F90 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index b2c34be04..73aca25d2 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -288,8 +288,8 @@ module constants ! Tally type integer, parameter :: & TALLY_VOLUME = 1, & - TALLY_SURFACE_CURRENT = 2, & - TALLY_SURFACE = 3 + TALLY_MESH_CURRENT = 2, & + TALLY_SURFACE = 3 ! Tally estimator types integer, parameter :: & diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 8b8367ca7..2bd6058b1 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3810,7 +3810,7 @@ contains t % score_bins(j) = SCORE_FISS_Q_RECOV case ('current') t % score_bins(j) = SCORE_CURRENT - t % type = TALLY_SURFACE_CURRENT + t % type = TALLY_MESH_CURRENT ! Check to make sure that current is the only desired response ! for this tally diff --git a/src/tally.F90 b/src/tally.F90 index 2c0f7de06..04af19f51 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4565,7 +4565,7 @@ contains elseif (user_tallies(i) % estimator == ESTIMATOR_COLLISION) then call active_collision_tallies % push_back(i_user_tallies + i) end if - elseif (user_tallies(i) % type == TALLY_SURFACE_CURRENT) then + elseif (user_tallies(i) % type == TALLY_MESH_CURRENT) then call active_current_tallies % push_back(i_user_tallies + i) elseif (user_tallies(i) % type == TALLY_SURFACE) then call active_surface_tallies % push_back(i_user_tallies + i) @@ -4618,7 +4618,7 @@ contains elseif (cmfd_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then call active_tracklength_tallies % push_back(i_cmfd_tallies + i) end if - elseif (cmfd_tallies(i) % type == TALLY_SURFACE_CURRENT) then + elseif (cmfd_tallies(i) % type == TALLY_MESH_CURRENT) then call active_current_tallies % push_back(i_cmfd_tallies + i) end if end do diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 6dc331001..0c97d9918 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -963,7 +963,7 @@ contains do i = 1, this % n_bins if (abs(p % surface) == this % surfaces(i)) then next_bin = i - weight = ONE + weight = sign(ONE, p % surface) exit end if end do From de803633fd7e81c17dcd853bea0a6ead402f14ef Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 13 Jul 2017 23:16:24 -0400 Subject: [PATCH 037/229] missed a few details on previous commit (function descriptions, some uses of tally_surface_current) --- src/cmfd_input.F90 | 6 +++--- src/output.F90 | 2 +- src/tally_filter.F90 | 2 +- src/trigger.F90 | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index d57c21beb..68cd94aa6 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -241,7 +241,7 @@ contains ! There are 3 tally types: ! 1: Only an energy in filter-> flux,total,p1 scatter ! 2: Energy in and energy out filter-> nu-scatter,nu-fission -! 3: Surface current +! 3: Mesh current !=============================================================================== subroutine create_cmfd_tally(root) @@ -425,7 +425,7 @@ contains end select end if - ! Duplicate the mesh filter for the surface current tally since other + ! Duplicate the mesh filter for the mesh current tally since other ! tallies use this filter and we need to change the dimension i_filt = i_filt + 1 allocate(MeshFilter :: filters(i_filt) % obj) @@ -597,7 +597,7 @@ contains ! Set macro bins t % score_bins(1) = SCORE_CURRENT - t % type = TALLY_SURFACE_CURRENT + t % type = TALLY_MESH_CURRENT end if end do diff --git a/src/output.F90 b/src/output.F90 index a260cbe03..c9eecd24c 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -792,7 +792,7 @@ contains end if ! Handle surface current tallies separately - if (t % type == TALLY_SURFACE_CURRENT) then + if (t % type == TALLY_MESH_CURRENT) then call write_surface_current(t, unit_tally) cycle end if diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 0c97d9918..906830611 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -963,7 +963,7 @@ contains do i = 1, this % n_bins if (abs(p % surface) == this % surfaces(i)) then next_bin = i - weight = sign(ONE, p % surface) + weight = sign(ONE, real(p % surface, 8)) exit end if end do diff --git a/src/trigger.F90 b/src/trigger.F90 index 9eb39e9cc..80bdd0e16 100644 --- a/src/trigger.F90 +++ b/src/trigger.F90 @@ -161,8 +161,8 @@ contains trigger % rel_err = ZERO trigger % variance = ZERO - ! Surface current tally triggers require special treatment - if (t % type == TALLY_SURFACE_CURRENT) then + ! Mesh current tally triggers require special treatment + if (t % type == TALLY_MESH_CURRENT) then call compute_tally_current(t, trigger) else @@ -281,7 +281,7 @@ contains !=============================================================================== -! COMPUTE_TALLY_CURRENT computes the current for a surface current tally with +! COMPUTE_TALLY_CURRENT computes the current for a mesh current tally with ! precision trigger(s). !=============================================================================== @@ -301,8 +301,8 @@ contains logical :: print_ebin ! should incoming energy bin be displayed? real(8) :: rel_err = ZERO ! temporary relative error of result real(8) :: std_dev = ZERO ! temporary standard deviration of result - type(TallyObject), pointer :: t ! surface current tally - type(TriggerObject) :: trigger ! surface current tally trigger + type(TallyObject), pointer :: t ! mesh current tally + type(TriggerObject) :: trigger ! mesh current tally trigger type(RegularMesh), pointer :: m ! surface current mesh ! Get pointer to mesh From 9fd8bd3fcf3c417f4dba83557e16139ba1a0d3c9 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 13 Jul 2017 23:19:06 -0400 Subject: [PATCH 038/229] better that way --- src/tally_filter.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 906830611..1e40c409f 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -963,7 +963,7 @@ contains do i = 1, this % n_bins if (abs(p % surface) == this % surfaces(i)) then next_bin = i - weight = sign(ONE, real(p % surface, 8)) + weight = sign(1, p % surface) exit end if end do From 4d6972f2720064e202075204f102bcf35410cfe9 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 00:17:22 -0400 Subject: [PATCH 039/229] only one score type for meshfilters and surface filters, updated docs, optimized last_cell data stored --- docs/source/io_formats/tallies.rst | 1 + docs/source/usersguide/tallies.rst | 28 ++--- src/geometry.F90 | 5 +- src/input_xml.F90 | 187 ++++++++++++++++------------- src/output.F90 | 2 +- src/particle_header.F90 | 26 +--- src/tally_filter.F90 | 6 +- src/tracking.F90 | 8 +- 8 files changed, 128 insertions(+), 135 deletions(-) diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 62075be93..35a205a35 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -162,6 +162,7 @@ should be set to: surface IDs should be given. By default, net currents are tallied, and to tally a partial current from one cell to another, this should be used in combination with a cell or cell_from filter that defines the other cell. + This filter should not be used in combination with a meshfilter. :cellfrom: This filter allows the tally to be scored when crossing a surface and the diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 35b2ff9ac..546dcabac 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -261,21 +261,19 @@ The following tables show all valid scores: +----------------------+---------------------------------------------------+ |Score | Description | +======================+===================================================+ - |current |Partial currents on the boundaries of each cell in | - | |a mesh. Units are particles per source | - | |particle. Note that this score can only be used if | - | |a mesh filter has been specified. Furthermore, it | - | |may not be used in conjunction with any other | - | |score. Only energy and mesh filters may be used. | - +----------------------+---------------------------------------------------+ - |total-current |Total currents on any surface previously defined | - | |in the geometry. Units are particles per source | - | |particle. Note that this score cannot be used with | - | |a current score or a mesh filter. | - | |It may be used along with any other filter. | - | |Surfaces can be defined with cell_from and cell | - | |(to) filters or surface filters, partial currents | - | |can be obtained with cell_from and cell filters. | + |current |Used in combination with a mesh filter: | + | |Partial currents on the boundaries of each cell in | + | |a mesh. It may not be used in conjunction with any | + | |other score. Only energy and mesh filters may be | + | |used. | + | |Used in combination with a surface filter: | + | |Net currents on any surface previously defined in | + | |the geometry. It may be used along with any other | + | |filter, except mesh filters. | + | |Surfaces can alternatively be defined with cell | + | |from and cell filters and partial currents can be | + | |obtained by using cell_from and cell filters. | + | |Units are particles per source particle. | +----------------------+---------------------------------------------------+ |events |Number of scoring events. Units are events per | | |source particle. | diff --git a/src/geometry.F90 b/src/geometry.F90 index f80bd7eb7..c451b6127 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -384,9 +384,8 @@ contains ! the geometry, is reflected, or crosses into a new lattice or cell !=============================================================================== - subroutine cross_surface(p, last_cell) + subroutine cross_surface(p) type(Particle), intent(inout) :: p - integer, intent(in) :: last_cell ! last cell particle was in real(8) :: u ! x-component of direction real(8) :: v ! y-component of direction @@ -469,7 +468,7 @@ contains p%coord(1)%uvw(:) = [u, v, w] / norm ! Reassign particle's cell and surface - p % coord(1) % cell = last_cell + p % coord(1) % cell = p % last_cell(p % last_n_coord) p % surface = -p % surface ! If a reflective surface is coincident with a lattice or universe diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 2bd6058b1..e0fa63e0d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3809,99 +3809,114 @@ contains case ('fission-q-recoverable') t % score_bins(j) = SCORE_FISS_Q_RECOV case ('current') - t % score_bins(j) = SCORE_CURRENT - t % type = TALLY_MESH_CURRENT - ! Check to make sure that current is the only desired response - ! for this tally - if (n_words > 1) then - call fatal_error("Cannot tally other scores in the & - &same tally as surface currents") - end if + ! Check which type of current is desired: mesh currents or + ! surface currents + if (t % find_filter(FILTER_SURFACE) > 0 .or. & + &t % find_filter(FILTER_CELL) > 0 .or. & + &t % find_filter(FILTER_CELLFROM) > 0) then - ! Get index of mesh filter - i_filter_mesh = t % filter(t % find_filter(FILTER_MESH)) - - ! Check to make sure mesh filter was specified - if (i_filter_mesh == 0) then - call fatal_error("Cannot tally surface current without a mesh & - &filter.") - end if - - ! Get pointer to mesh - select type(filt => filters(i_filter_mesh) % obj) - type is (MeshFilter) - i_mesh = filt % mesh - m => meshes(i_mesh) - end select - - ! Copy filter indices to temporary array - allocate(temp_filter(size(t % filter) + 1)) - temp_filter(1:size(t % filter)) = t % filter - - ! Move allocation back -- temp_filter becomes deallocated during - ! this call - call move_alloc(FROM=temp_filter, TO=t % filter) - n_filter = size(t % filter) - - ! Extend the filters array so we can add a surface filter and mesh - ! filter - call add_filters(2) - - ! Increment number of user filters - n_user_filters = n_user_filters + 2 - - ! Get index of the new mesh filter - i_filt = n_user_filters - 1 - - ! Duplicate the mesh filter since other tallies might use this - ! filter and we need to change the dimension - allocate(MeshFilter :: filters(i_filt) % obj) - select type(filt => filters(i_filt) % obj) - type is (MeshFilter) - filt % id = i_filt - filt % mesh = i_mesh - - ! We need to increase the dimension by one since we also need - ! currents coming into and out of the boundary mesh cells. - filt % n_bins = product(m % dimension + 1) - - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select - t % filter(t % find_filter(FILTER_MESH)) = i_filt - - ! Get index of the new surface filter - i_filt = n_user_filters - - ! Add surface filter - allocate(SurfaceFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) - type is (SurfaceFilter) - filt % id = i_filt - filt % n_bins = 4 * m % n_dimension - allocate(filt % surfaces(4 * m % n_dimension)) - if (m % n_dimension == 1) then - filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT /) - elseif (m % n_dimension == 2) then - filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT, & - OUT_BACK, IN_BACK, OUT_FRONT, IN_FRONT /) - elseif (m % n_dimension == 3) then - filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT, & - OUT_BACK, IN_BACK, OUT_FRONT, IN_FRONT, OUT_BOTTOM, & - IN_BOTTOM, OUT_TOP, IN_TOP /) + ! Check to make sure that mesh currents are not desired as well + if (t % find_filter(FILTER_MESH) > 0) then + call fatal_error("Cannot tally other mesh currents & + &in the same tally as surface currents") end if - filt % current = .true. + + t % type = TALLY_SURFACE + t % score_bins(j) = SCORE_CURRENT + + else if (t % find_filter(FILTER_MESH) > 0) then + t % score_bins(j) = SCORE_CURRENT + t % type = TALLY_MESH_CURRENT + + ! Check to make sure that current is the only desired response + ! for this tally + if (n_words > 1) then + call fatal_error("Cannot tally other scores in the & + &same tally as surface currents") + end if + + ! Get index of mesh filter + i_filter_mesh = t % filter(t % find_filter(FILTER_MESH)) + + ! Check to make sure mesh filter was specified + if (i_filter_mesh == 0) then + call fatal_error("Cannot tally surface current without a mesh & + &filter.") + end if + + ! Get pointer to mesh + select type(filt => filters(i_filter_mesh) % obj) + type is (MeshFilter) + i_mesh = filt % mesh + m => meshes(i_mesh) + end select + + ! Copy filter indices to temporary array + allocate(temp_filter(size(t % filter) + 1)) + temp_filter(1:size(t % filter)) = t % filter + + ! Move allocation back -- temp_filter becomes deallocated during + ! this call + call move_alloc(FROM=temp_filter, TO=t % filter) + n_filter = size(t % filter) + + ! Extend the filters array so we can add a surface filter and + ! mesh filter + call add_filters(2) + + ! Increment number of user filters + n_user_filters = n_user_filters + 2 + + ! Get index of the new mesh filter + i_filt = n_user_filters - 1 + + ! Duplicate the mesh filter since other tallies might use this + ! filter and we need to change the dimension + allocate(MeshFilter :: filters(i_filt) % obj) + select type(filt => filters(i_filt) % obj) + type is (MeshFilter) + filt % id = i_filt + filt % mesh = i_mesh + + ! We need to increase the dimension by one since we also need + ! currents coming into and out of the boundary mesh cells. + filt % n_bins = product(m % dimension + 1) ! Add filter to dictionary call filter_dict % add_key(filt % id, i_filt) - end select - t % find_filter(FILTER_SURFACE) = n_filter - t % filter(n_filter) = i_filt + end select + t % filter(t % find_filter(FILTER_MESH)) = i_filt + + ! Get index of the new surface filter + i_filt = n_user_filters + + ! Add surface filter + allocate(SurfaceFilter :: filters(i_filt) % obj) + select type (filt => filters(i_filt) % obj) + type is (SurfaceFilter) + filt % id = i_filt + filt % n_bins = 4 * m % n_dimension + allocate(filt % surfaces(4 * m % n_dimension)) + if (m % n_dimension == 1) then + filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT /) + elseif (m % n_dimension == 2) then + filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT, & + OUT_BACK, IN_BACK, OUT_FRONT, IN_FRONT /) + elseif (m % n_dimension == 3) then + filt % surfaces = (/ OUT_LEFT, IN_LEFT, OUT_RIGHT, IN_RIGHT, & + OUT_BACK, IN_BACK, OUT_FRONT, IN_FRONT, OUT_BOTTOM, & + IN_BOTTOM, OUT_TOP, IN_TOP /) + end if + filt % current = .true. + + ! Add filter to dictionary + call filter_dict % add_key(filt % id, i_filt) + end select + t % find_filter(FILTER_SURFACE) = n_filter + t % filter(n_filter) = i_filt + end if - case ('total-current') - t % type = TALLY_SURFACE - t % score_bins(j) = SCORE_CURRENT case ('events') t % score_bins(j) = SCORE_EVENTS case ('elastic', '(n,elastic)') diff --git a/src/output.F90 b/src/output.F90 index c9eecd24c..ade1a5c05 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -733,7 +733,7 @@ contains score_names(abs(SCORE_INVERSE_VELOCITY)) = "Flux-Weighted Inverse Velocity" score_names(abs(SCORE_FISS_Q_PROMPT)) = "Prompt fission power" score_names(abs(SCORE_FISS_Q_RECOV)) = "Recoverable fission power" - score_names(abs(SCORE_CURRENT)) = "Partial current" + score_names(abs(SCORE_CURRENT)) = "Current" ! Create filename for tally output filename = trim(path_output) // "tallies.out" diff --git a/src/particle_header.F90 b/src/particle_header.F90 index 7fcdf5668..76876f021 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -49,8 +49,8 @@ module particle_header type(LocalCoord) :: coord(MAX_COORD) ! coordinates for all levels ! Particle coordinates before crossing a surface - integer :: last_n_coord ! number of current coordinates - type(LocalCoord) :: last_coord(MAX_COORD) ! coordinates for all levels + integer :: last_n_coord ! number of current coordinates + integer :: last_cell(MAX_COORD) ! coordinates for all levels ! Energy Data real(8) :: E ! post-collision energy @@ -110,7 +110,6 @@ module particle_header procedure :: clear => clear_particle procedure :: initialize_from_source procedure :: create_secondary - procedure :: set_last_coord end type Particle contains @@ -152,7 +151,6 @@ contains ! Set up base level coordinates this % coord(1) % universe = root_universe this % n_coord = 1 - this % last_coord(1) % universe = root_universe this % last_n_coord = 1 end subroutine initialize_particle @@ -224,26 +222,6 @@ contains end subroutine initialize_from_source -!=============================================================================== -! SET_LAST_COORD copies all coordinate levels from coord to last_coord. This is -! meant to have information about the last cell in the cell_from filter -!=============================================================================== - - subroutine set_last_coord(this) - - class(Particle), intent(inout) :: this - integer :: i - - this % last_n_coord = this % n_coord - this % last_coord = this % coord - - ! reset the rest of former last_coord - do i = this % n_coord + 1, MAX_COORD - call this % last_coord(i) % reset() - end do - - end subroutine set_last_coord - !=============================================================================== ! CREATE_SECONDARY stores the current phase space attributes of the particle in ! the secondary bank and increments the number of sites in the secondary bank. diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 1e40c409f..908b6f1a6 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -746,7 +746,7 @@ contains start = 1 else do i = 1, p % last_n_coord - if (p % last_coord(i) % cell == this % cells(current_bin)) then + if (p % last_cell(i) == this % cells(current_bin)) then start = i + 1 exit end if @@ -757,8 +757,8 @@ contains next_bin = NO_BIN_FOUND weight = ERROR_REAL do i = start, p % last_n_coord - if (this % map % has_key(p % last_coord(i) % cell)) then - next_bin = this % map % get_key(p % last_coord(i) % cell) + if (this % map % has_key(p % last_cell(i))) then + next_bin = this % map % get_key(p % last_cell(i)) weight = ONE exit end if diff --git a/src/tracking.F90 b/src/tracking.F90 index 8e67843e8..042e63c27 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -150,8 +150,10 @@ contains if (next_level > 0) p % n_coord = next_level ! Saving previous cell data - last_cell = p % coord(p % n_coord) % cell - call p % set_last_coord() + do j = 1, p % n_coord + p % last_cell(j) = p % coord(j) % cell + end do + p % last_n_coord = p % n_coord ! Update last_ data. This is needed to use the same filters in ! surface tallies as the ones implemented for regular tallies @@ -168,7 +170,7 @@ contains ! Particle crosses surface p % surface = surface_crossed - call cross_surface(p, last_cell) + call cross_surface(p) p % event = EVENT_SURFACE end if ! Score cell to cell partial currents From 68ad95ac95b18319eccd434e989161a06381b40d Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 14:22:16 -0400 Subject: [PATCH 040/229] doc change --- docs/source/usersguide/tallies.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index 546dcabac..3a742b59e 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -271,8 +271,8 @@ The following tables show all valid scores: | |the geometry. It may be used along with any other | | |filter, except mesh filters. | | |Surfaces can alternatively be defined with cell | - | |from and cell filters and partial currents can be | - | |obtained by using cell_from and cell filters. | + | |from and cell filters thereby resulting in tallying| + | |partial currents. | | |Units are particles per source particle. | +----------------------+---------------------------------------------------+ |events |Number of scoring events. Units are events per | From 5ac313260ca39ce0b300bc779907f64f8fc49f0a Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 15:01:08 -0400 Subject: [PATCH 041/229] changed test to PythonAPItestharness and added tests on surface filter behavior at boundaries --- src/tracking.F90 | 1 - .../test_surface_tally/test_surface_tally.py | 156 +++++++++++++++++- 2 files changed, 154 insertions(+), 3 deletions(-) diff --git a/src/tracking.F90 b/src/tracking.F90 index 042e63c27..546ae3880 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -36,7 +36,6 @@ contains integer :: next_level ! next coordinate level to check integer :: surface_crossed ! surface which particle is on integer :: lattice_translation(3) ! in-lattice translation vector - integer :: last_cell ! most recent cell particle was in integer :: n_event ! number of collisions/crossings real(8) :: d_boundary ! distance to nearest boundary real(8) :: d_collision ! sampled distance to collision diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index b04fcc6eb..d4d1c8aaa 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -3,9 +3,161 @@ import os import sys sys.path.insert(0, os.pardir) -from testing_harness import TestHarness +from testing_harness import PyAPITestHarness +import openmc + + +class CreateSurfaceTallyTestHarness(PyAPITestHarness): + def _build_inputs(self): + # Instantiate some Materials and register the appropriate Nuclides + uo2 = openmc.Material(name='UO2 fuel at 2.4% wt enrichment') + uo2.set_density('g/cm3', 10.29769) + uo2.add_element('U', 1., enrichment=2.4) + uo2.add_element('O', 2.) + + borated_water = openmc.Material(name='Borated water') + borated_water.set_density('g/cm3', 0.740582) + borated_water.add_element('B', 4.0e-5) + borated_water.add_element('H', 5.0e-2) + borated_water.add_element('O', 2.4e-2) + borated_water.add_s_alpha_beta('c_H_in_H2O') + + # Instantiate a Materials collection and export to XML + materials_file = openmc.Materials([uo2, borated_water]) + + materials_file.export_to_xml() + + # Instantiate ZCylinder surfaces + fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.4, name='Fuel OR') + left = openmc.XPlane(surface_id=2, x0=-0.62992, name='left') + right = openmc.XPlane(x0=0.62992, name='right') + bottom = openmc.YPlane(y0=-0.62992, name='bottom') + top = openmc.YPlane(y0=0.62992, name='top') + + left.boundary_type = 'vacuum' + right.boundary_type = 'reflective' + top.boundary_type = 'reflective' + bottom.boundary_type = 'reflective' + + # Instantiate Cells + fuel = openmc.Cell(name='fuel') + water = openmc.Cell(name='water') + + # Use surface half-spaces to define regions + fuel.region = -fuel_or + water.region = +fuel_or & -right & +bottom & -top + + # Register Materials with Cells + fuel.fill = uo2 + water.fill = borated_water + + # Instantiate pin cell Universe + pin_cell = openmc.Universe(name='pin cell') + pin_cell.add_cells([fuel, water]) + + # Instantiate root Cell and Universe + root_cell = openmc.Cell(name='root cell') + root_cell.region = +left & -right & +bottom & -top + root_cell.fill = pin_cell + root_univ = openmc.Universe(universe_id=0, name='root universe') + root_univ.add_cell(root_cell) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry = openmc.Geometry(root_univ) + geometry.export_to_xml() + + # Instantiate a Settings object, set all runtime parameters, and export to XML + settings_file = openmc.Settings() + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Create an initial uniform spatial source distribution over fissionable zones + bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) + settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.export_to_xml() + + # Tallies file + tallies_file = openmc.Tallies() + + # Cell to cell tallies + # These filters are same for all tallies + energy_filter = openmc.EnergyFilter(two_groups) + polar_filter = openmc.PolarFilter([0, np.pi / 4, np.pi]) + azimuthal_filter = openmc.AzimuthalFilter([0, np.pi / 4, np.pi]) + + + cell_to_cell_tallies = [] + tally_index = 0 + + for cell1 in pin_cell.get_all_cells(): + for cell2 in pin_cell.get_all_cells(): + + if cell1 != cell2 and abs(abs(cell1-cell2)-1) < 0.1: # no need for cell1 to cell1 + + # Cell to cell filters for partial current + cell_from_filter = openmc.CellFromFilter(cell1) + cell_to_filter = openmc.CellFilter(cell2) + + cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name=str(cell1)+'-'+str(cell2))) + cell_to_cell_tallies[2*tally_index].filters = [cell_from_filter, cell_to_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[2*tally_index].scores = ['current'] + cell_to_cell_tallies[2*tally_index].estimator = 'analog' + + tallies_file.append(cell_to_cell_tallies[2*tally_index]) + + # Cell from + surface filters for partial current + surface_filter = openmc.SurfaceFilter([1]) + cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index+1, name=str(cell1)+'-surface1')) + cell_to_cell_tallies[2*tally_index+1].filters = [cell_from_filter, surface_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[2*tally_index+1].scores = ['current'] + cell_to_cell_tallies[2*tally_index+1].estimator = 'analog' + tallies_file.append(cell_to_cell_tallies[2*tally_index+1]) + + tally_index += 1 + + # Surface filter on inner surface, for net current + surface_filter = openmc.SurfaceFilter([1]) + cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) + cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[2*tally_index].scores = ['current'] + cell_to_cell_tallies[2*tally_index].estimator = 'analog' + tallies_file.append(cell_to_cell_tallies[2*tally_index]) + + # Surface filter on left surface, vacuum BC, for net current = leakage + surface_filter = openmc.SurfaceFilter([1]) + cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) + cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[2*tally_index].scores = ['current'] + cell_to_cell_tallies[2*tally_index].estimator = 'analog' + tallies_file.append(cell_to_cell_tallies[2*tally_index]) + + # Surface filter on right surface, reflective, for net current = 0 + surface_filter = openmc.SurfaceFilter([1]) + cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) + cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[2*tally_index].scores = ['current'] + cell_to_cell_tallies[2*tally_index].estimator = 'analog' + tallies_file.append(cell_to_cell_tallies[2*tally_index]) + + tallies_file.export_to_xml() + + def _get_results(self): + """Digest info in the statepoint and return as a string.""" + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # Write out tally data. + outstr = '' + t = sp.get_tally() + outstr += 'tally {}:\n'.format(t.id) + outstr += 'sum = {:12.6E}\n'.format(t.sum[0, 0, 0]) + outstr += 'sum_sq = {:12.6E}\n'.format(t.sum_sq[0, 0, 0]) + + return outstr if __name__ == '__main__': - harness = TestHarness('statepoint.10.h5') + harness = CreateSurfaceTallyTestHarness('statepoint.10.h5') harness.main() From 87a1139f6232cc7521991c7f59e6cf69b5c85eb7 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 15:13:27 -0400 Subject: [PATCH 042/229] cleaned up test and generated results --- tests/test_surface_tally/geometry.xml | 11 --- tests/test_surface_tally/materials.xml | 21 ----- tests/test_surface_tally/results_true.dat | 90 +------------------ tests/test_surface_tally/settings.xml | 12 --- tests/test_surface_tally/tallies.xml | 52 ----------- .../test_surface_tally/test_surface_tally.py | 59 ++++++------ 6 files changed, 32 insertions(+), 213 deletions(-) delete mode 100644 tests/test_surface_tally/geometry.xml delete mode 100644 tests/test_surface_tally/materials.xml delete mode 100644 tests/test_surface_tally/settings.xml delete mode 100644 tests/test_surface_tally/tallies.xml diff --git a/tests/test_surface_tally/geometry.xml b/tests/test_surface_tally/geometry.xml deleted file mode 100644 index 19eae6333..000000000 --- a/tests/test_surface_tally/geometry.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/tests/test_surface_tally/materials.xml b/tests/test_surface_tally/materials.xml deleted file mode 100644 index 506f5f74a..000000000 --- a/tests/test_surface_tally/materials.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index f9f473b19..e47a0635c 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -1,87 +1,3 @@ -k-combined: -1.177844E+00 1.713522E-02 -tally 1: -9.400000E-01 -1.778300E-01 -2.561000E+00 -1.315759E+00 -8.618000E+00 -1.487929E+01 -2.559600E+01 -1.311144E+02 -4.700000E-02 -4.870000E-04 -1.010000E-01 -2.207000E-03 -3.780000E-01 -2.889000E-02 -1.089000E+00 -2.432570E-01 -tally 2: -9.400000E-01 -1.778300E-01 -2.561000E+00 -1.315759E+00 -8.618000E+00 -1.487929E+01 -2.559600E+01 -1.311144E+02 -4.700000E-02 -4.870000E-04 -1.010000E-01 -2.207000E-03 -3.780000E-01 -2.889000E-02 -1.089000E+00 -2.432570E-01 -tally 3: -9.070000E-01 -1.648450E-01 -2.495000E+00 -1.247251E+00 -8.515000E+00 -1.452994E+01 -2.539500E+01 -1.290580E+02 -3.800000E-02 -3.220000E-04 -8.400000E-02 -1.480000E-03 -3.540000E-01 -2.528400E-02 -9.770000E-01 -1.957910E-01 -tally 4: -9.070000E-01 -1.648450E-01 -2.495000E+00 -1.247251E+00 -8.515000E+00 -1.452994E+01 -2.539500E+01 -1.290580E+02 -3.800000E-02 -3.220000E-04 -8.400000E-02 -1.480000E-03 -3.540000E-01 -2.528400E-02 -9.770000E-01 -1.957910E-01 -tally 5: -1.847000E+00 -6.843910E-01 -5.056000E+00 -5.124718E+00 -1.713300E+01 -5.881492E+01 -5.099100E+01 -5.203348E+02 -8.500000E-02 -1.595000E-03 -1.850000E-01 -7.259000E-03 -7.320000E-01 -1.080440E-01 -2.066000E+00 -8.753660E-01 +tally 0: +sum = 8.800000E-02 +sum_sq = 1.582000E-03 diff --git a/tests/test_surface_tally/settings.xml b/tests/test_surface_tally/settings.xml deleted file mode 100644 index d97ee454a..000000000 --- a/tests/test_surface_tally/settings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - eigenvalue - 1000 - 10 - 5 - - - -0.62992 -0.62992 -1 0.62992 0.62992 1 - - - diff --git a/tests/test_surface_tally/tallies.xml b/tests/test_surface_tally/tallies.xml deleted file mode 100644 index fd76a84d2..000000000 --- a/tests/test_surface_tally/tallies.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - 10000 - - - 10001 - - - 0.0 4000000.0 20000000.0 - - - 0.0 0.785398163397 3.14159265359 - - - 0.0 0.785398163397 3.14159265359 - - - 1 - - - 10001 - - - 10000 - - - 10003 10004 10000 10001 10002 - total-current - analog - - - 10003 10005 10000 10001 10002 - total-current - analog - - - 10006 10007 10000 10001 10002 - total-current - analog - - - 10006 10005 10000 10001 10002 - total-current - analog - - - 10005 10000 10001 10002 - total-current - analog - - diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index d4d1c8aaa..31850462c 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -4,6 +4,7 @@ import os import sys sys.path.insert(0, os.pardir) from testing_harness import PyAPITestHarness +import numpy as np import openmc @@ -30,7 +31,7 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Instantiate ZCylinder surfaces fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.4, name='Fuel OR') left = openmc.XPlane(surface_id=2, x0=-0.62992, name='left') - right = openmc.XPlane(x0=0.62992, name='right') + right = openmc.XPlane(surface_id=3, x0=0.62992, name='right') bottom = openmc.YPlane(y0=-0.62992, name='bottom') top = openmc.YPlane(y0=0.62992, name='top') @@ -83,6 +84,7 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Cell to cell tallies # These filters are same for all tallies + two_groups = np.array([0., 4, 20.]) * 1e6 energy_filter = openmc.EnergyFilter(two_groups) polar_filter = openmc.PolarFilter([0, np.pi / 4, np.pi]) azimuthal_filter = openmc.AzimuthalFilter([0, np.pi / 4, np.pi]) @@ -100,46 +102,43 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): cell_from_filter = openmc.CellFromFilter(cell1) cell_to_filter = openmc.CellFilter(cell2) - cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name=str(cell1)+'-'+str(cell2))) - cell_to_cell_tallies[2*tally_index].filters = [cell_from_filter, cell_to_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[2*tally_index].scores = ['current'] - cell_to_cell_tallies[2*tally_index].estimator = 'analog' - - tallies_file.append(cell_to_cell_tallies[2*tally_index]) + cell_to_cell_tallies.append(openmc.Tally(tally_id=tally_index, name=str(cell1)+'-'+str(cell2))) + cell_to_cell_tallies[tally_index].filters = [cell_from_filter, cell_to_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[tally_index].scores = ['current'] + tallies_file.append(cell_to_cell_tallies[tally_index]) + tally_index += 1 # Cell from + surface filters for partial current surface_filter = openmc.SurfaceFilter([1]) - cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index+1, name=str(cell1)+'-surface1')) - cell_to_cell_tallies[2*tally_index+1].filters = [cell_from_filter, surface_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[2*tally_index+1].scores = ['current'] - cell_to_cell_tallies[2*tally_index+1].estimator = 'analog' - tallies_file.append(cell_to_cell_tallies[2*tally_index+1]) - + cell_to_cell_tallies.append(openmc.Tally(tally_id=tally_index, name=str(cell1)+'-surface1')) + cell_to_cell_tallies[tally_index].filters = [cell_from_filter, surface_filter, energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tallies[tally_index].scores = ['current'] + tallies_file.append(cell_to_cell_tallies[tally_index]) tally_index += 1 # Surface filter on inner surface, for net current surface_filter = openmc.SurfaceFilter([1]) - cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) - cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[2*tally_index].scores = ['current'] - cell_to_cell_tallies[2*tally_index].estimator = 'analog' - tallies_file.append(cell_to_cell_tallies[2*tally_index]) + surf_tally1 = openmc.Tally(tally_id=tally_index, name='net_cylinder') + surf_tally1.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + surf_tally1.scores = ['current'] + tallies_file.append(surf_tally1) + tally_index += 1 # Surface filter on left surface, vacuum BC, for net current = leakage - surface_filter = openmc.SurfaceFilter([1]) - cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) - cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[2*tally_index].scores = ['current'] - cell_to_cell_tallies[2*tally_index].estimator = 'analog' - tallies_file.append(cell_to_cell_tallies[2*tally_index]) + surface_filter = openmc.SurfaceFilter([2]) + surf_tally2 = openmc.Tally(tally_id=tally_index, name='leakage_left') + surf_tally2.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + surf_tally2.scores = ['current'] + tallies_file.append(surf_tally2) + tally_index += 1 # Surface filter on right surface, reflective, for net current = 0 - surface_filter = openmc.SurfaceFilter([1]) - cell_to_cell_tallies.append(openmc.Tally(tally_id=2*tally_index, name='surface1')) - cell_to_cell_tallies[2*tally_index].filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[2*tally_index].scores = ['current'] - cell_to_cell_tallies[2*tally_index].estimator = 'analog' - tallies_file.append(cell_to_cell_tallies[2*tally_index]) + surface_filter = openmc.SurfaceFilter([3]) + surf_tally3 = openmc.Tally(tally_id=tally_index, name='net_right') + surf_tally3.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + surf_tally3.scores = ['current'] + tallies_file.append(surf_tally3) + tally_index += 1 tallies_file.export_to_xml() From 7a2ce111c6a580d3f1b2ba46732e611a4d885a91 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 15:14:38 -0400 Subject: [PATCH 043/229] added inputs_true to git --- tests/test_surface_tally/inputs_true.dat | 105 +++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tests/test_surface_tally/inputs_true.dat diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat new file mode 100644 index 000000000..b1a52992d --- /dev/null +++ b/tests/test_surface_tally/inputs_true.dat @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -0.62992 -0.62992 -1 0.62992 0.62992 1 + + + + + + + 10000 + + + 10001 + + + 0.0 4000000.0 20000000.0 + + + 0.0 0.785398163397 3.14159265359 + + + 0.0 0.785398163397 3.14159265359 + + + 1 + + + 10001 + + + 10000 + + + 2 + + + 3 + + + 10003 10004 10000 10001 10002 + current + + + 10003 10005 10000 10001 10002 + current + + + 10006 10007 10000 10001 10002 + current + + + 10006 10005 10000 10001 10002 + current + + + 10005 10000 10001 10002 + current + + + 10010 10000 10001 10002 + current + + + 10011 10000 10001 10002 + current + + From 74f56063582ee380b23ad97c872283f8c4efbaeb Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 15:30:02 -0400 Subject: [PATCH 044/229] white space 27 lines before what check_source was saying --- src/input_xml.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e0fa63e0d..dfc2e853c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3810,7 +3810,7 @@ contains t % score_bins(j) = SCORE_FISS_Q_RECOV case ('current') - ! Check which type of current is desired: mesh currents or + ! Check which type of current is desired: mesh currents or ! surface currents if (t % find_filter(FILTER_SURFACE) > 0 .or. & &t % find_filter(FILTER_CELL) > 0 .or. & From d28bb4f9b38a99f0686b21b762428bc151026aac Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 15:59:28 -0400 Subject: [PATCH 045/229] get_results now does all tallies instead of 1 --- tests/test_surface_tally/inputs_true.dat | 4 +- tests/test_surface_tally/results_true.dat | 60 ++++++++++++++++++- .../test_surface_tally/test_surface_tally.py | 20 ++++--- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index b1a52992d..d161c88dc 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -33,9 +33,9 @@ eigenvalue - 1000 + 100000 10 - 5 + 0 -0.62992 -0.62992 -1 0.62992 0.62992 1 diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index e47a0635c..cb9e76475 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -1,3 +1,57 @@ -tally 0: -sum = 8.800000E-02 -sum_sq = 1.582000E-03 +d_material,d_nuclide,d_variable,score,mean,std. dev. +,,,current,2.0521000e-02,1.8594772e-04 +,,,current,9.4192000e-02,4.2316217e-04 +,,,current,1.2748000e-01,5.1128596e-04 +,,,current,7.2691500e-01,2.2061909e-03 +,,,current,1.8240000e-03,4.3389707e-05 +,,,current,9.6750000e-03,1.7794662e-04 +,,,current,1.1288000e-02,2.4212394e-04 +,,,current,6.9557000e-02,8.3536692e-04 +,,,current,2.0521000e-02,1.8594772e-04 +,,,current,9.4192000e-02,4.2316217e-04 +,,,current,1.2748000e-01,5.1128596e-04 +,,,current,7.2691500e-01,2.2061909e-03 +,,,current,1.8240000e-03,4.3389707e-05 +,,,current,9.6750000e-03,1.7794662e-04 +,,,current,1.1288000e-02,2.4212394e-04 +,,,current,6.9557000e-02,8.3536692e-04 +,,,current,2.4030000e-03,6.0443730e-05 +,,,current,5.4706000e-02,2.8226150e-04 +,,,current,1.0554000e-02,9.9712921e-05 +,,,current,4.5515300e-01,1.1105905e-03 +,,,current,2.1000000e-05,5.0442487e-06 +,,,current,5.2200000e-03,1.2808851e-04 +,,,current,9.1000000e-05,9.0000000e-06 +,,,current,3.9997000e-02,4.9880981e-04 +,,,current,-2.4030000e-03,6.0443730e-05 +,,,current,-5.4706000e-02,2.8226150e-04 +,,,current,-1.0554000e-02,9.9712921e-05 +,,,current,-4.5515300e-01,1.1105905e-03 +,,,current,-2.1000000e-05,5.0442487e-06 +,,,current,-5.2200000e-03,1.2808851e-04 +,,,current,-9.1000000e-05,9.0000000e-06 +,,,current,-3.9997000e-02,4.9880981e-04 +,,,current,1.8118000e-02,1.6043552e-04 +,,,current,3.9486000e-02,2.7664337e-04 +,,,current,1.1692600e-01,4.8142889e-04 +,,,current,2.7176200e-01,1.5048527e-03 +,,,current,1.8030000e-03,4.0525712e-05 +,,,current,4.4550000e-03,1.6878816e-04 +,,,current,1.1197000e-02,2.4260187e-04 +,,,current,2.9560000e-02,4.5309307e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-4.9065000e-02,3.1853222e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-4.0249600e-01,3.6746338e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-4.9020000e-03,7.5627743e-05 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-3.5016000e-02,2.8455501e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-3.5893000e-02,1.9351170e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-2.5851100e-01,7.8233617e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-2.9840000e-03,7.1277237e-05 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-2.0319000e-02,2.5016195e-04 diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index 31850462c..dfed78615 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -6,7 +6,7 @@ sys.path.insert(0, os.pardir) from testing_harness import PyAPITestHarness import numpy as np import openmc - +import pandas as pd class CreateSurfaceTallyTestHarness(PyAPITestHarness): def _build_inputs(self): @@ -70,8 +70,8 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Instantiate a Settings object, set all runtime parameters, and export to XML settings_file = openmc.Settings() settings_file.batches = 10 - settings_file.inactive = 5 - settings_file.particles = 1000 + settings_file.inactive = 0 + settings_file.particles = 100000 # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] @@ -147,13 +147,15 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Read the statepoint file. sp = openmc.StatePoint(self._sp_name) - # Write out tally data. - outstr = '' - t = sp.get_tally() - outstr += 'tally {}:\n'.format(t.id) - outstr += 'sum = {:12.6E}\n'.format(t.sum[0, 0, 0]) - outstr += 'sum_sq = {:12.6E}\n'.format(t.sum_sq[0, 0, 0]) + # Extract the tally data as a Pandas DataFrame. + df = pd.DataFrame() + for t in sp.tallies.values(): + df = df.append(t.get_pandas_dataframe(), ignore_index=True) + # Extract the relevant data as a CSV string. + cols = ('d_material', 'd_nuclide', 'd_variable', 'score', 'mean', + 'std. dev.') + return df.to_csv(None, columns=cols, index=False, float_format='%.7e') return outstr From 1b4f2ae0254c1f364b0d15a2c80585772dd83545 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 16:19:58 -0400 Subject: [PATCH 046/229] not much --- tests/test_surface_tally/inputs_true.dat | 2 +- tests/test_surface_tally/results_true.dat | 96 +++++++++---------- .../test_surface_tally/test_surface_tally.py | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index d161c88dc..28c216075 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -33,7 +33,7 @@ eigenvalue - 100000 + 1000 10 0 diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index cb9e76475..41e548475 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -1,57 +1,57 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. -,,,current,2.0521000e-02,1.8594772e-04 -,,,current,9.4192000e-02,4.2316217e-04 -,,,current,1.2748000e-01,5.1128596e-04 -,,,current,7.2691500e-01,2.2061909e-03 -,,,current,1.8240000e-03,4.3389707e-05 -,,,current,9.6750000e-03,1.7794662e-04 -,,,current,1.1288000e-02,2.4212394e-04 -,,,current,6.9557000e-02,8.3536692e-04 -,,,current,2.0521000e-02,1.8594772e-04 -,,,current,9.4192000e-02,4.2316217e-04 -,,,current,1.2748000e-01,5.1128596e-04 -,,,current,7.2691500e-01,2.2061909e-03 -,,,current,1.8240000e-03,4.3389707e-05 -,,,current,9.6750000e-03,1.7794662e-04 -,,,current,1.1288000e-02,2.4212394e-04 -,,,current,6.9557000e-02,8.3536692e-04 -,,,current,2.4030000e-03,6.0443730e-05 -,,,current,5.4706000e-02,2.8226150e-04 -,,,current,1.0554000e-02,9.9712921e-05 -,,,current,4.5515300e-01,1.1105905e-03 -,,,current,2.1000000e-05,5.0442487e-06 -,,,current,5.2200000e-03,1.2808851e-04 -,,,current,9.1000000e-05,9.0000000e-06 -,,,current,3.9997000e-02,4.9880981e-04 -,,,current,-2.4030000e-03,6.0443730e-05 -,,,current,-5.4706000e-02,2.8226150e-04 -,,,current,-1.0554000e-02,9.9712921e-05 -,,,current,-4.5515300e-01,1.1105905e-03 -,,,current,-2.1000000e-05,5.0442487e-06 -,,,current,-5.2200000e-03,1.2808851e-04 -,,,current,-9.1000000e-05,9.0000000e-06 -,,,current,-3.9997000e-02,4.9880981e-04 -,,,current,1.8118000e-02,1.6043552e-04 -,,,current,3.9486000e-02,2.7664337e-04 -,,,current,1.1692600e-01,4.8142889e-04 -,,,current,2.7176200e-01,1.5048527e-03 -,,,current,1.8030000e-03,4.0525712e-05 -,,,current,4.4550000e-03,1.6878816e-04 -,,,current,1.1197000e-02,2.4260187e-04 -,,,current,2.9560000e-02,4.5309307e-04 +,,,current,2.4000000e-02,5.6725460e-03 +,,,current,1.0080000e-01,7.0266161e-03 +,,,current,1.2900000e-01,3.1304952e-03 +,,,current,7.2540000e-01,1.4240943e-02 +,,,current,1.8000000e-03,4.1633320e-04 +,,,current,8.3000000e-03,1.4146063e-03 +,,,current,1.5300000e-02,2.9666667e-03 +,,,current,7.9700000e-02,4.3717528e-03 +,,,current,2.4000000e-02,5.6725460e-03 +,,,current,1.0080000e-01,7.0266161e-03 +,,,current,1.2900000e-01,3.1304952e-03 +,,,current,7.2540000e-01,1.4240943e-02 +,,,current,1.8000000e-03,4.1633320e-04 +,,,current,8.3000000e-03,1.4146063e-03 +,,,current,1.5300000e-02,2.9666667e-03 +,,,current,7.9700000e-02,4.3717528e-03 +,,,current,1.5000000e-03,4.0138649e-04 +,,,current,5.7500000e-02,4.1075811e-03 +,,,current,1.0000000e-02,1.3416408e-03 +,,,current,4.5890000e-01,8.6941232e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.9065000e-02,3.1853222e-04 +,,,current,4.6000000e-03,1.0241528e-03 +,,,current,2.0000000e-04,1.3333333e-04 +,,,current,4.6700000e-02,3.5654203e-03 +,,,current,-1.5000000e-03,4.0138649e-04 +,,,current,-5.7500000e-02,4.1075811e-03 +,,,current,-1.0000000e-02,1.3416408e-03 +,,,current,-4.5890000e-01,8.6941232e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.0249600e-01,3.6746338e-04 +,,,current,-4.6000000e-03,1.0241528e-03 +,,,current,-2.0000000e-04,1.3333333e-04 +,,,current,-4.6700000e-02,3.5654203e-03 +,,,current,2.2500000e-02,5.6651959e-03 +,,,current,4.3300000e-02,4.1714639e-03 +,,,current,1.1900000e-01,2.8635642e-03 +,,,current,2.6650000e-01,1.4426249e-02 +,,,current,1.8000000e-03,4.1633320e-04 +,,,current,3.7000000e-03,1.0333333e-03 +,,,current,1.5100000e-02,2.8691849e-03 +,,,current,3.3000000e-02,1.7448336e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.9020000e-03,7.5627743e-05 +,,,current,-5.2600000e-02,4.8355167e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-3.5016000e-02,2.8455501e-04 +,,,current,-3.9890000e-01,8.1150751e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-3.5893000e-02,1.9351170e-04 +,,,current,-4.2000000e-03,7.1180522e-04 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.5851100e-01,7.8233617e-04 +,,,current,-3.9000000e-02,4.1686662e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.9840000e-03,7.1277237e-05 +,,,current,-4.0200000e-02,4.2656249e-03 ,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.0319000e-02,2.5016195e-04 +,,,current,-2.6310000e-01,1.0013824e-02 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-2.6000000e-03,4.0000000e-04 +,,,current,0.0000000e+00,0.0000000e+00 +,,,current,-2.6700000e-02,5.2218558e-03 diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index dfed78615..c8db320f9 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -71,7 +71,7 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): settings_file = openmc.Settings() settings_file.batches = 10 settings_file.inactive = 0 - settings_file.particles = 100000 + settings_file.particles = 1000 # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] From 937c5f6f5d68ebf51062929967f123b4800d7603 Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 16:50:59 -0400 Subject: [PATCH 047/229] rewording --- tests/test_surface_tally/test_surface_tally.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index c8db320f9..caa0737c5 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -132,10 +132,10 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): tallies_file.append(surf_tally2) tally_index += 1 - # Surface filter on right surface, reflective, for net current = 0 + # Surface filter on right surface, reflective, current tally doesnt pick up the zero net current though surface_filter = openmc.SurfaceFilter([3]) surf_tally3 = openmc.Tally(tally_id=tally_index, name='net_right') - surf_tally3.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] + surf_tally3.filters = [surface_filter, energy_filterr] surf_tally3.scores = ['current'] tallies_file.append(surf_tally3) tally_index += 1 From 5b2aae3b05b29fa9650a51fd54d47395d7e56b6c Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 14 Jul 2017 17:17:42 -0400 Subject: [PATCH 048/229] debugging test --- tests/test_surface_tally/inputs_true.dat | 2 +- tests/test_surface_tally/results_true.dat | 10 ++-------- tests/test_surface_tally/test_surface_tally.py | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index 28c216075..213097e8d 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -99,7 +99,7 @@ current - 10011 10000 10001 10002 + 10011 10000 current diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index 41e548475..df8c1597f 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -47,11 +47,5 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. ,,,current,-4.2000000e-03,7.1180522e-04 ,,,current,0.0000000e+00,0.0000000e+00 ,,,current,-3.9000000e-02,4.1686662e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.0200000e-02,4.2656249e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.6310000e-01,1.0013824e-02 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.6000000e-03,4.0000000e-04 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-2.6700000e-02,5.2218558e-03 +,,,current,-5.9230000e-01,1.2109730e-02 +,,,current,-5.1900000e-02,3.3381632e-03 diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index caa0737c5..cafdd84e2 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -135,7 +135,7 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Surface filter on right surface, reflective, current tally doesnt pick up the zero net current though surface_filter = openmc.SurfaceFilter([3]) surf_tally3 = openmc.Tally(tally_id=tally_index, name='net_right') - surf_tally3.filters = [surface_filter, energy_filterr] + surf_tally3.filters = [surface_filter, energy_filter] surf_tally3.scores = ['current'] tallies_file.append(surf_tally3) tally_index += 1 From 24f3dd6f55e1fd8dbeb5e0f587dfdbeda7578c5f Mon Sep 17 00:00:00 2001 From: tjlaboss Date: Tue, 25 Jul 2017 15:51:24 -0600 Subject: [PATCH 049/229] Replace ZAID notation with human-readable --- scripts/openmc-update-inputs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index 72aee9c0f..7143851d8 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -11,6 +11,7 @@ from itertools import chain from random import randint from shutil import move import xml.etree.ElementTree as ET +import re import openmc.data @@ -238,6 +239,18 @@ def update_geometry(geometry_root): return was_updated +def replace_zaid(name): + """Replace a nuclide name in the ZAID notation with the correct name.""" + # TODO: Account for metastable and any other special cases + name = name.strip() + z = int(name[:-3]) + a = int(name[-3:]) # Strips leading 0s + symbol = openmc.data.ATOMIC_SYMBOL[z] + name = str(symbol).title() + str(a) + return name + + + def update_materials(root): """Update the given XML materials tree. Return True if changes were made.""" was_updated = False @@ -247,6 +260,9 @@ def update_materials(root): if 'name' in nuclide.attrib: nucname = nuclide.attrib['name'] nucname = nucname.replace('-', '') + s = re.search("\s*(? Date: Tue, 25 Jul 2017 22:13:41 -0500 Subject: [PATCH 050/229] Make k-effective accessible from C API --- openmc/capi.py | 16 ++++++++++++++++ src/api.F90 | 3 ++- src/eigenvalue.F90 | 20 ++++++++++++++------ src/global.F90 | 1 - src/output.F90 | 11 +++++++++-- src/simulation.F90 | 15 ++------------- src/state_point.F90 | 8 +++++--- src/trigger.F90 | 6 ++++++ 8 files changed, 54 insertions(+), 26 deletions(-) diff --git a/openmc/capi.py b/openmc/capi.py index bb9241d7d..f4c9a7f3c 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -43,6 +43,8 @@ class OpenMCLibrary(object): self._dll.openmc_find.restype = None self._dll.openmc_init.argtypes = [POINTER(c_int)] self._dll.openmc_init.restype = None + self._dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] + self._dll.openmc_get_keff.restype = c_int self._dll.openmc_load_nuclide.argtypes = [c_char_p] self._dll.openmc_load_nuclide.restype = c_int self._dll.openmc_material_add_nuclide.argtypes = [ @@ -141,7 +143,21 @@ class OpenMCLibrary(object): else: return self._dll.openmc_init(None) + def keff(self): + """Return the calculated k-eigenvalue and its standard deviation. + + Returns + ------- + tuple + Mean k-eigenvalue and standard deviation of the mean + + """ + k = (c_double*2)() + err = self._dll.openmc_get_keff(k) + return tuple(k) + def load_nuclide(self, name): + """Load cross section data for a nuclide. Parameters diff --git a/src/api.F90 b/src/api.F90 index b00193fcf..45f511f9c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -5,7 +5,7 @@ module openmc_api use hdf5, only: HID_T use constants, only: K_BOLTZMANN - use eigenvalue, only: k_sum + use eigenvalue, only: k_sum, openmc_get_keff use finalize, only: openmc_finalize use geometry, only: find_cell use global @@ -23,6 +23,7 @@ module openmc_api public :: openmc_cell_set_temperature public :: openmc_finalize public :: openmc_find + public :: openmc_get_keff public :: openmc_init public :: openmc_load_nuclide public :: openmc_material_add_nuclide diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index f370ab38e..9f4da7c82 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -1,5 +1,6 @@ module eigenvalue + use, intrinsic :: ISO_C_BINDING use algorithm, only: binary_search use constants, only: ZERO @@ -439,8 +440,8 @@ contains end subroutine calculate_average_keff !=============================================================================== -! CALCULATE_COMBINED_KEFF calculates a minimum variance estimate of k-effective -! based on a linear combination of the collision, absorption, and tracklength +! OPENMC_GET_KEFF calculates a minimum variance estimate of k-effective based on +! a linear combination of the collision, absorption, and tracklength ! estimates. The theory behind this can be found in M. Halperin, "Almost ! linearly-optimum combination of unbiased estimates," J. Am. Stat. Assoc., 56, ! 36-43 (1961), doi:10.1080/01621459.1961.10482088. The implementation here @@ -448,7 +449,9 @@ contains ! of keff confidence intervals in MCNP," Nucl. Technol., 111, 169-182 (1995). !=============================================================================== - subroutine calculate_combined_keff() + function openmc_get_keff(k_combined) result(err) bind(C) + real(C_DOUBLE), intent(out) :: k_combined(2) + integer(C_INT) :: err integer :: l ! loop index integer :: i, j, k ! indices referring to collision, absorption, or track @@ -459,9 +462,14 @@ contains real(8) :: g ! sum of weighting factors real(8) :: S(3) ! sums used for variance calculation + k_combined = ZERO + ! Make sure we have at least four realizations. Notice that at the end, ! there is a N-3 term in a denominator. - if (n_realizations <= 3) return + if (n_realizations <= 3) then + err = -1 + return + end if ! Initialize variables n = real(n_realizations, 8) @@ -523,7 +531,6 @@ contains ! Initialize variables g = ZERO S = ZERO - k_combined = ZERO do l = 1, 3 ! Permutations of estimates @@ -590,8 +597,9 @@ contains k_combined(2) = sqrt(k_combined(2)) end if + err = 0 - end subroutine calculate_combined_keff + end function openmc_get_keff !=============================================================================== ! COUNT_SOURCE_FOR_UFS determines the source fraction in each UFS mesh cell and diff --git a/src/global.F90 b/src/global.F90 index 2690ed151..41f865469 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -256,7 +256,6 @@ module global real(8) :: k_col_abs = ZERO ! sum over batches of k_collision * k_absorption real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength - real(8) :: k_combined(2) ! combined best estimate of k-effective ! Shannon entropy logical :: entropy_on = .false. diff --git a/src/output.F90 b/src/output.F90 index 828af717d..9835225e0 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -1,8 +1,10 @@ module output + use, intrinsic :: ISO_C_BINDING use, intrinsic :: ISO_FORTRAN_ENV use constants + use eigenvalue, only: openmc_get_keff use endf, only: reaction_name use error, only: fatal_error, warning use geometry_header, only: Cell, Universe, Lattice, RectLattice, & @@ -608,6 +610,8 @@ contains real(8) :: t_n1 ! t-value with N-1 degrees of freedom real(8) :: t_n3 ! t-value with N-3 degrees of freedom real(8) :: x(2) ! mean and standard deviation + real(C_DOUBLE) :: k_combined(2) + integer(C_INT) :: err ! display header block for results call header("Results", 4) @@ -634,8 +638,11 @@ contains write(ou,102) "k-effective (Track-length)", x(1), t_n1 * x(2) x(:) = mean_stdev(r(:, K_ABSORPTION), n) write(ou,102) "k-effective (Absorption)", x(1), t_n1 * x(2) - if (n > 3) write(ou,102) "Combined k-effective", k_combined(1), & - t_n3 * k_combined(2) + if (n > 3) then + err = openmc_get_keff(k_combined) + write(ou,102) "Combined k-effective", k_combined(1), & + t_n3 * k_combined(2) + end if end if x(:) = mean_stdev(global_tallies(:, LEAKAGE), n) write(ou,102) "Leakage Fraction", x(1), t_n1 * x(2) diff --git a/src/simulation.F90 b/src/simulation.F90 index 87a17452d..505d5b528 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -5,9 +5,8 @@ module simulation use cmfd_execute, only: cmfd_init_batch, execute_cmfd use constants, only: ZERO use eigenvalue, only: count_source_for_ufs, calculate_average_keff, & - calculate_combined_keff, calculate_generation_keff, & - shannon_entropy, synchronize_bank, keff_generation, & - k_sum + calculate_generation_keff, shannon_entropy, & + synchronize_bank, keff_generation, k_sum #ifdef _OPENMP use eigenvalue, only: join_bank_from_threads #endif @@ -300,9 +299,6 @@ contains if (run_mode == MODE_EIGENVALUE) then ! Perform CMFD calculation if on if (cmfd_on) call execute_cmfd() - - ! Calculate combined estimate of k-effective - if (master) call calculate_combined_keff() end if ! Check_triggers @@ -327,13 +323,6 @@ contains call write_source_point() end if - if (master .and. current_batch == n_max_batches .and. & - run_mode == MODE_EIGENVALUE) then - ! Make sure combined estimate of k-effective is calculated at the last - ! batch in case no state point is written - call calculate_combined_keff() - end if - end subroutine finalize_batch !=============================================================================== diff --git a/src/state_point.F90 b/src/state_point.F90 index e4c9a43ae..f48b5638b 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -11,11 +11,12 @@ module state_point ! intervals, using the tag. !=============================================================================== - use, intrinsic :: ISO_C_BINDING, only: c_loc, c_ptr + use, intrinsic :: ISO_C_BINDING use hdf5 use constants + use eigenvalue, only: openmc_get_keff use endf, only: reaction_name use error, only: fatal_error, warning use global @@ -46,6 +47,8 @@ contains integer(HID_T) :: cmfd_group, tallies_group, tally_group, meshes_group, & mesh_group, filters_group, filter_group, derivs_group, & deriv_group, runtime_group + integer(C_INT) :: err + real(C_DOUBLE) :: k_combined(2) character(MAX_WORD_LEN), allocatable :: str_array(:) character(MAX_FILE_LEN) :: filename type(TallyObject), pointer :: tally @@ -117,6 +120,7 @@ contains call write_dataset(file_id, "k_col_abs", k_col_abs) call write_dataset(file_id, "k_col_tra", k_col_tra) call write_dataset(file_id, "k_abs_tra", k_abs_tra) + err = openmc_get_keff(k_combined) call write_dataset(file_id, "k_combined", k_combined) ! Write out CMFD info @@ -647,7 +651,6 @@ contains integer(HID_T) :: cmfd_group integer(HID_T) :: tallies_group integer(HID_T) :: tally_group - real(8) :: real_array(3) logical :: source_present character(MAX_WORD_LEN) :: word @@ -727,7 +730,6 @@ contains call read_dataset(k_col_abs, file_id, "k_col_abs") call read_dataset(k_col_tra, file_id, "k_col_tra") call read_dataset(k_abs_tra, file_id, "k_abs_tra") - call read_dataset(real_array(1:2), file_id, "k_combined") ! Take maximum of statepoint n_inactive and input n_inactive n_inactive = max(n_inactive, int_array(1)) diff --git a/src/trigger.F90 b/src/trigger.F90 index 9eb39e9cc..dc0a10b15 100644 --- a/src/trigger.F90 +++ b/src/trigger.F90 @@ -1,10 +1,13 @@ module trigger + use, intrinsic :: ISO_C_BINDING + #ifdef MPI use message_passing #endif use constants + use eigenvalue, only: openmc_get_keff use global use string, only: to_str use output, only: warning, write_message @@ -101,10 +104,12 @@ contains integer :: score_index ! scoring bin index integer :: n_order ! loop index for moment orders integer :: nm_order ! loop index for Ynm moment orders + integer(C_INT) :: err real(8) :: uncertainty ! trigger uncertainty real(8) :: std_dev = ZERO ! trigger standard deviation real(8) :: rel_err = ZERO ! trigger relative error real(8) :: ratio ! ratio of the uncertainty/trigger threshold + real(C_DOUBLE) :: k_combined(2) type(TallyObject), pointer :: t ! tally pointer type(TriggerObject), pointer :: trigger ! tally trigger @@ -119,6 +124,7 @@ contains ! Check eigenvalue trigger if (run_mode == MODE_EIGENVALUE) then if (keff_trigger % trigger_type /= 0) then + err = openmc_get_keff(k_combined) select case (keff_trigger % trigger_type) case(VARIANCE) uncertainty = k_combined(2) ** 2 From 09d1dd7f3c53aaf1c80e4510e5f75175ec960e5a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 11:05:07 -0500 Subject: [PATCH 051/229] Reset global variables on openmc_finalize --- CMakeLists.txt | 1 - src/api.F90 | 104 +++++++++++++++++++++++++++++++++++++++++++---- src/finalize.F90 | 40 ------------------ src/global.F90 | 13 ++++-- src/main.F90 | 9 ++-- 5 files changed, 107 insertions(+), 60 deletions(-) delete mode 100644 src/finalize.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index f83d95625..386c07100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,7 +320,6 @@ set(LIBOPENMC_FORTRAN_SRC src/endf_header.F90 src/energy_distribution.F90 src/error.F90 - src/finalize.F90 src/geometry.F90 src/geometry_header.F90 src/global.F90 diff --git a/src/api.F90 b/src/api.F90 index 45f511f9c..efe772a8c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -2,19 +2,20 @@ module openmc_api use, intrinsic :: ISO_C_BINDING - use hdf5, only: HID_T + use hdf5, only: HID_T, h5tclose_f, h5close_f use constants, only: K_BOLTZMANN use eigenvalue, only: k_sum, openmc_get_keff - use finalize, only: openmc_finalize use geometry, only: find_cell + use geometry_header, only: root_universe use global use hdf5_interface - use message_passing, only: master + use message_passing use initialize, only: openmc_init use input_xml, only: assign_0K_elastic_scattering, check_data_version use particle_header, only: Particle use plot, only: openmc_plot_geometry + use random_lcg, only: seed use simulation, only: openmc_run use volume_calc, only: openmc_calculate_volumes @@ -70,6 +71,89 @@ contains end if end function openmc_cell_set_temperature +!=============================================================================== +! OPENMC_FINALIZE frees up memory by deallocating arrays and resetting global +! variables +!=============================================================================== + + subroutine openmc_finalize() bind(C) + + integer :: hdf5_err + + ! Clear results + call openmc_reset() + + ! Reset global variables + assume_separate = .false. + check_overlaps = .false. + confidence_intervals = .false. + create_fission_neutrons = .true. + current_batch = 0 + current_gen = 0 + energy_cutoff = ZERO + energy_max_neutron = INFINITY + energy_min_neutron = ZERO + entropy_on = .false. + gen_per_batch = 1 + i_user_tallies = -1 + i_cmfd_tallies = -1 + keff = ONE + legendre_to_tabular = .true. + legendre_to_tabular_points = 33 + n_batch_interval = 1 + n_particles = 0 + n_source_points = 0 + n_state_points = 0 + output_summary = .true. + output_tallies = .true. + particle_restart_run = .false. + pred_batches = .false. + reduce_tallies = .true. + res_scat_on = .false. + res_scat_method = RES_SCAT_ARES + res_scat_energy_min = 0.01_8 + res_scat_energy_max = 1000.0_8 + restart_run = .false. + root_universe = -1 + run_CE = .true. + run_mode = NONE + satisfy_triggers = .false. + seed = 1_8 + source_latest = .false. + source_separate = .false. + source_write = .true. + survival_biasing = .false. + temperature_default = 293.6_8 + temperature_method = TEMPERATURE_NEAREST + temperature_multipole = .false. + temperature_range = [ZERO, ZERO] + temperature_tolerance = 10.0_8 + total_gen = 0 + trigger_on = .false. + ufs = .false. + urr_ptables_on = .true. + verbosity = 7 + weight_cutoff = 0.25_8 + weight_survive = ONE + write_all_tracks = .false. + write_initial_source = .false. + + ! Deallocate arrays + call free_memory() + + ! Release compound datatypes + call h5tclose_f(hdf5_bank_t, hdf5_err) + + ! Close FORTRAN interface. + call h5close_f(hdf5_err) + +#ifdef MPI + ! Free all MPI types + call MPI_TYPE_FREE(MPI_BANK, mpi_err) +#endif + + end subroutine openmc_finalize + !=============================================================================== ! OPENMC_FIND determines the ID or a cell or material at a given point in space !=============================================================================== @@ -291,12 +375,14 @@ contains subroutine openmc_reset() bind(C) integer :: i - do i = 1, size(tallies) - tallies(i) % n_realizations = 0 - if (allocated(tallies(i) % results)) then - tallies(i) % results(:, :, :) = ZERO - end if - end do + if (allocated(tallies)) then + do i = 1, size(tallies) + tallies(i) % n_realizations = 0 + if (allocated(tallies(i) % results)) then + tallies(i) % results(:, :, :) = ZERO + end if + end do + end if ! Reset global tallies n_realizations = 0 diff --git a/src/finalize.F90 b/src/finalize.F90 deleted file mode 100644 index 6164371a0..000000000 --- a/src/finalize.F90 +++ /dev/null @@ -1,40 +0,0 @@ -module finalize - - use, intrinsic :: ISO_C_BINDING - - use hdf5, only: h5tclose_f, h5close_f - - use global - use hdf5_interface, only: hdf5_bank_t - use message_passing - - implicit none - -contains - -!=============================================================================== -! FINALIZE_RUN does all post-simulation tasks such as calculating tally -! statistics and writing out tallies -!=============================================================================== - - subroutine openmc_finalize() bind(C) - - integer :: hdf5_err - - ! Deallocate arrays - call free_memory() - - ! Release compound datatypes - call h5tclose_f(hdf5_bank_t, hdf5_err) - - ! Close FORTRAN interface. - call h5close_f(hdf5_err) - -#ifdef MPI - ! Free all MPI types - call MPI_TYPE_FREE(MPI_BANK, mpi_err) -#endif - - end subroutine openmc_finalize - -end module finalize diff --git a/src/global.F90 b/src/global.F90 index 41f865469..9d9002e9c 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -140,7 +140,7 @@ module global integer :: max_order ! Whether or not to convert Legendres to tabulars - logical :: legendre_to_tabular = .True. + logical :: legendre_to_tabular = .true. ! Number of points to use in the Legendre to tabular conversion integer :: legendre_to_tabular_points = 33 @@ -466,6 +466,7 @@ contains if (allocated(surfaces)) deallocate(surfaces) if (allocated(materials)) deallocate(materials) if (allocated(plots)) deallocate(plots) + if (allocated(volume_calcs)) deallocate(volume_calcs) ! Deallocate geometry debugging information if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) @@ -478,6 +479,7 @@ contains end do deallocate(nuclides) end if + if (allocated(libraries)) deallocate(libraries) if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides) @@ -486,7 +488,6 @@ contains if (allocated(macro_xs)) deallocate(macro_xs) if (allocated(sab_tables)) deallocate(sab_tables) - if (allocated(micro_xs)) deallocate(micro_xs) ! Deallocate external source if (allocated(external_source)) deallocate(external_source) @@ -501,21 +502,24 @@ contains if (allocated(meshes)) deallocate(meshes) if (allocated(filters)) deallocate(filters) if (allocated(tallies)) deallocate(tallies) - if (allocated(filter_matches)) deallocate(filter_matches) ! Deallocate fission and source bank and entropy !$omp parallel if (allocated(fission_bank)) deallocate(fission_bank) + if (allocated(filter_matches)) deallocate(filter_matches) + if (allocated(tally_derivs)) deallocate(tally_derivs) !$omp end parallel #ifdef _OPENMP if (allocated(master_fission_bank)) deallocate(master_fission_bank) #endif if (allocated(source_bank)) deallocate(source_bank) - if (allocated(entropy_p)) deallocate(entropy_p) ! Deallocate array of work indices if (allocated(work_index)) deallocate(work_index) + if (allocated(energy_bins)) deallocate(energy_bins) + if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) + ! Deallocate CMFD call deallocate_cmfd(cmfd) @@ -541,6 +545,7 @@ contains call plot_dict % clear() call nuclide_dict % clear() call sab_dict % clear() + call library_dict % clear() ! Clear statepoint and sourcepoint batch set call statepoint_batch % clear() diff --git a/src/main.F90 b/src/main.F90 index 723c87df9..b8c96927e 100644 --- a/src/main.F90 +++ b/src/main.F90 @@ -1,14 +1,11 @@ program main use constants - use finalize, only: openmc_finalize use global - use initialize, only: openmc_init use message_passing - use particle_restart, only: run_particle_restart - use plot, only: openmc_plot_geometry - use simulation, only: openmc_run - use volume_calc, only: openmc_calculate_volumes + use openmc_api, only: openmc_init, openmc_finalize, openmc_run, & + openmc_plot_geometry, openmc_calculate_volumes + use particle_restart, only: run_particle_restart implicit none From 27870417ca64be355117b5cdd7f80c1e22129ba3 Mon Sep 17 00:00:00 2001 From: tjlaboss Date: Thu, 27 Jul 2017 11:32:15 -0600 Subject: [PATCH 052/229] Make use of openmc.data.neutron.get_metadata() Changed _get_metadata() to a public function and used it in openmc-update-inputs --- openmc/data/neutron.py | 4 ++-- scripts/openmc-update-inputs | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 1d3a0176d..07b1f7686 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -34,7 +34,7 @@ from openmc.mixin import EqualityMixin _RESONANCE_ENERGY_GRID = np.logspace(-3, 3, 61) -def _get_metadata(zaid, metastable_scheme='nndc'): +def get_metadata(zaid, metastable_scheme='nndc'): """Return basic identifying data for a nuclide with a given ZAID. Parameters @@ -677,7 +677,7 @@ class IncidentNeutron(EqualityMixin): # If mass number hasn't been specified, make an educated guess zaid, xs = ace.name.split('.') name, element, Z, mass_number, metastable = \ - _get_metadata(int(zaid), metastable_scheme) + get_metadata(int(zaid), metastable_scheme) # Assign temperature to the running list kTs = [ace.temperature*EV_PER_MEV] diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index 7143851d8..ea6506942 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -241,15 +241,9 @@ def update_geometry(geometry_root): def replace_zaid(name): """Replace a nuclide name in the ZAID notation with the correct name.""" - # TODO: Account for metastable and any other special cases - name = name.strip() - z = int(name[:-3]) - a = int(name[-3:]) # Strips leading 0s - symbol = openmc.data.ATOMIC_SYMBOL[z] - name = str(symbol).title() + str(a) + zaid = int(name.strip()) + name = openmc.data.neutron.get_metadata(zaid)[0] return name - - def update_materials(root): """Update the given XML materials tree. Return True if changes were made.""" From 6cada92c50c8e2bdec93b9610ec54ab86c3d151a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 13:18:49 -0500 Subject: [PATCH 053/229] Update tallies.xml in examples to separate --- examples/xml/basic/tallies.xml | 21 +++++++++++++++------ examples/xml/lattice/nested/tallies.xml | 6 +++++- examples/xml/lattice/simple/tallies.xml | 6 +++++- examples/xml/pincell/tallies.xml | 11 +++++++++-- examples/xml/pincell_multigroup/tallies.xml | 9 +++++++-- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/examples/xml/basic/tallies.xml b/examples/xml/basic/tallies.xml index 26e61995d..a125e9ca2 100644 --- a/examples/xml/basic/tallies.xml +++ b/examples/xml/basic/tallies.xml @@ -1,21 +1,30 @@ + + 100 + + + + 0 20.0e6 + + + + 0 20.0e6 + + - + 1 total scatter nu-scatter absorption fission nu-fission - - + 1 2 total scatter nu-scatter absorption fission nu-fission - - - + 1 2 3 scatter nu-scatter nu-fission diff --git a/examples/xml/lattice/nested/tallies.xml b/examples/xml/lattice/nested/tallies.xml index 89c0774f1..d342174a9 100644 --- a/examples/xml/lattice/nested/tallies.xml +++ b/examples/xml/lattice/nested/tallies.xml @@ -8,8 +8,12 @@ 1.0 1.0 + + 1 + + - + 1 total diff --git a/examples/xml/lattice/simple/tallies.xml b/examples/xml/lattice/simple/tallies.xml index 89c0774f1..d342174a9 100644 --- a/examples/xml/lattice/simple/tallies.xml +++ b/examples/xml/lattice/simple/tallies.xml @@ -8,8 +8,12 @@ 1.0 1.0 + + 1 + + - + 1 total diff --git a/examples/xml/pincell/tallies.xml b/examples/xml/pincell/tallies.xml index f740530cf..642bdd7cd 100644 --- a/examples/xml/pincell/tallies.xml +++ b/examples/xml/pincell/tallies.xml @@ -7,9 +7,16 @@ 0.62992 0.62992 1.e50 + + 1 + + + + 0. 4. 20.0e6 + + - - + 1 2 flux fission nu-fission diff --git a/examples/xml/pincell_multigroup/tallies.xml b/examples/xml/pincell_multigroup/tallies.xml index 1591a556b..d84e129f2 100644 --- a/examples/xml/pincell_multigroup/tallies.xml +++ b/examples/xml/pincell_multigroup/tallies.xml @@ -5,9 +5,14 @@ -0.63 -0.63 -1e+50 0.63 0.63 1e+50 + + 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + + + 1 + - - + 1 2 flux fission nu-fission From 306c96c74b20e9813d1a444605e6ca6079480c78 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 14:00:49 -0500 Subject: [PATCH 054/229] Broadcast tally results at end of simulation --- src/simulation.F90 | 33 ++++++++++++++++++++++++++++++--- src/tally.F90 | 6 +++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/simulation.F90 b/src/simulation.F90 index 505d5b528..7edaf8be2 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -20,7 +20,7 @@ module simulation use source, only: initialize_source, sample_external_source use state_point, only: write_state_point, write_source_point use string, only: to_str - use tally, only: synchronize_tallies, setup_active_usertallies + use tally, only: accumulate_tallies, setup_active_usertallies use trigger, only: check_triggers use tracking, only: transport @@ -285,9 +285,9 @@ contains subroutine finalize_batch() - ! Collect tallies + ! Reduce tallies onto master process and accumulate call time_tallies % start() - call synchronize_tallies() + call accumulate_tallies() call time_tallies % stop() ! Reset global tally results @@ -390,6 +390,10 @@ contains subroutine finalize_simulation() + integer :: i ! loop index for tallies + integer :: n ! size of arrays + real(8) :: temp(3) ! temporary array for communication + !$omp parallel deallocate(micro_xs) !$omp end parallel @@ -400,6 +404,29 @@ contains ! Start finalization timer call time_finalize % start() +#ifdef MPI + ! Broadcast tally results so that each process has access to results + do i = 1, size(tallies) + n = size(tallies(i) % results) + call MPI_BCAST(tallies(i) % results, n, MPI_DOUBLE, 0, & + mpi_intracomm, mpi_err) + end do + + ! Also broadcast global tally results + n = size(global_tallies) + call MPI_BCAST(global_tallies, n, MPI_DOUBLE, 0, mpi_intracomm, mpi_err) + + ! These guys are needed so that non-master processes can calculate the + ! combined estimate of k-effective + temp(1) = k_col_abs + temp(2) = k_col_tra + temp(3) = k_abs_tra + call MPI_BCAST(temp, 3, MPI_REAL8, 0, mpi_intracomm, mpi_err) + k_col_abs = temp(1) + k_col_tra = temp(2) + k_abs_tra = temp(3) +#endif + ! Write tally results to tallies.out if (output_tallies .and. master) call write_tallies() if (check_overlaps) call reduce_overlap_count() diff --git a/src/tally.F90 b/src/tally.F90 index 14940551b..b8e46678c 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4182,11 +4182,11 @@ contains end subroutine zero_flux_derivs !=============================================================================== -! SYNCHRONIZE_TALLIES accumulates the sum of the contributions from each history +! ACCUMULATE_TALLIES accumulates the sum of the contributions from each history ! within the batch to a new random variable !=============================================================================== - subroutine synchronize_tallies() + subroutine accumulate_tallies() integer :: i real(C_DOUBLE) :: k_col ! Copy of batch collision estimate of keff @@ -4236,7 +4236,7 @@ contains end do end if - end subroutine synchronize_tallies + end subroutine accumulate_tallies !=============================================================================== ! REDUCE_TALLY_RESULTS collects all the results from tallies onto one processor From 0fba66b8fe847d0b6081e262d88ea5f5a3b315ef Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 14:16:00 -0500 Subject: [PATCH 055/229] Reset a few more global variables, ugh --- src/api.F90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api.F90 b/src/api.F90 index efe772a8c..dc9548f10 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -101,9 +101,15 @@ contains legendre_to_tabular = .true. legendre_to_tabular_points = 33 n_batch_interval = 1 + n_filters = 0 + n_meshes = 0 n_particles = 0 n_source_points = 0 n_state_points = 0 + n_tallies = 0 + n_user_filters = 0 + n_user_meshes = 0 + n_user_tallies = 0 output_summary = .true. output_tallies = .true. particle_restart_run = .false. From c124a4e8e3c43fccb6bff981ea13027c602f84fd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 14:53:35 -0500 Subject: [PATCH 056/229] Get rid of almost all MPI_IN_PLACE specifiers --- src/mesh.F90 | 36 ++++++++++++------------------------ src/simulation.F90 | 12 +++++------- src/state_point.F90 | 19 +++++-------------- src/tally.F90 | 38 +++++++++++++------------------------- 4 files changed, 35 insertions(+), 70 deletions(-) diff --git a/src/mesh.F90 b/src/mesh.F90 index b778cbdf0..393df5dda 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -137,21 +137,19 @@ contains real(8), intent(in), optional :: energies(:) ! energy grid to search integer(8), intent(in), optional :: size_bank ! # of bank sites (on each proc) logical, intent(inout), optional :: sites_outside ! were there sites outside mesh? + real(8), allocatable :: cnt_(:,:,:,:) integer :: i ! loop index for local fission sites integer :: n_sites ! size of bank array integer :: ijk(3) ! indices on mesh - integer :: n_groups ! number of groups in energies + integer :: n ! number of energy groups / size integer :: e_bin ! energy_bin logical :: in_mesh ! was single site outside mesh? logical :: outside ! was any site outside mesh? -#ifdef MPI - integer :: n ! total size of count variable - real(8) :: dummy ! temporary receive buffer for non-root reductions -#endif ! initialize variables - cnt = ZERO + allocate(cnt_(size(cnt,1), size(cnt,2), size(cnt,3), size(cnt,4))) + cnt_ = ZERO outside = .false. ! Set size of bank @@ -163,9 +161,9 @@ contains ! Determine number of energies in group structure if (present(energies)) then - n_groups = size(energies) - 1 + n = size(energies) - 1 else - n_groups = 1 + n = 1 end if ! loop over fission sites and count how many are in each mesh box @@ -183,40 +181,30 @@ contains if (present(energies)) then if (bank_array(i) % E < energies(1)) then e_bin = 1 - elseif (bank_array(i) % E > energies(n_groups+1)) then - e_bin = n_groups + elseif (bank_array(i) % E > energies(n + 1)) then + e_bin = n else - e_bin = binary_search(energies, n_groups + 1, bank_array(i) % E) + e_bin = binary_search(energies, n + 1, bank_array(i) % E) end if else e_bin = 1 end if ! add to appropriate mesh box - cnt(e_bin,ijk(1),ijk(2),ijk(3)) = cnt(e_bin,ijk(1),ijk(2),ijk(3)) + & + cnt_(e_bin,ijk(1),ijk(2),ijk(3)) = cnt_(e_bin,ijk(1),ijk(2),ijk(3)) + & bank_array(i) % wgt end do FISSION_SITES #ifdef MPI - ! determine total number of mesh cells - n = n_groups * size(cnt,2) * size(cnt,3) * size(cnt,4) - ! collect values from all processors - if (master) then - call MPI_REDUCE(MPI_IN_PLACE, cnt, n, MPI_REAL8, MPI_SUM, 0, & - mpi_intracomm, mpi_err) - else - ! Receive buffer not significant at other processors - call MPI_REDUCE(cnt, dummy, n, MPI_REAL8, MPI_SUM, 0, & - mpi_intracomm, mpi_err) - end if + n = size(cnt_) + call MPI_REDUCE(cnt_, cnt, n, MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err) ! Check if there were sites outside the mesh for any processor if (present(sites_outside)) then call MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, & mpi_intracomm, mpi_err) end if - #else sites_outside = outside #endif diff --git a/src/simulation.F90 b/src/simulation.F90 index 7edaf8be2..ced5a74f1 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -448,14 +448,12 @@ contains subroutine reduce_overlap_count() + integer(8) :: temp + #ifdef MPI - if (master) then - call MPI_REDUCE(MPI_IN_PLACE, overlap_check_cnt, n_cells, & - MPI_INTEGER8, MPI_SUM, 0, mpi_intracomm, mpi_err) - else - call MPI_REDUCE(overlap_check_cnt, overlap_check_cnt, n_cells, & - MPI_INTEGER8, MPI_SUM, 0, mpi_intracomm, mpi_err) - end if + call MPI_REDUCE(overlap_check_cnt, temp, n_cells, MPI_INTEGER8, & + MPI_SUM, 0, mpi_intracomm, mpi_err) + overlap_check_cnt = temp #endif end subroutine reduce_overlap_count diff --git a/src/state_point.F90 b/src/state_point.F90 index f48b5638b..301a4efdd 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -539,18 +539,15 @@ contains tallies_group = open_group(file_id, "tallies") end if - ! Copy global tallies into temporary array for reducing - n_bins = 3 * N_GLOBAL_TALLIES - global_temp(:,:) = global_tallies(:,:) - if (master) then - ! The MPI_IN_PLACE specifier allows the master to copy values into a - ! receive buffer without having a temporary variable #ifdef MPI - call MPI_REDUCE(MPI_IN_PLACE, global_temp, n_bins, MPI_REAL8, MPI_SUM, & - 0, mpi_intracomm, mpi_err) + ! Reduce global tallies + n_bins = size(global_tallies) + call MPI_REDUCE(global_tallies, global_temp, n_bins, MPI_REAL8, MPI_SUM, & + 0, mpi_intracomm, mpi_err) #endif + if (master) then ! Transfer values to value on master if (current_batch == n_max_batches .or. satisfy_triggers) then global_tallies(:,:) = global_temp(:,:) @@ -558,12 +555,6 @@ contains ! Write out global tallies sum and sum_sq call write_dataset(file_id, "global_tallies", global_temp) - else - ! Receive buffer not significant at other processors -#ifdef MPI - call MPI_REDUCE(global_temp, dummy, n_bins, MPI_REAL8, MPI_SUM, & - 0, mpi_intracomm, mpi_err) -#endif end if if (tallies_on) then diff --git a/src/tally.F90 b/src/tally.F90 index b8e46678c..8f871e39b 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4249,13 +4249,12 @@ contains integer :: n ! number of filter bins integer :: m ! number of score bins integer :: n_bins ! total number of bins - real(8), allocatable :: tally_temp(:,:) ! contiguous array of results - real(8) :: global_temp(N_GLOBAL_TALLIES) + real(C_DOUBLE), allocatable :: tally_temp(:,:) ! contiguous array of results + real(C_DOUBLE) :: temp(N_GLOBAL_TALLIES), temp2(N_GLOBAL_TALLIES) real(8) :: dummy ! temporary receive buffer for non-root reduces - type(TallyObject), pointer :: t do i = 1, active_tallies % size() - t => tallies(active_tallies % data(i)) + associate (t => tallies(active_tallies % data(i))) m = t % total_score_bins n = t % total_filter_bins @@ -4282,37 +4281,26 @@ contains t % results(RESULT_VALUE,:,:) = ZERO end if + end associate + deallocate(tally_temp) end do - ! Copy global tallies into array to be reduced - global_temp = global_tallies(RESULT_VALUE, :) - + ! Reduce global tallies onto master + temp = global_tallies(RESULT_VALUE, :) + call MPI_REDUCE(temp, temp2, N_GLOBAL_TALLIES, MPI_DOUBLE, MPI_SUM, & + 0, mpi_intracomm, mpi_err) if (master) then - call MPI_REDUCE(MPI_IN_PLACE, global_temp, N_GLOBAL_TALLIES, & - MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err) - - ! Transfer values back to global_tallies on master - global_tallies(RESULT_VALUE, :) = global_temp + global_tallies(RESULT_VALUE, :) = temp2 else - ! Receive buffer not significant at other processors - call MPI_REDUCE(global_temp, dummy, N_GLOBAL_TALLIES, & - MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err) - - ! Reset value on other processors global_tallies(RESULT_VALUE, :) = ZERO end if ! We also need to determine the total starting weight of particles from the ! last realization - if (master) then - call MPI_REDUCE(MPI_IN_PLACE, total_weight, 1, MPI_REAL8, MPI_SUM, & - 0, mpi_intracomm, mpi_err) - else - ! Receive buffer not significant at other processors - call MPI_REDUCE(total_weight, dummy, 1, MPI_REAL8, MPI_SUM, & - 0, mpi_intracomm, mpi_err) - end if + temp(1) = total_weight + call MPI_REDUCE(temp, total_weight, 1, MPI_REAL8, MPI_SUM, & + 0, mpi_intracomm, mpi_err) end subroutine reduce_tally_results #endif From ba318df3c42d8706bb0a6ea2b2fe9d4ec68e512d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 15:25:06 -0500 Subject: [PATCH 057/229] Don't use MPI_IN_PLACE for reducing tally results --- src/tally.F90 | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 8f871e39b..8b52ad032 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4249,41 +4249,34 @@ contains integer :: n ! number of filter bins integer :: m ! number of score bins integer :: n_bins ! total number of bins - real(C_DOUBLE), allocatable :: tally_temp(:,:) ! contiguous array of results + real(C_DOUBLE), allocatable :: tally_temp(:,:) ! contiguous array of results + real(C_DOUBLE), allocatable :: tally_temp2(:,:) ! reduced contiguous results real(C_DOUBLE) :: temp(N_GLOBAL_TALLIES), temp2(N_GLOBAL_TALLIES) - real(8) :: dummy ! temporary receive buffer for non-root reduces do i = 1, active_tallies % size() associate (t => tallies(active_tallies % data(i))) - m = t % total_score_bins - n = t % total_filter_bins - n_bins = m*n + m = size(t % results, 2) + n = size(t % results, 3) + n_bins = m*n - allocate(tally_temp(m,n)) + allocate(tally_temp(m,n), tally_temp2(m,n)) - tally_temp = t % results(RESULT_VALUE,:,:) - - if (master) then - ! The MPI_IN_PLACE specifier allows the master to copy values into - ! a receive buffer without having a temporary variable - call MPI_REDUCE(MPI_IN_PLACE, tally_temp, n_bins, MPI_REAL8, & + ! Reduce contiguous set of tally results + tally_temp = t % results(RESULT_VALUE,:,:) + call MPI_REDUCE(tally_temp, tally_temp2, n_bins, MPI_DOUBLE, & MPI_SUM, 0, mpi_intracomm, mpi_err) - ! Transfer values to value on master - t % results(RESULT_VALUE,:,:) = tally_temp - else - ! Receive buffer not significant at other processors - call MPI_REDUCE(tally_temp, dummy, n_bins, MPI_REAL8, & - MPI_SUM, 0, mpi_intracomm, mpi_err) - - ! Reset value on other processors - t % results(RESULT_VALUE,:,:) = ZERO - end if + if (master) then + ! Transfer values to value on master + t % results(RESULT_VALUE,:,:) = tally_temp2 + else + ! Reset value on other processors + t % results(RESULT_VALUE,:,:) = ZERO + end if + deallocate(tally_temp, tally_temp2) end associate - - deallocate(tally_temp) end do ! Reduce global tallies onto master From b4b7e3f7c62b478cd4df0daeee24ce00cd495051 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 27 Jul 2017 16:02:02 -0500 Subject: [PATCH 058/229] Fix two bugs --- src/mesh.F90 | 1 + src/simulation.F90 | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mesh.F90 b/src/mesh.F90 index 393df5dda..427710790 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -207,6 +207,7 @@ contains end if #else sites_outside = outside + cnt = cnt_ #endif end subroutine count_bank_sites diff --git a/src/simulation.F90 b/src/simulation.F90 index ced5a74f1..8a32493ca 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -406,11 +406,13 @@ contains #ifdef MPI ! Broadcast tally results so that each process has access to results - do i = 1, size(tallies) - n = size(tallies(i) % results) - call MPI_BCAST(tallies(i) % results, n, MPI_DOUBLE, 0, & - mpi_intracomm, mpi_err) - end do + if (allocated(tallies)) then + do i = 1, size(tallies) + n = size(tallies(i) % results) + call MPI_BCAST(tallies(i) % results, n, MPI_DOUBLE, 0, & + mpi_intracomm, mpi_err) + end do + end if ! Also broadcast global tally results n = size(global_tallies) From 35d24a955d29abfde0d3c08970a6f2836621f73c Mon Sep 17 00:00:00 2001 From: liangjg Date: Fri, 28 Jul 2017 10:08:37 -0400 Subject: [PATCH 059/229] skip adding 0K elastic xs if it already exists --- openmc/data/neutron.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 1d3a0176d..ed2f4f8b7 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -866,12 +866,13 @@ class IncidentNeutron(EqualityMixin): data.fission_energy = FissionEnergyRelease.from_endf(ev, data) # Add 0K elastic scattering cross section - pendf = Evaluation(pendf_file) - file_obj = StringIO(pendf.section[3, 2]) - get_head_record(file_obj) - params, xs = get_tab1_record(file_obj) - data.energy['0K'] = xs.x - data[2].xs['0K'] = xs + if '0K' not in data.energy: + pendf = Evaluation(pendf_file) + file_obj = StringIO(pendf.section[3, 2]) + get_head_record(file_obj) + params, xs = get_tab1_record(file_obj) + data.energy['0K'] = xs.x + data[2].xs['0K'] = xs finally: # Get rid of temporary files From 3a6ee672c61609e62ca0d4623fabe7b28f5b1e94 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 28 Jul 2017 10:31:28 -0500 Subject: [PATCH 060/229] Add three more functions for getting/setting nuclide densities in materials --- openmc/capi.py | 88 ++++++++++++++++++++++++++++++++++++++++ src/api.F90 | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/openmc/capi.py b/openmc/capi.py index f4c9a7f3c..2164a9d81 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -12,6 +12,7 @@ __all__ = ['OpenMCLibrary', 'lib', 'lib_context'] _int3 = c_int*3 _double3 = c_double*3 +_int_array = POINTER(POINTER(c_int)) _double_array = POINTER(POINTER(c_double)) @@ -47,14 +48,25 @@ class OpenMCLibrary(object): self._dll.openmc_get_keff.restype = c_int self._dll.openmc_load_nuclide.argtypes = [c_char_p] self._dll.openmc_load_nuclide.restype = c_int + + # Material interface self._dll.openmc_material_add_nuclide.argtypes = [ c_int32, c_char_p, c_double] self._dll.openmc_material_add_nuclide.restype = c_int self._dll.openmc_material_get_densities.argtypes = [ c_int32, _double_array] self._dll.openmc_material_get_densities.restype = c_int + self._dll.openmc_material_get_nuclides.argtypes = [ + c_int32, _int_array] + self._dll.openmc_material_get_nuclides.restype = c_int self._dll.openmc_material_set_density.argtypes = [c_int32, c_double] self._dll.openmc_material_set_density.restype = c_int + self._dll.openmc_material_set_densities.argtypes = [ + c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] + self._dll.openmc_material_set_densities.restype = c_int + + self._dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] + self._dll.openmc_nuclide_name.restype = c_int self._dll.openmc_plot_geometry.restype = None self._dll.openmc_run.restype = None self._dll.openmc_reset.restype = None @@ -215,6 +227,27 @@ class OpenMCLibrary(object): else: return None + def material_get_nuclides(self, mat_id): + """Get list of nuclides in a material. + + Parameters + ---------- + mat_id : int + ID of the material + + Returns + ------- + list of str + Nuclides in specified material + + """ + data = POINTER(c_int)() + n = self._dll.openmc_material_get_nuclides(mat_id, data) + if data: + return [self.nuclide_name(data[i]) for i in range(n)] + else: + return None + def material_set_density(self, mat_id, density): """Set density of a material. @@ -233,6 +266,61 @@ class OpenMCLibrary(object): """ return self._dll.openmc_material_set_density(mat_id, density) + def material_set_densities(self, mat_id, nuclides, densities): + """Set the densities of a list of nuclides in a material + + Parameters + ---------- + mat_id : int + ID of the material + nuclides : iterable of str + Nuclide names + densities : iterable of float + Corresponding densities in atom/b-cm + + Returns + ------- + int + Return status (negative if an error occurs). + + """ + # Convert strings to an array of char* + nucs = (c_char_p * len(nuclides))() + nucs[:] = [x.encode() for x in nuclides] + + # Get numpy array as a double* + d = np.asarray(densities) + dp = d.ctypes.data_as(POINTER(c_double)) + + return self._dll.openmc_material_set_densities( + mat_id, len(nuclides), nucs, dp) + + def nuclide_name(self, index): + """Name of nuclide with given index + + Parameter + --------- + index : int + Index in internal nuclides array + + Returns + ------- + str + Name of nuclide + + """ + name = c_char_p() + err = self._dll.openmc_nuclide_name(index, name) + + # Find blank in name + if err == 0: + i = 0 + while name.value[i:i+1] != b' ': + i += 1 + return name.value[:i].decode() + else: + return None + def plot_geometry(self): """Plot geometry""" return self._dll.openmc_plot_geometry() diff --git a/src/api.F90 b/src/api.F90 index dc9548f10..50beddd5d 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -19,6 +19,8 @@ module openmc_api use simulation, only: openmc_run use volume_calc, only: openmc_calculate_volumes + implicit none + private public :: openmc_calculate_volumes public :: openmc_cell_set_temperature @@ -29,7 +31,10 @@ module openmc_api public :: openmc_load_nuclide public :: openmc_material_add_nuclide public :: openmc_material_get_densities + public :: openmc_material_get_nuclides public :: openmc_material_set_density + public :: openmc_material_set_densities + public :: openmc_nuclide_name public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run @@ -202,6 +207,7 @@ contains character(kind=C_CHAR) :: name(*) integer(C_INT) :: err + integer :: i_library integer :: n integer(HID_T) :: file_id integer(HID_T) :: group_id @@ -337,6 +343,8 @@ contains type(C_PTR), intent(out) :: ptr integer(C_INT) :: n + integer :: i + ptr = C_NULL_PTR n = 0 if (allocated(materials)) then @@ -352,6 +360,55 @@ contains end if end function openmc_material_get_densities +!=============================================================================== +! OPENMC_MATERIAL_GET_NUCLIDES returns an array that indicates for each nuclide +! in a material its index in the global nuclides array +!=============================================================================== + + function openmc_material_get_nuclides(id, ptr) result(n) bind(C) + integer(C_INT32_T), intent(in), value :: id + type(C_PTR), intent(out) :: ptr + integer(C_INT) :: n + + integer :: i + + ptr = C_NULL_PTR + n = 0 + if (allocated(materials)) then + if (material_dict % has_key(id)) then + i = material_dict % get_key(id) + associate (m => materials(i)) + if (allocated(m % nuclide)) then + ptr = C_LOC(m % nuclide(1)) + n = size(m % nuclide) + end if + end associate + end if + end if + end function openmc_material_get_nuclides + +!=============================================================================== +! OPENMC_NUCLIDE_NAME returns the name of a nuclide with a given index +!=============================================================================== + + function openmc_nuclide_name(index, name) result(err) bind(C) + integer(C_INT), value, intent(in) :: index + type(c_ptr), intent(out) :: name + integer(C_INT) :: err + + character(C_CHAR), pointer :: name_ + + err = -1 + name = C_NULL_PTR + if (allocated(nuclides)) then + if (index >= 1 .and. index <= size(nuclides)) then + name_ => nuclides(index) % name(1:1) + name = C_LOC(name_) + err = 0 + end if + end if + end function openmc_nuclide_name + !=============================================================================== ! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm !=============================================================================== @@ -374,6 +431,57 @@ contains end if end function openmc_material_set_density +!=============================================================================== +! OPENMC_MATERIAL_SET_DENSITIES sets the densities for a list of nuclides in a +! material. If the nuclides don't already exist in the material, they will be +! added +!=============================================================================== + + function openmc_material_set_densities(id, n, name, density) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: id + integer(C_INT), value, intent(in) :: n + type(C_PTR), intent(in) :: name(n) + real(C_DOUBLE), intent(in) :: density(n) + integer(C_INT) :: err + + integer :: i, j, k + logical :: has_nuclide + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: name_ + + err = -1 + if (allocated(materials)) then + if (material_dict % has_key(id)) then + i = material_dict % get_key(id) + associate (m => materials(i)) + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(name(i), string, [10]) + name_ = to_f_string(string) + + ! Find corresponding nuclide and set density + has_nuclide = .false. + do j = 1, size(m % nuclide) + k = m % nuclide(j) + if (nuclides(k) % name == name_) then + m % atom_density(j) = density(i) + has_nuclide = .true. + end if + end do + + ! If nuclide wasn't found, try to load it + err = openmc_material_add_nuclide(id, string, density(i)) + if (err /= 0) return + end do + + ! Set total density to the sum of the vector + err = m % set_density(sum(m % atom_density), nuclides) + end associate + end if + end if + + end function openmc_material_set_densities + !=============================================================================== ! OPENMC_RESET resets all tallies !=============================================================================== From 7988bad6dacdf29b04210f8f16edc7a29fb2d684 Mon Sep 17 00:00:00 2001 From: liangjg Date: Fri, 28 Jul 2017 11:56:32 -0400 Subject: [PATCH 061/229] made error tolerance a parameter for generating data from njoy --- openmc/data/neutron.py | 6 ++++-- openmc/data/njoy.py | 24 +++++++++++++++--------- openmc/data/thermal.py | 7 +++++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index ed2f4f8b7..8accabfc7 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -824,7 +824,7 @@ class IncidentNeutron(EqualityMixin): return data @classmethod - def from_njoy(cls, filename, temperatures=None, **kwargs): + def from_njoy(cls, filename, temperatures=None, error=0.001, **kwargs): """Generate incident neutron data by running NJOY. Parameters @@ -834,6 +834,8 @@ class IncidentNeutron(EqualityMixin): temperatures : iterable of float Temperatures in Kelvin to produce data at. If omitted, data is produced at room temperature (293.6 K) + error : float, optional + Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace` @@ -851,7 +853,7 @@ class IncidentNeutron(EqualityMixin): ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') pendf_file = os.path.join(tmpdir, 'pendf') - make_ace(filename, temperatures, ace_file, xsdir_file, + make_ace(filename, temperatures, error, ace_file, xsdir_file, pendf_file, **kwargs) # Create instance from ACE tables within library diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index b6fce5e3e..5365d9740 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -68,14 +68,14 @@ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% 20 21 '{library} PENDF for {zsymam}'/ {mat} 2/ -0.001 0.0 0.003/ err tempr errmax +{error}/ err '{library}: {zsymam}'/ 'Processed by NJOY'/ 0/ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 21 22 {mat} {num_temp} 0 0 0. / -0.001 1.0e6 0.003 / +{error}/ errthn {temps} 0/ heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -104,26 +104,26 @@ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% 20 22 '{library} PENDF for {zsymam}'/ {mat} 2/ -0.001 0. 0.001/ err tempr errmax +{error}/ err '{library}: PENDF for {zsymam}'/ 'Processed by NJOY'/ 0/ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 22 23 {mat} {num_temp} 0 0 0./ -0.001 2.0e+6 0.001/ errthn thnmax errmax +{error}/ errthn {temps} 0/ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%% 0 23 62 0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/ {temps} -0.001 {energy_max} +{error} {energy_max} thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (bound) %%%%%%%%%%%%%%%%%% 60 62 27 {mat_thermal} {mat} 16 {num_temp} {inelastic} {elastic} {iform} {natom} 222 1/ {temps} -0.001 {energy_max} +{error} {energy_max} """ _ACE_THERMAL_TEMPLATE_ACER = """acer / @@ -195,7 +195,7 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'): return njoy.returncode -def make_pendf(filename, pendf='pendf', stdout=False): +def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): """Generate ACE file from an ENDF file Parameters @@ -204,6 +204,8 @@ def make_pendf(filename, pendf='pendf', stdout=False): Path to ENDF file pendf : str, optional Path of pointwise ENDF file to write + error : float, optional + Fractional error tolerance for NJOY processing. stdout : bool Whether to display NJOY standard output @@ -226,7 +228,7 @@ def make_pendf(filename, pendf='pendf', stdout=False): return run(commands, tapein, tapeout, stdout) -def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', +def make_ace(filename, temperatures=None, error=0.001, ace='ace', xsdir='xsdir', pendf=None, **kwargs): """Generate incident neutron ACE file from an ENDF file @@ -237,6 +239,8 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', temperatures : iterable of float, optional Temperatures in Kelvin to produce ACE files at. If omitted, data is produced at room temperature (293.6 K). + error : float, optional + Fractional error tolerance for NJOY processing. ace : str, optional Path of ACE file to write xsdir : str, optional @@ -311,7 +315,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', return retcode -def make_ace_thermal(filename, filename_thermal, temperatures=None, +def make_ace_thermal(filename, filename_thermal, temperatures=None, error=0.001, ace='ace', xsdir='xsdir', **kwargs): """Generate thermal scattering ACE file from ENDF files @@ -324,6 +328,8 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, temperatures : iterable of float, optional Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures given in the ENDF thermal scattering sublibrary. + error : float, optional + Fractional error tolerance for NJOY processing. ace : str, optional Path of ACE file to write xsdir : str, optional diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 6e7b0fe02..1d63c1ade 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -588,7 +588,8 @@ class ThermalScattering(EqualityMixin): return table @classmethod - def from_njoy(cls, filename, filename_thermal, temperatures=None, **kwargs): + def from_njoy(cls, filename, filename_thermal, temperatures=None, + error=0.001, **kwargs): """Generate incident neutron data by running NJOY. Parameters @@ -601,6 +602,8 @@ class ThermalScattering(EqualityMixin): Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures in the ENDF thermal scattering sublibrary. + error : float, optional + Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace_thermal` @@ -617,7 +620,7 @@ class ThermalScattering(EqualityMixin): # Run NJOY to create an ACE library ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') - make_ace_thermal(filename, filename_thermal, temperatures, + make_ace_thermal(filename, filename_thermal, temperatures, error, ace_file, xsdir_file, **kwargs) # Create instance from ACE tables within library From 851e50afbcdff9385efa8f089626a99d57dca1a3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 28 Jul 2017 14:59:29 -0500 Subject: [PATCH 062/229] Awesome error handling thanks to ctypes --- openmc/capi.py | 150 ++++++++++++++++++++++++++++--------------------- src/api.F90 | 112 +++++++++++++++++++++++++++--------- 2 files changed, 171 insertions(+), 91 deletions(-) diff --git a/openmc/capi.py b/openmc/capi.py index 2164a9d81..a2225b571 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -16,6 +16,53 @@ _int_array = POINTER(POINTER(c_int)) _double_array = POINTER(POINTER(c_double)) +class GeometryError(Exception): + pass + + +def _error_code(s): + """Get error code corresponding to global constant.""" + return c_int.in_dll(lib._dll, s).value + + +def _error_handler(err, func, args): + """Raise exception according to error code.""" + if err == _error_code('e_out_of_bounds'): + raise IndexError('Array index out of bounds.') + + elif err == _error_code('e_cell_not_allocated'): + raise MemoryError("Memory has not been allocated for cells.") + + elif err == _error_code('e_cell_invalid_id'): + raise KeyError("No cell exists with ID={}.".format(args[0])) + + elif err == _error_code('e_cell_not_found'): + raise GeometryError("Could not find cell at position ({}, {}, {})" + .format(*args[0])) + + elif err == _error_code('e_nuclide_not_allocated'): + raise MemoryError("Memory has not been allocated for nuclides.") + + elif err == _error_code('e_nuclide_not_in_library'): + raise KeyError("Specified nuclide doesn't exist in the cross " + "section library.") + + elif err == _error_code('e_material_not_allocated'): + raise MemoryError("Memory has not been allocated for materials.") + + elif err == _error_code('e_material_invalid_id'): + raise KeyError("No material exists with ID={}.".format(args[0])) + + elif err == _error_code('e_tally_not_allocated'): + raise MemoryError("Memory has not been allocated for tallies.") + + elif err == _error_code('e_tally_invalid_id'): + raise KeyError("No tally exists with ID={}.".format(args[0])) + + elif err < 0: + raise Exception("Unknown error encountered (code {}).".format(err)) + + class OpenMCLibrary(object): """Provides bindings to C functions defined by OpenMC shared library. @@ -36,47 +83,58 @@ class OpenMCLibrary(object): # Set argument/return types self._dll.openmc_calculate_volumes.restype = None self._dll.openmc_cell_set_temperature.argtypes = [ - c_int32, c_double, c_int32] + c_int32, c_double, POINTER(c_int32)] self._dll.openmc_cell_set_temperature.restype = c_int + self._dll.openmc_cell_set_temperature.errcheck = _error_handler self._dll.openmc_finalize.restype = None self._dll.openmc_find.argtypes = [ POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] - self._dll.openmc_find.restype = None + self._dll.openmc_find.restype = c_int + self._dll.openmc_find.errcheck = _error_handler self._dll.openmc_init.argtypes = [POINTER(c_int)] self._dll.openmc_init.restype = None self._dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] self._dll.openmc_get_keff.restype = c_int + self._dll.openmc_get_keff.errcheck = _error_handler self._dll.openmc_load_nuclide.argtypes = [c_char_p] self._dll.openmc_load_nuclide.restype = c_int + self._dll.openmc_load_nuclide.errcheck = _error_handler # Material interface self._dll.openmc_material_add_nuclide.argtypes = [ c_int32, c_char_p, c_double] self._dll.openmc_material_add_nuclide.restype = c_int + self._dll.openmc_material_add_nuclide.errcheck = _error_handler self._dll.openmc_material_get_densities.argtypes = [ - c_int32, _double_array] + c_int32, _double_array, POINTER(c_int)] self._dll.openmc_material_get_densities.restype = c_int + self._dll.openmc_material_get_densities.errcheck = _error_handler self._dll.openmc_material_get_nuclides.argtypes = [ - c_int32, _int_array] + c_int32, _int_array, POINTER(c_int)] self._dll.openmc_material_get_nuclides.restype = c_int + self._dll.openmc_material_get_nuclides.errcheck = _error_handler self._dll.openmc_material_set_density.argtypes = [c_int32, c_double] self._dll.openmc_material_set_density.restype = c_int + self._dll.openmc_material_set_density.errcheck = _error_handler self._dll.openmc_material_set_densities.argtypes = [ c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] self._dll.openmc_material_set_densities.restype = c_int + self._dll.openmc_material_set_densities.errcheck = _error_handler self._dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] self._dll.openmc_nuclide_name.restype = c_int + self._dll.openmc_nuclide_name.errcheck = _error_handler self._dll.openmc_plot_geometry.restype = None self._dll.openmc_run.restype = None self._dll.openmc_reset.restype = None self._dll.openmc_tally_results.argtypes = [ c_int32, _double_array, POINTER(_int3)] - self._dll.openmc_tally_results.restype = None + self._dll.openmc_tally_results.restype = c_int + self._dll.openmc_tally_results.errcheck = _error_handler def calculate_volumes(self): """Run stochastic volume calculation""" - return self._dll.openmc_calculate_volumes() + self._dll.openmc_calculate_volumes() def cell_set_temperature(self, cell_id, T, instance=None): """Set the temperature of a cell @@ -91,15 +149,11 @@ class OpenMCLibrary(object): Which instance of the cell """ - if instance is not None: - return self._dll.openmc_cell_set_temperature( - cell_id, T, instance) - else: - return self._dll.openmc_cell_set_temperature(cell_id, T, None) + self._dll.openmc_cell_set_temperature(cell_id, T, instance) def finalize(self): """Finalize simulation and free memory""" - return self._dll.openmc_finalize() + self._dll.openmc_finalize() def find(self, xyz, rtype='cell'): """Find the cell or material at a given point @@ -151,9 +205,9 @@ class OpenMCLibrary(object): intracomm = intracomm.py2f() except AttributeError: pass - return self._dll.openmc_init(c_int(intracomm)) + self._dll.openmc_init(c_int(intracomm)) else: - return self._dll.openmc_init(None) + self._dll.openmc_init(None) def keff(self): """Return the calculated k-eigenvalue and its standard deviation. @@ -165,7 +219,7 @@ class OpenMCLibrary(object): """ k = (c_double*2)() - err = self._dll.openmc_get_keff(k) + self._dll.openmc_get_keff(k) return tuple(k) def load_nuclide(self, name): @@ -177,13 +231,8 @@ class OpenMCLibrary(object): name : str Name of nuclide, e.g. 'U235' - Returns - ------- - int - Return status (negative if an error occurs). - """ - return self._dll.openmc_load_nuclide(name.encode()) + self._dll.openmc_load_nuclide(name.encode()) def material_add_nuclide(self, mat_id, name, density): """Add a nuclide to a material. @@ -197,14 +246,8 @@ class OpenMCLibrary(object): density : float Density in atom/b-cm - Returns - ------- - int - Return status (negative if an error occurs). - """ - return self._dll.openmc_material_add_nuclide( - mat_id, name.encode(), density) + self._dll.openmc_material_add_nuclide(mat_id, name.encode(), density) def material_get_densities(self, mat_id): """Get atom densities in a material. @@ -221,11 +264,9 @@ class OpenMCLibrary(object): """ data = POINTER(c_double)() - n = self._dll.openmc_material_get_densities(mat_id, data) - if data: - return as_array(data, (n,)) - else: - return None + n = c_int() + self._dll.openmc_material_get_densities(mat_id, data, n) + return as_array(data, (n.value,)) def material_get_nuclides(self, mat_id): """Get list of nuclides in a material. @@ -242,11 +283,9 @@ class OpenMCLibrary(object): """ data = POINTER(c_int)() - n = self._dll.openmc_material_get_nuclides(mat_id, data) - if data: - return [self.nuclide_name(data[i]) for i in range(n)] - else: - return None + n = c_int() + self._dll.openmc_material_get_nuclides(mat_id, data, n) + return [self.nuclide_name(data[i]) for i in range(n.value)] def material_set_density(self, mat_id, density): """Set density of a material. @@ -258,13 +297,8 @@ class OpenMCLibrary(object): density : float Density in atom/b-cm - Returns - ------- - int - Return status (negative if an error occurs). - """ - return self._dll.openmc_material_set_density(mat_id, density) + self._dll.openmc_material_set_density(mat_id, density) def material_set_densities(self, mat_id, nuclides, densities): """Set the densities of a list of nuclides in a material @@ -278,11 +312,6 @@ class OpenMCLibrary(object): densities : iterable of float Corresponding densities in atom/b-cm - Returns - ------- - int - Return status (negative if an error occurs). - """ # Convert strings to an array of char* nucs = (c_char_p * len(nuclides))() @@ -292,8 +321,7 @@ class OpenMCLibrary(object): d = np.asarray(densities) dp = d.ctypes.data_as(POINTER(c_double)) - return self._dll.openmc_material_set_densities( - mat_id, len(nuclides), nucs, dp) + self._dll.openmc_material_set_densities(mat_id, len(nuclides), nucs, dp) def nuclide_name(self, index): """Name of nuclide with given index @@ -310,28 +338,25 @@ class OpenMCLibrary(object): """ name = c_char_p() - err = self._dll.openmc_nuclide_name(index, name) + self._dll.openmc_nuclide_name(index, name) # Find blank in name - if err == 0: - i = 0 - while name.value[i:i+1] != b' ': - i += 1 - return name.value[:i].decode() - else: - return None + i = 0 + while name.value[i:i+1] != b' ': + i += 1 + return name.value[:i].decode() def plot_geometry(self): """Plot geometry""" - return self._dll.openmc_plot_geometry() + self._dll.openmc_plot_geometry() def reset(self): """Reset tallies""" - return self._dll.openmc_reset() + self._dll.openmc_reset() def run(self): """Run simulation""" - return self._dll.openmc_run() + self._dll.openmc_run() def tally_results(self, tally_id): """Get tally results array @@ -363,7 +388,6 @@ class OpenMCLibrary(object): raise AttributeError("OpenMC library doesn't have a '{}' function" .format(key)) - @contextmanager def lib_context(intracomm=None): """Provides context manager for calling OpenMC shared library functions. diff --git a/src/api.F90 b/src/api.F90 index 50beddd5d..3bea4af99 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -40,6 +40,19 @@ module openmc_api public :: openmc_run public :: openmc_tally_results + ! Error codes + integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1 + integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -2 + integer(C_INT), public, bind(C) :: E_CELL_NOT_ALLOCATED = -3 + integer(C_INT), public, bind(C) :: E_CELL_INVALID_ID = -4 + integer(C_INT), public, bind(C) :: E_CELL_NOT_FOUND = -5 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_ALLOCATED = -6 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -7 + integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -8 + integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -9 + integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -10 + integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -11 + contains !=============================================================================== @@ -54,7 +67,7 @@ contains integer :: i, n - err = -1 + err = E_UNASSIGNED if (allocated(cells)) then if (cell_dict % has_key(id)) then i = cell_dict % get_key(id) @@ -72,7 +85,11 @@ contains end if end if end associate + else + err = E_CELL_INVALID_ID end if + else + err = E_CELL_NOT_ALLOCATED end if end function openmc_cell_set_temperature @@ -169,11 +186,12 @@ contains ! OPENMC_FIND determines the ID or a cell or material at a given point in space !=============================================================================== - subroutine openmc_find(xyz, rtype, id, instance) bind(C) + function openmc_find(xyz, rtype, id, instance) result(err) bind(C) real(C_DOUBLE), intent(in) :: xyz(3) ! Cartesian point integer(C_INT), intent(in), value :: rtype ! 1 for cell, 2 for material integer(C_INT32_T), intent(out) :: id integer(C_INT32_T), intent(out) :: instance + integer(C_INT) :: err logical :: found type(Particle) :: p @@ -185,6 +203,8 @@ contains id = -1 instance = -1 + err = E_UNASSIGNED + if (found) then if (rtype == 1) then id = cells(p % coord(p % n_coord) % cell) % id @@ -196,8 +216,12 @@ contains end if end if instance = p % cell_instance - 1 + err = 0 + else + err = E_CELL_NOT_FOUND end if - end subroutine openmc_find + + end function openmc_find !=============================================================================== ! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library @@ -219,7 +243,7 @@ contains ! Copy array of C_CHARs to normal Fortran string name_ = to_f_string(name) - err = -1 + err = 0 if (.not. nuclide_dict % has_key(to_lower(name_))) then if (library_dict % has_key(to_lower(name_))) then ! allocate extra space in nuclides array @@ -253,10 +277,8 @@ contains ! Initialize nuclide grid call nuclides(n) % init_grid(energy_min_neutron, & energy_max_neutron, n_log_bins) - - err = 0 else - err = -2 + err = E_NUCLIDE_NOT_IN_LIBRARY end if end if @@ -273,7 +295,6 @@ contains integer(C_INT) :: err integer :: i, j, k, n - integer :: err2 real(8) :: awr integer, allocatable :: new_nuclide(:) real(8), allocatable :: new_density(:) @@ -281,7 +302,7 @@ contains name_ = to_f_string(name) - err = -1 + err = E_UNASSIGNED if (allocated(materials)) then if (material_dict % has_key(id)) then i = material_dict % get_key(id) @@ -302,9 +323,9 @@ contains ! If nuclide wasn't found, extend nuclide/density arrays if (err /= 0) then ! If nuclide hasn't been loaded, load it now - err2 = openmc_load_nuclide(name) + err = openmc_load_nuclide(name) - if (err2 /= -2) then + if (err == 0) then ! Extend arrays n = size(m % nuclide) allocate(new_nuclide(n + 1)) @@ -323,12 +344,14 @@ contains m % density_gpcc = m % density_gpcc + & density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO m % n_nuclides = n + 1 - - err = 0 end if end if end associate + else + err = E_MATERIAL_INVALID_ID end if + else + err = E_MATERIAL_NOT_ALLOCATED end if end function openmc_material_add_nuclide @@ -338,15 +361,17 @@ contains ! material !=============================================================================== - function openmc_material_get_densities(id, ptr) result(n) bind(C) + function openmc_material_get_densities(id, ptr, n) result(err) bind(C) integer(C_INT32_T), intent(in), value :: id type(C_PTR), intent(out) :: ptr - integer(C_INT) :: n + integer(C_INT), intent(out) :: n + integer(C_INT) :: err integer :: i ptr = C_NULL_PTR - n = 0 + n = -1 + err = E_UNASSIGNED if (allocated(materials)) then if (material_dict % has_key(id)) then i = material_dict % get_key(id) @@ -354,9 +379,14 @@ contains if (allocated(m % atom_density)) then ptr = C_LOC(m % atom_density(1)) n = size(m % atom_density) + err = 0 end if end associate + else + err = E_MATERIAL_INVALID_ID end if + else + err = E_MATERIAL_NOT_ALLOCATED end if end function openmc_material_get_densities @@ -365,15 +395,17 @@ contains ! in a material its index in the global nuclides array !=============================================================================== - function openmc_material_get_nuclides(id, ptr) result(n) bind(C) + function openmc_material_get_nuclides(id, ptr, n) result(err) bind(C) integer(C_INT32_T), intent(in), value :: id type(C_PTR), intent(out) :: ptr - integer(C_INT) :: n + integer(C_INT), intent(out) :: n + integer(C_INT) :: err integer :: i ptr = C_NULL_PTR - n = 0 + n = -1 + err = E_UNASSIGNED if (allocated(materials)) then if (material_dict % has_key(id)) then i = material_dict % get_key(id) @@ -381,9 +413,14 @@ contains if (allocated(m % nuclide)) then ptr = C_LOC(m % nuclide(1)) n = size(m % nuclide) + err = 0 end if end associate + else + err = E_MATERIAL_INVALID_ID end if + else + err = E_MATERIAL_NOT_ALLOCATED end if end function openmc_material_get_nuclides @@ -398,14 +435,18 @@ contains character(C_CHAR), pointer :: name_ - err = -1 + err = E_UNASSIGNED name = C_NULL_PTR if (allocated(nuclides)) then if (index >= 1 .and. index <= size(nuclides)) then name_ => nuclides(index) % name(1:1) name = C_LOC(name_) err = 0 + else + err = E_OUT_OF_BOUNDS end if + else + err = E_NUCLIDE_NOT_ALLOCATED end if end function openmc_nuclide_name @@ -427,7 +468,11 @@ contains associate (m => materials(i)) err = m % set_density(density, nuclides) end associate + else + err = E_MATERIAL_INVALID_ID end if + else + err = E_MATERIAL_NOT_ALLOCATED end if end function openmc_material_set_density @@ -445,11 +490,10 @@ contains integer(C_INT) :: err integer :: i, j, k - logical :: has_nuclide character(C_CHAR), pointer :: string(:) character(len=:, kind=C_CHAR), allocatable :: name_ - err = -1 + err = E_UNASSIGNED if (allocated(materials)) then if (material_dict % has_key(id)) then i = material_dict % get_key(id) @@ -460,24 +504,29 @@ contains name_ = to_f_string(string) ! Find corresponding nuclide and set density - has_nuclide = .false. do j = 1, size(m % nuclide) k = m % nuclide(j) if (nuclides(k) % name == name_) then m % atom_density(j) = density(i) - has_nuclide = .true. + err = 0 end if end do ! If nuclide wasn't found, try to load it - err = openmc_material_add_nuclide(id, string, density(i)) - if (err /= 0) return + if (err /= 0) then + err = openmc_material_add_nuclide(id, string, density(i)) + if (err /= 0) return + end if end do ! Set total density to the sum of the vector err = m % set_density(sum(m % atom_density), nuclides) end associate + else + err = E_MATERIAL_INVALID_ID end if + else + err = E_MATERIAL_NOT_ALLOCATED end if end function openmc_material_set_densities @@ -527,24 +576,31 @@ contains ! directly. !=============================================================================== - subroutine openmc_tally_results(id, ptr, shape_) bind(C) + function openmc_tally_results(id, ptr, shape_) result(err) bind(C) integer(C_INT32_T), intent(in), value :: id type(C_PTR), intent(out) :: ptr integer(C_INT), intent(out) :: shape_(3) + integer(C_INT) :: err integer :: i ptr = C_NULL_PTR + err = E_UNASSIGNED if (allocated(tallies)) then if (tally_dict % has_key(id)) then i = tally_dict % get_key(id) if (allocated(tallies(i) % results)) then ptr = C_LOC(tallies(i) % results(1,1,1)) shape_(:) = shape(tallies(i) % results) + err = 0 end if + else + err = E_TALLY_INVALID_ID end if + else + err = E_TALLY_NOT_ALLOCATED end if - end subroutine openmc_tally_results + end function openmc_tally_results function to_f_string(c_string) result(f_string) character(kind=C_CHAR), intent(in) :: c_string(*) From 25e585881f8de46c37154f5b2bfc4841b9044003 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 28 Jul 2017 15:17:57 -0500 Subject: [PATCH 063/229] Combine material_get_densities and material_get_nuclides --- openmc/capi.py | 37 ++++++++++++------------------------- src/api.F90 | 47 ++++++++--------------------------------------- 2 files changed, 20 insertions(+), 64 deletions(-) diff --git a/openmc/capi.py b/openmc/capi.py index a2225b571..7712e0e3e 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -106,13 +106,9 @@ class OpenMCLibrary(object): self._dll.openmc_material_add_nuclide.restype = c_int self._dll.openmc_material_add_nuclide.errcheck = _error_handler self._dll.openmc_material_get_densities.argtypes = [ - c_int32, _double_array, POINTER(c_int)] + c_int32, _int_array, _double_array, POINTER(c_int)] self._dll.openmc_material_get_densities.restype = c_int self._dll.openmc_material_get_densities.errcheck = _error_handler - self._dll.openmc_material_get_nuclides.argtypes = [ - c_int32, _int_array, POINTER(c_int)] - self._dll.openmc_material_get_nuclides.restype = c_int - self._dll.openmc_material_get_nuclides.errcheck = _error_handler self._dll.openmc_material_set_density.argtypes = [c_int32, c_double] self._dll.openmc_material_set_density.restype = c_int self._dll.openmc_material_set_density.errcheck = _error_handler @@ -259,33 +255,24 @@ class OpenMCLibrary(object): Returns ------- + list of string + List of nuclide names numpy.ndarray Array of densities in atom/b-cm """ - data = POINTER(c_double)() + # Allocate memory for arguments that are written to + nuclides = POINTER(c_int)() + densities = POINTER(c_double)() n = c_int() - self._dll.openmc_material_get_densities(mat_id, data, n) - return as_array(data, (n.value,)) - def material_get_nuclides(self, mat_id): - """Get list of nuclides in a material. + # Get nuclide names and densities + self._dll.openmc_material_get_densities(mat_id, nuclides, densities, n) - Parameters - ---------- - mat_id : int - ID of the material - - Returns - ------- - list of str - Nuclides in specified material - - """ - data = POINTER(c_int)() - n = c_int() - self._dll.openmc_material_get_nuclides(mat_id, data, n) - return [self.nuclide_name(data[i]) for i in range(n.value)] + # Convert to appropriate types and return + nuclide_list = [self.nuclide_name(nuclides[i]) for i in range(n.value)] + density_array = as_array(densities, (n.value,)) + return nuclide_list, density_array def material_set_density(self, mat_id, density): """Set density of a material. diff --git a/src/api.F90 b/src/api.F90 index 3bea4af99..6b71bf2fc 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -31,7 +31,6 @@ module openmc_api public :: openmc_load_nuclide public :: openmc_material_add_nuclide public :: openmc_material_get_densities - public :: openmc_material_get_nuclides public :: openmc_material_set_density public :: openmc_material_set_densities public :: openmc_nuclide_name @@ -361,15 +360,18 @@ contains ! material !=============================================================================== - function openmc_material_get_densities(id, ptr, n) result(err) bind(C) + function openmc_material_get_densities(id, nuclides, densities, n) & + result(err) bind(C) integer(C_INT32_T), intent(in), value :: id - type(C_PTR), intent(out) :: ptr + type(C_PTR), intent(out) :: nuclides + type(C_PTR), intent(out) :: densities integer(C_INT), intent(out) :: n integer(C_INT) :: err integer :: i - ptr = C_NULL_PTR + nuclides = C_NULL_PTR + densities = C_NULL_PTR n = -1 err = E_UNASSIGNED if (allocated(materials)) then @@ -377,7 +379,8 @@ contains i = material_dict % get_key(id) associate (m => materials(i)) if (allocated(m % atom_density)) then - ptr = C_LOC(m % atom_density(1)) + nuclides = C_LOC(m % nuclide(1)) + densities = C_LOC(m % atom_density(1)) n = size(m % atom_density) err = 0 end if @@ -390,40 +393,6 @@ contains end if end function openmc_material_get_densities -!=============================================================================== -! OPENMC_MATERIAL_GET_NUCLIDES returns an array that indicates for each nuclide -! in a material its index in the global nuclides array -!=============================================================================== - - function openmc_material_get_nuclides(id, ptr, n) result(err) bind(C) - integer(C_INT32_T), intent(in), value :: id - type(C_PTR), intent(out) :: ptr - integer(C_INT), intent(out) :: n - integer(C_INT) :: err - - integer :: i - - ptr = C_NULL_PTR - n = -1 - err = E_UNASSIGNED - if (allocated(materials)) then - if (material_dict % has_key(id)) then - i = material_dict % get_key(id) - associate (m => materials(i)) - if (allocated(m % nuclide)) then - ptr = C_LOC(m % nuclide(1)) - n = size(m % nuclide) - err = 0 - end if - end associate - else - err = E_MATERIAL_INVALID_ID - end if - else - err = E_MATERIAL_NOT_ALLOCATED - end if - end function openmc_material_get_nuclides - !=============================================================================== ! OPENMC_NUCLIDE_NAME returns the name of a nuclide with a given index !=============================================================================== From a33502e8fa1f482bceda48ffd55a583279c03956 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 28 Jul 2017 15:46:35 -0500 Subject: [PATCH 064/229] Get rid of OpenMCLibrary object and make all methods regular functions --- openmc/__init__.py | 2 +- openmc/capi.py | 647 ++++++++++++++++++++++----------------------- 2 files changed, 324 insertions(+), 325 deletions(-) diff --git a/openmc/__init__.py b/openmc/__init__.py index a0fe26491..571b5a93a 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -27,6 +27,6 @@ from openmc.particle_restart import * from openmc.mixin import * from openmc.plotter import * from openmc.search import * -from openmc.capi import * +import openmc.capi __version__ = '0.9.0' diff --git a/openmc/capi.py b/openmc/capi.py index 7712e0e3e..2e6b17d43 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -1,3 +1,15 @@ +"""Provides bindings to C functions defined by OpenMC shared library. + +When the :mod:`openmc` package is imported, the OpenMC shared library is +automatically loaded. Calls to the OpenMC library can then be made, for example: + +.. code-block:: python + + openmc.capi.init() + openmc.capi.run() + +""" + from contextlib import contextmanager from ctypes import CDLL, c_int, c_int32, c_double, c_char_p, POINTER import sys @@ -5,11 +17,8 @@ from warnings import warn import numpy as np from numpy.ctypeslib import as_array - import pkg_resources -__all__ = ['OpenMCLibrary', 'lib', 'lib_context'] - _int3 = c_int*3 _double3 = c_double*3 _int_array = POINTER(POINTER(c_int)) @@ -22,7 +31,7 @@ class GeometryError(Exception): def _error_code(s): """Get error code corresponding to global constant.""" - return c_int.in_dll(lib._dll, s).value + return c_int.in_dll(_dll, s).value def _error_handler(err, func, args): @@ -63,332 +72,70 @@ def _error_handler(err, func, args): raise Exception("Unknown error encountered (code {}).".format(err)) -class OpenMCLibrary(object): - """Provides bindings to C functions defined by OpenMC shared library. +def calculate_volumes(): + """Run stochastic volume calculation""" + _dll.openmc_calculate_volumes() - This class is normally not directly instantiated. Instead, when the - :mod:`openmc` package is imported, an instance is automatically created with - the name :data:`openmc.lib`. Calls to the OpenMC can then be made using that - instance, for example: - .. code-block:: python +def cell_set_temperature(cell_id, T, instance=None): + """Set the temperature of a cell - openmc.lib.init() - openmc.lib.run() + Parameters + ---------- + cell_id : int + ID of the cell + T : float + Temperature in K + instance : int or None + Which instance of the cell """ - def __init__(self, filename): - self._dll = CDLL(filename) + _dll.openmc_cell_set_temperature(cell_id, T, instance) - # Set argument/return types - self._dll.openmc_calculate_volumes.restype = None - self._dll.openmc_cell_set_temperature.argtypes = [ - c_int32, c_double, POINTER(c_int32)] - self._dll.openmc_cell_set_temperature.restype = c_int - self._dll.openmc_cell_set_temperature.errcheck = _error_handler - self._dll.openmc_finalize.restype = None - self._dll.openmc_find.argtypes = [ - POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] - self._dll.openmc_find.restype = c_int - self._dll.openmc_find.errcheck = _error_handler - self._dll.openmc_init.argtypes = [POINTER(c_int)] - self._dll.openmc_init.restype = None - self._dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] - self._dll.openmc_get_keff.restype = c_int - self._dll.openmc_get_keff.errcheck = _error_handler - self._dll.openmc_load_nuclide.argtypes = [c_char_p] - self._dll.openmc_load_nuclide.restype = c_int - self._dll.openmc_load_nuclide.errcheck = _error_handler - # Material interface - self._dll.openmc_material_add_nuclide.argtypes = [ - c_int32, c_char_p, c_double] - self._dll.openmc_material_add_nuclide.restype = c_int - self._dll.openmc_material_add_nuclide.errcheck = _error_handler - self._dll.openmc_material_get_densities.argtypes = [ - c_int32, _int_array, _double_array, POINTER(c_int)] - self._dll.openmc_material_get_densities.restype = c_int - self._dll.openmc_material_get_densities.errcheck = _error_handler - self._dll.openmc_material_set_density.argtypes = [c_int32, c_double] - self._dll.openmc_material_set_density.restype = c_int - self._dll.openmc_material_set_density.errcheck = _error_handler - self._dll.openmc_material_set_densities.argtypes = [ - c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] - self._dll.openmc_material_set_densities.restype = c_int - self._dll.openmc_material_set_densities.errcheck = _error_handler - self._dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] - self._dll.openmc_nuclide_name.restype = c_int - self._dll.openmc_nuclide_name.errcheck = _error_handler - self._dll.openmc_plot_geometry.restype = None - self._dll.openmc_run.restype = None - self._dll.openmc_reset.restype = None - self._dll.openmc_tally_results.argtypes = [ - c_int32, _double_array, POINTER(_int3)] - self._dll.openmc_tally_results.restype = c_int - self._dll.openmc_tally_results.errcheck = _error_handler +def finalize(): + """Finalize simulation and free memory""" + _dll.openmc_finalize() - def calculate_volumes(self): - """Run stochastic volume calculation""" - self._dll.openmc_calculate_volumes() - def cell_set_temperature(self, cell_id, T, instance=None): - """Set the temperature of a cell +def find(xyz, rtype='cell'): + """Find the cell or material at a given point - Parameters - ---------- - cell_id : int - ID of the cell - T : float - Temperature in K - instance : int or None - Which instance of the cell + Parameters + ---------- + xyz : iterable of float + Cartesian coordinates of position + rtype : {'cell', 'material'} + Whether to return the cell or material ID - """ - self._dll.openmc_cell_set_temperature(cell_id, T, instance) + Returns + ------- + int or None + ID of the cell or material. If 'material' is requested and no + material exists at the given coordinate, None is returned. + int + If the cell at the given point is repeated in the geometry, this + indicates which instance it is, i.e., 0 would be the first instance. - def finalize(self): - """Finalize simulation and free memory""" - self._dll.openmc_finalize() + """ + # Set second argument to openmc_find + if rtype == 'cell': + r_int = 1 + elif rtype == 'material': + r_int = 2 + else: + raise ValueError('Unknown return type: {}'.format(rtype)) - def find(self, xyz, rtype='cell'): - """Find the cell or material at a given point + # Call openmc_find + uid = c_int32() + instance = c_int32() + _dll.openmc_find(_double3(*xyz), r_int, uid, instance) + return (uid.value if uid != 0 else None), instance.value - Parameters - ---------- - xyz : iterable of float - Cartesian coordinates of position - rtype : {'cell', 'material'} - Whether to return the cell or material ID - Returns - ------- - int or None - ID of the cell or material. If 'material' is requested and no - material exists at the given coordinate, None is returned. - int - If the cell at the given point is repeated in the geometry, this - indicates which instance it is, i.e., 0 would be the first instance. - - """ - # Set second argument to openmc_find - if rtype == 'cell': - r_int = 1 - elif rtype == 'material': - r_int = 2 - else: - raise ValueError('Unknown return type: {}'.format(rtype)) - - # Call openmc_find - uid = c_int32() - instance = c_int32() - self._dll.openmc_find(_double3(*xyz), r_int, uid, instance) - return (uid.value if uid != 0 else None), instance.value - - def init(self, intracomm=None): - """Initialize OpenMC - - Parameters - ---------- - intracomm : mpi4py.MPI.Intracomm or None - MPI intracommunicator - - """ - if intracomm is not None: - # If an mpi4py communicator was passed, convert it to an integer to - # be passed to openmc_init - try: - intracomm = intracomm.py2f() - except AttributeError: - pass - self._dll.openmc_init(c_int(intracomm)) - else: - self._dll.openmc_init(None) - - def keff(self): - """Return the calculated k-eigenvalue and its standard deviation. - - Returns - ------- - tuple - Mean k-eigenvalue and standard deviation of the mean - - """ - k = (c_double*2)() - self._dll.openmc_get_keff(k) - return tuple(k) - - def load_nuclide(self, name): - - """Load cross section data for a nuclide. - - Parameters - ---------- - name : str - Name of nuclide, e.g. 'U235' - - """ - self._dll.openmc_load_nuclide(name.encode()) - - def material_add_nuclide(self, mat_id, name, density): - """Add a nuclide to a material. - - Parameters - ---------- - mat_id : int - ID of the material - name : str - Name of nuclide, e.g. 'U235' - density : float - Density in atom/b-cm - - """ - self._dll.openmc_material_add_nuclide(mat_id, name.encode(), density) - - def material_get_densities(self, mat_id): - """Get atom densities in a material. - - Parameters - ---------- - mat_id : int - ID of the material - - Returns - ------- - list of string - List of nuclide names - numpy.ndarray - Array of densities in atom/b-cm - - """ - # Allocate memory for arguments that are written to - nuclides = POINTER(c_int)() - densities = POINTER(c_double)() - n = c_int() - - # Get nuclide names and densities - self._dll.openmc_material_get_densities(mat_id, nuclides, densities, n) - - # Convert to appropriate types and return - nuclide_list = [self.nuclide_name(nuclides[i]) for i in range(n.value)] - density_array = as_array(densities, (n.value,)) - return nuclide_list, density_array - - def material_set_density(self, mat_id, density): - """Set density of a material. - - Parameters - ---------- - mat_id : int - ID of the material - density : float - Density in atom/b-cm - - """ - self._dll.openmc_material_set_density(mat_id, density) - - def material_set_densities(self, mat_id, nuclides, densities): - """Set the densities of a list of nuclides in a material - - Parameters - ---------- - mat_id : int - ID of the material - nuclides : iterable of str - Nuclide names - densities : iterable of float - Corresponding densities in atom/b-cm - - """ - # Convert strings to an array of char* - nucs = (c_char_p * len(nuclides))() - nucs[:] = [x.encode() for x in nuclides] - - # Get numpy array as a double* - d = np.asarray(densities) - dp = d.ctypes.data_as(POINTER(c_double)) - - self._dll.openmc_material_set_densities(mat_id, len(nuclides), nucs, dp) - - def nuclide_name(self, index): - """Name of nuclide with given index - - Parameter - --------- - index : int - Index in internal nuclides array - - Returns - ------- - str - Name of nuclide - - """ - name = c_char_p() - self._dll.openmc_nuclide_name(index, name) - - # Find blank in name - i = 0 - while name.value[i:i+1] != b' ': - i += 1 - return name.value[:i].decode() - - def plot_geometry(self): - """Plot geometry""" - self._dll.openmc_plot_geometry() - - def reset(self): - """Reset tallies""" - self._dll.openmc_reset() - - def run(self): - """Run simulation""" - self._dll.openmc_run() - - def tally_results(self, tally_id): - """Get tally results array - - Parameters - ---------- - tally_id : int - ID of tally - - Returns - ------- - numpy.ndarray - Array that exposes the internal tally results array - - """ - data = POINTER(c_double)() - shape = _int3() - self._dll.openmc_tally_results(tally_id, data, shape) - if data: - return as_array(data, tuple(shape[::-1])) - else: - return None - - def __getattr__(self, key): - # Fall-back for other functions that may be available from library - try: - return getattr(self._dll, 'openmc_{}'.format(key)) - except AttributeError: - raise AttributeError("OpenMC library doesn't have a '{}' function" - .format(key)) - -@contextmanager -def lib_context(intracomm=None): - """Provides context manager for calling OpenMC shared library functions. - - This function is intended to be used in a 'with' statement and ensures that - OpenMC is properly initialized/finalized. At the completion of the 'with' - block, all memory that was allocated during the block is freed. For - example:: - - with openmc.lib_context() as lib: - for i in range(n_iters): - lib.reset() - do_stuff() - lib.run() +def init(intracomm=None): + """Initialize OpenMC Parameters ---------- @@ -396,24 +143,276 @@ def lib_context(intracomm=None): MPI intracommunicator """ - lib.init(comm) - yield lib - lib.finalize() + if intracomm is not None: + # If an mpi4py communicator was passed, convert it to an integer to + # be passed to openmc_init + try: + intracomm = intracomm.py2f() + except AttributeError: + pass + _dll.openmc_init(c_int(intracomm)) + else: + _dll.openmc_init(None) + + +def keff(): + """Return the calculated k-eigenvalue and its standard deviation. + + Returns + ------- + tuple + Mean k-eigenvalue and standard deviation of the mean + + """ + k = (c_double*2)() + _dll.openmc_get_keff(k) + return tuple(k) + + +def load_nuclide(name): + """Load cross section data for a nuclide. + + Parameters + ---------- + name : str + Name of nuclide, e.g. 'U235' + + """ + _dll.openmc_load_nuclide(name.encode()) + + +def material_add_nuclide(mat_id, name, density): + """Add a nuclide to a material. + + Parameters + ---------- + mat_id : int + ID of the material + name : str + Name of nuclide, e.g. 'U235' + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_add_nuclide(mat_id, name.encode(), density) + + +def material_get_densities(mat_id): + """Get atom densities in a material. + + Parameters + ---------- + mat_id : int + ID of the material + + Returns + ------- + list of string + List of nuclide names + numpy.ndarray + Array of densities in atom/b-cm + + """ + # Allocate memory for arguments that are written to + nuclides = POINTER(c_int)() + densities = POINTER(c_double)() + n = c_int() + + # Get nuclide names and densities + _dll.openmc_material_get_densities(mat_id, nuclides, densities, n) + + # Convert to appropriate types and return + nuclide_list = [nuclide_name(nuclides[i]) for i in range(n.value)] + density_array = as_array(densities, (n.value,)) + return nuclide_list, density_array + + +def material_set_density(mat_id, density): + """Set density of a material. + + Parameters + ---------- + mat_id : int + ID of the material + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_set_density(mat_id, density) + + +def material_set_densities(mat_id, nuclides, densities): + """Set the densities of a list of nuclides in a material + + Parameters + ---------- + mat_id : int + ID of the material + nuclides : iterable of str + Nuclide names + densities : iterable of float + Corresponding densities in atom/b-cm + + """ + # Convert strings to an array of char* + nucs = (c_char_p * len(nuclides))() + nucs[:] = [x.encode() for x in nuclides] + + # Get numpy array as a double* + d = np.asarray(densities) + dp = d.ctypes.data_as(POINTER(c_double)) + + _dll.openmc_material_set_densities(mat_id, len(nuclides), nucs, dp) + + +def nuclide_name(index): + """Name of nuclide with given index + + Parameter + --------- + index : int + Index in internal nuclides array + + Returns + ------- + str + Name of nuclide + + """ + name = c_char_p() + _dll.openmc_nuclide_name(index, name) + + # Find blank in name + i = 0 + while name.value[i:i+1] != b' ': + i += 1 + return name.value[:i].decode() + + +def plot_geometry(): + """Plot geometry""" + _dll.openmc_plot_geometry() + + +def reset(): + """Reset tallies""" + _dll.openmc_reset() + + +def run(): + """Run simulation""" + _dll.openmc_run() + + +def tally_results(tally_id): + """Get tally results array + + Parameters + ---------- + tally_id : int + ID of tally + + Returns + ------- + numpy.ndarray + Array that exposes the internal tally results array + + """ + data = POINTER(c_double)() + shape = _int3() + _dll.openmc_tally_results(tally_id, data, shape) + return as_array(data, tuple(shape[::-1])) + + +@contextmanager +def run_in_memory(intracomm=None): + """Provides context manager for calling OpenMC shared library functions. + + This function is intended to be used in a 'with' statement and ensures that + OpenMC is properly initialized/finalized. At the completion of the 'with' + block, all memory that was allocated during the block is freed. For + example:: + + with openmc.capi.run_in_memory(): + for i in range(n_iters): + openmc.capi.reset() + do_stuff() + openmc.capi.run() + + Parameters + ---------- + intracomm : mpi4py.MPI.Intracomm or None + MPI intracommunicator + + """ + init(intracomm) + yield + finalize() # Determine shared-library suffix if sys.platform == 'darwin': - suffix = 'dylib' + _suffix = 'dylib' else: - suffix = 'so' + _suffix = 'so' # Open shared library -filename = pkg_resources.resource_filename( - __name__, '_libopenmc.{}'.format(suffix)) +_filename = pkg_resources.resource_filename( + __name__, '_libopenmc.{}'.format(_suffix)) try: - lib = OpenMCLibrary(filename) + _dll = CDLL(_filename) + _available = True except OSError: warn("OpenMC shared library is not available from the Python API. This " - "means you will not be able to use openmc.lib to make in-memory " + "means you will not be able to use openmc.capi to make in-memory " "calls to OpenMC.") - lib = None + _available = False + +if _available: + # Set argument/return types + _dll.openmc_calculate_volumes.restype = None + _dll.openmc_cell_set_temperature.argtypes = [ + c_int32, c_double, POINTER(c_int32)] + _dll.openmc_cell_set_temperature.restype = c_int + _dll.openmc_cell_set_temperature.errcheck = _error_handler + _dll.openmc_finalize.restype = None + _dll.openmc_find.argtypes = [ + POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] + _dll.openmc_find.restype = c_int + _dll.openmc_find.errcheck = _error_handler + _dll.openmc_init.argtypes = [POINTER(c_int)] + _dll.openmc_init.restype = None + _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] + _dll.openmc_get_keff.restype = c_int + _dll.openmc_get_keff.errcheck = _error_handler + _dll.openmc_load_nuclide.argtypes = [c_char_p] + _dll.openmc_load_nuclide.restype = c_int + _dll.openmc_load_nuclide.errcheck = _error_handler + + # Material interface + _dll.openmc_material_add_nuclide.argtypes = [ + c_int32, c_char_p, c_double] + _dll.openmc_material_add_nuclide.restype = c_int + _dll.openmc_material_add_nuclide.errcheck = _error_handler + _dll.openmc_material_get_densities.argtypes = [ + c_int32, _int_array, _double_array, POINTER(c_int)] + _dll.openmc_material_get_densities.restype = c_int + _dll.openmc_material_get_densities.errcheck = _error_handler + _dll.openmc_material_set_density.argtypes = [c_int32, c_double] + _dll.openmc_material_set_density.restype = c_int + _dll.openmc_material_set_density.errcheck = _error_handler + _dll.openmc_material_set_densities.argtypes = [ + c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] + _dll.openmc_material_set_densities.restype = c_int + _dll.openmc_material_set_densities.errcheck = _error_handler + + _dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] + _dll.openmc_nuclide_name.restype = c_int + _dll.openmc_nuclide_name.errcheck = _error_handler + _dll.openmc_plot_geometry.restype = None + _dll.openmc_run.restype = None + _dll.openmc_reset.restype = None + _dll.openmc_tally_results.argtypes = [ + c_int32, _double_array, POINTER(_int3)] + _dll.openmc_tally_results.restype = c_int + _dll.openmc_tally_results.errcheck = _error_handler From 21aa92e4ad92e153b60bf3b622adbab2e26aabb7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 08:23:46 -0500 Subject: [PATCH 065/229] Refactor C API bindings into Mapping and View classes --- openmc/capi.py | 310 +++++++++++++++++++++++++---------------- src/api.F90 | 364 +++++++++++++++++++++++++++---------------------- src/global.F90 | 9 +- 3 files changed, 403 insertions(+), 280 deletions(-) diff --git a/openmc/capi.py b/openmc/capi.py index 2e6b17d43..0706d4c77 100644 --- a/openmc/capi.py +++ b/openmc/capi.py @@ -10,10 +10,12 @@ automatically loaded. Calls to the OpenMC library can then be made, for example: """ +from collections import Mapping from contextlib import contextmanager from ctypes import CDLL, c_int, c_int32, c_double, c_char_p, POINTER import sys from warnings import warn +from weakref import WeakValueDictionary import numpy as np from numpy.ctypeslib import as_array @@ -52,6 +54,9 @@ def _error_handler(err, func, args): elif err == _error_code('e_nuclide_not_allocated'): raise MemoryError("Memory has not been allocated for nuclides.") + elif err == _error_code('e_nuclide_not_loaded'): + raise KeyError("No nuclide named '{}' has been loaded.") + elif err == _error_code('e_nuclide_not_in_library'): raise KeyError("Specified nuclide doesn't exist in the cross " "section library.") @@ -72,6 +77,172 @@ def _error_handler(err, func, args): raise Exception("Unknown error encountered (code {}).".format(err)) + + +class MaterialView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + mat_id = c_int32() + _dll.openmc_material_id(self._index, mat_id) + return mat_id.value + + @property + def nuclides(self): + return self._get_densities()[0] + return nuclides + + @property + def densities(self): + return self._get_densities()[1] + + def _get_densities(self): + """Get atom densities in a material. + + Returns + ------- + list of string + List of nuclide names + numpy.ndarray + Array of densities in atom/b-cm + + """ + # Allocate memory for arguments that are written to + nuclides = POINTER(c_int)() + densities = POINTER(c_double)() + n = c_int() + + # Get nuclide names and densities + _dll.openmc_material_get_densities(self._index, nuclides, densities, n) + + # Convert to appropriate types and return + nuclide_list = [NuclideView(nuclides[i]).name for i in range(n.value)] + density_array = as_array(densities, (n.value,)) + return nuclide_list, density_array + + def add_nuclide(name, density): + """Add a nuclide to a material. + + Parameters + ---------- + name : str + Name of nuclide, e.g. 'U235' + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_add_nuclide(self._index, name.encode(), density) + + def set_density(self, density): + """Set density of a material. + + Parameters + ---------- + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_set_density(self._index, density) + + def set_densities(self, nuclides, densities): + """Set the densities of a list of nuclides in a material + + Parameters + ---------- + nuclides : iterable of str + Nuclide names + densities : iterable of float + Corresponding densities in atom/b-cm + + """ + # Convert strings to an array of char* + nucs = (c_char_p * len(nuclides))() + nucs[:] = [x.encode() for x in nuclides] + + # Get numpy array as a double* + d = np.asarray(densities) + dp = d.ctypes.data_as(POINTER(c_double)) + + _dll.openmc_material_set_densities(self._index, len(nuclides), nucs, dp) + + +class _MaterialMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_material(key, index) + return MaterialView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield MaterialView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_materials').value + +materials = _MaterialMapping() + + +class NuclideView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def name(self): + """Name of nuclide with given index + + Parameter + --------- + index : int + Index in internal nuclides array + + Returns + ------- + str + Name of nuclide + + """ + name = c_char_p() + _dll.openmc_nuclide_name(self._index, name) + + # Find blank in name + i = 0 + while name.value[i:i+1] != b' ': + i += 1 + return name.value[:i].decode() + + +class _NuclideMapping(Mapping): + def __getitem__(self, key): + index = c_int() + _dll.openmc_get_nuclide(key.encode(), index) + return NuclideView(index) + + def __iter__(self): + for i in range(len(self)): + yield NuclideView(i + 1).name + + def __len__(self): + return c_int.in_dll(_dll, 'n_nuclides').value + +nuclides = _NuclideMapping() + + def calculate_volumes(): """Run stochastic volume calculation""" _dll.openmc_calculate_volumes() @@ -181,112 +352,6 @@ def load_nuclide(name): _dll.openmc_load_nuclide(name.encode()) -def material_add_nuclide(mat_id, name, density): - """Add a nuclide to a material. - - Parameters - ---------- - mat_id : int - ID of the material - name : str - Name of nuclide, e.g. 'U235' - density : float - Density in atom/b-cm - - """ - _dll.openmc_material_add_nuclide(mat_id, name.encode(), density) - - -def material_get_densities(mat_id): - """Get atom densities in a material. - - Parameters - ---------- - mat_id : int - ID of the material - - Returns - ------- - list of string - List of nuclide names - numpy.ndarray - Array of densities in atom/b-cm - - """ - # Allocate memory for arguments that are written to - nuclides = POINTER(c_int)() - densities = POINTER(c_double)() - n = c_int() - - # Get nuclide names and densities - _dll.openmc_material_get_densities(mat_id, nuclides, densities, n) - - # Convert to appropriate types and return - nuclide_list = [nuclide_name(nuclides[i]) for i in range(n.value)] - density_array = as_array(densities, (n.value,)) - return nuclide_list, density_array - - -def material_set_density(mat_id, density): - """Set density of a material. - - Parameters - ---------- - mat_id : int - ID of the material - density : float - Density in atom/b-cm - - """ - _dll.openmc_material_set_density(mat_id, density) - - -def material_set_densities(mat_id, nuclides, densities): - """Set the densities of a list of nuclides in a material - - Parameters - ---------- - mat_id : int - ID of the material - nuclides : iterable of str - Nuclide names - densities : iterable of float - Corresponding densities in atom/b-cm - - """ - # Convert strings to an array of char* - nucs = (c_char_p * len(nuclides))() - nucs[:] = [x.encode() for x in nuclides] - - # Get numpy array as a double* - d = np.asarray(densities) - dp = d.ctypes.data_as(POINTER(c_double)) - - _dll.openmc_material_set_densities(mat_id, len(nuclides), nucs, dp) - - -def nuclide_name(index): - """Name of nuclide with given index - - Parameter - --------- - index : int - Index in internal nuclides array - - Returns - ------- - str - Name of nuclide - - """ - name = c_char_p() - _dll.openmc_nuclide_name(index, name) - - # Find blank in name - i = 0 - while name.value[i:i+1] != b' ': - i += 1 - return name.value[:i].decode() def plot_geometry(): @@ -368,13 +433,9 @@ except OSError: "calls to OpenMC.") _available = False +# Set argument/return types if _available: - # Set argument/return types _dll.openmc_calculate_volumes.restype = None - _dll.openmc_cell_set_temperature.argtypes = [ - c_int32, c_double, POINTER(c_int32)] - _dll.openmc_cell_set_temperature.restype = c_int - _dll.openmc_cell_set_temperature.errcheck = _error_handler _dll.openmc_finalize.restype = None _dll.openmc_find.argtypes = [ POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] @@ -385,15 +446,24 @@ if _available: _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] _dll.openmc_get_keff.restype = c_int _dll.openmc_get_keff.errcheck = _error_handler - _dll.openmc_load_nuclide.argtypes = [c_char_p] - _dll.openmc_load_nuclide.restype = c_int - _dll.openmc_load_nuclide.errcheck = _error_handler - # Material interface + # Cell functions + _dll.openmc_cell_set_temperature.argtypes = [ + c_int32, c_double, POINTER(c_int32)] + _dll.openmc_cell_set_temperature.restype = c_int + _dll.openmc_cell_set_temperature.errcheck = _error_handler + + # Material functions + _dll.openmc_get_material.argtypes = [c_int32, POINTER(c_int32)] + _dll.openmc_get_material.restype = c_int + _dll.openmc_get_material.errcheck = _error_handler _dll.openmc_material_add_nuclide.argtypes = [ c_int32, c_char_p, c_double] _dll.openmc_material_add_nuclide.restype = c_int _dll.openmc_material_add_nuclide.errcheck = _error_handler + _dll.openmc_material_id.argtypes = [c_int32, POINTER(c_int32)] + _dll.openmc_material_id.restype = c_int + _dll.openmc_material_id.errcheck = _error_handler _dll.openmc_material_get_densities.argtypes = [ c_int32, _int_array, _double_array, POINTER(c_int)] _dll.openmc_material_get_densities.restype = c_int @@ -406,12 +476,22 @@ if _available: _dll.openmc_material_set_densities.restype = c_int _dll.openmc_material_set_densities.errcheck = _error_handler + # Nuclide functions + _dll.openmc_get_nuclide.argtypes = [c_char_p, POINTER(c_int)] + _dll.openmc_get_nuclide.restype = c_int + _dll.openmc_get_nuclide.errcheck = _error_handler + _dll.openmc_load_nuclide.argtypes = [c_char_p] + _dll.openmc_load_nuclide.restype = c_int + _dll.openmc_load_nuclide.errcheck = _error_handler _dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] _dll.openmc_nuclide_name.restype = c_int _dll.openmc_nuclide_name.errcheck = _error_handler + _dll.openmc_plot_geometry.restype = None _dll.openmc_run.restype = None _dll.openmc_reset.restype = None + + # Tally functions _dll.openmc_tally_results.argtypes = [ c_int32, _double_array, POINTER(_int3)] _dll.openmc_tally_results.restype = c_int diff --git a/src/api.F90 b/src/api.F90 index 6b71bf2fc..0d4c50f41 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -27,8 +27,11 @@ module openmc_api public :: openmc_finalize public :: openmc_find public :: openmc_get_keff + public :: openmc_get_material + public :: openmc_get_nuclide public :: openmc_init public :: openmc_load_nuclide + public :: openmc_material_id public :: openmc_material_add_nuclide public :: openmc_material_get_densities public :: openmc_material_set_density @@ -46,11 +49,12 @@ module openmc_api integer(C_INT), public, bind(C) :: E_CELL_INVALID_ID = -4 integer(C_INT), public, bind(C) :: E_CELL_NOT_FOUND = -5 integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_ALLOCATED = -6 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -7 - integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -8 - integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -9 - integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -10 - integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -11 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_LOADED = -7 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -8 + integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -9 + integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -10 + integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -11 + integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 contains @@ -223,11 +227,60 @@ contains end function openmc_find !=============================================================================== -! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library +! OPENMC_GET_MATERIAL returns the index in the materials array of a material +! with a given ID +!=============================================================================== + + function openmc_get_material(id, index) result(err) bind(C) + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(materials)) then + if (material_dict % has_key(id)) then + index = material_dict % get_key(id) + err = 0 + else + err = E_MATERIAL_INVALID_ID + end if + else + err = E_MATERIAL_NOT_ALLOCATED + end if + end function openmc_get_material + +!=============================================================================== +! OPENMC_GET_NUCLIDE returns the index in the nuclides array of a nuclide +! with a given name +!=============================================================================== + + function openmc_get_nuclide(name, index) result(err) bind(C) + character(kind=C_CHAR), intent(in) :: name(*) + integer(C_INT), intent(out) :: index + integer(C_INT) :: err + + character(:), allocatable :: name_ + + ! Copy array of C_CHARs to normal Fortran string + name_ = to_f_string(name) + + if (allocated(nuclides)) then + if (nuclide_dict % has_key(to_lower(name_))) then + index = nuclide_dict % get_key(to_lower(name_)) + err = 0 + else + err = E_NUCLIDE_NOT_LOADED + end if + else + err = E_NUCLIDE_NOT_ALLOCATED + end if + end function openmc_get_nuclide + +!=============================================================================== +! OPENMC_LOAD_LOAD loads a nuclide from the cross section library !=============================================================================== function openmc_load_nuclide(name) result(err) bind(C) - character(kind=C_CHAR) :: name(*) + character(kind=C_CHAR), intent(in) :: name(*) integer(C_INT) :: err integer :: i_library @@ -287,13 +340,13 @@ contains ! OPENMC_MATERIAL_ADD_NUCLIDE !=============================================================================== - function openmc_material_add_nuclide(id, name, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: id + function openmc_material_add_nuclide(index, name, density) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index character(kind=C_CHAR) :: name(*) real(C_DOUBLE), value, intent(in) :: density integer(C_INT) :: err - integer :: i, j, k, n + integer :: j, k, n real(8) :: awr integer, allocatable :: new_nuclide(:) real(8), allocatable :: new_density(:) @@ -302,55 +355,50 @@ contains name_ = to_f_string(name) err = E_UNASSIGNED - if (allocated(materials)) then - if (material_dict % has_key(id)) then - i = material_dict % get_key(id) - associate (m => materials(i)) - ! Check if nuclide is already in material - do j = 1, size(m % nuclide) - k = m % nuclide(j) - if (nuclides(k) % name == name_) then - awr = nuclides(k) % awr - m % density = m % density + density - m % atom_density(j) - m % density_gpcc = m % density_gpcc + (density - & - m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO - m % atom_density(j) = density - err = 0 - end if - end do - - ! If nuclide wasn't found, extend nuclide/density arrays - if (err /= 0) then - ! If nuclide hasn't been loaded, load it now - err = openmc_load_nuclide(name) - - if (err == 0) then - ! Extend arrays - n = size(m % nuclide) - allocate(new_nuclide(n + 1)) - new_nuclide(1:n) = m % nuclide - call move_alloc(FROM=new_nuclide, TO=m % nuclide) - - allocate(new_density(n + 1)) - new_density(1:n) = m % atom_density - call move_alloc(FROM=new_density, TO=m % atom_density) - - ! Append new nuclide/density - k = nuclide_dict % get_key(to_lower(name_)) - m % nuclide(n + 1) = k - m % atom_density(n + 1) = density - m % density = m % density + density - m % density_gpcc = m % density_gpcc + & - density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO - m % n_nuclides = n + 1 - end if + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + ! Check if nuclide is already in material + do j = 1, size(m % nuclide) + k = m % nuclide(j) + if (nuclides(k) % name == name_) then + awr = nuclides(k) % awr + m % density = m % density + density - m % atom_density(j) + m % density_gpcc = m % density_gpcc + (density - & + m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO + m % atom_density(j) = density + err = 0 end if - end associate - else - err = E_MATERIAL_INVALID_ID - end if + end do + + ! If nuclide wasn't found, extend nuclide/density arrays + if (err /= 0) then + ! If nuclide hasn't been loaded, load it now + err = openmc_load_nuclide(name) + + if (err == 0) then + ! Extend arrays + n = size(m % nuclide) + allocate(new_nuclide(n + 1)) + new_nuclide(1:n) = m % nuclide + call move_alloc(FROM=new_nuclide, TO=m % nuclide) + + allocate(new_density(n + 1)) + new_density(1:n) = m % atom_density + call move_alloc(FROM=new_density, TO=m % atom_density) + + ! Append new nuclide/density + k = nuclide_dict % get_key(to_lower(name_)) + m % nuclide(n + 1) = k + m % atom_density(n + 1) = density + m % density = m % density + density + m % density_gpcc = m % density_gpcc + & + density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO + m % n_nuclides = n + 1 + end if + end if + end associate else - err = E_MATERIAL_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_material_add_nuclide @@ -360,39 +408,115 @@ contains ! material !=============================================================================== - function openmc_material_get_densities(id, nuclides, densities, n) & + function openmc_material_get_densities(index, nuclides, densities, n) & result(err) bind(C) - integer(C_INT32_T), intent(in), value :: id + integer(C_INT32_T), value :: index type(C_PTR), intent(out) :: nuclides type(C_PTR), intent(out) :: densities integer(C_INT), intent(out) :: n integer(C_INT) :: err - integer :: i - - nuclides = C_NULL_PTR - densities = C_NULL_PTR - n = -1 err = E_UNASSIGNED - if (allocated(materials)) then - if (material_dict % has_key(id)) then - i = material_dict % get_key(id) - associate (m => materials(i)) - if (allocated(m % atom_density)) then - nuclides = C_LOC(m % nuclide(1)) - densities = C_LOC(m % atom_density(1)) - n = size(m % atom_density) - err = 0 - end if - end associate - else - err = E_MATERIAL_INVALID_ID - end if + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + if (allocated(m % atom_density)) then + nuclides = C_LOC(m % nuclide(1)) + densities = C_LOC(m % atom_density(1)) + n = size(m % atom_density) + err = 0 + end if + end associate else - err = E_MATERIAL_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_material_get_densities +!=============================================================================== +! OPENMC_MATERIAL_ID returns the ID of a material +!=============================================================================== + + function openmc_material_id(index, id) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(materials)) then + id = materials(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_id + +!=============================================================================== +! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm +!=============================================================================== + + function openmc_material_set_density(index, density) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index + real(C_DOUBLE), value, intent(in) :: density + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + err = m % set_density(density, nuclides) + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_set_density + +!=============================================================================== +! OPENMC_MATERIAL_SET_DENSITIES sets the densities for a list of nuclides in a +! material. If the nuclides don't already exist in the material, they will be +! added +!=============================================================================== + + function openmc_material_set_densities(index, n, name, density) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), value, intent(in) :: n + type(C_PTR), intent(in) :: name(n) + real(C_DOUBLE), intent(in) :: density(n) + integer(C_INT) :: err + + integer :: i, j, k + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: name_ + + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(name(i), string, [10]) + name_ = to_f_string(string) + + ! Find corresponding nuclide and set density + err = E_UNASSIGNED + do j = 1, size(m % nuclide) + k = m % nuclide(j) + if (nuclides(k) % name == name_) then + m % atom_density(j) = density(i) + err = 0 + end if + end do + + ! If nuclide wasn't found, try to load it + if (err /= 0) then + err = openmc_material_add_nuclide(index, string, density(i)) + if (err /= 0) return + end if + end do + + ! Set total density to the sum of the vector + err = m % set_density(sum(m % atom_density), nuclides) + end associate + else + err = E_OUT_OF_BOUNDS + end if + + end function openmc_material_set_densities + !=============================================================================== ! OPENMC_NUCLIDE_NAME returns the name of a nuclide with a given index !=============================================================================== @@ -405,7 +529,6 @@ contains character(C_CHAR), pointer :: name_ err = E_UNASSIGNED - name = C_NULL_PTR if (allocated(nuclides)) then if (index >= 1 .and. index <= size(nuclides)) then name_ => nuclides(index) % name(1:1) @@ -419,87 +542,6 @@ contains end if end function openmc_nuclide_name -!=============================================================================== -! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm -!=============================================================================== - - function openmc_material_set_density(id, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: id - real(C_DOUBLE), value, intent(in) :: density - integer(C_INT) :: err - - integer :: i - - err = -1 - if (allocated(materials)) then - if (material_dict % has_key(id)) then - i = material_dict % get_key(id) - associate (m => materials(i)) - err = m % set_density(density, nuclides) - end associate - else - err = E_MATERIAL_INVALID_ID - end if - else - err = E_MATERIAL_NOT_ALLOCATED - end if - end function openmc_material_set_density - -!=============================================================================== -! OPENMC_MATERIAL_SET_DENSITIES sets the densities for a list of nuclides in a -! material. If the nuclides don't already exist in the material, they will be -! added -!=============================================================================== - - function openmc_material_set_densities(id, n, name, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: id - integer(C_INT), value, intent(in) :: n - type(C_PTR), intent(in) :: name(n) - real(C_DOUBLE), intent(in) :: density(n) - integer(C_INT) :: err - - integer :: i, j, k - character(C_CHAR), pointer :: string(:) - character(len=:, kind=C_CHAR), allocatable :: name_ - - err = E_UNASSIGNED - if (allocated(materials)) then - if (material_dict % has_key(id)) then - i = material_dict % get_key(id) - associate (m => materials(i)) - do i = 1, n - ! Convert C string to Fortran string - call c_f_pointer(name(i), string, [10]) - name_ = to_f_string(string) - - ! Find corresponding nuclide and set density - do j = 1, size(m % nuclide) - k = m % nuclide(j) - if (nuclides(k) % name == name_) then - m % atom_density(j) = density(i) - err = 0 - end if - end do - - ! If nuclide wasn't found, try to load it - if (err /= 0) then - err = openmc_material_add_nuclide(id, string, density(i)) - if (err /= 0) return - end if - end do - - ! Set total density to the sum of the vector - err = m % set_density(sum(m % atom_density), nuclides) - end associate - else - err = E_MATERIAL_INVALID_ID - end if - else - err = E_MATERIAL_NOT_ALLOCATED - end if - - end function openmc_material_set_densities - !=============================================================================== ! OPENMC_RESET resets all tallies !=============================================================================== diff --git a/src/global.F90 b/src/global.F90 index 9d9002e9c..5661cf2af 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -43,11 +43,11 @@ module global type(VolumeCalculation), allocatable :: volume_calcs(:) ! Size of main arrays - integer :: n_cells ! # of cells + integer(C_INT32_T), bind(C) :: n_cells ! # of cells integer :: n_universes ! # of universes integer :: n_lattices ! # of lattices integer :: n_surfaces ! # of surfaces - integer :: n_materials ! # of materials + integer(C_INT32_T), bind(C) :: n_materials ! # of materials integer :: n_plots ! # of plots ! These dictionaries provide a fast lookup mechanism -- the key is the @@ -73,7 +73,8 @@ module global ! ============================================================================ ! CROSS SECTION RELATED VARIABLES NEEDED REGARDLESS OF CE OR MG - integer :: n_nuclides_total ! Number of nuclide cross section tables + ! Number of nuclide cross section tables + integer(C_INT), bind(C, name='n_nuclides') :: n_nuclides_total ! Cross section caches type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide @@ -192,7 +193,7 @@ module global integer :: n_user_meshes = 0 ! # of structured user meshes integer :: n_filters = 0 ! # of filters integer :: n_user_filters = 0 ! # of user filters - integer :: n_tallies = 0 ! # of tallies + integer(C_INT32_T), bind(C) :: n_tallies = 0 ! # of tallies integer :: n_user_tallies = 0 ! # of user tallies ! Tally derivatives From d9e1d0d4f6725623cde361f51b083a5cad9fa118 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 08:29:56 -0500 Subject: [PATCH 066/229] Move Python bindins to C API into subpackage --- CMakeLists.txt | 2 +- openmc/{capi.py => capi/__init__.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename openmc/{capi.py => capi/__init__.py} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 386c07100..c21b44cc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,7 @@ target_link_libraries(${program} ${ldflags} libopenmc) add_custom_command(TARGET libopenmc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_CURRENT_SOURCE_DIR}/openmc/_$ + ${CMAKE_CURRENT_SOURCE_DIR}/openmc/capi/_$ COMMENT "Copying libopenmc to Python module directory") #=============================================================================== diff --git a/openmc/capi.py b/openmc/capi/__init__.py similarity index 100% rename from openmc/capi.py rename to openmc/capi/__init__.py From 692765ef4ac641276a16a4db153a33e6e9240423 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 08:43:48 -0500 Subject: [PATCH 067/229] Move material/nuclide related C API bindings into separate files --- openmc/capi/__init__.py | 261 ++++------------------------------------ openmc/capi/material.py | 147 ++++++++++++++++++++++ openmc/capi/nuclide.py | 86 +++++++++++++ 3 files changed, 256 insertions(+), 238 deletions(-) create mode 100644 openmc/capi/material.py create mode 100644 openmc/capi/nuclide.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 0706d4c77..f8beb2fd7 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -10,21 +10,36 @@ automatically loaded. Calls to the OpenMC library can then be made, for example: """ -from collections import Mapping from contextlib import contextmanager from ctypes import CDLL, c_int, c_int32, c_double, c_char_p, POINTER import sys from warnings import warn -from weakref import WeakValueDictionary -import numpy as np from numpy.ctypeslib import as_array import pkg_resources + +# Determine shared-library suffix +if sys.platform == 'darwin': + _suffix = 'dylib' +else: + _suffix = 'so' + +# Open shared library +_filename = pkg_resources.resource_filename( + __name__, '_libopenmc.{}'.format(_suffix)) +try: + _dll = CDLL(_filename) + _available = True +except OSError: + warn("OpenMC shared library is not available from the Python API. This " + "means you will not be able to use openmc.capi to make in-memory " + "calls to OpenMC.") + _available = False + + _int3 = c_int*3 _double3 = c_double*3 -_int_array = POINTER(POINTER(c_int)) -_double_array = POINTER(POINTER(c_double)) class GeometryError(Exception): @@ -77,172 +92,6 @@ def _error_handler(err, func, args): raise Exception("Unknown error encountered (code {}).".format(err)) - - -class MaterialView(object): - __instances = WeakValueDictionary() - def __new__(cls, *args): - if args not in cls.__instances: - instance = super().__new__(cls) - cls.__instances[args] = instance - return cls.__instances[args] - - def __init__(self, index): - self._index = index - - @property - def id(self): - mat_id = c_int32() - _dll.openmc_material_id(self._index, mat_id) - return mat_id.value - - @property - def nuclides(self): - return self._get_densities()[0] - return nuclides - - @property - def densities(self): - return self._get_densities()[1] - - def _get_densities(self): - """Get atom densities in a material. - - Returns - ------- - list of string - List of nuclide names - numpy.ndarray - Array of densities in atom/b-cm - - """ - # Allocate memory for arguments that are written to - nuclides = POINTER(c_int)() - densities = POINTER(c_double)() - n = c_int() - - # Get nuclide names and densities - _dll.openmc_material_get_densities(self._index, nuclides, densities, n) - - # Convert to appropriate types and return - nuclide_list = [NuclideView(nuclides[i]).name for i in range(n.value)] - density_array = as_array(densities, (n.value,)) - return nuclide_list, density_array - - def add_nuclide(name, density): - """Add a nuclide to a material. - - Parameters - ---------- - name : str - Name of nuclide, e.g. 'U235' - density : float - Density in atom/b-cm - - """ - _dll.openmc_material_add_nuclide(self._index, name.encode(), density) - - def set_density(self, density): - """Set density of a material. - - Parameters - ---------- - density : float - Density in atom/b-cm - - """ - _dll.openmc_material_set_density(self._index, density) - - def set_densities(self, nuclides, densities): - """Set the densities of a list of nuclides in a material - - Parameters - ---------- - nuclides : iterable of str - Nuclide names - densities : iterable of float - Corresponding densities in atom/b-cm - - """ - # Convert strings to an array of char* - nucs = (c_char_p * len(nuclides))() - nucs[:] = [x.encode() for x in nuclides] - - # Get numpy array as a double* - d = np.asarray(densities) - dp = d.ctypes.data_as(POINTER(c_double)) - - _dll.openmc_material_set_densities(self._index, len(nuclides), nucs, dp) - - -class _MaterialMapping(Mapping): - def __getitem__(self, key): - index = c_int32() - _dll.openmc_get_material(key, index) - return MaterialView(index.value) - - def __iter__(self): - for i in range(len(self)): - yield MaterialView(i + 1).id - - def __len__(self): - return c_int32.in_dll(_dll, 'n_materials').value - -materials = _MaterialMapping() - - -class NuclideView(object): - __instances = WeakValueDictionary() - def __new__(cls, *args): - if args not in cls.__instances: - instance = super().__new__(cls) - cls.__instances[args] = instance - return cls.__instances[args] - - def __init__(self, index): - self._index = index - - @property - def name(self): - """Name of nuclide with given index - - Parameter - --------- - index : int - Index in internal nuclides array - - Returns - ------- - str - Name of nuclide - - """ - name = c_char_p() - _dll.openmc_nuclide_name(self._index, name) - - # Find blank in name - i = 0 - while name.value[i:i+1] != b' ': - i += 1 - return name.value[:i].decode() - - -class _NuclideMapping(Mapping): - def __getitem__(self, key): - index = c_int() - _dll.openmc_get_nuclide(key.encode(), index) - return NuclideView(index) - - def __iter__(self): - for i in range(len(self)): - yield NuclideView(i + 1).name - - def __len__(self): - return c_int.in_dll(_dll, 'n_nuclides').value - -nuclides = _NuclideMapping() - - def calculate_volumes(): """Run stochastic volume calculation""" _dll.openmc_calculate_volumes() @@ -264,7 +113,6 @@ def cell_set_temperature(cell_id, T, instance=None): _dll.openmc_cell_set_temperature(cell_id, T, instance) - def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() @@ -340,20 +188,6 @@ def keff(): return tuple(k) -def load_nuclide(name): - """Load cross section data for a nuclide. - - Parameters - ---------- - name : str - Name of nuclide, e.g. 'U235' - - """ - _dll.openmc_load_nuclide(name.encode()) - - - - def plot_geometry(): """Plot geometry""" _dll.openmc_plot_geometry() @@ -415,24 +249,6 @@ def run_in_memory(intracomm=None): finalize() -# Determine shared-library suffix -if sys.platform == 'darwin': - _suffix = 'dylib' -else: - _suffix = 'so' - -# Open shared library -_filename = pkg_resources.resource_filename( - __name__, '_libopenmc.{}'.format(_suffix)) -try: - _dll = CDLL(_filename) - _available = True -except OSError: - warn("OpenMC shared library is not available from the Python API. This " - "means you will not be able to use openmc.capi to make in-memory " - "calls to OpenMC.") - _available = False - # Set argument/return types if _available: _dll.openmc_calculate_volumes.restype = None @@ -453,40 +269,6 @@ if _available: _dll.openmc_cell_set_temperature.restype = c_int _dll.openmc_cell_set_temperature.errcheck = _error_handler - # Material functions - _dll.openmc_get_material.argtypes = [c_int32, POINTER(c_int32)] - _dll.openmc_get_material.restype = c_int - _dll.openmc_get_material.errcheck = _error_handler - _dll.openmc_material_add_nuclide.argtypes = [ - c_int32, c_char_p, c_double] - _dll.openmc_material_add_nuclide.restype = c_int - _dll.openmc_material_add_nuclide.errcheck = _error_handler - _dll.openmc_material_id.argtypes = [c_int32, POINTER(c_int32)] - _dll.openmc_material_id.restype = c_int - _dll.openmc_material_id.errcheck = _error_handler - _dll.openmc_material_get_densities.argtypes = [ - c_int32, _int_array, _double_array, POINTER(c_int)] - _dll.openmc_material_get_densities.restype = c_int - _dll.openmc_material_get_densities.errcheck = _error_handler - _dll.openmc_material_set_density.argtypes = [c_int32, c_double] - _dll.openmc_material_set_density.restype = c_int - _dll.openmc_material_set_density.errcheck = _error_handler - _dll.openmc_material_set_densities.argtypes = [ - c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] - _dll.openmc_material_set_densities.restype = c_int - _dll.openmc_material_set_densities.errcheck = _error_handler - - # Nuclide functions - _dll.openmc_get_nuclide.argtypes = [c_char_p, POINTER(c_int)] - _dll.openmc_get_nuclide.restype = c_int - _dll.openmc_get_nuclide.errcheck = _error_handler - _dll.openmc_load_nuclide.argtypes = [c_char_p] - _dll.openmc_load_nuclide.restype = c_int - _dll.openmc_load_nuclide.errcheck = _error_handler - _dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] - _dll.openmc_nuclide_name.restype = c_int - _dll.openmc_nuclide_name.errcheck = _error_handler - _dll.openmc_plot_geometry.restype = None _dll.openmc_run.restype = None _dll.openmc_reset.restype = None @@ -496,3 +278,6 @@ if _available: c_int32, _double_array, POINTER(_int3)] _dll.openmc_tally_results.restype = c_int _dll.openmc_tally_results.errcheck = _error_handler + + from .nuclide import * + from .material import * diff --git a/openmc/capi/material.py b/openmc/capi/material.py new file mode 100644 index 000000000..186395788 --- /dev/null +++ b/openmc/capi/material.py @@ -0,0 +1,147 @@ +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from weakref import WeakValueDictionary + +import numpy as np +from numpy.ctypeslib import as_array + +from openmc.capi import _dll, _error_handler, NuclideView + +__all__ = ['MaterialView', 'materials'] + + +# Material functions +_dll.openmc_get_material.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_material.restype = c_int +_dll.openmc_get_material.errcheck = _error_handler +_dll.openmc_material_add_nuclide.argtypes = [ + c_int32, c_char_p, c_double] +_dll.openmc_material_add_nuclide.restype = c_int +_dll.openmc_material_add_nuclide.errcheck = _error_handler +_dll.openmc_material_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_material_id.restype = c_int +_dll.openmc_material_id.errcheck = _error_handler +_dll.openmc_material_get_densities.argtypes = [ + c_int32, POINTER(POINTER(c_int)), POINTER(POINTER(c_double)), + POINTER(c_int)] +_dll.openmc_material_get_densities.restype = c_int +_dll.openmc_material_get_densities.errcheck = _error_handler +_dll.openmc_material_set_density.argtypes = [c_int32, c_double] +_dll.openmc_material_set_density.restype = c_int +_dll.openmc_material_set_density.errcheck = _error_handler +_dll.openmc_material_set_densities.argtypes = [ + c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] +_dll.openmc_material_set_densities.restype = c_int +_dll.openmc_material_set_densities.errcheck = _error_handler + + +class MaterialView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + mat_id = c_int32() + _dll.openmc_material_id(self._index, mat_id) + return mat_id.value + + @property + def nuclides(self): + return self._get_densities()[0] + return nuclides + + @property + def densities(self): + return self._get_densities()[1] + + def _get_densities(self): + """Get atom densities in a material. + + Returns + ------- + list of string + List of nuclide names + numpy.ndarray + Array of densities in atom/b-cm + + """ + # Allocate memory for arguments that are written to + nuclides = POINTER(c_int)() + densities = POINTER(c_double)() + n = c_int() + + # Get nuclide names and densities + _dll.openmc_material_get_densities(self._index, nuclides, densities, n) + + # Convert to appropriate types and return + nuclide_list = [NuclideView(nuclides[i]).name for i in range(n.value)] + density_array = as_array(densities, (n.value,)) + return nuclide_list, density_array + + def add_nuclide(name, density): + """Add a nuclide to a material. + + Parameters + ---------- + name : str + Name of nuclide, e.g. 'U235' + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_add_nuclide(self._index, name.encode(), density) + + def set_density(self, density): + """Set density of a material. + + Parameters + ---------- + density : float + Density in atom/b-cm + + """ + _dll.openmc_material_set_density(self._index, density) + + def set_densities(self, nuclides, densities): + """Set the densities of a list of nuclides in a material + + Parameters + ---------- + nuclides : iterable of str + Nuclide names + densities : iterable of float + Corresponding densities in atom/b-cm + + """ + # Convert strings to an array of char* + nucs = (c_char_p * len(nuclides))() + nucs[:] = [x.encode() for x in nuclides] + + # Get numpy array as a double* + d = np.asarray(densities) + dp = d.ctypes.data_as(POINTER(c_double)) + + _dll.openmc_material_set_densities(self._index, len(nuclides), nucs, dp) + + +class _MaterialMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_material(key, index) + return MaterialView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield MaterialView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_materials').value + +materials = _MaterialMapping() diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py new file mode 100644 index 000000000..7a2f7a37b --- /dev/null +++ b/openmc/capi/nuclide.py @@ -0,0 +1,86 @@ +from collections import Mapping +from ctypes import c_int, c_char_p, POINTER +from weakref import WeakValueDictionary + +import numpy as np +from numpy.ctypeslib import as_array + +from openmc.capi import _dll, _error_handler + + +__all__ = ['NuclideView', 'nuclides', 'load_nuclide'] + +# Nuclide functions +_dll.openmc_get_nuclide.argtypes = [c_char_p, POINTER(c_int)] +_dll.openmc_get_nuclide.restype = c_int +_dll.openmc_get_nuclide.errcheck = _error_handler +_dll.openmc_load_nuclide.argtypes = [c_char_p] +_dll.openmc_load_nuclide.restype = c_int +_dll.openmc_load_nuclide.errcheck = _error_handler +_dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)] +_dll.openmc_nuclide_name.restype = c_int +_dll.openmc_nuclide_name.errcheck = _error_handler + + +def load_nuclide(name): + """Load cross section data for a nuclide. + + Parameters + ---------- + name : str + Name of nuclide, e.g. 'U235' + + """ + _dll.openmc_load_nuclide(name.encode()) + + +class NuclideView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def name(self): + """Name of nuclide with given index + + Parameter + --------- + index : int + Index in internal nuclides array + + Returns + ------- + str + Name of nuclide + + """ + name = c_char_p() + _dll.openmc_nuclide_name(self._index, name) + + # Find blank in name + i = 0 + while name.value[i:i+1] != b' ': + i += 1 + return name.value[:i].decode() + + +class _NuclideMapping(Mapping): + def __getitem__(self, key): + index = c_int() + _dll.openmc_get_nuclide(key.encode(), index) + return NuclideView(index) + + def __iter__(self): + for i in range(len(self)): + yield NuclideView(i + 1).name + + def __len__(self): + return c_int.in_dll(_dll, 'n_nuclides').value + +nuclides = _NuclideMapping() From 050cb6e016ff6ddb29db07170a2d19a9eac9a259 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 09:04:41 -0500 Subject: [PATCH 068/229] Move cell/tally functionality into View/Mapping classes --- openmc/capi/__init__.py | 56 ++-------------- openmc/capi/cell.py | 68 +++++++++++++++++++ openmc/capi/tally.py | 71 ++++++++++++++++++++ src/api.F90 | 140 +++++++++++++++++++++++++++++----------- 4 files changed, 247 insertions(+), 88 deletions(-) create mode 100644 openmc/capi/cell.py create mode 100644 openmc/capi/tally.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index f8beb2fd7..b3b5731c1 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -38,8 +38,6 @@ except OSError: _available = False -_int3 = c_int*3 -_double3 = c_double*3 class GeometryError(Exception): @@ -97,22 +95,6 @@ def calculate_volumes(): _dll.openmc_calculate_volumes() -def cell_set_temperature(cell_id, T, instance=None): - """Set the temperature of a cell - - Parameters - ---------- - cell_id : int - ID of the cell - T : float - Temperature in K - instance : int or None - Which instance of the cell - - """ - _dll.openmc_cell_set_temperature(cell_id, T, instance) - - def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() @@ -149,7 +131,7 @@ def find(xyz, rtype='cell'): # Call openmc_find uid = c_int32() instance = c_int32() - _dll.openmc_find(_double3(*xyz), r_int, uid, instance) + _dll.openmc_find((c_double*3)(*xyz), r_int, uid, instance) return (uid.value if uid != 0 else None), instance.value @@ -203,25 +185,6 @@ def run(): _dll.openmc_run() -def tally_results(tally_id): - """Get tally results array - - Parameters - ---------- - tally_id : int - ID of tally - - Returns - ------- - numpy.ndarray - Array that exposes the internal tally results array - - """ - data = POINTER(c_double)() - shape = _int3() - _dll.openmc_tally_results(tally_id, data, shape) - return as_array(data, tuple(shape[::-1])) - @contextmanager def run_in_memory(intracomm=None): @@ -254,7 +217,7 @@ if _available: _dll.openmc_calculate_volumes.restype = None _dll.openmc_finalize.restype = None _dll.openmc_find.argtypes = [ - POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] + POINTER(c_double*3), c_int, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_find.restype = c_int _dll.openmc_find.errcheck = _error_handler _dll.openmc_init.argtypes = [POINTER(c_int)] @@ -262,22 +225,11 @@ if _available: _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] _dll.openmc_get_keff.restype = c_int _dll.openmc_get_keff.errcheck = _error_handler - - # Cell functions - _dll.openmc_cell_set_temperature.argtypes = [ - c_int32, c_double, POINTER(c_int32)] - _dll.openmc_cell_set_temperature.restype = c_int - _dll.openmc_cell_set_temperature.errcheck = _error_handler - _dll.openmc_plot_geometry.restype = None _dll.openmc_run.restype = None _dll.openmc_reset.restype = None - # Tally functions - _dll.openmc_tally_results.argtypes = [ - c_int32, _double_array, POINTER(_int3)] - _dll.openmc_tally_results.restype = c_int - _dll.openmc_tally_results.errcheck = _error_handler - from .nuclide import * from .material import * + from .cell import * + from .tally import * diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py new file mode 100644 index 000000000..fba34db85 --- /dev/null +++ b/openmc/capi/cell.py @@ -0,0 +1,68 @@ +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from weakref import WeakValueDictionary + +import numpy as np + +from openmc.capi import _dll, _error_handler + +__all__ = ['CellView', 'cells'] + +# Cell functions +_dll.openmc_cell_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_cell_id.restype = c_int +_dll.openmc_cell_id.errcheck = _error_handler +_dll.openmc_cell_set_temperature.argtypes = [ + c_int32, c_double, POINTER(c_int32)] +_dll.openmc_cell_set_temperature.restype = c_int +_dll.openmc_cell_set_temperature.errcheck = _error_handler +_dll.openmc_get_cell.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_cell.restype = c_int +_dll.openmc_get_cell.errcheck = _error_handler + + +class CellView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + cell_id = c_int32() + _dll.openmc_cell_id(self._index, cell_id) + return cell_id.value + + def set_temperature(self, T, instance=None): + """Set the temperature of a cell + + Parameters + ---------- + T : float + Temperature in K + instance : int or None + Which instance of the cell + + """ + _dll.openmc_cell_set_temperature(self._index, T, instance) + + +class _CellMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_cell(key, index) + return CellView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield CellView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_cells').value + +cells = _CellMapping() diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py new file mode 100644 index 000000000..f60d94e92 --- /dev/null +++ b/openmc/capi/tally.py @@ -0,0 +1,71 @@ +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from weakref import WeakValueDictionary + +from numpy.ctypeslib import as_array + +from openmc.capi import _dll, _error_handler, NuclideView + + +__all__ = ['TallyView', 'tallies'] + +# Tally functions +_dll.openmc_get_tally.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_tally.restype = c_int +_dll.openmc_get_tally.errcheck = _error_handler +_dll.openmc_tally_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_tally_id.restype = c_int +_dll.openmc_tally_id.errcheck = _error_handler +_dll.openmc_tally_results.argtypes = [ + c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] +_dll.openmc_tally_results.restype = c_int +_dll.openmc_tally_results.errcheck = _error_handler + + +class TallyView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + tally_id = c_int32() + _dll.openmc_tally_id(self._index, tally_id) + return tally_id.value + + @property + def results(self): + """Get tally results array + + Returns + ------- + numpy.ndarray + Array that exposes the internal tally results array + + """ + data = POINTER(c_double)() + shape = (c_int*3)() + _dll.openmc_tally_results(self._index, data, shape) + return as_array(data, tuple(shape[::-1])) + + +class _TallyMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_tally(key, index) + return TallyView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield TallyView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_tallies').value + +tallies = _TallyMapping() diff --git a/src/api.F90 b/src/api.F90 index 0d4c50f41..6d50ca51e 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -23,12 +23,15 @@ module openmc_api private public :: openmc_calculate_volumes + public :: openmc_cell_id public :: openmc_cell_set_temperature public :: openmc_finalize public :: openmc_find + public :: openmc_get_cell public :: openmc_get_keff public :: openmc_get_material public :: openmc_get_nuclide + public :: openmc_get_tally public :: openmc_init public :: openmc_load_nuclide public :: openmc_material_id @@ -40,6 +43,7 @@ module openmc_api public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run + public :: openmc_tally_id public :: openmc_tally_results ! Error codes @@ -58,12 +62,29 @@ module openmc_api contains +!=============================================================================== +! OPENMC_CELL_ID returns the ID of a cell +!=============================================================================== + + function openmc_cell_id(index, id) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(cells)) then + id = cells(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_cell_id + !=============================================================================== ! OPENMC_CELL_SET_TEMPERATURE sets the temperature of a cell !=============================================================================== - function openmc_cell_set_temperature(id, T, instance) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: id ! id of cell + function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index real(C_DOUBLE), value, intent(in) :: T integer(C_INT32_T), optional, intent(in) :: instance integer(C_INT) :: err @@ -71,28 +92,23 @@ contains integer :: i, n err = E_UNASSIGNED - if (allocated(cells)) then - if (cell_dict % has_key(id)) then - i = cell_dict % get_key(id) - associate (c => cells(i)) - if (allocated(c % sqrtkT)) then - n = size(c % sqrtkT) - if (present(instance) .and. n > 1) then - if (instance >= 0 .and. instance < n) then - c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T) - err = 0 - end if - else - c % sqrtkT(:) = sqrt(K_BOLTZMANN * T) + if (index >= 1 .and. index <= size(cells)) then + associate (c => cells(i)) + if (allocated(c % sqrtkT)) then + n = size(c % sqrtkT) + if (present(instance) .and. n > 1) then + if (instance >= 0 .and. instance < n) then + c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T) err = 0 end if + else + c % sqrtkT(:) = sqrt(K_BOLTZMANN * T) + err = 0 end if - end associate - else - err = E_CELL_INVALID_ID - end if + end if + end associate else - err = E_CELL_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_cell_set_temperature @@ -226,6 +242,27 @@ contains end function openmc_find +!=============================================================================== +! OPENMC_GET_CELL returns the index in the cells array of a cell with a given ID +!=============================================================================== + + function openmc_get_cell(id, index) result(err) bind(C) + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(cells)) then + if (cell_dict % has_key(id)) then + index = cell_dict % get_key(id) + err = 0 + else + err = E_CELL_INVALID_ID + end if + else + err = E_CELL_NOT_ALLOCATED + end if + end function openmc_get_cell + !=============================================================================== ! OPENMC_GET_MATERIAL returns the index in the materials array of a material ! with a given ID @@ -275,6 +312,28 @@ contains end if end function openmc_get_nuclide +!=============================================================================== +! OPENMC_GET_TALLY returns the index in the tallies array of a tally +! with a given ID +!=============================================================================== + + function openmc_get_tally(id, index) result(err) bind(C) + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(tallies)) then + if (tally_dict % has_key(id)) then + index = tally_dict % get_key(id) + err = 0 + else + err = E_TALLY_INVALID_ID + end if + else + err = E_TALLY_NOT_ALLOCATED + end if + end function openmc_get_tally + !=============================================================================== ! OPENMC_LOAD_LOAD loads a nuclide from the cross section library !=============================================================================== @@ -581,35 +640,44 @@ contains end subroutine openmc_reset +!=============================================================================== +! OPENMC_TALLY_ID returns the ID of a tally +!=============================================================================== + + function openmc_tally_id(index, id) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(tallies)) then + id = tallies(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_id + !=============================================================================== ! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its ! shape. This allows a user to obtain in-memory tally results from Python ! directly. !=============================================================================== - function openmc_tally_results(id, ptr, shape_) result(err) bind(C) - integer(C_INT32_T), intent(in), value :: id + function openmc_tally_results(index, ptr, shape_) result(err) bind(C) + integer(C_INT32_T), intent(in), value :: index type(C_PTR), intent(out) :: ptr integer(C_INT), intent(out) :: shape_(3) integer(C_INT) :: err - integer :: i - - ptr = C_NULL_PTR err = E_UNASSIGNED - if (allocated(tallies)) then - if (tally_dict % has_key(id)) then - i = tally_dict % get_key(id) - if (allocated(tallies(i) % results)) then - ptr = C_LOC(tallies(i) % results(1,1,1)) - shape_(:) = shape(tallies(i) % results) - err = 0 - end if - else - err = E_TALLY_INVALID_ID + if (index >= 1 .and. index <= size(tallies)) then + if (allocated(tallies(index) % results)) then + ptr = C_LOC(tallies(index) % results(1,1,1)) + shape_(:) = shape(tallies(index) % results) + err = 0 end if else - err = E_TALLY_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_tally_results From 20331519beb2e940fff582f46423e4635bc61684 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 15:15:39 -0500 Subject: [PATCH 069/229] Add TallyView.nuclides --- openmc/capi/tally.py | 12 ++++++++++++ src/api.F90 | 27 ++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index f60d94e92..b7139bcb6 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -16,6 +16,10 @@ _dll.openmc_get_tally.errcheck = _error_handler _dll.openmc_tally_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_id.restype = c_int _dll.openmc_tally_id.errcheck = _error_handler +_dll.openmc_tally_nuclides.argtypes = [ + c_int32, POINTER(POINTER(c_int)), POINTER(c_int)] +_dll.openmc_tally_nuclides.restype = c_int +_dll.openmc_tally_nuclides.errcheck = _error_handler _dll.openmc_tally_results.argtypes = [ c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] _dll.openmc_tally_results.restype = c_int @@ -39,6 +43,14 @@ class TallyView(object): _dll.openmc_tally_id(self._index, tally_id) return tally_id.value + @property + def nuclides(self): + nucs = POINTER(c_int)() + n = c_int() + _dll.openmc_tally_nuclides(self._index, nucs, n) + return [NuclideView(nucs[i]).name if nucs[i] > 0 else 'total' + for i in range(n.value)] + @property def results(self): """Get tally results array diff --git a/src/api.F90 b/src/api.F90 index 6d50ca51e..cd8a8a064 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -44,6 +44,7 @@ module openmc_api public :: openmc_reset public :: openmc_run public :: openmc_tally_id + public :: openmc_tally_nuclides public :: openmc_tally_results ! Error codes @@ -335,7 +336,7 @@ contains end function openmc_get_tally !=============================================================================== -! OPENMC_LOAD_LOAD loads a nuclide from the cross section library +! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library !=============================================================================== function openmc_load_nuclide(name) result(err) bind(C) @@ -657,6 +658,30 @@ contains end if end function openmc_tally_id +!=============================================================================== +! OPENMC_TALLY_NUCLIDES returns the list of nuclides assigned to a tally +!=============================================================================== + + function openmc_tally_nuclides(index, ptr, n) result(err) bind(C) + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: ptr + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % nuclide_bins)) then + ptr = C_LOC(t % nuclide_bins(1)) + n = size(t % nuclide_bins) + err = 0 + end if + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_nuclides + !=============================================================================== ! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its ! shape. This allows a user to obtain in-memory tally results from Python From a1a29aeb02911fa12b10823615d0e73c79c9e2c1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 15:49:36 -0500 Subject: [PATCH 070/229] Add TallyView.nuclides setter --- openmc/capi/cell.py | 8 ++--- openmc/capi/material.py | 8 ++--- openmc/capi/tally.py | 25 ++++++++----- src/api.F90 | 79 +++++++++++++++++++++++++++++++++-------- 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index fba34db85..1dbe50d51 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -9,9 +9,9 @@ from openmc.capi import _dll, _error_handler __all__ = ['CellView', 'cells'] # Cell functions -_dll.openmc_cell_id.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_cell_id.restype = c_int -_dll.openmc_cell_id.errcheck = _error_handler +_dll.openmc_cell_get_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_cell_get_id.restype = c_int +_dll.openmc_cell_get_id.errcheck = _error_handler _dll.openmc_cell_set_temperature.argtypes = [ c_int32, c_double, POINTER(c_int32)] _dll.openmc_cell_set_temperature.restype = c_int @@ -35,7 +35,7 @@ class CellView(object): @property def id(self): cell_id = c_int32() - _dll.openmc_cell_id(self._index, cell_id) + _dll.openmc_cell_get_id(self._index, cell_id) return cell_id.value def set_temperature(self, T, instance=None): diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 186395788..c917d3331 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -18,9 +18,9 @@ _dll.openmc_material_add_nuclide.argtypes = [ c_int32, c_char_p, c_double] _dll.openmc_material_add_nuclide.restype = c_int _dll.openmc_material_add_nuclide.errcheck = _error_handler -_dll.openmc_material_id.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_material_id.restype = c_int -_dll.openmc_material_id.errcheck = _error_handler +_dll.openmc_material_get_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_material_get_id.restype = c_int +_dll.openmc_material_get_id.errcheck = _error_handler _dll.openmc_material_get_densities.argtypes = [ c_int32, POINTER(POINTER(c_int)), POINTER(POINTER(c_double)), POINTER(c_int)] @@ -49,7 +49,7 @@ class MaterialView(object): @property def id(self): mat_id = c_int32() - _dll.openmc_material_id(self._index, mat_id) + _dll.openmc_material_get_id(self._index, mat_id) return mat_id.value @property diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index b7139bcb6..b1fc49d04 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -13,17 +13,20 @@ __all__ = ['TallyView', 'tallies'] _dll.openmc_get_tally.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_tally.restype = c_int _dll.openmc_get_tally.errcheck = _error_handler -_dll.openmc_tally_id.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_tally_id.restype = c_int -_dll.openmc_tally_id.errcheck = _error_handler -_dll.openmc_tally_nuclides.argtypes = [ +_dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_tally_get_id.restype = c_int +_dll.openmc_tally_get_id.errcheck = _error_handler +_dll.openmc_tally_get_nuclides.argtypes = [ c_int32, POINTER(POINTER(c_int)), POINTER(c_int)] -_dll.openmc_tally_nuclides.restype = c_int -_dll.openmc_tally_nuclides.errcheck = _error_handler +_dll.openmc_tally_get_nuclides.restype = c_int +_dll.openmc_tally_get_nuclides.errcheck = _error_handler _dll.openmc_tally_results.argtypes = [ c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] _dll.openmc_tally_results.restype = c_int _dll.openmc_tally_results.errcheck = _error_handler +_dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] +_dll.openmc_tally_set_nuclides.restype = c_int +_dll.openmc_tally_set_nuclides.errcheck = _error_handler class TallyView(object): @@ -40,14 +43,14 @@ class TallyView(object): @property def id(self): tally_id = c_int32() - _dll.openmc_tally_id(self._index, tally_id) + _dll.openmc_tally_get_id(self._index, tally_id) return tally_id.value @property def nuclides(self): nucs = POINTER(c_int)() n = c_int() - _dll.openmc_tally_nuclides(self._index, nucs, n) + _dll.openmc_tally_get_nuclides(self._index, nucs, n) return [NuclideView(nucs[i]).name if nucs[i] > 0 else 'total' for i in range(n.value)] @@ -66,6 +69,12 @@ class TallyView(object): _dll.openmc_tally_results(self._index, data, shape) return as_array(data, tuple(shape[::-1])) + @nuclides.setter + def nuclides(self, nuclides): + nucs = (c_char_p * len(nuclides))() + nucs[:] = [x.encode() for x in nuclides] + _dll.openmc_tally_set_nuclides(self._index, len(nuclides), nucs) + class _TallyMapping(Mapping): def __getitem__(self, key): diff --git a/src/api.F90 b/src/api.F90 index cd8a8a064..a06866425 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -23,7 +23,7 @@ module openmc_api private public :: openmc_calculate_volumes - public :: openmc_cell_id + public :: openmc_cell_get_id public :: openmc_cell_set_temperature public :: openmc_finalize public :: openmc_find @@ -34,8 +34,8 @@ module openmc_api public :: openmc_get_tally public :: openmc_init public :: openmc_load_nuclide - public :: openmc_material_id public :: openmc_material_add_nuclide + public :: openmc_material_get_id public :: openmc_material_get_densities public :: openmc_material_set_density public :: openmc_material_set_densities @@ -43,9 +43,10 @@ module openmc_api public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run - public :: openmc_tally_id - public :: openmc_tally_nuclides + public :: openmc_tally_get_id + public :: openmc_tally_get_nuclides public :: openmc_tally_results + public :: openmc_tally_set_nuclides ! Error codes integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1 @@ -67,7 +68,7 @@ contains ! OPENMC_CELL_ID returns the ID of a cell !=============================================================================== - function openmc_cell_id(index, id) result(err) bind(C) + function openmc_cell_get_id(index, id) result(err) bind(C) integer(C_INT32_T), value :: index integer(C_INT32_T), intent(out) :: id integer(C_INT) :: err @@ -78,7 +79,7 @@ contains else err = E_OUT_OF_BOUNDS end if - end function openmc_cell_id + end function openmc_cell_get_id !=============================================================================== ! OPENMC_CELL_SET_TEMPERATURE sets the temperature of a cell @@ -492,10 +493,10 @@ contains end function openmc_material_get_densities !=============================================================================== -! OPENMC_MATERIAL_ID returns the ID of a material +! OPENMC_MATERIAL_GET_ID returns the ID of a material !=============================================================================== - function openmc_material_id(index, id) result(err) bind(C) + function openmc_material_get_id(index, id) result(err) bind(C) integer(C_INT32_T), value :: index integer(C_INT32_T), intent(out) :: id integer(C_INT) :: err @@ -506,7 +507,7 @@ contains else err = E_OUT_OF_BOUNDS end if - end function openmc_material_id + end function openmc_material_get_id !=============================================================================== ! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm @@ -642,10 +643,10 @@ contains end subroutine openmc_reset !=============================================================================== -! OPENMC_TALLY_ID returns the ID of a tally +! OPENMC_TALLY_GET_ID returns the ID of a tally !=============================================================================== - function openmc_tally_id(index, id) result(err) bind(C) + function openmc_tally_get_id(index, id) result(err) bind(C) integer(C_INT32_T), value :: index integer(C_INT32_T), intent(out) :: id integer(C_INT) :: err @@ -656,13 +657,13 @@ contains else err = E_OUT_OF_BOUNDS end if - end function openmc_tally_id + end function openmc_tally_get_id !=============================================================================== ! OPENMC_TALLY_NUCLIDES returns the list of nuclides assigned to a tally !=============================================================================== - function openmc_tally_nuclides(index, ptr, n) result(err) bind(C) + function openmc_tally_get_nuclides(index, ptr, n) result(err) bind(C) integer(C_INT32_T), value :: index type(C_PTR), intent(out) :: ptr integer(C_INT), intent(out) :: n @@ -680,7 +681,7 @@ contains else err = E_OUT_OF_BOUNDS end if - end function openmc_tally_nuclides + end function openmc_tally_get_nuclides !=============================================================================== ! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its @@ -706,6 +707,56 @@ contains end if end function openmc_tally_results + function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT), value :: n + type(C_PTR), intent(in) :: nuclides(n) + integer(C_INT) :: err + + integer :: i + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: nuclide_ + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % nuclide_bins)) deallocate(t % nuclide_bins) + allocate(t % nuclide_bins(n)) + t % n_nuclide_bins = n + + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(nuclides(i), string, [10]) + nuclide_ = to_lower(to_f_string(string)) + + select case (nuclide_) + case ('total') + t % nuclide_bins(i) = -1 + case default + if (nuclide_dict % has_key(nuclide_)) then + t % nuclide_bins(i) = nuclide_dict % get_key(nuclide_) + else + err = E_NUCLIDE_NOT_LOADED + return + end if + end select + end do + + ! Recalculate total number of scoring bins + t % total_score_bins = t % n_score_bins * t % n_nuclide_bins + + ! (Re)allocate results array + if (allocated(t % results)) deallocate(t % results) + allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) + t % results(:,:,:) = ZERO + + err = 0 + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_nuclides + function to_f_string(c_string) result(f_string) character(kind=C_CHAR), intent(in) :: c_string(*) character(:), allocatable :: f_string From 894e95d9018678a453bd1164daeb764633ce29c9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 30 Jul 2017 08:13:45 -0500 Subject: [PATCH 071/229] Reset timers in openmc_reset --- src/api.F90 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/api.F90 b/src/api.F90 index a06866425..b31bf387a 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -640,6 +640,21 @@ contains call active_collision_tallies % clear() call active_tallies % clear() + ! Reset timers + call time_total % reset() + call time_total % reset() + call time_initialize % reset() + call time_read_xs % reset() + call time_unionize % reset() + call time_bank % reset() + call time_bank_sample % reset() + call time_bank_sendrecv % reset() + call time_tallies % reset() + call time_inactive % reset() + call time_active % reset() + call time_transport % reset() + call time_finalize % reset() + end subroutine openmc_reset !=============================================================================== From 1066489c66221bd6f100995d5275edd602f55d53 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 30 Jul 2017 08:28:05 -0500 Subject: [PATCH 072/229] Get rid of defaults for current_batch and current_gen --- src/api.F90 | 8 +++----- src/global.F90 | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index b31bf387a..77b3dd576 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -131,8 +131,6 @@ contains check_overlaps = .false. confidence_intervals = .false. create_fission_neutrons = .true. - current_batch = 0 - current_gen = 0 energy_cutoff = ZERO energy_max_neutron = INFINITY energy_min_neutron = ZERO @@ -144,12 +142,12 @@ contains legendre_to_tabular = .true. legendre_to_tabular_points = 33 n_batch_interval = 1 - n_filters = 0 - n_meshes = 0 + n_filters = 0 + n_meshes = 0 n_particles = 0 n_source_points = 0 n_state_points = 0 - n_tallies = 0 + n_tallies = 0 n_user_filters = 0 n_user_meshes = 0 n_user_tallies = 0 diff --git a/src/global.F90 b/src/global.F90 index 5661cf2af..2f47a9dce 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -222,8 +222,8 @@ module global integer :: n_inactive ! # of inactive batches integer :: n_active ! # of active batches integer :: gen_per_batch = 1 ! # of generations per batch - integer :: current_batch = 0 ! current batch - integer :: current_gen = 0 ! current generation within a batch + integer :: current_batch ! current batch + integer :: current_gen ! current generation within a batch integer :: total_gen = 0 ! total number of generations simulated ! ============================================================================ From 9edad4876f7c2c2dd6f1961aa437ccf69b0004da Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 30 Jul 2017 14:07:06 -0500 Subject: [PATCH 073/229] Add hard reset function --- openmc/capi/__init__.py | 14 +++++++++----- src/api.F90 | 23 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index b3b5731c1..6ae49c4ff 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -1,17 +1,19 @@ """Provides bindings to C functions defined by OpenMC shared library. When the :mod:`openmc` package is imported, the OpenMC shared library is -automatically loaded. Calls to the OpenMC library can then be made, for example: +automatically loaded. Calls to the OpenMC library can then be via functions or +objects in the :mod:`openmc.capi` subpackage, for example: .. code-block:: python openmc.capi.init() openmc.capi.run() + openmc.capi.finalize() """ from contextlib import contextmanager -from ctypes import CDLL, c_int, c_int32, c_double, c_char_p, POINTER +from ctypes import CDLL, c_int, c_int32, c_double, POINTER import sys from warnings import warn @@ -38,8 +40,6 @@ except OSError: _available = False - - class GeometryError(Exception): pass @@ -135,6 +135,10 @@ def find(xyz, rtype='cell'): return (uid.value if uid != 0 else None), instance.value +def hard_reset(): + _dll.openmc_hard_reset() + + def init(intracomm=None): """Initialize OpenMC @@ -185,7 +189,6 @@ def run(): _dll.openmc_run() - @contextmanager def run_in_memory(intracomm=None): """Provides context manager for calling OpenMC shared library functions. @@ -220,6 +223,7 @@ if _available: POINTER(c_double*3), c_int, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_find.restype = c_int _dll.openmc_find.errcheck = _error_handler + _dll.openmc_hard_reset.restype = None _dll.openmc_init.argtypes = [POINTER(c_int)] _dll.openmc_init.restype = None _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] diff --git a/src/api.F90 b/src/api.F90 index 77b3dd576..2c1fc968b 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -15,7 +15,7 @@ module openmc_api use input_xml, only: assign_0K_elastic_scattering, check_data_version use particle_header, only: Particle use plot, only: openmc_plot_geometry - use random_lcg, only: seed + use random_lcg, only: seed, initialize_prng use simulation, only: openmc_run use volume_calc, only: openmc_calculate_volumes @@ -32,6 +32,7 @@ module openmc_api public :: openmc_get_material public :: openmc_get_nuclide public :: openmc_get_tally + public :: openmc_hard_reset public :: openmc_init public :: openmc_load_nuclide public :: openmc_material_add_nuclide @@ -334,6 +335,24 @@ contains end if end function openmc_get_tally +!=============================================================================== +! OPENMC_HARD_RESET reset tallies and timers as well as the pseudorandom +! generator state +!=============================================================================== + + subroutine openmc_hard_reset() bind(C) + ! Reset all tallies and timers + call openmc_reset() + + ! Reset total generations and keff guess + keff = ONE + total_gen = 0 + + ! Reset the random number generator state + seed = 1_8 + call initialize_prng() + end subroutine openmc_hard_reset + !=============================================================================== ! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library !=============================================================================== @@ -602,7 +621,7 @@ contains end function openmc_nuclide_name !=============================================================================== -! OPENMC_RESET resets all tallies +! OPENMC_RESET resets tallies and timers !=============================================================================== subroutine openmc_reset() bind(C) From dae2a169e6daa1b6d58e513b15f6831983eaefe5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 31 Jul 2017 06:57:09 -0500 Subject: [PATCH 074/229] Get rid of mpi_err global variable --- src/api.F90 | 12 +++++------ src/cmfd_execute.F90 | 6 ++++++ src/eigenvalue.F90 | 5 +++++ src/initialize.F90 | 1 + src/main.F90 | 4 ++++ src/mesh.F90 | 3 +++ src/message_passing.F90 | 1 - src/simulation.F90 | 47 +++++++++++++++++++---------------------- src/state_point.F90 | 4 +++- src/tally.F90 | 7 +++--- src/volume_calc.F90 | 1 + 11 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 2c1fc968b..b767d1ab4 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -92,11 +92,11 @@ contains integer(C_INT32_T), optional, intent(in) :: instance integer(C_INT) :: err - integer :: i, n + integer :: n err = E_UNASSIGNED if (index >= 1 .and. index <= size(cells)) then - associate (c => cells(i)) + associate (c => cells(index)) if (allocated(c % sqrtkT)) then n = size(c % sqrtkT) if (present(instance) .and. n > 1) then @@ -122,7 +122,7 @@ contains subroutine openmc_finalize() bind(C) - integer :: hdf5_err + integer :: err ! Clear results call openmc_reset() @@ -190,14 +190,14 @@ contains call free_memory() ! Release compound datatypes - call h5tclose_f(hdf5_bank_t, hdf5_err) + call h5tclose_f(hdf5_bank_t, err) ! Close FORTRAN interface. - call h5close_f(hdf5_err) + call h5close_f(err) #ifdef MPI ! Free all MPI types - call MPI_TYPE_FREE(MPI_BANK, mpi_err) + call MPI_TYPE_FREE(MPI_BANK, err) #endif end subroutine openmc_finalize diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 0d4a9f4d3..e87bff930 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -108,6 +108,9 @@ contains real(8) :: hxyz(3) ! cell dimensions of current ijk cell real(8) :: vol ! volume of cell real(8),allocatable :: source(:,:,:,:) ! tmp source array for entropy +#ifdef MPI + integer :: mpi_err ! MPI error code +#endif ! Get maximum of spatial and group indices nx = cmfd % indices(1) @@ -232,6 +235,9 @@ contains logical :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh type(RegularMesh), pointer :: m ! point to mesh +#ifdef MPI + integer :: mpi_err +#endif ! Associate pointer m => meshes(n_user_meshes + 1) diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 9f4da7c82..accf80b31 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -40,6 +40,7 @@ contains & temp_sites(:) ! local array of extra sites on each node #ifdef MPI + integer :: mpi_err ! MPI error code integer(8) :: n ! number of sites to send/recv integer :: neighbor ! processor to send/recv data from #ifdef MPIF08 @@ -372,6 +373,9 @@ contains subroutine calculate_generation_keff() integer :: i ! overall generation +#ifdef MPI + integer :: mpi_err ! MPI error code +#endif ! Get keff for this generation by subtracting off the starting value keff_generation = global_tallies(RESULT_VALUE, K_TRACKLENGTH) - keff_generation @@ -614,6 +618,7 @@ contains logical :: sites_outside ! were there sites outside the ufs mesh? #ifdef MPI integer :: n ! total number of ufs mesh cells + integer :: mpi_err ! MPI error code #endif if (current_batch == 1 .and. current_gen == 1) then diff --git a/src/initialize.F90 b/src/initialize.F90 index 69479907e..1e29c638c 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -172,6 +172,7 @@ contains integer, intent(in) :: intracomm ! MPI intracommunicator #endif + integer :: mpi_err ! MPI error code integer :: bank_blocks(5) ! Count for each datatype #ifdef MPIF08 type(MPI_Datatype) :: bank_types(5) diff --git a/src/main.F90 b/src/main.F90 index b8c96927e..fadf9f3bb 100644 --- a/src/main.F90 +++ b/src/main.F90 @@ -9,6 +9,10 @@ program main implicit none +#ifdef MPI + integer :: mpi_err ! MPI error code +#endif + ! Initialize run -- when run with MPI, pass communicator #ifdef MPI #ifdef MPIF08 diff --git a/src/mesh.F90 b/src/mesh.F90 index 427710790..c25e3f7a6 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -144,6 +144,9 @@ contains integer :: ijk(3) ! indices on mesh integer :: n ! number of energy groups / size integer :: e_bin ! energy_bin +#ifdef MPI + integer :: mpi_err ! MPI error code +#endif logical :: in_mesh ! was single site outside mesh? logical :: outside ! was any site outside mesh? diff --git a/src/message_passing.F90 b/src/message_passing.F90 index 6c13b00e8..0f2b94d1a 100644 --- a/src/message_passing.F90 +++ b/src/message_passing.F90 @@ -16,7 +16,6 @@ module message_passing integer :: rank = 0 ! rank of process logical :: master = .true. ! master process? logical :: mpi_enabled = .false. ! is MPI in use and initialized? - integer :: mpi_err ! MPI error code #ifdef MPIF08 type(MPI_Datatype) :: MPI_BANK ! MPI datatype for fission bank type(MPI_Comm) :: mpi_intracomm ! MPI intra-communicator diff --git a/src/simulation.F90 b/src/simulation.F90 index 8a32493ca..b406679ce 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -285,6 +285,10 @@ contains subroutine finalize_batch() +#ifdef MPI + integer :: mpi_err ! MPI error code +#endif + ! Reduce tallies onto master process and accumulate call time_tallies % start() call accumulate_tallies() @@ -392,7 +396,11 @@ contains integer :: i ! loop index for tallies integer :: n ! size of arrays - real(8) :: temp(3) ! temporary array for communication +#ifdef MPI + integer :: mpi_err ! MPI error code + integer(8) :: temp + real(8) :: tempr(3) ! temporary array for communication +#endif !$omp parallel deallocate(micro_xs) @@ -420,18 +428,23 @@ contains ! These guys are needed so that non-master processes can calculate the ! combined estimate of k-effective - temp(1) = k_col_abs - temp(2) = k_col_tra - temp(3) = k_abs_tra - call MPI_BCAST(temp, 3, MPI_REAL8, 0, mpi_intracomm, mpi_err) - k_col_abs = temp(1) - k_col_tra = temp(2) - k_abs_tra = temp(3) + tempr(1) = k_col_abs + tempr(2) = k_col_tra + tempr(3) = k_abs_tra + call MPI_BCAST(tempr, 3, MPI_REAL8, 0, mpi_intracomm, mpi_err) + k_col_abs = tempr(1) + k_col_tra = tempr(2) + k_abs_tra = tempr(3) + + if (check_overlaps) then + call MPI_REDUCE(overlap_check_cnt, temp, n_cells, MPI_INTEGER8, & + MPI_SUM, 0, mpi_intracomm, mpi_err) + overlap_check_cnt = temp + end if #endif ! Write tally results to tallies.out if (output_tallies .and. master) call write_tallies() - if (check_overlaps) call reduce_overlap_count() ! Stop timers and show timing statistics call time_finalize%stop() @@ -444,20 +457,4 @@ contains end subroutine finalize_simulation -!=============================================================================== -! REDUCE_OVERLAP_COUNT accumulates cell overlap check counts to master -!=============================================================================== - - subroutine reduce_overlap_count() - - integer(8) :: temp - -#ifdef MPI - call MPI_REDUCE(overlap_check_cnt, temp, n_cells, MPI_INTEGER8, & - MPI_SUM, 0, mpi_intracomm, mpi_err) - overlap_check_cnt = temp -#endif - - end subroutine reduce_overlap_count - end module simulation diff --git a/src/state_point.F90 b/src/state_point.F90 index 301a4efdd..e2a476e7e 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -522,7 +522,8 @@ contains real(8), allocatable :: tally_temp(:,:,:) ! contiguous array of results real(8), target :: global_temp(3,N_GLOBAL_TALLIES) #ifdef MPI - real(8) :: dummy ! temporary receive buffer for non-root reduces + integer :: mpi_err ! MPI error code + real(8) :: dummy ! temporary receive buffer for non-root reduces #endif type(TallyObject) :: dummy_tally @@ -841,6 +842,7 @@ contains #else integer :: i #ifdef MPI + integer :: mpi_err ! MPI error code type(Bank), allocatable, target :: temp_source(:) #endif #endif diff --git a/src/tally.F90 b/src/tally.F90 index 8b52ad032..cf62412f0 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -4246,9 +4246,10 @@ contains subroutine reduce_tally_results() integer :: i - integer :: n ! number of filter bins - integer :: m ! number of score bins - integer :: n_bins ! total number of bins + integer :: n ! number of filter bins + integer :: m ! number of score bins + integer :: n_bins ! total number of bins + integer :: mpi_err ! MPI error code real(C_DOUBLE), allocatable :: tally_temp(:,:) ! contiguous array of results real(C_DOUBLE), allocatable :: tally_temp2(:,:) ! reduced contiguous results real(C_DOUBLE) :: temp(N_GLOBAL_TALLIES), temp2(N_GLOBAL_TALLIES) diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index 3659293b3..f8cf4085a 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -132,6 +132,7 @@ contains integer :: min_samples ! minimum number of samples per process integer :: remainder ! leftover samples from uneven divide #ifdef MPI + integer :: mpi_err ! MPI error code integer :: m ! index over materials integer :: n ! number of materials integer, allocatable :: data(:) ! array used to send number of hits From d0faebe11d00239bc012c16dc09f8b2a03aa55fc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 31 Jul 2017 08:18:55 -0500 Subject: [PATCH 075/229] Update documentation --- docs/source/capi/index.rst | 190 +++++++++++++++++++++++++++++---- docs/source/pythonapi/capi.rst | 25 ++++- openmc/capi/__init__.py | 7 +- openmc/capi/cell.py | 17 +++ openmc/capi/material.py | 23 +++- openmc/capi/nuclide.py | 33 +++--- openmc/capi/tally.py | 29 +++-- openmc/nuclide.py | 4 +- src/api.F90 | 13 ++- 9 files changed, 284 insertions(+), 57 deletions(-) diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index 9bb1b2c66..1e30eacf1 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -8,17 +8,28 @@ C API Run a stochastic volume calculation -.. c:function:: int openmc_cell_set_temperature(int id, double T, int* instance) +.. c:function:: int openmc_cell_get_id(int32_t index, int32_t* id) + + Get the ID of a cell + + :param index: Index in the cells array + :type index: int32_t + :param id: ID of the cell + :type id: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_cell_set_temperature(index index, double T, int32_t* instance) Set the temperature of a cell. - :param id: ID of the cell - :type id: int + :param index: Index in the cells array + :type index: int32_t :param T: Temperature in Kelvin :type T: double :param instance: Which instance of the cell. To set the temperature for all instances, pass a null pointer. - :type instance: int* + :type instance: int32_t* :return: Return status (negative if an error occurred) :rtype: int @@ -26,7 +37,7 @@ C API Finalize a simulation -.. c:function:: void openmc_find(double* xyz, int rtype, int* id, int* instance) +.. c:function:: void openmc_find(double* xyz, int rtype, int32_t* id, int32_t* instance) Determine the ID of the cell/material containing a given point @@ -36,10 +47,65 @@ C API :type rtype: int :param id: ID of the cell/material found. If a material is requested and the point is in a void, the ID is 0. If an error occurs, the ID is -1. - :type id: int + :type id: int32_t* :param instance: If a cell is repetaed in the geometry, the instance of the cell that was found and zero otherwise. - :type instance: int + :type instance: int32_t* + +.. c:function:: int openmc_get_cell(int32_t id, int32_t* index) + + Get the index in the cells array for a cell with a given ID + + :param id: ID of the cell + :type id: int32_t + :param index: Index in the cells array + :type index: int32_t* + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: int openmc_get_keff(double k_combined[]) + + :param k_combined: Combined estimate of k-effective + :type k_combined: double[2] + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: int openmc_get_nuclide(char name[], int* index) + + Get the index in the nuclides array for a nuclide with a given name + + :param name: Name of the nuclide + :type name: char[] + :param index: Index in the nuclides array + :type index: int* + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: int openmc_get_tally(int32_t id, int32_t* index) + + Get the index in the tallies array for a tally with a given ID + + :param id: ID of the tally + :type id: int32_t + :param index: Index in the tallies array + :type index: int32_t* + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: int openmc_get_material(int32_t id, int32_t* index) + + Get the index in the materials array for a material with a given ID + + :param id: ID of the material + :type id: int32_t + :param index: Index in the materials array + :type index: int32_t* + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: void openmc_hard_reset() + + Reset tallies, timers, and pseudo-random number generator state .. c:function:: void openmc_init(int intracomm) @@ -57,13 +123,13 @@ C API :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_material_add_nuclide(int id, char name[], double density) +.. c:function:: int openmc_material_add_nuclide(int32_t index, char name[], double density) Add a nuclide to an existing material. If the nuclide already exists, the density is overwritten. - :param id: ID of the material - :type id: int + :param index: Index in the materials array + :type index: int32_t :param name: Name of the nuclide :type name: char[] :param density: Density in atom/b-cm @@ -71,28 +137,67 @@ C API :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_material_get_densities(int id, double* ptr) +.. c:function:: int openmc_material_get_densities(int32_t index, int* nuclides[], double* densities[]) - Get an array of nuclide densities for a material. + Get density for each nuclide in a material. - :param id: ID of the material - :type id: int - :param ptr: Pointer to the array of densities - :type ptr: double* - :return: Length of the array + :param index: Index in the materials array + :type index: int32_t + :param nuclides: Pointer to array of nuclide indices + :type nuclides: int** + :param densities: Pointer to the array of densities + :type densities: double** + :param n: Length of the array + :type n: int + :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_material_set_density(int id, double density) +.. c:function:: int openmc_material_get_id(int32_t index, int32_t* id) + + Get the ID of a material + + :param index: Index in the materials array + :type index: int32_t + :param id: ID of the material + :type id: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_material_set_density(int32_t index, double density) Set the density of a material. - :param id: ID of the material - :type id: int + :param index: Index in the materials array + :type index: int32_t :param density: Density of the material in atom/b-cm :type density: double :return: Return status (negative if an error occurs) :rtype: int +.. c:function:: int openmc_material_set_densities(int32_t, n, char* name[], double density[]) + + :param index: Index in the materials array + :type index: int32_t + :param n: Length of name/density + :type n: int + :param name: Array of nuclide names + :type name: char** + :param density: Array of densities + :type density: double[] + :return: Return status (negative if an error occurs) + :rtype: int + +.. c:function:: int openmc_nuclide_name(int index, char* name[]) + + Get name of a nuclide + + :param index: Index in the nuclides array + :type index: int + :param name: Name of the nuclide + :type name: char** + :return: Return status (negative if an error occurs) + :rtype: int + .. c:function:: void openmc_plot_geometry() Run plotting mode. @@ -105,13 +210,52 @@ C API Run a simulation -.. c:function:: void openmc_tally_results(int id, double** ptr, int shape_[3]) +.. c:function:: int openmc_tally_get_id(int32_t index, int32_t* id) + + Get the ID of a tally + + :param index: Index in the tallies array + :type index: int32_t + :param id: ID of the tally + :type id: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_tally_get_nuclides(int32_t index, int* nuclides[], int* n) + + Get nuclides specified in a tally + + :param index: Index in the tallies array + :type index: int32_t + :param nuclides: Array of nuclide indices + :type nuclides: int** + :param n: Number of nuclides + :type n: int* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_tally_results(int32_t index, double** ptr, int shape_[3]) Get a pointer to tally results array. - :param id: ID of the tally - :type id: int + :param index: Index in the tallies array + :type index: int32_t :param ptr: Pointer to the results array :type ptr: double** :param shape_: Shape of the results array :type shape_: int[3] + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_tally_set_nuclides(int32_t index, int n, char* nuclides[]) + + Set the nuclides for a tally + + :param index: Index in the tallies array + :type index: int32_t + :param n: Number of nuclides + :type n: int + :param nuclides: Array of nuclide names + :type nuclides: char** + :return: Return status (negative if an error occurred) + :rtype: int diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index af00363cc..a586cb4ad 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -2,16 +2,37 @@ :data:`openmc.capi` -- Python bindings to the C API --------------------------------------------------- +.. automodule:: openmc.capi + +Functions +--------- + .. autosummary:: :toctree: generated :nosignatures: :template: myfunction.rst - openmc.capi.lib_context + openmc.capi.calculate_volumes + openmc.capi.finalize + openmc.capi.find + openmc.capi.hard_reset + openmc.capi.init + openmc.capi.keff + openmc.capi.load_nuclide + openmc.capi.plot_geometry + openmc.capi.reset + openmc.capi.run + openmc.capi.run_in_memory + +Classes +------- .. autosummary:: :toctree: generated :nosignatures: :template: myclass.rst - openmc.capi.OpenMCLibrary + openmc.capi.CellView + openmc.capi.MaterialView + openmc.capi.NuclideView + openmc.capi.TallyView diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 6ae49c4ff..a4f16ab71 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -1,5 +1,5 @@ -"""Provides bindings to C functions defined by OpenMC shared library. - +""" +This module provides bindings to C functions defined by OpenMC shared library. When the :mod:`openmc` package is imported, the OpenMC shared library is automatically loaded. Calls to the OpenMC library can then be via functions or objects in the :mod:`openmc.capi` subpackage, for example: @@ -136,6 +136,7 @@ def find(xyz, rtype='cell'): def hard_reset(): + """Reset tallies, timers, and pseudo-random number generator state.""" _dll.openmc_hard_reset() @@ -180,7 +181,7 @@ def plot_geometry(): def reset(): - """Reset tallies""" + """Reset tallies and timers.""" _dll.openmc_reset() diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 1dbe50d51..9abada00c 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -22,6 +22,23 @@ _dll.openmc_get_cell.errcheck = _error_handler class CellView(object): + """View of a cell. + + This class exposes a cell that is stored internally in the OpenMC solver. To + obtain a view of a cell with a given ID, use the + :data:`openmc.capi.nuclides` mapping. + + Parameters + ---------- + index : int + Index in the `cells` array. + + Attributes + ---------- + id : int + ID of the cell + + """ __instances = WeakValueDictionary() def __new__(cls, *args): if args not in cls.__instances: diff --git a/openmc/capi/material.py b/openmc/capi/material.py index c917d3331..564ecaa05 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -7,8 +7,8 @@ from numpy.ctypeslib import as_array from openmc.capi import _dll, _error_handler, NuclideView -__all__ = ['MaterialView', 'materials'] +__all__ = ['MaterialView', 'materials'] # Material functions _dll.openmc_get_material.argtypes = [c_int32, POINTER(c_int32)] @@ -36,6 +36,27 @@ _dll.openmc_material_set_densities.errcheck = _error_handler class MaterialView(object): + """View of a material. + + This class exposes a material that is stored internally in the OpenMC + solver. To obtain a view of a material with a given ID, use the + :data:`openmc.capi.materials` mapping. + + Parameters + ---------- + index : int + Index in the `materials` array. + + Attributes + ---------- + id : int + ID of the material + nuclides : list of str + List of nuclides in the material + densities : numpy.ndarray + Array of densities in atom/b-cm + + """ __instances = WeakValueDictionary() def __new__(cls, *args): if args not in cls.__instances: diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 7a2f7a37b..384d0ae91 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -28,13 +28,30 @@ def load_nuclide(name): Parameters ---------- name : str - Name of nuclide, e.g. 'U235' + Name of the nuclide, e.g. 'U235' """ _dll.openmc_load_nuclide(name.encode()) class NuclideView(object): + """View of a nuclide. + + This class exposes a nuclide that is stored internally in the OpenMC + solver. To obtain a view of a nuclide with a given name, use the + :data:`openmc.capi.nuclides` mapping. + + Parameters + ---------- + index : int + Index in the `nuclides` array. + + Attributes + ---------- + name : str + Name of the nuclide, e.g. 'U235' + + """ __instances = WeakValueDictionary() def __new__(cls, *args): if args not in cls.__instances: @@ -47,19 +64,6 @@ class NuclideView(object): @property def name(self): - """Name of nuclide with given index - - Parameter - --------- - index : int - Index in internal nuclides array - - Returns - ------- - str - Name of nuclide - - """ name = c_char_p() _dll.openmc_nuclide_name(self._index, name) @@ -71,6 +75,7 @@ class NuclideView(object): class _NuclideMapping(Mapping): + """Provide mapping from nuclide name to index in nuclides array.""" def __getitem__(self, key): index = c_int() _dll.openmc_get_nuclide(key.encode(), index) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index b1fc49d04..cc8c13a5a 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -30,6 +30,27 @@ _dll.openmc_tally_set_nuclides.errcheck = _error_handler class TallyView(object): + """View of a tally. + + This class exposes a tally that is stored internally in the OpenMC + solver. To obtain a view of a tally with a given ID, use the + :data:`openmc.capi.tallies` mapping. + + Parameters + ---------- + index : int + Index in the `tallys` array. + + Attributes + ---------- + id : int + ID of the tally + nuclides : list of str + List of nuclides to score results for + results : numpy.ndarray + Array of tally results + + """ __instances = WeakValueDictionary() def __new__(cls, *args): if args not in cls.__instances: @@ -56,14 +77,6 @@ class TallyView(object): @property def results(self): - """Get tally results array - - Returns - ------- - numpy.ndarray - Array that exposes the internal tally results array - - """ data = POINTER(c_double)() shape = (c_int*3)() _dll.openmc_tally_results(self._index, data, shape) diff --git a/openmc/nuclide.py b/openmc/nuclide.py index 03062ee0e..fc0d7ef07 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -11,12 +11,12 @@ class Nuclide(object): Parameters ---------- name : str - Name of the nuclide, e.g. U235 + Name of the nuclide, e.g. 'U235' Attributes ---------- name : str - Name of the nuclide, e.g. U235 + Name of the nuclide, e.g. 'U235' scattering : 'data' or 'iso-in-lab' or None The type of angular scattering distribution to use diff --git a/src/api.F90 b/src/api.F90 index b767d1ab4..40ac0f01f 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -66,7 +66,7 @@ module openmc_api contains !=============================================================================== -! OPENMC_CELL_ID returns the ID of a cell +! OPENMC_CELL_GET_ID returns the ID of a cell !=============================================================================== function openmc_cell_get_id(index, id) result(err) bind(C) @@ -695,9 +695,9 @@ contains ! OPENMC_TALLY_NUCLIDES returns the list of nuclides assigned to a tally !=============================================================================== - function openmc_tally_get_nuclides(index, ptr, n) result(err) bind(C) + function openmc_tally_get_nuclides(index, nuclides, n) result(err) bind(C) integer(C_INT32_T), value :: index - type(C_PTR), intent(out) :: ptr + type(C_PTR), intent(out) :: nuclides integer(C_INT), intent(out) :: n integer(C_INT) :: err @@ -705,7 +705,7 @@ contains if (index >= 1 .and. index <= size(tallies)) then associate (t => tallies(index)) if (allocated(t % nuclide_bins)) then - ptr = C_LOC(t % nuclide_bins(1)) + nuclides = C_LOC(t % nuclide_bins(1)) n = size(t % nuclide_bins) err = 0 end if @@ -739,6 +739,11 @@ contains end if end function openmc_tally_results +!=============================================================================== +! OPENMC_TALLY_SET_NUCLIDES sets the nuclides in the tally which results should +! be scored for +!=============================================================================== + function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) integer(C_INT32_T), value :: index integer(C_INT), value :: n From 7337d59e775ed5fcf1313ed3421e67eedb60799c Mon Sep 17 00:00:00 2001 From: tjlaboss Date: Mon, 31 Jul 2017 08:39:47 -0600 Subject: [PATCH 076/229] Addressed suggestions by @paulromano --- openmc/data/neutron.py | 2 +- scripts/openmc-update-inputs | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 07b1f7686..64634f2af 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -34,7 +34,7 @@ from openmc.mixin import EqualityMixin _RESONANCE_ENERGY_GRID = np.logspace(-3, 3, 61) -def get_metadata(zaid, metastable_scheme='nndc'): +def _get_metadata(zaid, metastable_scheme='nndc'): """Return basic identifying data for a nuclide with a given ZAID. Parameters diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index ea6506942..3eb850207 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -11,7 +11,6 @@ from itertools import chain from random import randint from shutil import move import xml.etree.ElementTree as ET -import re import openmc.data @@ -239,12 +238,6 @@ def update_geometry(geometry_root): return was_updated -def replace_zaid(name): - """Replace a nuclide name in the ZAID notation with the correct name.""" - zaid = int(name.strip()) - name = openmc.data.neutron.get_metadata(zaid)[0] - return name - def update_materials(root): """Update the given XML materials tree. Return True if changes were made.""" was_updated = False @@ -254,9 +247,11 @@ def update_materials(root): if 'name' in nuclide.attrib: nucname = nuclide.attrib['name'] nucname = nucname.replace('-', '') - s = re.search("\s*(? Date: Mon, 31 Jul 2017 08:58:26 -0600 Subject: [PATCH 077/229] Reverted get_metadata() to _get_metadata() (I need coffee) --- openmc/data/neutron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 64634f2af..1d3a0176d 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -677,7 +677,7 @@ class IncidentNeutron(EqualityMixin): # If mass number hasn't been specified, make an educated guess zaid, xs = ace.name.split('.') name, element, Z, mass_number, metastable = \ - get_metadata(int(zaid), metastable_scheme) + _get_metadata(int(zaid), metastable_scheme) # Assign temperature to the running list kTs = [ace.temperature*EV_PER_MEV] From 8bb990b65a70d249ec0766ef8db9849822c6fbd5 Mon Sep 17 00:00:00 2001 From: liangjg Date: Mon, 31 Jul 2017 17:52:55 -0400 Subject: [PATCH 078/229] remove the argument "error" out of "from_njoy" function --- openmc/data/neutron.py | 6 ++---- openmc/data/njoy.py | 16 ++++++++-------- openmc/data/thermal.py | 7 ++----- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 8accabfc7..ed2f4f8b7 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -824,7 +824,7 @@ class IncidentNeutron(EqualityMixin): return data @classmethod - def from_njoy(cls, filename, temperatures=None, error=0.001, **kwargs): + def from_njoy(cls, filename, temperatures=None, **kwargs): """Generate incident neutron data by running NJOY. Parameters @@ -834,8 +834,6 @@ class IncidentNeutron(EqualityMixin): temperatures : iterable of float Temperatures in Kelvin to produce data at. If omitted, data is produced at room temperature (293.6 K) - error : float, optional - Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace` @@ -853,7 +851,7 @@ class IncidentNeutron(EqualityMixin): ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') pendf_file = os.path.join(tmpdir, 'pendf') - make_ace(filename, temperatures, error, ace_file, xsdir_file, + make_ace(filename, temperatures, ace_file, xsdir_file, pendf_file, **kwargs) # Create instance from ACE tables within library diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 5365d9740..cf5c4b6c7 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -228,8 +228,8 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): return run(commands, tapein, tapeout, stdout) -def make_ace(filename, temperatures=None, error=0.001, ace='ace', xsdir='xsdir', - pendf=None, **kwargs): +def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', + pendf=None, error=0.001, **kwargs): """Generate incident neutron ACE file from an ENDF file Parameters @@ -239,14 +239,14 @@ def make_ace(filename, temperatures=None, error=0.001, ace='ace', xsdir='xsdir', temperatures : iterable of float, optional Temperatures in Kelvin to produce ACE files at. If omitted, data is produced at room temperature (293.6 K). - error : float, optional - Fractional error tolerance for NJOY processing. ace : str, optional Path of ACE file to write xsdir : str, optional Path of xsdir file to write pendf : str, optional Path of pendf file to write. If omitted, the pendf file is not saved. + error : float, optional + Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -315,8 +315,8 @@ def make_ace(filename, temperatures=None, error=0.001, ace='ace', xsdir='xsdir', return retcode -def make_ace_thermal(filename, filename_thermal, temperatures=None, error=0.001, - ace='ace', xsdir='xsdir', **kwargs): +def make_ace_thermal(filename, filename_thermal, temperatures=None, + ace='ace', xsdir='xsdir', error=0.001, **kwargs): """Generate thermal scattering ACE file from ENDF files Parameters @@ -328,12 +328,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, error=0.001, temperatures : iterable of float, optional Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures given in the ENDF thermal scattering sublibrary. - error : float, optional - Fractional error tolerance for NJOY processing. ace : str, optional Path of ACE file to write xsdir : str, optional Path of xsdir file to write + error : float, optional + Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 1d63c1ade..6e7b0fe02 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -588,8 +588,7 @@ class ThermalScattering(EqualityMixin): return table @classmethod - def from_njoy(cls, filename, filename_thermal, temperatures=None, - error=0.001, **kwargs): + def from_njoy(cls, filename, filename_thermal, temperatures=None, **kwargs): """Generate incident neutron data by running NJOY. Parameters @@ -602,8 +601,6 @@ class ThermalScattering(EqualityMixin): Temperatures in Kelvin to produce data at. If omitted, data is produced at all temperatures in the ENDF thermal scattering sublibrary. - error : float, optional - Fractional error tolerance for NJOY processing. **kwargs Keyword arguments passed to :func:`openmc.data.njoy.make_ace_thermal` @@ -620,7 +617,7 @@ class ThermalScattering(EqualityMixin): # Run NJOY to create an ACE library ace_file = os.path.join(tmpdir, 'ace') xsdir_file = os.path.join(tmpdir, 'xsdir') - make_ace_thermal(filename, filename_thermal, temperatures, error, + make_ace_thermal(filename, filename_thermal, temperatures, ace_file, xsdir_file, **kwargs) # Create instance from ACE tables within library From ac4b8d752a71e9a0f24c15b2a3a10107cfa05cb0 Mon Sep 17 00:00:00 2001 From: liangjg Date: Mon, 31 Jul 2017 17:55:04 -0400 Subject: [PATCH 079/229] allow to omit specific modules in generating data from njoy added several arguments for the modules --- openmc/data/njoy.py | 185 +++++++++++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 71 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index cf5c4b6c7..85597562a 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -50,40 +50,36 @@ _THERMAL_DATA = { 75: ThermalTuple('ouo2', [8016, 8017, 8018], 1), } - -_PENDF_TEMPLATE = """ +_ACE_TEMPLATE_RECONR = """ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% -20 22 -'{library} PENDF for {zsymam}'/ -{mat} 2/ -0.001 0.0 0.003/ err tempr errmax -'{library}: {zsymam}'/ -'Processed by NJOY'/ -0/ -stop -""" - -_ACE_TEMPLATE = """ -reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% -20 21 +{nendf} {npendf} '{library} PENDF for {zsymam}'/ {mat} 2/ {error}/ err '{library}: {zsymam}'/ 'Processed by NJOY'/ 0/ +""" + +_ACE_TEMPLATE_BROADR = """ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% -20 21 22 +{nendf} {npendf} {nbroadr} {mat} {num_temp} 0 0 0. / {error}/ errthn {temps} 0/ +""" + +_ACE_TEMPLATE_HEATR = """ heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%% -20 22 23 / +{nendf} {nheatr_in} {nheatr} / {mat} 3 / 302 318 402 / +""" + +_ACE_TEMPLATE_PURR = """ purr / %%%%%%%%%%%%%%%%%%%%%%%% Add probability tables %%%%%%%%%%%%%%%%%%%%%%%%% -20 23 24 +{nendf} {npurr_in} {npurr} / {mat} {num_temp} 1 20 64 / {temps} 1.e10 @@ -91,7 +87,7 @@ purr / %%%%%%%%%%%%%%%%%%%%%%%% Add probability tables %%%%%%%%%%%%%%%%%%%%%%%%% """ _ACE_TEMPLATE_ACER = """acer / -20 24 0 {nace} {ndir} +{nendf} {nacer_in} 0 {nace} {ndir} 1 0 1 .{ext} / '{library}: {zsymam} at {temperature}'/ {mat} {temperature} @@ -99,35 +95,21 @@ _ACE_TEMPLATE_ACER = """acer / / """ -_ACE_THERMAL_TEMPLATE = """ -reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% -20 22 -'{library} PENDF for {zsymam}'/ -{mat} 2/ -{error}/ err -'{library}: PENDF for {zsymam}'/ -'Processed by NJOY'/ -0/ -broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% -20 22 23 -{mat} {num_temp} 0 0 0./ -{error}/ errthn -{temps} -0/ +_ACE_TEMPLATE_THERMR = """ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%% -0 23 62 +0 {nthermr1_in} {nthermr1} 0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/ {temps} {error} {energy_max} thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (bound) %%%%%%%%%%%%%%%%%% -60 62 27 +{nthermal_endf} {nthermr2_in} {nthermr2} {mat_thermal} {mat} 16 {num_temp} {inelastic} {elastic} {iform} {natom} 222 1/ {temps} {error} {energy_max} """ _ACE_THERMAL_TEMPLATE_ACER = """acer / -20 27 0 {nace} {ndir} +{nendf} {nthermal_acer_in} 0 {nace} {ndir} 2 0 1 .{ext}/ '{library}: {zsymam_thermal} processed by NJOY'/ {mat} {temperature} '{data.name}' / @@ -205,7 +187,7 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): pendf : str, optional Path of pointwise ENDF file to write error : float, optional - Fractional error tolerance for NJOY processing. + Fractional error tolerance for NJOY processing stdout : bool Whether to display NJOY standard output @@ -215,21 +197,14 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): Return code of NJOY process """ - ev = endf.Evaluation(filename) - mat = ev.material - zsymam = ev.target['zsymam'] - # Determine name of library - library = '{}-{}.{}'.format(*ev.info['library']) - - commands = _PENDF_TEMPLATE.format(**locals()) - tapein = {20: filename} - tapeout = {22: pendf} - return run(commands, tapein, tapeout, stdout) + return make_ace(filename, pendf=pendf, error=error, broadr=False, + heatr=False, purr=False, acer=False, stdout=stdout) -def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', - pendf=None, error=0.001, **kwargs): +def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, + error=0.001, broadr=True, heatr=True, purr=True, acer=True, + **kwargs): """Generate incident neutron ACE file from an ENDF file Parameters @@ -246,7 +221,15 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf : str, optional Path of pendf file to write. If omitted, the pendf file is not saved. error : float, optional - Fractional error tolerance for NJOY processing. + Fractional error tolerance for NJOY processing + broadr : bool, optional + Indicating whether to Doppler broaden XS in running NJOY + heatr : bool, optional + Indicating whether to add heating kerma in running NJOY + purr : bool, optional + Indicating whether to add probability table in running NJOY + acer : bool, optional + Indicating whether to generate ACE file in running NJOY **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -268,26 +251,60 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', num_temp = len(temperatures) temps = ' '.join(str(i) for i in temperatures) - commands = _ACE_TEMPLATE.format(**locals()) - tapein = {20: filename} + # Create njoy commands by modules + commands = "" + + nendf, npendf = 20, 21 + tapein = {nendf: filename} tapeout = {} if pendf is not None: - tapeout[21] = pendf - fname = '{}_{:.1f}' - for i, temperature in enumerate(temperatures): - # Extend input with an ACER run for each temperature - nace = 25 + 2*i - ndir = 25 + 2*i + 1 - ext = '{:02}'.format(i + 1) - commands += _ACE_TEMPLATE_ACER.format(**locals()) + tapeout[npendf] = pendf + + # reconr + commands += _ACE_TEMPLATE_RECONR + nlast = npendf + + # broadr + if broadr: + nbroadr = nlast + 1 + commands += _ACE_TEMPLATE_BROADR + nlast = nbroadr + + # heatr + if heatr: + nheatr_in = nlast + 1 + nheatr = nheatr_in + 1 + commands += _ACE_TEMPLATE_HEATR + nlast = nheatr + + # purr + if purr: + npurr_in = nlast + 1 + npurr = npurr_in + 1 + commands += _ACE_TEMPLATE_PURR + nlast = npurr + + commands = commands.format(**locals()) + + # acer + if acer: + nacer_in = nlast + fname = '{}_{:.1f}' + for i, temperature in enumerate(temperatures): + # Extend input with an ACER run for each temperature + nace = nacer_in + 1 + 2*i + ndir = nace + 1 + ext = '{:02}'.format(i + 1) + commands += _ACE_TEMPLATE_ACER.format(**locals()) + + # Indicate tapes to save for each ACER run + tapeout[nace] = fname.format(ace, temperature) + tapeout[ndir] = fname.format(xsdir, temperature) - # Indicate tapes to save for each ACER run - tapeout[nace] = fname.format(ace, temperature) - tapeout[ndir] = fname.format(xsdir, temperature) commands += 'stop\n' retcode = run(commands, tapein, tapeout, **kwargs) - if retcode == 0: + if acer and retcode == 0: with open(ace, 'w') as ace_file, open(xsdir, 'w') as xsdir_file: for temperature in temperatures: # Get contents of ACE file @@ -315,7 +332,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', return retcode -def make_ace_thermal(filename, filename_thermal, temperatures=None, +def make_ace_thermal(filename, filename_thermal, temperatures=None, ace='ace', xsdir='xsdir', error=0.001, **kwargs): """Generate thermal scattering ACE file from ENDF files @@ -333,7 +350,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, xsdir : str, optional Path of xsdir file to write error : float, optional - Fractional error tolerance for NJOY processing. + Fractional error tolerance for NJOY processing **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -396,20 +413,46 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, num_temp = len(temperatures) temps = ' '.join(str(i) for i in temperatures) - commands = _ACE_THERMAL_TEMPLATE.format(**locals()) - tapein = {20: filename, 60: filename_thermal} + # Create njoy commands by modules + commands = "" + + nendf, nthermal_endf, npendf = 20, 21, 22 + tapein = {nendf: filename, nthermal_endf:filename_thermal} tapeout = {} + + # reconr + commands += _ACE_TEMPLATE_RECONR + nlast = npendf + + # broadr + nbroadr = nlast + 1 + commands += _ACE_TEMPLATE_BROADR + nlast = nbroadr + + # thermr + nthermr1_in = nlast + nthermr1 = nthermr_in + 1 + nthermr2_in = nthermr1 + nthermr2 = nthermr2_in + 1 + commands += _ACE_TEMPLATE_THERMR + nlast = nthermr2 + + commands = commands.format(**locals()) + + # acer + nthermal_acer_in = nlast fname = '{}_{:.1f}' for i, temperature in enumerate(temperatures): # Extend input with an ACER run for each temperature - nace = 28 + 2*i - ndir = 28 + 2*i + 1 + nace = nthermal_acer_in + 1 + 2*i + ndir = nace + 1 ext = '{:02}'.format(i + 1) commands += _ACE_THERMAL_TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run tapeout[nace] = fname.format(ace, temperature) tapeout[ndir] = fname.format(xsdir, temperature) + commands += 'stop\n' retcode = run(commands, tapein, tapeout, **kwargs) From 3f1416a17c0fe593898138606e3ebfb2b0348856 Mon Sep 17 00:00:00 2001 From: liangjg Date: Tue, 1 Aug 2017 09:46:49 -0400 Subject: [PATCH 080/229] add argument to support printing NJOY input commands --- openmc/data/njoy.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 85597562a..d229ea91c 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -95,7 +95,7 @@ _ACE_TEMPLATE_ACER = """acer / / """ -_ACE_TEMPLATE_THERMR = """ +_ACE_THERMAL_TEMPLATE_THERMR = """ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%% 0 {nthermr1_in} {nthermr1} 0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/ @@ -118,7 +118,8 @@ _ACE_THERMAL_TEMPLATE_ACER = """acer / """ -def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'): +def run(commands, tapein, tapeout, print_commands=False, stdout=False, + njoy_exec='njoy'): """Run NJOY with given commands Parameters @@ -129,6 +130,8 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'): Dictionary mapping tape numbers to paths for any input files tapeout : dict Dictionary mapping tape numbers to paths for any output files + print_commands : bool, optional + Whether to display input commands when running NJOY stdout : bool, optional Whether to display output when running NJOY njoy_exec : str, optional @@ -141,6 +144,11 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'): """ + if print_commands: + # If user requested showing commands, print to screen + print("NJOY INPUTS:") + print(commands) + # Create temporary directory -- it would be preferable to use # TemporaryDirectory(), but it is only available in Python 3.2 tmpdir = tempfile.mkdtemp() @@ -223,13 +231,13 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, error : float, optional Fractional error tolerance for NJOY processing broadr : bool, optional - Indicating whether to Doppler broaden XS in running NJOY + Indicating whether to Doppler broaden XS when running NJOY heatr : bool, optional - Indicating whether to add heating kerma in running NJOY + Indicating whether to add heating kerma when running NJOY purr : bool, optional - Indicating whether to add probability table in running NJOY + Indicating whether to add probability table when running NJOY acer : bool, optional - Indicating whether to generate ACE file in running NJOY + Indicating whether to generate ACE file when running NJOY **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -272,14 +280,14 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, # heatr if heatr: - nheatr_in = nlast + 1 + nheatr_in = nlast nheatr = nheatr_in + 1 commands += _ACE_TEMPLATE_HEATR nlast = nheatr # purr if purr: - npurr_in = nlast + 1 + npurr_in = nlast npurr = npurr_in + 1 commands += _ACE_TEMPLATE_PURR nlast = npurr @@ -300,7 +308,6 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, # Indicate tapes to save for each ACER run tapeout[nace] = fname.format(ace, temperature) tapeout[ndir] = fname.format(xsdir, temperature) - commands += 'stop\n' retcode = run(commands, tapein, tapeout, **kwargs) @@ -431,10 +438,10 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, # thermr nthermr1_in = nlast - nthermr1 = nthermr_in + 1 + nthermr1 = nthermr1_in + 1 nthermr2_in = nthermr1 nthermr2 = nthermr2_in + 1 - commands += _ACE_TEMPLATE_THERMR + commands += _ACE_THERMAL_TEMPLATE_THERMR nlast = nthermr2 commands = commands.format(**locals()) @@ -452,7 +459,6 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, # Indicate tapes to save for each ACER run tapeout[nace] = fname.format(ace, temperature) tapeout[ndir] = fname.format(xsdir, temperature) - commands += 'stop\n' retcode = run(commands, tapein, tapeout, **kwargs) From 18f7ae3a46d116bf9ae46ccd1c1327bd965259a9 Mon Sep 17 00:00:00 2001 From: liangjg Date: Wed, 2 Aug 2017 11:08:33 -0400 Subject: [PATCH 081/229] address @Paul's comments write NJOY input into file rather than printing on screen _ACE_TEMPLATE -> _TEMPLATE --- openmc/data/njoy.py | 47 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index d229ea91c..ac98af7fb 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -50,7 +50,7 @@ _THERMAL_DATA = { 75: ThermalTuple('ouo2', [8016, 8017, 8018], 1), } -_ACE_TEMPLATE_RECONR = """ +_TEMPLATE_RECONR = """ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% {nendf} {npendf} '{library} PENDF for {zsymam}'/ @@ -61,7 +61,7 @@ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% 0/ """ -_ACE_TEMPLATE_BROADR = """ +_TEMPLATE_BROADR = """ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% {nendf} {npendf} {nbroadr} {mat} {num_temp} 0 0 0. / @@ -70,14 +70,14 @@ broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%% 0/ """ -_ACE_TEMPLATE_HEATR = """ +_TEMPLATE_HEATR = """ heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%% {nendf} {nheatr_in} {nheatr} / {mat} 3 / 302 318 402 / """ -_ACE_TEMPLATE_PURR = """ +_TEMPLATE_PURR = """ purr / %%%%%%%%%%%%%%%%%%%%%%%% Add probability tables %%%%%%%%%%%%%%%%%%%%%%%%% {nendf} {npurr_in} {npurr} / {mat} {num_temp} 1 20 64 / @@ -86,7 +86,8 @@ purr / %%%%%%%%%%%%%%%%%%%%%%%% Add probability tables %%%%%%%%%%%%%%%%%%%%%%%%% 0/ """ -_ACE_TEMPLATE_ACER = """acer / +_TEMPLATE_ACER = """ +acer / %%%%%%%%%%%%%%%%%%%%%%%% Write out in ACE format %%%%%%%%%%%%%%%%%%%%%%%% {nendf} {nacer_in} 0 {nace} {ndir} 1 0 1 .{ext} / '{library}: {zsymam} at {temperature}'/ @@ -95,7 +96,7 @@ _ACE_TEMPLATE_ACER = """acer / / """ -_ACE_THERMAL_TEMPLATE_THERMR = """ +_THERMAL_TEMPLATE_THERMR = """ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%% 0 {nthermr1_in} {nthermr1} 0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/ @@ -108,7 +109,8 @@ thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (bound) %%%%%%%%%%%%%%%%%% {error} {energy_max} """ -_ACE_THERMAL_TEMPLATE_ACER = """acer / +_THERMAL_TEMPLATE_ACER = """ +acer / %%%%%%%%%%%%%%%%%%%%%%%% Write out in ACE format %%%%%%%%%%%%%%%%%%%%%%%% {nendf} {nthermal_acer_in} 0 {nace} {ndir} 2 0 1 .{ext}/ '{library}: {zsymam_thermal} processed by NJOY'/ @@ -118,7 +120,7 @@ _ACE_THERMAL_TEMPLATE_ACER = """acer / """ -def run(commands, tapein, tapeout, print_commands=False, stdout=False, +def run(commands, tapein, tapeout, input_filename=None, stdout=False, njoy_exec='njoy'): """Run NJOY with given commands @@ -130,8 +132,8 @@ def run(commands, tapein, tapeout, print_commands=False, stdout=False, Dictionary mapping tape numbers to paths for any input files tapeout : dict Dictionary mapping tape numbers to paths for any output files - print_commands : bool, optional - Whether to display input commands when running NJOY + input_filename : str, optional + File name to write out NJOY input commands stdout : bool, optional Whether to display output when running NJOY njoy_exec : str, optional @@ -144,10 +146,9 @@ def run(commands, tapein, tapeout, print_commands=False, stdout=False, """ - if print_commands: - # If user requested showing commands, print to screen - print("NJOY INPUTS:") - print(commands) + if input_filename is not None: + with open(input_filename, 'w') as f: + f.write(commands) # Create temporary directory -- it would be preferable to use # TemporaryDirectory(), but it is only available in Python 3.2 @@ -269,27 +270,27 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, tapeout[npendf] = pendf # reconr - commands += _ACE_TEMPLATE_RECONR + commands += _TEMPLATE_RECONR nlast = npendf # broadr if broadr: nbroadr = nlast + 1 - commands += _ACE_TEMPLATE_BROADR + commands += _TEMPLATE_BROADR nlast = nbroadr # heatr if heatr: nheatr_in = nlast nheatr = nheatr_in + 1 - commands += _ACE_TEMPLATE_HEATR + commands += _TEMPLATE_HEATR nlast = nheatr # purr if purr: npurr_in = nlast npurr = npurr_in + 1 - commands += _ACE_TEMPLATE_PURR + commands += _TEMPLATE_PURR nlast = npurr commands = commands.format(**locals()) @@ -303,7 +304,7 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None, nace = nacer_in + 1 + 2*i ndir = nace + 1 ext = '{:02}'.format(i + 1) - commands += _ACE_TEMPLATE_ACER.format(**locals()) + commands += _TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run tapeout[nace] = fname.format(ace, temperature) @@ -428,12 +429,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, tapeout = {} # reconr - commands += _ACE_TEMPLATE_RECONR + commands += _TEMPLATE_RECONR nlast = npendf # broadr nbroadr = nlast + 1 - commands += _ACE_TEMPLATE_BROADR + commands += _TEMPLATE_BROADR nlast = nbroadr # thermr @@ -441,7 +442,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, nthermr1 = nthermr1_in + 1 nthermr2_in = nthermr1 nthermr2 = nthermr2_in + 1 - commands += _ACE_THERMAL_TEMPLATE_THERMR + commands += _THERMAL_TEMPLATE_THERMR nlast = nthermr2 commands = commands.format(**locals()) @@ -454,7 +455,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, nace = nthermal_acer_in + 1 + 2*i ndir = nace + 1 ext = '{:02}'.format(i + 1) - commands += _ACE_THERMAL_TEMPLATE_ACER.format(**locals()) + commands += _THERMAL_TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run tapeout[nace] = fname.format(ace, temperature) From f155dfad29e40eb2a99482909923bca391e80c2d Mon Sep 17 00:00:00 2001 From: April Novak Date: Mon, 31 Jul 2017 16:13:12 -0500 Subject: [PATCH 082/229] added check to make sure that temperature is not set to a value outside data bounds and that cell cannot be filled with a universe. Added several more error codes. Refs #7 --- src/api.F90 | 99 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 15 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 40ac0f01f..d17d57ef9 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -62,6 +62,12 @@ module openmc_api integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -10 integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -11 integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 + integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 + integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 + + ! Warning codes + integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 + integer(C_INT), public, bind(C) :: W_ABOVE_MAX_BOUND = 2 contains @@ -87,29 +93,92 @@ contains !=============================================================================== function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index - real(C_DOUBLE), value, intent(in) :: T - integer(C_INT32_T), optional, intent(in) :: instance - integer(C_INT) :: err + integer(C_INT32_T), value, intent(in) :: index ! cell index in cells + real(C_DOUBLE), value, intent(in) :: T ! temperature + integer(C_INT32_T), optional, intent(in) :: instance ! cell instance - integer :: n + integer(C_INT) :: err ! error code + integer :: j ! looping variable + integer :: n ! number of cell instances + integer :: material_ID ! material associated with cell + integer :: material_index ! material index in materials array + integer :: num_nuclides ! num nuclides in material + integer :: nuclide_index ! index of nuclide in nuclides array + real(8) :: min_temp ! min common-denominator avail temp + real(8) :: max_temp ! max common-denominator avail temp + real(8) :: temp ! actual temp we'll assign + logical :: outside_low ! lower than available data + logical :: outside_high ! higher than available data + + outside_low = .false. + outside_high = .false. err = E_UNASSIGNED + if (index >= 1 .and. index <= size(cells)) then - associate (c => cells(index)) - if (allocated(c % sqrtkT)) then - n = size(c % sqrtkT) - if (present(instance) .and. n > 1) then - if (instance >= 0 .and. instance < n) then - c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T) + + ! error if the cell is filled with another universe + if (cells(index) % fill /= NONE) then + err = E_CELL_NO_MATERIAL + else + ! find which material is associated with this cell + if (present(instance)) then + material_ID = cells(index) % material(instance) + else + material_ID = cells(index) % material(1) + end if + + ! index of that material into the materials array + material_index = material_dict % get_key(material_ID) + + ! number of nuclides associated with this material + num_nuclides = size(materials(material_index) % nuclide) + + min_temp = ZERO + max_temp = INFINITY + + do j = 1, num_nuclides + nuclide_index = materials(material_index) % nuclide(j) + min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs)) + max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs)) + end do + + ! adjust the temperature to be within bounds if necessary + if (K_BOLTZMANN * T < min_temp) then + outside_low = .true. + temp = min_temp / K_BOLTZMANN + else if (K_BOLTZMANN * T > max_temp) then + outside_high = .true. + temp = max_temp / K_BOLTZMANN + else + temp = T + end if + + associate (c => cells(index)) + if (allocated(c % sqrtkT)) then + n = size(c % sqrtkT) + if (present(instance) .and. n > 1) then + if (instance >= 0 .and. instance < n) then + c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp) + err = 0 + end if + else + c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp) err = 0 end if - else - c % sqrtkT(:) = sqrt(K_BOLTZMANN * T) - err = 0 end if + end associate + + ! assign error codes for outside of temperature bounds provided the + ! temperature was changed correctly. This needs to be done after + ! changing the temperature based on the logical structure above. + if (err == 0) then + if (outside_low) err = W_BELOW_MIN_BOUND + if (outside_high) err = W_ABOVE_MAX_BOUND end if - end associate + + end if + else err = E_OUT_OF_BOUNDS end if From 064e1aef596ebd0e780d433d192ae0cc8224e252 Mon Sep 17 00:00:00 2001 From: April Novak Date: Mon, 31 Jul 2017 17:29:35 -0500 Subject: [PATCH 083/229] added error and warning code handling in Python API for new codes. Refs #7 --- openmc/capi/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index a4f16ab71..fabeac947 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -86,6 +86,19 @@ def _error_handler(err, func, args): elif err == _error_code('e_tally_invalid_id'): raise KeyError("No tally exists with ID={}.".format(args[0])) + elif err == _error_code('e_invalid_size'): + raise MemoryError("Array size mismatch with memory allocated.") + + elif err == _error_code('e_cell_no_material'): + raise GeometryError("Operation on cell requires that it be filled" + " with a material.") + + elif err == _error_code('w_below_min_bound'): + warn("Data has not been loaded beyond lower bound of {}.".format(args[0])) + + elif err == _error_code('w_above_max_bound'): + warn("Data has not been loaded beyond upper bound of {}.".format(args[0])) + elif err < 0: raise Exception("Unknown error encountered (code {}).".format(err)) From a49b4246f455c9ce270469b2a325c6c220c00155 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 31 Jul 2017 23:00:37 -0500 Subject: [PATCH 084/229] Reimplement openmc_material_set_densities. Move assign_sab_tables to material_header. --- src/api.F90 | 37 ++++++------ src/input_xml.F90 | 123 +--------------------------------------- src/material_header.F90 | 120 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 136 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index d17d57ef9..0941e60fe 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -633,30 +633,35 @@ contains if (index >= 1 .and. index <= size(materials)) then associate (m => materials(index)) + ! If nuclide/density arrays are not correct size, reallocate + if (n /= size(m % nuclide)) then + deallocate(m % nuclide, m % atom_density, m % p0) + allocate(m % nuclide(n), m % atom_density(n), m % p0(n)) + end if + do i = 1, n ! Convert C string to Fortran string call c_f_pointer(name(i), string, [10]) - name_ = to_f_string(string) + name_ = to_lower(to_f_string(string)) - ! Find corresponding nuclide and set density - err = E_UNASSIGNED - do j = 1, size(m % nuclide) - k = m % nuclide(j) - if (nuclides(k) % name == name_) then - m % atom_density(j) = density(i) - err = 0 - end if - end do - - ! If nuclide wasn't found, try to load it - if (err /= 0) then - err = openmc_material_add_nuclide(index, string, density(i)) - if (err /= 0) return + if (.not. nuclide_dict % has_key(name_)) then + err = openmc_load_nuclide(string) + if (err < 0) return end if + + m % nuclide(i) = nuclide_dict % get_key(name_) + m % atom_density(i) = density(i) end do + m % n_nuclides = n + + ! Set isotropic flags to flags + m % p0(:) = .false. ! Set total density to the sum of the vector - err = m % set_density(sum(m % atom_density), nuclides) + err = m % set_density(sum(density), nuclides) + + ! Assign S(a,b) tables + call m % assign_sab_tables(nuclides, sab_tables) end associate else err = E_OUT_OF_BOUNDS diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 322ca8a76..2fc6ef918 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -5146,123 +5146,6 @@ contains end subroutine normalize_ao -!=============================================================================== -! ASSIGN_SAB_TABLES assigns S(alpha,beta) tables to specific nuclides within -! materials so the code knows when to apply bound thermal scattering data -!=============================================================================== - - subroutine assign_sab_tables() - integer :: i ! index in materials array - integer :: j ! index over nuclides in material - integer :: k ! index over S(a,b) tables in material - integer :: m ! position for sorting - integer :: temp_nuclide ! temporary value for sorting - integer :: temp_table ! temporary value for sorting - real(8) :: temp_frac ! temporary value for sorting - logical :: found - type(VectorInt) :: i_sab_tables - type(VectorInt) :: i_sab_nuclides - type(VectorReal) :: sab_fracs - - do i = 1, size(materials) - ! Skip materials with no S(a,b) tables - if (.not. allocated(materials(i) % i_sab_tables)) cycle - - associate (mat => materials(i)) - - ASSIGN_SAB: do k = 1, size(mat % i_sab_tables) - ! 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 - ! name - found = .false. - associate (sab => sab_tables(mat % i_sab_tables(k))) - FIND_NUCLIDE: do j = 1, size(mat % nuclide) - if (any(sab % nuclides == nuclides(mat % nuclide(j)) % name)) then - call i_sab_tables % push_back(mat % i_sab_tables(k)) - call i_sab_nuclides % push_back(j) - call sab_fracs % push_back(mat % sab_fracs(k)) - found = .true. - end if - end do FIND_NUCLIDE - end associate - - ! Check to make sure S(a,b) table matched a nuclide - if (.not. found) then - call fatal_error("S(a,b) table " // trim(mat % & - sab_names(k)) // " did not match any nuclide on material " & - // trim(to_str(mat % id))) - end if - end do ASSIGN_SAB - - ! Make sure each nuclide only appears in one table. - do j = 1, i_sab_nuclides % size() - do k = j+1, i_sab_nuclides % size() - if (i_sab_nuclides % data(j) == i_sab_nuclides % data(k)) then - call fatal_error(trim( & - nuclides(mat % nuclide(i_sab_nuclides % data(j))) % name) & - // " in material " // trim(to_str(mat % id)) // " was found & - &in multiple S(a,b) tables. Each nuclide can only appear in & - &one S(a,b) table per material.") - end if - end do - end do - - ! Update i_sab_tables and i_sab_nuclides - deallocate(mat % i_sab_tables) - deallocate(mat % sab_fracs) - m = i_sab_tables % size() - allocate(mat % i_sab_tables(m)) - allocate(mat % i_sab_nuclides(m)) - allocate(mat % sab_fracs(m)) - mat % i_sab_tables(:) = i_sab_tables % data(1:m) - mat % i_sab_nuclides(:) = i_sab_nuclides % data(1:m) - mat % sab_fracs(:) = sab_fracs % data(1:m) - - ! Clear entries in vectors for next material - call i_sab_tables % clear() - call i_sab_nuclides % clear() - call sab_fracs % clear() - - ! If there are multiple S(a,b) tables, we need to make sure that the - ! entries in i_sab_nuclides are sorted or else they won't be applied - ! correctly in the cross_section module. The algorithm here is a simple - ! insertion sort -- don't need anything fancy! - - if (size(mat % i_sab_tables) > 1) then - SORT_SAB: do k = 2, size(mat % i_sab_tables) - ! Save value to move - m = k - temp_nuclide = mat % i_sab_nuclides(k) - temp_table = mat % i_sab_tables(k) - temp_frac = mat % i_sab_tables(k) - - MOVE_OVER: do - ! Check if insertion value is greater than (m-1)th value - if (temp_nuclide >= mat % i_sab_nuclides(m-1)) exit - - ! Move values over until hitting one that's not larger - mat % i_sab_nuclides(m) = mat % i_sab_nuclides(m-1) - mat % i_sab_tables(m) = mat % i_sab_tables(m-1) - mat % sab_fracs(m) = mat % sab_fracs(m-1) - m = m - 1 - - ! Exit if we've reached the beginning of the list - if (m == 1) exit - end do MOVE_OVER - - ! Put the original value into its new position - mat % i_sab_nuclides(m) = temp_nuclide - mat % i_sab_tables(m) = temp_table - mat % sab_fracs(m) = temp_frac - end do SORT_SAB - end if - - ! Deallocate temporary arrays for names of nuclides and S(a,b) tables - if (allocated(mat % names)) deallocate(mat % names) - end associate - end do - end subroutine assign_sab_tables - subroutine read_ce_cross_sections(nuc_temps, sab_temps) type(VectorReal), intent(in) :: nuc_temps(:) type(VectorReal), intent(in) :: sab_temps(:) @@ -5367,10 +5250,10 @@ contains call already_read % add(name) end if end do - end do - ! Associate S(a,b) tables with specific nuclides - call assign_sab_tables() + ! Associate S(a,b) tables with specific nuclides + call materials(i) % assign_sab_tables(nuclides, sab_tables) + end do ! Show which nuclide results in lowest energy for neutron transport do i = 1, size(nuclides) diff --git a/src/material_header.F90 b/src/material_header.F90 index 4415ad086..5d45c40d6 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -1,7 +1,11 @@ module material_header use constants + use error, only: fatal_error use nuclide_header, only: Nuclide + use sab_header, only: SAlphaBeta + use stl_vector, only: VectorReal, VectorInt + use string, only: to_str implicit none @@ -44,6 +48,7 @@ module material_header contains procedure :: set_density => material_set_density + procedure :: assign_sab_tables => material_assign_sab_tables end type Material contains @@ -85,4 +90,119 @@ contains end if end function material_set_density +!=============================================================================== +! ASSIGN_SAB_TABLES assigns S(alpha,beta) tables to specific nuclides within +! materials so the code knows when to apply bound thermal scattering data +!=============================================================================== + + subroutine material_assign_sab_tables(this, nuclides, sab_tables) + class(Material), intent(inout) :: this + type(Nuclide), intent(in) :: nuclides(:) + type(SAlphaBeta), intent(in) :: sab_tables(:) + + integer :: j ! index over nuclides in material + integer :: k ! index over S(a,b) tables in material + integer :: m ! position for sorting + integer :: temp_nuclide ! temporary value for sorting + integer :: temp_table ! temporary value for sorting + real(8) :: temp_frac ! temporary value for sorting + logical :: found + type(VectorInt) :: i_sab_tables + type(VectorInt) :: i_sab_nuclides + type(VectorReal) :: sab_fracs + + if (.not. allocated(this % i_sab_tables)) return + + ASSIGN_SAB: do k = 1, size(this % i_sab_tables) + ! 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 + ! name + found = .false. + associate (sab => sab_tables(this % i_sab_tables(k))) + FIND_NUCLIDE: do j = 1, size(this % nuclide) + if (any(sab % nuclides == nuclides(this % nuclide(j)) % name)) then + call i_sab_tables % push_back(this % i_sab_tables(k)) + call i_sab_nuclides % push_back(j) + call sab_fracs % push_back(this % sab_fracs(k)) + found = .true. + end if + end do FIND_NUCLIDE + end associate + + ! Check to make sure S(a,b) table matched a nuclide + if (.not. found) then + call fatal_error("S(a,b) table " // trim(this % & + sab_names(k)) // " did not match any nuclide on material " & + // trim(to_str(this % id))) + end if + end do ASSIGN_SAB + + ! Make sure each nuclide only appears in one table. + do j = 1, i_sab_nuclides % size() + do k = j+1, i_sab_nuclides % size() + if (i_sab_nuclides % data(j) == i_sab_nuclides % data(k)) then + call fatal_error(trim( & + nuclides(this % nuclide(i_sab_nuclides % data(j))) % name) & + // " in material " // trim(to_str(this % id)) // " was found & + &in multiple S(a,b) tables. Each nuclide can only appear in & + &one S(a,b) table per material.") + end if + end do + end do + + ! Update i_sab_tables and i_sab_nuclides + deallocate(this % i_sab_tables) + deallocate(this % sab_fracs) + if (allocated(this % i_sab_nuclides)) deallocate(this % i_sab_nuclides) + m = i_sab_tables % size() + allocate(this % i_sab_tables(m)) + allocate(this % i_sab_nuclides(m)) + allocate(this % sab_fracs(m)) + this % i_sab_tables(:) = i_sab_tables % data(1:m) + this % i_sab_nuclides(:) = i_sab_nuclides % data(1:m) + this % sab_fracs(:) = sab_fracs % data(1:m) + + ! Clear entries in vectors for next material + call i_sab_tables % clear() + call i_sab_nuclides % clear() + call sab_fracs % clear() + + ! If there are multiple S(a,b) tables, we need to make sure that the + ! entries in i_sab_nuclides are sorted or else they won't be applied + ! correctly in the cross_section module. The algorithm here is a simple + ! insertion sort -- don't need anything fancy! + + if (size(this % i_sab_tables) > 1) then + SORT_SAB: do k = 2, size(this % i_sab_tables) + ! Save value to move + m = k + temp_nuclide = this % i_sab_nuclides(k) + temp_table = this % i_sab_tables(k) + temp_frac = this % i_sab_tables(k) + + MOVE_OVER: do + ! Check if insertion value is greater than (m-1)th value + if (temp_nuclide >= this % i_sab_nuclides(m-1)) exit + + ! Move values over until hitting one that's not larger + this % i_sab_nuclides(m) = this % i_sab_nuclides(m-1) + this % i_sab_tables(m) = this % i_sab_tables(m-1) + this % sab_fracs(m) = this % sab_fracs(m-1) + m = m - 1 + + ! Exit if we've reached the beginning of the list + if (m == 1) exit + end do MOVE_OVER + + ! Put the original value into its new position + this % i_sab_nuclides(m) = temp_nuclide + this % i_sab_tables(m) = temp_table + this % sab_fracs(m) = temp_frac + end do SORT_SAB + end if + + ! Deallocate temporary arrays for names of nuclides and S(a,b) tables + if (allocated(this % names)) deallocate(this % names) + end subroutine material_assign_sab_tables + end module material_header From d0676c7a857488028a9a912d8ceae90b7dd55b9d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Aug 2017 06:31:09 -0500 Subject: [PATCH 085/229] Break up capi/__init__ into __init__, core, and error --- openmc/__init__.py | 1 - openmc/capi/__init__.py | 218 +--------------------------------------- openmc/capi/cell.py | 4 +- openmc/capi/core.py | 149 +++++++++++++++++++++++++++ openmc/capi/error.py | 66 ++++++++++++ openmc/capi/material.py | 4 +- openmc/capi/nuclide.py | 4 +- openmc/capi/tally.py | 4 +- 8 files changed, 231 insertions(+), 219 deletions(-) create mode 100644 openmc/capi/core.py create mode 100644 openmc/capi/error.py diff --git a/openmc/__init__.py b/openmc/__init__.py index 571b5a93a..d692ebbae 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -27,6 +27,5 @@ from openmc.particle_restart import * from openmc.mixin import * from openmc.plotter import * from openmc.search import * -import openmc.capi __version__ = '0.9.0' diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index fabeac947..2452da7b1 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -12,12 +12,10 @@ objects in the :mod:`openmc.capi` subpackage, for example: """ -from contextlib import contextmanager -from ctypes import CDLL, c_int, c_int32, c_double, POINTER +from ctypes import CDLL import sys from warnings import warn -from numpy.ctypeslib import as_array import pkg_resources @@ -32,221 +30,13 @@ _filename = pkg_resources.resource_filename( __name__, '_libopenmc.{}'.format(_suffix)) try: _dll = CDLL(_filename) - _available = True except OSError: warn("OpenMC shared library is not available from the Python API. This " "means you will not be able to use openmc.capi to make in-memory " "calls to OpenMC.") - _available = False - - -class GeometryError(Exception): - pass - - -def _error_code(s): - """Get error code corresponding to global constant.""" - return c_int.in_dll(_dll, s).value - - -def _error_handler(err, func, args): - """Raise exception according to error code.""" - if err == _error_code('e_out_of_bounds'): - raise IndexError('Array index out of bounds.') - - elif err == _error_code('e_cell_not_allocated'): - raise MemoryError("Memory has not been allocated for cells.") - - elif err == _error_code('e_cell_invalid_id'): - raise KeyError("No cell exists with ID={}.".format(args[0])) - - elif err == _error_code('e_cell_not_found'): - raise GeometryError("Could not find cell at position ({}, {}, {})" - .format(*args[0])) - - elif err == _error_code('e_nuclide_not_allocated'): - raise MemoryError("Memory has not been allocated for nuclides.") - - elif err == _error_code('e_nuclide_not_loaded'): - raise KeyError("No nuclide named '{}' has been loaded.") - - elif err == _error_code('e_nuclide_not_in_library'): - raise KeyError("Specified nuclide doesn't exist in the cross " - "section library.") - - elif err == _error_code('e_material_not_allocated'): - raise MemoryError("Memory has not been allocated for materials.") - - elif err == _error_code('e_material_invalid_id'): - raise KeyError("No material exists with ID={}.".format(args[0])) - - elif err == _error_code('e_tally_not_allocated'): - raise MemoryError("Memory has not been allocated for tallies.") - - elif err == _error_code('e_tally_invalid_id'): - raise KeyError("No tally exists with ID={}.".format(args[0])) - - elif err == _error_code('e_invalid_size'): - raise MemoryError("Array size mismatch with memory allocated.") - - elif err == _error_code('e_cell_no_material'): - raise GeometryError("Operation on cell requires that it be filled" - " with a material.") - - elif err == _error_code('w_below_min_bound'): - warn("Data has not been loaded beyond lower bound of {}.".format(args[0])) - - elif err == _error_code('w_above_max_bound'): - warn("Data has not been loaded beyond upper bound of {}.".format(args[0])) - - elif err < 0: - raise Exception("Unknown error encountered (code {}).".format(err)) - - -def calculate_volumes(): - """Run stochastic volume calculation""" - _dll.openmc_calculate_volumes() - - -def finalize(): - """Finalize simulation and free memory""" - _dll.openmc_finalize() - - -def find(xyz, rtype='cell'): - """Find the cell or material at a given point - - Parameters - ---------- - xyz : iterable of float - Cartesian coordinates of position - rtype : {'cell', 'material'} - Whether to return the cell or material ID - - Returns - ------- - int or None - ID of the cell or material. If 'material' is requested and no - material exists at the given coordinate, None is returned. - int - If the cell at the given point is repeated in the geometry, this - indicates which instance it is, i.e., 0 would be the first instance. - - """ - # Set second argument to openmc_find - if rtype == 'cell': - r_int = 1 - elif rtype == 'material': - r_int = 2 - else: - raise ValueError('Unknown return type: {}'.format(rtype)) - - # Call openmc_find - uid = c_int32() - instance = c_int32() - _dll.openmc_find((c_double*3)(*xyz), r_int, uid, instance) - return (uid.value if uid != 0 else None), instance.value - - -def hard_reset(): - """Reset tallies, timers, and pseudo-random number generator state.""" - _dll.openmc_hard_reset() - - -def init(intracomm=None): - """Initialize OpenMC - - Parameters - ---------- - intracomm : mpi4py.MPI.Intracomm or None - MPI intracommunicator - - """ - if intracomm is not None: - # If an mpi4py communicator was passed, convert it to an integer to - # be passed to openmc_init - try: - intracomm = intracomm.py2f() - except AttributeError: - pass - _dll.openmc_init(c_int(intracomm)) - else: - _dll.openmc_init(None) - - -def keff(): - """Return the calculated k-eigenvalue and its standard deviation. - - Returns - ------- - tuple - Mean k-eigenvalue and standard deviation of the mean - - """ - k = (c_double*2)() - _dll.openmc_get_keff(k) - return tuple(k) - - -def plot_geometry(): - """Plot geometry""" - _dll.openmc_plot_geometry() - - -def reset(): - """Reset tallies and timers.""" - _dll.openmc_reset() - - -def run(): - """Run simulation""" - _dll.openmc_run() - - -@contextmanager -def run_in_memory(intracomm=None): - """Provides context manager for calling OpenMC shared library functions. - - This function is intended to be used in a 'with' statement and ensures that - OpenMC is properly initialized/finalized. At the completion of the 'with' - block, all memory that was allocated during the block is freed. For - example:: - - with openmc.capi.run_in_memory(): - for i in range(n_iters): - openmc.capi.reset() - do_stuff() - openmc.capi.run() - - Parameters - ---------- - intracomm : mpi4py.MPI.Intracomm or None - MPI intracommunicator - - """ - init(intracomm) - yield - finalize() - - -# Set argument/return types -if _available: - _dll.openmc_calculate_volumes.restype = None - _dll.openmc_finalize.restype = None - _dll.openmc_find.argtypes = [ - POINTER(c_double*3), c_int, POINTER(c_int32), POINTER(c_int32)] - _dll.openmc_find.restype = c_int - _dll.openmc_find.errcheck = _error_handler - _dll.openmc_hard_reset.restype = None - _dll.openmc_init.argtypes = [POINTER(c_int)] - _dll.openmc_init.restype = None - _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] - _dll.openmc_get_keff.restype = c_int - _dll.openmc_get_keff.errcheck = _error_handler - _dll.openmc_plot_geometry.restype = None - _dll.openmc_run.restype = None - _dll.openmc_reset.restype = None - +else: + from .error import * + from .core import * from .nuclide import * from .material import * from .cell import * diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 9abada00c..f519d2f6d 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -4,7 +4,8 @@ from weakref import WeakValueDictionary import numpy as np -from openmc.capi import _dll, _error_handler +from . import _dll +from .error import _error_handler __all__ = ['CellView', 'cells'] @@ -40,6 +41,7 @@ class CellView(object): """ __instances = WeakValueDictionary() + def __new__(cls, *args): if args not in cls.__instances: instance = super().__new__(cls) diff --git a/openmc/capi/core.py b/openmc/capi/core.py new file mode 100644 index 000000000..74669540b --- /dev/null +++ b/openmc/capi/core.py @@ -0,0 +1,149 @@ +from contextlib import contextmanager +from ctypes import CDLL, c_int, c_int32, c_double, POINTER +from warnings import warn + +from . import _dll +from .error import _error_handler + + +_dll.openmc_calculate_volumes.restype = None +_dll.openmc_finalize.restype = None +_dll.openmc_find.argtypes = [POINTER(c_double*3), c_int, POINTER(c_int32), + POINTER(c_int32)] +_dll.openmc_find.restype = c_int +_dll.openmc_find.errcheck = _error_handler +_dll.openmc_hard_reset.restype = None +_dll.openmc_init.argtypes = [POINTER(c_int)] +_dll.openmc_init.restype = None +_dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] +_dll.openmc_get_keff.restype = c_int +_dll.openmc_get_keff.errcheck = _error_handler +_dll.openmc_plot_geometry.restype = None +_dll.openmc_run.restype = None +_dll.openmc_reset.restype = None + + +def calculate_volumes(): + """Run stochastic volume calculation""" + _dll.openmc_calculate_volumes() + + +def finalize(): + """Finalize simulation and free memory""" + _dll.openmc_finalize() + + +def find(xyz, rtype='cell'): + """Find the cell or material at a given point + + Parameters + ---------- + xyz : iterable of float + Cartesian coordinates of position + rtype : {'cell', 'material'} + Whether to return the cell or material ID + + Returns + ------- + int or None + ID of the cell or material. If 'material' is requested and no + material exists at the given coordinate, None is returned. + int + If the cell at the given point is repeated in the geometry, this + indicates which instance it is, i.e., 0 would be the first instance. + + """ + # Set second argument to openmc_find + if rtype == 'cell': + r_int = 1 + elif rtype == 'material': + r_int = 2 + else: + raise ValueError('Unknown return type: {}'.format(rtype)) + + # Call openmc_find + uid = c_int32() + instance = c_int32() + _dll.openmc_find((c_double*3)(*xyz), r_int, uid, instance) + return (uid.value if uid != 0 else None), instance.value + + +def hard_reset(): + """Reset tallies, timers, and pseudo-random number generator state.""" + _dll.openmc_hard_reset() + + +def init(intracomm=None): + """Initialize OpenMC + + Parameters + ---------- + intracomm : mpi4py.MPI.Intracomm or None + MPI intracommunicator + + """ + if intracomm is not None: + # If an mpi4py communicator was passed, convert it to an integer to + # be passed to openmc_init + try: + intracomm = intracomm.py2f() + except AttributeError: + pass + _dll.openmc_init(c_int(intracomm)) + else: + _dll.openmc_init(None) + + +def keff(): + """Return the calculated k-eigenvalue and its standard deviation. + + Returns + ------- + tuple + Mean k-eigenvalue and standard deviation of the mean + + """ + k = (c_double*2)() + _dll.openmc_get_keff(k) + return tuple(k) + + +def plot_geometry(): + """Plot geometry""" + _dll.openmc_plot_geometry() + + +def reset(): + """Reset tallies and timers.""" + _dll.openmc_reset() + + +def run(): + """Run simulation""" + _dll.openmc_run() + + +@contextmanager +def run_in_memory(intracomm=None): + """Provides context manager for calling OpenMC shared library functions. + + This function is intended to be used in a 'with' statement and ensures that + OpenMC is properly initialized/finalized. At the completion of the 'with' + block, all memory that was allocated during the block is freed. For + example:: + + with openmc.capi.run_in_memory(): + for i in range(n_iters): + openmc.capi.reset() + do_stuff() + openmc.capi.run() + + Parameters + ---------- + intracomm : mpi4py.MPI.Intracomm or None + MPI intracommunicator + + """ + init(intracomm) + yield + finalize() diff --git a/openmc/capi/error.py b/openmc/capi/error.py new file mode 100644 index 000000000..2058ceb20 --- /dev/null +++ b/openmc/capi/error.py @@ -0,0 +1,66 @@ +from ctypes import c_int + +from . import _dll + + +class GeometryError(Exception): + pass + + +def _error_handler(err, func, args): + """Raise exception according to error code.""" + + # Get error code corresponding to global constant. + def errcode(s): + return c_int.in_dll(_dll, s).value + + if err == errcode('e_out_of_bounds'): + raise IndexError('Array index out of bounds.') + + elif err == errcode('e_cell_not_allocated'): + raise MemoryError("Memory has not been allocated for cells.") + + elif err == errcode('e_cell_invalid_id'): + raise KeyError("No cell exists with ID={}.".format(args[0])) + + elif err == errcode('e_cell_not_found'): + raise GeometryError("Could not find cell at position ({}, {}, {})" + .format(*args[0])) + + elif err == errcode('e_nuclide_not_allocated'): + raise MemoryError("Memory has not been allocated for nuclides.") + + elif err == errcode('e_nuclide_not_loaded'): + raise KeyError("No nuclide named '{}' has been loaded.") + + elif err == errcode('e_nuclide_not_in_library'): + raise KeyError("Specified nuclide doesn't exist in the cross " + "section library.") + + elif err == errcode('e_material_not_allocated'): + raise MemoryError("Memory has not been allocated for materials.") + + elif err == errcode('e_material_invalid_id'): + raise KeyError("No material exists with ID={}.".format(args[0])) + + elif err == errcode('e_tally_not_allocated'): + raise MemoryError("Memory has not been allocated for tallies.") + + elif err == errcode('e_tally_invalid_id'): + raise KeyError("No tally exists with ID={}.".format(args[0])) + + elif err == errcode('e_invalid_size'): + raise MemoryError("Array size mismatch with memory allocated.") + + elif err == errcode('e_cell_no_material'): + raise GeometryError("Operation on cell requires that it be filled" + " with a material.") + + elif err == errcode('w_below_min_bound'): + warn("Data has not been loaded beyond lower bound of {}.".format(args[0])) + + elif err == errcode('w_above_max_bound'): + warn("Data has not been loaded beyond upper bound of {}.".format(args[0])) + + elif err < 0: + raise Exception("Unknown error encountered (code {}).".format(err)) diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 564ecaa05..d07d7aa8a 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -5,7 +5,8 @@ from weakref import WeakValueDictionary import numpy as np from numpy.ctypeslib import as_array -from openmc.capi import _dll, _error_handler, NuclideView +from . import _dll, NuclideView +from .error import _error_handler __all__ = ['MaterialView', 'materials'] @@ -58,6 +59,7 @@ class MaterialView(object): """ __instances = WeakValueDictionary() + def __new__(cls, *args): if args not in cls.__instances: instance = super().__new__(cls) diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 384d0ae91..4c6248d6b 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -5,7 +5,8 @@ from weakref import WeakValueDictionary import numpy as np from numpy.ctypeslib import as_array -from openmc.capi import _dll, _error_handler +from . import _dll +from .error import _error_handler __all__ = ['NuclideView', 'nuclides', 'load_nuclide'] @@ -53,6 +54,7 @@ class NuclideView(object): """ __instances = WeakValueDictionary() + def __new__(cls, *args): if args not in cls.__instances: instance = super().__new__(cls) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index cc8c13a5a..611f1ce87 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -4,7 +4,8 @@ from weakref import WeakValueDictionary from numpy.ctypeslib import as_array -from openmc.capi import _dll, _error_handler, NuclideView +from . import _dll, NuclideView +from .error import _error_handler __all__ = ['TallyView', 'tallies'] @@ -52,6 +53,7 @@ class TallyView(object): """ __instances = WeakValueDictionary() + def __new__(cls, *args): if args not in cls.__instances: instance = super().__new__(cls) From 745b0b2d83cdbd28fcb4f565b77b31ef6f888350 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Aug 2017 06:33:46 -0500 Subject: [PATCH 086/229] Remove try/except block around CDLL --- openmc/capi/__init__.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 2452da7b1..355304a31 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -28,16 +28,11 @@ else: # Open shared library _filename = pkg_resources.resource_filename( __name__, '_libopenmc.{}'.format(_suffix)) -try: - _dll = CDLL(_filename) -except OSError: - warn("OpenMC shared library is not available from the Python API. This " - "means you will not be able to use openmc.capi to make in-memory " - "calls to OpenMC.") -else: - from .error import * - from .core import * - from .nuclide import * - from .material import * - from .cell import * - from .tally import * +_dll = CDLL(_filename) + +from .error import * +from .core import * +from .nuclide import * +from .material import * +from .cell import * +from .tally import * From cd8a297353c37cfeb4fdf4ef5600baa592b5e7d9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Aug 2017 07:12:37 -0500 Subject: [PATCH 087/229] Break up capi.find into find_cell and find_material --- docs/source/pythonapi/capi.rst | 3 ++- openmc/capi/core.py | 44 ++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index a586cb4ad..6e4e860fa 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -14,7 +14,8 @@ Functions openmc.capi.calculate_volumes openmc.capi.finalize - openmc.capi.find + openmc.capi.find_cell + openmc.capi.find_material openmc.capi.hard_reset openmc.capi.init openmc.capi.keff diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 74669540b..fe5416dd6 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -33,39 +33,47 @@ def finalize(): _dll.openmc_finalize() -def find(xyz, rtype='cell'): - """Find the cell or material at a given point +def find_cell(xyz): + """Find the cell at a given point Parameters ---------- xyz : iterable of float Cartesian coordinates of position - rtype : {'cell', 'material'} - Whether to return the cell or material ID Returns ------- - int or None - ID of the cell or material. If 'material' is requested and no - material exists at the given coordinate, None is returned. + int + ID of the cell. int If the cell at the given point is repeated in the geometry, this indicates which instance it is, i.e., 0 would be the first instance. """ - # Set second argument to openmc_find - if rtype == 'cell': - r_int = 1 - elif rtype == 'material': - r_int = 2 - else: - raise ValueError('Unknown return type: {}'.format(rtype)) - - # Call openmc_find uid = c_int32() instance = c_int32() - _dll.openmc_find((c_double*3)(*xyz), r_int, uid, instance) - return (uid.value if uid != 0 else None), instance.value + _dll.openmc_find((c_double*3)(*xyz), 1, uid, instance) + return uid.value, instance.value + + +def find_material(xyz): + """Find the material at a given point + + Parameters + ---------- + xyz : iterable of float + Cartesian coordinates of position + + Returns + ------- + int or None + ID of the material or None is no material is found + + """ + uid = c_int32() + instance = c_int32() + _dll.openmc_find((c_double*3)(*xyz), 2, uid, instance) + return uid.value if uid != 0 else None def hard_reset(): From 242d633185828d48e522350a48fae96ffbe0c8f9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Aug 2017 10:35:23 -0500 Subject: [PATCH 088/229] Address more @smharper comments --- src/api.F90 | 9 +++++++-- src/simulation.F90 | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 0941e60fe..d45360d28 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -169,7 +169,7 @@ contains end if end associate - ! assign error codes for outside of temperature bounds provided the + ! Assign error codes for outside of temperature bounds provided the ! temperature was changed correctly. This needs to be done after ! changing the temperature based on the logical structure above. if (err == 0) then @@ -627,7 +627,7 @@ contains real(C_DOUBLE), intent(in) :: density(n) integer(C_INT) :: err - integer :: i, j, k + integer :: i character(C_CHAR), pointer :: string(:) character(len=:, kind=C_CHAR), allocatable :: name_ @@ -868,6 +868,11 @@ contains end if end function openmc_tally_set_nuclides +!=============================================================================== +! TO_F_STRING takes a null-terminated array of C chars and turns it into a +! deferred-length character string. Yay Fortran 2003! +!=============================================================================== + function to_f_string(c_string) result(f_string) character(kind=C_CHAR), intent(in) :: c_string(*) character(:), allocatable :: f_string diff --git a/src/simulation.F90 b/src/simulation.F90 index b406679ce..7427443bb 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -394,9 +394,9 @@ contains subroutine finalize_simulation() - integer :: i ! loop index for tallies - integer :: n ! size of arrays #ifdef MPI + integer :: i ! loop index for tallies + integer :: n ! size of arrays integer :: mpi_err ! MPI error code integer(8) :: temp real(8) :: tempr(3) ! temporary array for communication From db3fb155bd29a43b151efe95fd2b33fadb1e41c2 Mon Sep 17 00:00:00 2001 From: Brittany Grayson Date: Thu, 3 Aug 2017 14:44:23 -0600 Subject: [PATCH 089/229] get_all_bins subroutine This alters tally_filter.F90, tally.F90 and tally_filter_header.F90 --- .DS_Store | Bin 0 -> 10244 bytes examples/jupyter/pincell.ipynb | 380 +--- src/CTestTestfile.cmake | 170 ++ src/DartConfiguration.tcl | 112 ++ src/Makefile | 3358 ++++++++++++++++++++++++++++++++ src/tally.F90 | 53 +- src/tally_filter.F90 | 527 ++--- src/tally_filter_header.F90 | 11 +- tests/.DS_Store | Bin 0 -> 14340 bytes 9 files changed, 3907 insertions(+), 704 deletions(-) create mode 100644 .DS_Store create mode 100644 src/CTestTestfile.cmake create mode 100644 src/DartConfiguration.tcl create mode 100644 src/Makefile create mode 100644 tests/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..140d256a9a1efe014802c226c6d782f149adf8ab GIT binary patch literal 10244 zcmeHMTWl298UBA?@C+H0d{t;g)9`o0JGx!&KA-xT1Yb=@r%3GLJsnv!b#8r zCw(6Y8w1E?&;$Jf2?wce7d*N<=s5#k$oDy_JLua$z8TQDPY>8&!35PXN#38(I<|&t zr~ys1IlrZf@i3fCwYrr!yb!8SqTbBVX!1}XmZ)bT{69kYIvR5?jbcAM3`4NL63tkJ zX98SFWv19Tss0e2@e{;X^Et38QJjMyY7vdBKz+3coeN>v_=4E_AeMO6iS0@FEcJ$Q zZ-=~z?FtqbgF_xFahWIEL2oqMAs@z2u*D^W$-xQ2Gd(e7%uvd#^y2!H0!-C$FNgY7 zV0sFni6;!AB|__jD-ybc?%7H_W2^#SO?YP^t`}8rRx{jf@!#3XXjO{s;;SB zR42)@Brla79Xer84|%FrbknLc%HIr4&-&?%ZJXt^nmuCZ)8k50k8OFXVd+i)K6ccw zG?`%(O?b>nntR%Ir+p@d& zcz*WunJ=9^_dS{fy3qd(g?jN`etw@)J_$x{${!xSSsLCS6{S4D#YDOz zVNE9Y{9TYJCsP|mN`YjF*JSFM<2)@Xn6Ye2C)A)QOs4vLlmwe#F9nM+I0bX?UAP3V z!8`CP_zT>Ek8mlr;JvsB+i@#y#}xMB7x5rIf`@Qa_*a$Ybd6u1Z&0IzKc`bej%C`` zB;_!4EiDZZWJ3!HX|YyFK7hPiWgi$~K>DwKy7ZfyTUwh}tcdMskQ9GR z2)nHJ)#APM1lDj-@coqFDUEL%l7rzVf=BKg6Rs+brfScU)=6 zsb;Qds-C{rG+7X!yl~(N%yOt`_?T-u9tAL}Y+O-_u6{_Tx{N7(AJs@zEfAQJsZKF8 z`T1q7tM6HN|K_e8yVF-#T`u8}qM!_$W5ofuKwoNj3pkdD#sjO7^ z*e+)*HLqW3R2u3@s`24s);Lu(yjdkFNusW`@r10rCXH#-lYU!co*FNSuZ@33l15p6 zkE7F5WXCqd?~@f(%DBXWsG>dAAuFz&IY~cO!gWjR0ZGy1!#seBtZlJwN$Hc1PKmfH zGMi$bm*nA`ozGLJU6HpZzE@J-l^$aaA5>j$prBjSHXB0E+IW0~5t;1V3d431zHbExA4o#d|Gp>xvss?}>^ZHGyT`b>Cj zl-7(=$5w`Pg`w}cx2;WKdK0hfH?+kRr1c>4(oGwvw8}5r+(~8CBz;lVwKdkJ)RM}D z=Z>ARm{LQ_K$JeXhe{Wb;6-WA8Y%_a9o|l{x7F*f;X3>kKENspkV{FYank5U?7%L3 z5WhfSvX8a}{dfe2@feQc7%6lT4Sbxdbc(C=JU)RJ@XMstuj4oIY5X>R2QT7}@DlzQ ze}XTNVqf8keFNXZxA7hP8NP>C@J2|jrEQBZSNubzT0>h69~GH9ih*j;n*{s*zyFi} z|G%U99CapQAY$Nu%K+Bw8`_tqI!kBBaP{n4dxGxcbhC@$=7i-g^x&W4$@0(f^uj*J u^OG>;`8!zdm!f>;KPN1u==#6^84#WSiS@wdGW20AI{%9!Bi_a5|NjCSzqYpk literal 0 HcmV?d00001 diff --git a/examples/jupyter/pincell.ipynb b/examples/jupyter/pincell.ipynb index 163429688..6c02f3648 100644 --- a/examples/jupyter/pincell.ipynb +++ b/examples/jupyter/pincell.ipynb @@ -10,9 +10,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -31,9 +29,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "u235 = openmc.Nuclide('U235')\n", @@ -53,9 +49,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -88,9 +82,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -123,9 +115,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -203,9 +193,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "zirconium = openmc.Material(2, \"zirconium\")\n", @@ -228,9 +216,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "water.add_s_alpha_beta('c_H_in_H2O')" @@ -286,9 +272,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -318,9 +302,7 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -375,9 +357,7 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -439,9 +419,7 @@ { "cell_type": "code", "execution_count": 15, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -464,7 +442,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "\n" @@ -489,9 +467,7 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "uo2_three = openmc.Material()\n", @@ -542,9 +518,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "inside_sphere = -sph\n", @@ -561,9 +535,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -608,9 +580,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -637,9 +607,7 @@ { "cell_type": "code", "execution_count": 22, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "cell = openmc.Cell()\n", @@ -706,15 +674,13 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -735,15 +701,13 @@ { "cell_type": "code", "execution_count": 26, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "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\nkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw\n8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUp\nCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNf\nkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpJoNPAj4qkRcUNETEfEYxGxMSKW\nL3DMbRGxt+WxJyKuarKfkpTBwQ2//o3ACuA04EnANcDVwPp5jinAJ4H3AVFv29VcFyUph8YCPyJW\nAeuAsVLKnfW2PwJuiYh3lVJ2zHP4rlLKI031TZIyanJKZy3w2EzY1zZTVfDPW+DYsyPikYj4RkRc\nHBFPaayXkpREk1M6K4GHWzeUUvZExA/rfXO5AXgAeAg4Efgw8GzgrIb6KUkptB34EXEJcOE8TQqw\nutMOlVI2tjy9JyJ2AJsj4rhSyn1zHbdhwwZGRkb22TY+Ps74+HinXZGkxk1MTDAxMbHPtunp6Ube\nK0op7R0Q8TTgaQs0+w7wJuAjpZSft42IZcDjwFmllM8v8v0OA/4XWFdK+dJ+9o8Ck5OTk4yOji7y\nU0hS/5qammJsbAyqa6BTS/W6bVf4pZRHgUcXahcRW4AjI2JNyzz+aVQrb+5o4y3XUP3W8P12+ypJ\n+oXGLtqWUrYDm4BPRcSpEfFC4C+BiZkVOhHxjIjYFhGn1M+fFRHvjYjRiDgmIs4ErgW+Wkr596b6\nKkkZNL0O/43Ax6lW5+wF/h54Z8v+Q6guyB5WP/8p8LK6zXLgv4C/Az7UcD8laeg1GvillP9mnj+y\nKqU8ACxref4g8JIm+yRJWXkvHUlKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElK\nwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCX\npCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQM\nfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElK\n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\n", + "image/png": "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\nUWSzAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -764,15 +728,13 @@ { "cell_type": "code", "execution_count": 27, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAFkCAYAAAAjYoA8AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAFEZJREFUeJzt3X+MZWV9x/H31wVF1jBYaXdrpPwIVZZEYGeguhqtFXFD\njWhS1IysktK0GrTaIRYT46/SKNEKW2y7LbpRoMA0tiZIxWbjomhTdjGdAbR2QY2gRdx1RTq27qKy\n+/SPc0bvTnd+3Lv33F/f9yu5gXvuc+597rPnfuZ7n/PMmSilIEkafU/qdwckSb1h4EtSEga+JCVh\n4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEo0GfkS8KCJui4jvRcTBiLhwBfu8JCJmIuLx\niPhGRFzSZB8lKYumK/zVwL3AZcCyF+2JiJOBzwJ3AGcB1wJbI+L85rooSTlEry6eFhEHgVeXUm5b\nos2HgAtKKWe2bJsGxkopv9uDbkrSyBq0OfznA9sXbNsGbOhDXyRppBzV7w4ssBbYs2DbHuC4iHhK\nKeWnC3eIiGcAG4GHgMcb76EkNe8Y4GRgWynl0W496aAFfic2Ajf3uxOS1ICLgVu69WSDFvi7gTUL\ntq0Bfny46r72EMBNN93EunXrGuza6JmammLz5s397kZ3TPTmZaaYYjM9GrOZ3rxML4zUsdYDu3bt\nYtOmTVDnW7cMWuDvAC5YsO3l9fbFPA6wbt06xsfHm+rXSBobGxueMYt+d6Ayxhjj9GjMlvshNkR/\nrG6ojrXB0tVp6qbX4a+OiLMi4ux606n1/RPrx6+KiBtadvm7us2HIuI5EXEZcBFwTZP9lKQMmq7w\nzwG+SFWLFODqevsNwKVUJ2lPnG9cSnkoIl4BbAbeBjwM/EEpZeHKHY2qAankh8JiYzVElb96q9HA\nL6V8iSW+RZRSfv8w275Mz2Zk1TcGe3P8QaBFDNo6fPXQ5ORkv7swdCZxzDrhsTYYBu2krXqoZx/C\nEarmhzrwD/fv0KOq38AfDAa+mjFCIT/SWv+dnPIZeU7pSFISVvg6clbzo6GPUz7qDQNfnTHkc3DK\nZ6Q4pSNJSVjha2Ws6LXwGLDiHzpW+JKUhBW+FmdVr6U4vz90DHz9kgGvTjndMxSc0pGkJAx8Vazu\n1U0eTwPJKZ3M/FCqSc7xDxwrfElKwgo/G6t69YPV/kAw8LMw6DUo5o9Fg7/nnNKRpCSs8EeZVb0G\nmdM8PWfgjxpDXsPI8O8Jp3QkKQkr/FFhZa9R4UndxljhS1ISBv4osLrXKPK47jqndIaVHwZl4Mnc\nrrLCl6QkrPCHjZW9svJk7hGzwh8mhr3k5+AIGPiSlIRTOsPAikY6lNM7HTHwB5UhLy3PVTxtcUpH\nkpKwwh80VvZSZ5zmWZYV/iAx7KUj5+doUQa+JCXhlM4gsCKRusvpncOywpekJAz8frO6l5rj5+sQ\nTun0iwei1BtO7/yCFb4kJWHg94PVvdR7fu6c0ukpDzipv5JP71jhS1ISVvi9YGUvDZaklb4VftMM\ne2lwJft8GviSlIRTOk1JVjlIQyvR9I4VviQlYeBLUhIGfhOczpGGT4LPrYEvSUl40rabElQI0kgb\n8RO4VvjdYthLo2NEP88GviQl4ZTOkRrRSkBKbwSnd6zwJSkJA1+SkjDwj4TTOdLoG6HPuXP4nRih\nA0DSCozIfL4VviQlYYXfDit7Kbchr/St8CUpCQNfkpIw8FfK6RxJ84Y0Dwx8SUrCwJekJHoS+BHx\nloh4MCL2R8TOiDh3ibaXRMTBiDhQ//dgROzrRT8P3yGG9uubpAYNYTY0HvgR8TrgauB9wHrgPmBb\nRJywxG5zwNqW20lN91OSRl0vKvwp4LpSyo2llPuBNwP7gEuX2KeUUvaWUn5Q3/b2oJ//35D99JbU\nB0OUE40GfkQcDUwAd8xvK6UUYDuwYYldnxYRD0XEdyPi1og4o8l+SlIGTVf4JwCrgD0Ltu+hmqo5\nnAeoqv8LgYup+nhXRDyzqU5KUgYDd2mFUspOYOf8/YjYAewC3kR1HqB5Q/QVTdIAGJJLLjQd+D8E\nDgBrFmxfA+xeyROUUp6IiHuA05ZqNzU1xdjY2CHbJicnmZycXHlvJanHpqenmZ6ePmTb3NxcI68V\n1ZR6cyJiJ3B3KeXt9f0Avgt8tJTyFyvY/0nA14HbSynvOMzj48DMzMwM4+PjXep0d55GUjJditPZ\n2VkmJiYAJkops9151t5M6VwDXB8RM8BXqFbtHAtcDxARNwIPl1LeVd9/D9WUzreA44ErgN8Atvag\nr4a9pM4FAz2t03jgl1I+Va+5v5JqKudeYGPLUstnAU+07PJ04GNUJ3UfA2aADfWSzuYY9JK6YYDn\n83ty0raUsgXYsshjL11w/3Lg8l70S5Iy8Vo6kpSEgS9JSRj44Py9pO4bwFwx8CUpCQNfkpIYuEsr\n9NQAfuWSNEIGbImmFb4kJWHgS1ISBr4kJZFzDt+5e0m9NCBz+Vb4kpSEgS9JSeQLfKdzJPVLn/Mn\nX+BLUlIGviQlYeBLUhIGviQlkWcdvidrJQ2CPq7Jt8KXpCQMfElKIkfgO50jadD0IZdyBL4kycCX\npCwMfElKwsCXpCRGex2+J2slDbIer8m3wpekJAx8SUrCwJekJAx8SUrCwJekJEY38F2hI2lY9Civ\nRjfwJUmHMPAlKQkDX5KSMPAlKQkDX5KSGL1r6bg6R9Iw6sF1dazwJSkJA1+SkjDwJSkJA1+SkjDw\nJSkJA1+SkjDwJSmJ0Qp81+BLGnYN5thoBb4kaVEGviQlYeBLUhIGviQlYeBLUhIGviQlYeBLUhIG\nviQlYeBLUhIGviQlMTqBP9HvDkhSlzSUZ6MT+JKkJRn4kpSEgS9JSRj4kpSEgS9JSRj4kpSEgS9J\nSRj4kpSEgS9JSRj4kpRETwI/It4SEQ9GxP6I2BkR5y7T/jURsatuf19EXNCLfkrSKGs88CPidcDV\nwPuA9cB9wLaIOGGR9i8AbgE+DpwNfAa4NSLOaLqvkjTKelHhTwHXlVJuLKXcD7wZ2Adcukj7twH/\nUkq5ppTyQCnlvcAs8NYe9FWSRlajgR8RR1Nd9+2O+W2llAJsBzYsstuG+vFW25ZoL0lagaYr/BOA\nVcCeBdv3AGsX2Wdtm+0lSStwVL870C1TL55ibGzskG2Tk5NMTk72qUeStLzp6Wmmp6cP2TY3Nwdf\n7v5rNR34PwQOAGsWbF8D7F5kn91ttgdg8+bNjI+Pd9JHSeqbwxWms7OzTEx0/6+gNDqlU0r5OTAD\nnDe/LSKivn/XIrvtaG1fO7/eLknqUC+mdK4Bro+IGeArVKt2jgWuB4iIG4GHSynvqttfC9wZEZcD\ntwOTVCd+/7AHfZWkkdV44JdSPlWvub+SamrmXmBjKWVv3eRZwBMt7XdExOuBD9S3bwKvKqX8Z9N9\nlaRR1pOTtqWULcCWRR576WG2fRr4dNP9kqRMvJaOJCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+\nJCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh\n4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtS\nEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+\nJCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh\n4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCXRaOBHxNMj4uaImIuI\nxyJia0SsXmafOyPiYMvtQERsabKfkpTBUQ0//y3AGuA84MnA9cB1wKYl9inAx4D3AFFv29dcFyUp\nh8YCPyJOBzYCE6WUe+ptfwzcHhHvKKXsXmL3faWUvU31TZIyanJKZwPw2HzY17ZTVfDPW2bfiyNi\nb0R8LSI+GBFPbayXkpREk1M6a4EftG4opRyIiB/Vjy3mZuA7wCPAmcCHgWcDFzXUT0lKoe3Aj4ir\ngHcu0aQA6zrtUClla8vdr0fEbmB7RJxSSnlwsf2mpqYYGxs7ZNvk5CSTk5OddkWSGjc9Pc309PQh\n2+bm5hp5rSiltLdDxDOAZyzT7NvAG4CPlFJ+0TYiVgGPAxeVUj6zwtc7FvhfYGMp5fOHeXwcmJmZ\nmWF8fHyF70KSBtfs7CwTExNQnQOd7dbztl3hl1IeBR5drl1E7ACOj4j1LfP451GtvLm7jZdcT/Wt\n4fvt9lWS9EuNnbQtpdwPbAM+HhHnRsQLgb8CpudX6ETEMyNiV0ScU98/NSLeHRHjEXFSRFwI3AB8\nqZTyH031VZIyaHod/uuBv6ZanXMQ+Cfg7S2PH011QvbY+v7PgJfVbVYD/wX8I/CBhvspSSOv0cAv\npfw3S/ySVSnlO8CqlvsPAy9psk+SlJXX0pGkJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8\nSUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrC\nwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJek\nJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8\nSUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrC\n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\n", + "image/png": "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\nSUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -891,9 +853,7 @@ { "cell_type": "code", "execution_count": 32, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "water_region = +left & -right & +bottom & -top & +clad_or\n", @@ -913,9 +873,7 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -962,9 +920,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1045,9 +1001,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1110,9 +1064,7 @@ { "cell_type": "code", "execution_count": 40, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "t.nuclides = ['U235']\n", @@ -1129,9 +1081,7 @@ { "cell_type": "code", "execution_count": 41, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1167,7 +1117,6 @@ "cell_type": "code", "execution_count": 42, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1203,9 +1152,9 @@ " | The OpenMC Monte Carlo Code\n", " Copyright | 2011-2017 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.8.0\n", - " Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n", - " Date/Time | 2017-04-13 17:17:32\n", + " Version | 0.9.0\n", + " Git SHA1 | a8bee7757465e4617eb76e0c72f20cdf57771dd9\n", + " Date/Time | 2017-08-03 13:37:33\n", " MPI Processes | 1\n", " OpenMP Threads | 4\n", "\n", @@ -1213,159 +1162,33 @@ " Reading geometry XML file...\n", " Reading materials XML file...\n", " Reading cross sections XML file...\n", - " Reading U235 from /home/smharper/openmc/data/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/smharper/openmc/data/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/smharper/openmc/data/nndc_hdf5/O16.h5\n", - " Reading Zr90 from /home/smharper/openmc/data/nndc_hdf5/Zr90.h5\n", - " Reading Zr91 from /home/smharper/openmc/data/nndc_hdf5/Zr91.h5\n", - " Reading Zr92 from /home/smharper/openmc/data/nndc_hdf5/Zr92.h5\n", - " Reading Zr94 from /home/smharper/openmc/data/nndc_hdf5/Zr94.h5\n", - " Reading Zr96 from /home/smharper/openmc/data/nndc_hdf5/Zr96.h5\n", - " Reading H1 from /home/smharper/openmc/data/nndc_hdf5/H1.h5\n", - " Reading O17 from /home/smharper/openmc/data/nndc_hdf5/O17.h5\n", - " Reading c_H_in_H2O from /home/smharper/openmc/data/nndc_hdf5/c_H_in_H2O.h5\n", + " Reading U235 from /Users/brittanygrayson/nndc_hdf5/U235.h5\n", + " Reading U238 from /Users/brittanygrayson/nndc_hdf5/U238.h5\n", + " Reading O16 from /Users/brittanygrayson/nndc_hdf5/O16.h5\n", + " Reading Zr90 from /Users/brittanygrayson/nndc_hdf5/Zr90.h5\n", + " Reading Zr91 from /Users/brittanygrayson/nndc_hdf5/Zr91.h5\n", + " Reading Zr92 from /Users/brittanygrayson/nndc_hdf5/Zr92.h5\n", + " Reading Zr94 from /Users/brittanygrayson/nndc_hdf5/Zr94.h5\n", + " Reading Zr96 from /Users/brittanygrayson/nndc_hdf5/Zr96.h5\n", + " Reading H1 from /Users/brittanygrayson/nndc_hdf5/H1.h5\n", + " Reading O17 from /Users/brittanygrayson/nndc_hdf5/O17.h5\n", + " Reading c_H_in_H2O from /Users/brittanygrayson/nndc_hdf5/c_H_in_H2O.h5\n", " Maximum neutron transport energy: 2.00000E+07 eV for U235\n", " Reading tallies XML file...\n", - " Building neighboring cells lists for each surface...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k \n", - " ========= ======== ==================== \n", - " 1/1 1.32572 \n", - " 2/1 1.46138 \n", - " 3/1 1.46068 \n", - " 4/1 1.39592 \n", - " 5/1 1.37519 \n", - " 6/1 1.38777 \n", - " 7/1 1.50242 \n", - " 8/1 1.42042 \n", - " 9/1 1.47458 \n", - " 10/1 1.49148 \n", - " 11/1 1.39339 \n", - " 12/1 1.40637 1.39988 +/- 0.00649\n", - " 13/1 1.42972 1.40983 +/- 0.01063\n", - " 14/1 1.46319 1.42317 +/- 0.01531\n", - " 15/1 1.41538 1.42161 +/- 0.01196\n", - " 16/1 1.38163 1.41494 +/- 0.01182\n", - " 17/1 1.41257 1.41461 +/- 0.01000\n", - " 18/1 1.43455 1.41710 +/- 0.00901\n", - " 19/1 1.33136 1.40757 +/- 0.01241\n", - " 20/1 1.41560 1.40837 +/- 0.01113\n", - " 21/1 1.38911 1.40662 +/- 0.01021\n", - " 22/1 1.28621 1.39659 +/- 0.01370\n", - " 23/1 1.45693 1.40123 +/- 0.01343\n", - " 24/1 1.46839 1.40603 +/- 0.01333\n", - " 25/1 1.46738 1.41012 +/- 0.01306\n", - " 26/1 1.43977 1.41197 +/- 0.01236\n", - " 27/1 1.44066 1.41366 +/- 0.01173\n", - " 28/1 1.39358 1.41254 +/- 0.01112\n", - " 29/1 1.39142 1.41143 +/- 0.01057\n", - " 30/1 1.38525 1.41012 +/- 0.01012\n", - " 31/1 1.38025 1.40870 +/- 0.00973\n", - " 32/1 1.45348 1.41074 +/- 0.00949\n", - " 33/1 1.35893 1.40848 +/- 0.00935\n", - " 34/1 1.32332 1.40493 +/- 0.00963\n", - " 35/1 1.46285 1.40725 +/- 0.00952\n", - " 36/1 1.33760 1.40457 +/- 0.00953\n", - " 37/1 1.41117 1.40482 +/- 0.00917\n", - " 38/1 1.45574 1.40664 +/- 0.00903\n", - " 39/1 1.43472 1.40760 +/- 0.00876\n", - " 40/1 1.30110 1.40405 +/- 0.00918\n", - " 41/1 1.41765 1.40449 +/- 0.00889\n", - " 42/1 1.45300 1.40601 +/- 0.00874\n", - " 43/1 1.40491 1.40597 +/- 0.00847\n", - " 44/1 1.42053 1.40640 +/- 0.00823\n", - " 45/1 1.38805 1.40588 +/- 0.00801\n", - " 46/1 1.34293 1.40413 +/- 0.00798\n", - " 47/1 1.35441 1.40279 +/- 0.00787\n", - " 48/1 1.29370 1.39991 +/- 0.00818\n", - " 49/1 1.48467 1.40209 +/- 0.00826\n", - " 50/1 1.41759 1.40248 +/- 0.00806\n", - " 51/1 1.37151 1.40172 +/- 0.00790\n", - " 52/1 1.42403 1.40225 +/- 0.00773\n", - " 53/1 1.38826 1.40193 +/- 0.00755\n", - " 54/1 1.48944 1.40392 +/- 0.00764\n", - " 55/1 1.41452 1.40415 +/- 0.00747\n", - " 56/1 1.47337 1.40566 +/- 0.00746\n", - " 57/1 1.35700 1.40462 +/- 0.00738\n", - " 58/1 1.40305 1.40459 +/- 0.00722\n", - " 59/1 1.41608 1.40482 +/- 0.00708\n", - " 60/1 1.47254 1.40618 +/- 0.00706\n", - " 61/1 1.36847 1.40544 +/- 0.00696\n", - " 62/1 1.34103 1.40420 +/- 0.00694\n", - " 63/1 1.39510 1.40403 +/- 0.00681\n", - " 64/1 1.40228 1.40399 +/- 0.00668\n", - " 65/1 1.29401 1.40200 +/- 0.00686\n", - " 66/1 1.42693 1.40244 +/- 0.00675\n", - " 67/1 1.36447 1.40177 +/- 0.00666\n", - " 68/1 1.37498 1.40131 +/- 0.00656\n", - " 69/1 1.36958 1.40077 +/- 0.00647\n", - " 70/1 1.38585 1.40053 +/- 0.00637\n", - " 71/1 1.42133 1.40087 +/- 0.00627\n", - " 72/1 1.44900 1.40164 +/- 0.00622\n", - " 73/1 1.37696 1.40125 +/- 0.00613\n", - " 74/1 1.48851 1.40261 +/- 0.00619\n", - " 75/1 1.38933 1.40241 +/- 0.00610\n", - " 76/1 1.41780 1.40264 +/- 0.00601\n", - " 77/1 1.41054 1.40276 +/- 0.00592\n", - " 78/1 1.38194 1.40246 +/- 0.00584\n", - " 79/1 1.38446 1.40219 +/- 0.00576\n", - " 80/1 1.37504 1.40181 +/- 0.00569\n", - " 81/1 1.40550 1.40186 +/- 0.00561\n", - " 82/1 1.49785 1.40319 +/- 0.00569\n", - " 83/1 1.35613 1.40255 +/- 0.00565\n", - " 84/1 1.41786 1.40275 +/- 0.00557\n", - " 85/1 1.38444 1.40251 +/- 0.00550\n", - " 86/1 1.40459 1.40254 +/- 0.00543\n", - " 87/1 1.39923 1.40249 +/- 0.00536\n", - " 88/1 1.44540 1.40304 +/- 0.00532\n", - " 89/1 1.45962 1.40376 +/- 0.00530\n", - " 90/1 1.37057 1.40335 +/- 0.00525\n", - " 91/1 1.38115 1.40307 +/- 0.00519\n", - " 92/1 1.35758 1.40252 +/- 0.00516\n", - " 93/1 1.34508 1.40182 +/- 0.00514\n", - " 94/1 1.31471 1.40079 +/- 0.00519\n", - " 95/1 1.41434 1.40095 +/- 0.00513\n", - " 96/1 1.33895 1.40023 +/- 0.00512\n", - " 97/1 1.44716 1.40077 +/- 0.00509\n", - " 98/1 1.38455 1.40058 +/- 0.00503\n", - " 99/1 1.52127 1.40194 +/- 0.00516\n", - " 100/1 1.35488 1.40141 +/- 0.00513\n", - " Creating state point statepoint.100.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 5.3000E-01 seconds\n", - " Reading cross sections = 4.7425E-01 seconds\n", - " Total time in simulation = 5.9503E+00 seconds\n", - " Time in transport only = 5.6693E+00 seconds\n", - " Time in inactive batches = 5.9508E-01 seconds\n", - " Time in active batches = 5.3552E+00 seconds\n", - " Time synchronizing fission bank = 4.5385E-03 seconds\n", - " Sampling source sites = 2.4558E-03 seconds\n", - " SEND/RECV source sites = 1.0922E-03 seconds\n", - " Time accumulating tallies = 4.2963E-04 seconds\n", - " Total time for finalization = 4.4542E-04 seconds\n", - " Total time elapsed = 6.4846E+00 seconds\n", - " Calculation Rate (inactive) = 16804.5 neutrons/second\n", - " Calculation Rate (active) = 16806.1 neutrons/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.39737 +/- 0.00470\n", - " k-effective (Track-length) = 1.40141 +/- 0.00513\n", - " k-effective (Absorption) = 1.39596 +/- 0.00308\n", - " Combined k-effective = 1.39719 +/- 0.00286\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" + " ERROR: Tally filters must be specified independently of tallies in a \n", + " element. The element itself should have a list of filters that\n", + " apply, e.g., 1 2 where 1 and 2 are the IDs of filters\n", + " specified outside of .\n", + "application called MPI_Abort(MPI_COMM_WORLD, -1) - process 0\n", + "[unset]: write_line error; fd=-1 buf=:cmd=abort exitcode=-1\n", + ":\n", + "system msg for write_line failure : Bad file descriptor\n" ] }, { "data": { "text/plain": [ - "0" + "255" ] }, "execution_count": 42, @@ -1387,23 +1210,13 @@ { "cell_type": "code", "execution_count": 43, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\r\n", - " ============================> TALLY 1 <============================\r\n", - "\r\n", - " Cell 1\r\n", - " U235\r\n", - " Total Reaction Rate 0.731003 +/- 2.53759E-03\r\n", - " Fission Rate 0.547587 +/- 2.10114E-03\r\n", - " Absorption Rate 0.657406 +/- 2.45390E-03\r\n", - " (n,gamma) 0.109821 +/- 3.68054E-04\r\n" + "cat: tallies.out: No such file or directory\r\n" ] } ], @@ -1446,9 +1259,7 @@ { "cell_type": "code", "execution_count": 45, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1483,9 +1294,7 @@ { "cell_type": "code", "execution_count": 46, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1519,9 +1328,9 @@ " | The OpenMC Monte Carlo Code\n", " Copyright | 2011-2017 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.8.0\n", - " Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n", - " Date/Time | 2017-04-13 17:18:01\n", + " Version | 0.9.0\n", + " Git SHA1 | a8bee7757465e4617eb76e0c72f20cdf57771dd9\n", + " Date/Time | 2017-08-03 13:37:50\n", " MPI Processes | 1\n", " OpenMP Threads | 4\n", "\n", @@ -1573,10 +1382,16 @@ { "cell_type": "code", "execution_count": 47, - "metadata": { - "collapsed": false - }, - "outputs": [], + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/bin/sh: convert: command not found\r\n" + ] + } + ], "source": [ "!convert pinplot.ppm pinplot.png" ] @@ -1592,13 +1407,12 @@ "cell_type": "code", "execution_count": 48, "metadata": { - "collapsed": false, "scrolled": false }, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///8AAP9yEhL//wDh\n3HbeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUSBp1cqOcAAAKHSURBVGje7dlLjoJAEAZgMrNj\n4z28hKcYFhzBU5hwAFfsTQwJcIqJyzkNcU3SAw2j/agq4Zegk3Rv9Ut3VSt0V0XR/PE1ewQSSCCB\nBHIfSTGT1Hrk00lSj6OYTOrbyCeS/Z3U00hqiLqaQpLaGsUEsrdJ/Zg4kxDTRI8m8afxyPi9Q/ca\nZRLtkiFd5fDqjcmkRdQkZbRR3WhHk4tkCD7aqWFEWyIBDtHBHzaj6OYhEuAQvaxPdRtN7K/MJnpd\nB2WMb39lNunzVW5M0sZezmziTTJOk7Mk8SYZpylY0q/rtLOJ+nBXZpE+xZ+OUM3WSbNF+nW5kygV\nO8GYJPGD/0tAwZCUWtewsoohe3Jdw8p4ciKEuvCk+ySjSGPHb5A++g1F2q0Vv0FSJhQdTEUSLhQ3\nGJtkNGk4woUyBJMTJGFD0cEUNGFC0cFQJJVJRZOMIw1N9mz0Q/wE6RLGRa+UmTKTlDyJKSIlzE7Z\nM0RKmJ0ykxx50lJEyrGdZZPwCdNZJkgpkZgg3bYIQv3cN8YgJ4lcSHKWyNUnibgtemOKRchRIq1P\nUnEn9V5WixBpJ/vtd8mDzTe3/zkiiv4XswQ5yeTikXoCyRcgZ5lcX0YymTSBWOTR08J8XqxK3jZj\n70ze9l+5xkMJeFqu9Rhf45UEvCvXeYkDp4t1jj3AeQw79c0+WwInWOicPPs0Dpz5gZvFOlce4C6G\n3PiAeyVwewXuyMBNHLjvA1UFpHYBVEiAOgxQ7QFqSkjlCqiPAVU4oNYHVBSRuiVQHQVqsEClF6kn\nA1VroDaOVOCBOj/QTUB6FkBnBOm/AF0eoJeEdKyAvhjSfUN6fEgnEehX6pkK7pP/1+ENJJBAAnkF\n+QXfoOhE52QgVwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNC0xM1QxNzoxODowMS0wNDowMJXP\nFDgAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDQtMTNUMTc6MTg6MDEtMDQ6MDDkkqyEAAAAAElF\nTkSuQmCC\n", + "image/png": "pinplot.png", "text/plain": [ "" ] @@ -1623,24 +1437,46 @@ { "cell_type": "code", "execution_count": 49, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///8AAP9yEhL//wDh\n3HbeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUSCQ3jtXYAAAKHSURBVGje7dlLjoJAEAZgMrNj\n4z28hKcYFhzBU5hwAFfsTQwJcIqJyzkNcU3SAw2j/agq4Zegk3Rv9Ut3VSt0V0XR/PE1ewQSSCCB\nBHIfSTGT1Hrk00lSj6OYTOrbyCeS/Z3U00hqiLqaQpLaGsUEsrdJ/Zg4kxDTRI8m8afxyPi9Q/ca\nZRLtkiFd5fDqjcmkRdQkZbRR3WhHk4tkCD7aqWFEWyIBDtHBHzaj6OYhEuAQvaxPdRtN7K/MJnpd\nB2WMb39lNunzVW5M0sZezmziTTJOk7Mk8SYZpylY0q/rtLOJ+nBXZpE+xZ+OUM3WSbNF+nW5kygV\nO8GYJPGD/0tAwZCUWtewsoohe3Jdw8p4ciKEuvCk+ySjSGPHb5A++g1F2q0Vv0FSJhQdTEUSLhQ3\nGJtkNGk4woUyBJMTJGFD0cEUNGFC0cFQJJVJRZOMIw1N9mz0Q/wE6RLGRa+UmTKTlDyJKSIlzE7Z\nM0RKmJ0ykxx50lJEyrGdZZPwCdNZJkgpkZgg3bYIQv3cN8YgJ4lcSHKWyNUnibgtemOKRchRIq1P\nUnEn9V5WixBpJ/vtd8mDzTe3/zkiiv4XswQ5yeTikXoCyRcgZ5lcX0YymTSBWOTR08J8XqxK3jZj\n70ze9l+5xkMJeFqu9Rhf45UEvCvXeYkDp4t1jj3AeQw79c0+WwInWOicPPs0Dpz5gZvFOlce4C6G\n3PiAeyVwewXuyMBNHLjvA1UFpHYBVEiAOgxQ7QFqSkjlCqiPAVU4oNYHVBSRuiVQHQVqsEClF6kn\nA1VroDaOVOCBOj/QTUB6FkBnBOm/AF0eoJeEdKyAvhjSfUN6fEgnEehX6pkK7pP/1+ENJJBAAnkF\n+QXfoOhE52QgVwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNC0xM1QxNzoxODowOS0wNDowMKYg\nWl8AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDQtMTNUMTc6MTg6MDktMDQ6MDDXfeLjAAAAAElF\nTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "FileNotFoundError", + "evalue": "[Errno 2] No such file or directory: 'convert'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mopenmc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot_inline\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/Users/brittanygrayson/openmc/openmc/executor.py\u001b[0m in \u001b[0;36mplot_inline\u001b[0;34m(plots, openmc_exec, cwd, convert_exec)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0mppm_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'plot_{}.ppm'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0mpng_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mppm_file\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreplace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'.ppm'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'.png'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mconvert_exec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mppm_file\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpng_file\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 87\u001b[0m \u001b[0mimages\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mImage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpng_file\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mimages\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36mcheck_call\u001b[0;34m(*popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[0mcheck_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"ls\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-l\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 285\u001b[0m \"\"\"\n\u001b[0;32m--> 286\u001b[0;31m \u001b[0mretcode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mpopenargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 287\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mretcode\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 288\u001b[0m \u001b[0mcmd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"args\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36mcall\u001b[0;34m(timeout, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 265\u001b[0m \u001b[0mretcode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"ls\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-l\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 266\u001b[0m \"\"\"\n\u001b[0;32m--> 267\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mPopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mpopenargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 268\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)\u001b[0m\n\u001b[1;32m 705\u001b[0m \u001b[0mc2pread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc2pwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 706\u001b[0m \u001b[0merrread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merrwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 707\u001b[0;31m restore_signals, start_new_session)\n\u001b[0m\u001b[1;32m 708\u001b[0m \u001b[0;32mexcept\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 709\u001b[0m \u001b[0;31m# Cleanup if the child failed starting.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)\u001b[0m\n\u001b[1;32m 1324\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1325\u001b[0m \u001b[0merr_msg\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m': '\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0morig_executable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1326\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrno_num\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1327\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1328\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'convert'" + ] } ], "source": [ "openmc.plot_inline(p)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { @@ -1660,9 +1496,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.6.0" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/src/CTestTestfile.cmake b/src/CTestTestfile.cmake new file mode 100644 index 000000000..65ad509b2 --- /dev/null +++ b/src/CTestTestfile.cmake @@ -0,0 +1,170 @@ +# CMake generated Testfile for +# Source directory: /Users/brittanygrayson/openmc_develop/OpenMC +# Build directory: /Users/brittanygrayson/openmc_develop/OpenMC/src +# +# This file includes the relevant testing commands required for +# testing this directory and lists subdirectories to be tested as well. +add_test(test_asymmetric_lattice.py "/Users/brittanygrayson/miniconda3/bin/python" "test_asymmetric_lattice.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_asymmetric_lattice.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_asymmetric_lattice") +add_test(test_cmfd_feed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_cmfd_feed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_cmfd_feed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_cmfd_feed") +add_test(test_cmfd_nofeed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_cmfd_nofeed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_cmfd_nofeed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_cmfd_nofeed") +add_test(test_complex_cell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_complex_cell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_complex_cell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_complex_cell") +add_test(test_confidence_intervals.py "/Users/brittanygrayson/miniconda3/bin/python" "test_confidence_intervals.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_confidence_intervals.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_confidence_intervals") +add_test(test_create_fission_neutrons.py "/Users/brittanygrayson/miniconda3/bin/python" "test_create_fission_neutrons.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_create_fission_neutrons.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_create_fission_neutrons") +add_test(test_density.py "/Users/brittanygrayson/miniconda3/bin/python" "test_density.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_density.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_density") +add_test(test_diff_tally.py "/Users/brittanygrayson/miniconda3/bin/python" "test_diff_tally.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_diff_tally.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_diff_tally") +add_test(test_distribmat.py "/Users/brittanygrayson/miniconda3/bin/python" "test_distribmat.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_distribmat.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_distribmat") +add_test(test_eigenvalue_genperbatch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_eigenvalue_genperbatch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_eigenvalue_genperbatch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_eigenvalue_genperbatch") +add_test(test_eigenvalue_no_inactive.py "/Users/brittanygrayson/miniconda3/bin/python" "test_eigenvalue_no_inactive.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_eigenvalue_no_inactive.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_eigenvalue_no_inactive") +add_test(test_element_wo.py "/Users/brittanygrayson/miniconda3/bin/python" "test_element_wo.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_element_wo.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_element_wo") +add_test(test_energy_cutoff.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_cutoff.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_energy_cutoff.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_cutoff") +add_test(test_energy_grid.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_grid.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_energy_grid.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_grid") +add_test(test_energy_laws.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_laws.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_energy_laws.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_laws") +add_test(test_enrichment.py "/Users/brittanygrayson/miniconda3/bin/python" "test_enrichment.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_enrichment.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_enrichment") +add_test(test_entropy.py "/Users/brittanygrayson/miniconda3/bin/python" "test_entropy.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_entropy.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_entropy") +add_test(test_filter_distribcell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_distribcell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_filter_distribcell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_distribcell") +add_test(test_filter_energyfun.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_energyfun.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_filter_energyfun.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_energyfun") +add_test(test_filter_mesh.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_mesh.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_filter_mesh.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_mesh") +add_test(test_fixed_source.py "/Users/brittanygrayson/miniconda3/bin/python" "test_fixed_source.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_fixed_source.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_fixed_source") +add_test(test_infinite_cell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_infinite_cell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_infinite_cell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_infinite_cell") +add_test(test_iso_in_lab.py "/Users/brittanygrayson/miniconda3/bin/python" "test_iso_in_lab.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_iso_in_lab.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_iso_in_lab") +add_test(test_lattice.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_lattice.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice") +add_test(test_lattice_hex.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_hex.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_lattice_hex.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_hex") +add_test(test_lattice_mixed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_mixed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_lattice_mixed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_mixed") +add_test(test_lattice_multiple.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_multiple.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_lattice_multiple.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_multiple") +add_test(test_mg_basic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_basic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_basic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_basic") +add_test(test_mg_convert.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_convert.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_convert.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_convert") +add_test(test_mg_legendre.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_legendre.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_legendre.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_legendre") +add_test(test_mg_max_order.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_max_order.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_max_order.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_max_order") +add_test(test_mg_nuclide.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_nuclide.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_nuclide.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_nuclide") +add_test(test_mg_survival_biasing.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_survival_biasing.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_survival_biasing.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_survival_biasing") +add_test(test_mg_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mg_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_tallies") +add_test(test_mgxs_library_ce_to_mg.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_ce_to_mg.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_ce_to_mg.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_ce_to_mg") +add_test(test_mgxs_library_condense.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_condense.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_condense.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_condense") +add_test(test_mgxs_library_distribcell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_distribcell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_distribcell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_distribcell") +add_test(test_mgxs_library_hdf5.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_hdf5.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_hdf5.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_hdf5") +add_test(test_mgxs_library_mesh.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_mesh.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_mesh.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_mesh") +add_test(test_mgxs_library_no_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_no_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_no_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_no_nuclides") +add_test(test_mgxs_library_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_mgxs_library_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_nuclides") +add_test(test_multipole.py "/Users/brittanygrayson/miniconda3/bin/python" "test_multipole.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_multipole.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_multipole") +add_test(test_output.py "/Users/brittanygrayson/miniconda3/bin/python" "test_output.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_output.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_output") +add_test(test_particle_restart_eigval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_particle_restart_eigval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_particle_restart_eigval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_particle_restart_eigval") +add_test(test_particle_restart_fixed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_particle_restart_fixed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_particle_restart_fixed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_particle_restart_fixed") +add_test(test_periodic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_periodic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_periodic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_periodic") +add_test(test_plot.py "/Users/brittanygrayson/miniconda3/bin/python" "test_plot.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_plot.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_plot") +add_test(test_ptables_off.py "/Users/brittanygrayson/miniconda3/bin/python" "test_ptables_off.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_ptables_off.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_ptables_off") +add_test(test_quadric_surfaces.py "/Users/brittanygrayson/miniconda3/bin/python" "test_quadric_surfaces.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_quadric_surfaces.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_quadric_surfaces") +add_test(test_reflective_plane.py "/Users/brittanygrayson/miniconda3/bin/python" "test_reflective_plane.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_reflective_plane.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_reflective_plane") +add_test(test_resonance_scattering.py "/Users/brittanygrayson/miniconda3/bin/python" "test_resonance_scattering.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_resonance_scattering.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_resonance_scattering") +add_test(test_rotation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_rotation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_rotation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_rotation") +add_test(test_salphabeta.py "/Users/brittanygrayson/miniconda3/bin/python" "test_salphabeta.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_salphabeta.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_salphabeta") +add_test(test_score_current.py "/Users/brittanygrayson/miniconda3/bin/python" "test_score_current.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_score_current.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_score_current") +add_test(test_seed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_seed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_seed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_seed") +add_test(test_source.py "/Users/brittanygrayson/miniconda3/bin/python" "test_source.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_source.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_source") +add_test(test_source_file.py "/Users/brittanygrayson/miniconda3/bin/python" "test_source_file.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_source_file.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_source_file") +add_test(test_sourcepoint_batch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_batch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_sourcepoint_batch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_batch") +add_test(test_sourcepoint_latest.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_latest.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_sourcepoint_latest.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_latest") +add_test(test_sourcepoint_restart.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_restart.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_sourcepoint_restart.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_restart") +add_test(test_statepoint_batch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_batch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_statepoint_batch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_batch") +add_test(test_statepoint_restart.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_restart.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_statepoint_restart.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_restart") +add_test(test_statepoint_sourcesep.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_sourcesep.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_statepoint_sourcesep.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_sourcesep") +add_test(test_survival_biasing.py "/Users/brittanygrayson/miniconda3/bin/python" "test_survival_biasing.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_survival_biasing.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_survival_biasing") +add_test(test_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tallies") +add_test(test_tally_aggregation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_aggregation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tally_aggregation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_aggregation") +add_test(test_tally_arithmetic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_arithmetic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tally_arithmetic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_arithmetic") +add_test(test_tally_assumesep.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_assumesep.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tally_assumesep.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_assumesep") +add_test(test_tally_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tally_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_nuclides") +add_test(test_tally_slice_merge.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_slice_merge.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_tally_slice_merge.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_slice_merge") +add_test(test_trace.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trace.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_trace.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trace") +add_test(test_track_output.py "/Users/brittanygrayson/miniconda3/bin/python" "test_track_output.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_track_output.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_track_output") +add_test(test_translation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_translation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_translation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_translation") +add_test(test_trigger_batch_interval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_batch_interval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_trigger_batch_interval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_batch_interval") +add_test(test_trigger_no_batch_interval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_no_batch_interval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_trigger_no_batch_interval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_no_batch_interval") +add_test(test_trigger_no_status.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_no_status.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_trigger_no_status.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_no_status") +add_test(test_trigger_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_trigger_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_tallies") +add_test(test_triso.py "/Users/brittanygrayson/miniconda3/bin/python" "test_triso.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_triso.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_triso") +add_test(test_uniform_fs.py "/Users/brittanygrayson/miniconda3/bin/python" "test_uniform_fs.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_uniform_fs.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_uniform_fs") +add_test(test_universe.py "/Users/brittanygrayson/miniconda3/bin/python" "test_universe.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_universe.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_universe") +add_test(test_void.py "/Users/brittanygrayson/miniconda3/bin/python" "test_void.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_void.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_void") +add_test(test_volume_calc.py "/Users/brittanygrayson/miniconda3/bin/python" "test_volume_calc.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") +set_tests_properties(test_volume_calc.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_volume_calc") diff --git a/src/DartConfiguration.tcl b/src/DartConfiguration.tcl new file mode 100644 index 000000000..7534bcf7e --- /dev/null +++ b/src/DartConfiguration.tcl @@ -0,0 +1,112 @@ +# This file is configured by CMake automatically as DartConfiguration.tcl +# If you choose not to use CMake, this file may be hand configured, by +# filling in the required variables. + + +# Configuration directories and files +SourceDirectory: /Users/brittanygrayson/openmc_develop/OpenMC +BuildDirectory: /Users/brittanygrayson/openmc_develop/OpenMC/src + +# Where to place the cost data store +CostDataFile: + +# Site is something like machine.domain, i.e. pragmatic.crd +Site: Brittanys-Air.PK5001Z + +# Build name is osname-revision-compiler, i.e. Linux-2.4.2-2smp-c++ +BuildName: Darwin-mpicxx + +# Submission information +IsCDash: TRUE +CDashVersion: +QueryCDashVersion: +DropSite: openmc.mit.edu +DropLocation: /cdash/submit.php?project=OpenMC +DropSiteUser: +DropSitePassword: +DropSiteMode: +DropMethod: http +TriggerSite: +ScpCommand: /usr/bin/scp + +# Dashboard start time +NightlyStartTime: 01:00:00 UTC + +# Commands for the build/test/submit cycle +ConfigureCommand: "/Applications/CMake.app/Contents/bin/cmake" "/Users/brittanygrayson/openmc_develop/OpenMC" +MakeCommand: /Applications/CMake.app/Contents/bin/cmake --build . --config "${CTEST_CONFIGURATION_TYPE}" -- -i +DefaultCTestConfigurationType: Release + +# version control +UpdateVersionOnly: + +# CVS options +# Default is "-d -P -A" +CVSCommand: CVSCOMMAND-NOTFOUND +CVSUpdateOptions: -d -A -P + +# Subversion options +SVNCommand: /usr/bin/svn +SVNOptions: +SVNUpdateOptions: + +# Git options +GITCommand: /usr/bin/git +GITInitSubmodules: +GITUpdateOptions: +GITUpdateCustom: + +# Perforce options +P4Command: P4COMMAND-NOTFOUND +P4Client: +P4Options: +P4UpdateOptions: +P4UpdateCustom: + +# Generic update command +UpdateCommand: /usr/bin/git +UpdateOptions: +UpdateType: git + +# Compiler info +Compiler: /Users/brittanygrayson/miniconda3/bin/mpicxx +CompilerVersion: 3.9.0 + +# Dynamic analysis (MemCheck) +PurifyCommand: +ValgrindCommand: +ValgrindCommandOptions: +MemoryCheckType: +MemoryCheckSanitizerOptions: +MemoryCheckCommand: MEMORYCHECK_COMMAND-NOTFOUND +MemoryCheckCommandOptions: +MemoryCheckSuppressionFile: + +# Coverage +CoverageCommand: /Users/brittanygrayson/miniconda3/bin/gcov +CoverageExtraFlags: -l + +# Cluster commands +SlurmBatchCommand: SLURM_SBATCH_COMMAND-NOTFOUND +SlurmRunCommand: SLURM_SRUN_COMMAND-NOTFOUND + +# Testing options +# TimeOut is the amount of time in seconds to wait for processes +# to complete during testing. After TimeOut seconds, the +# process will be summarily terminated. +# Currently set to 25 minutes +TimeOut: 1500 + +# During parallel testing CTest will not start a new test if doing +# so would cause the system load to exceed this value. +TestLoad: + +UseLaunchers: +CurlOptions: +# warning, if you add new options here that have to do with submit, +# you have to update cmCTestSubmitCommand.cxx + +# For CTest submissions that timeout, these options +# specify behavior for retrying the submission +CTestSubmitRetryDelay: 5 +CTestSubmitRetryCount: 3 diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 000000000..ba2ba0a57 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3358 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.8 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /Applications/CMake.app/Contents/bin/cmake + +# The command to remove a file. +RM = /Applications/CMake.app/Contents/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/brittanygrayson/openmc_develop/OpenMC + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/brittanygrayson/openmc_develop/OpenMC/src + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /Applications/CMake.app/Contents/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /Applications/CMake.app/Contents/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /Applications/CMake.app/Contents/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target test +test: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." + /Applications/CMake.app/Contents/bin/ctest --force-new-ctest-process $(ARGS) +.PHONY : test + +# Special rule for the target test +test/fast: test + +.PHONY : test/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /Applications/CMake.app/Contents/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named ContinuousCoverage + +# Build rule for target. +ContinuousCoverage: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousCoverage +.PHONY : ContinuousCoverage + +# fast build rule for target. +ContinuousCoverage/fast: + $(MAKE) -f CMakeFiles/ContinuousCoverage.dir/build.make CMakeFiles/ContinuousCoverage.dir/build +.PHONY : ContinuousCoverage/fast + +#============================================================================= +# Target rules for targets named ContinuousBuild + +# Build rule for target. +ContinuousBuild: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousBuild +.PHONY : ContinuousBuild + +# fast build rule for target. +ContinuousBuild/fast: + $(MAKE) -f CMakeFiles/ContinuousBuild.dir/build.make CMakeFiles/ContinuousBuild.dir/build +.PHONY : ContinuousBuild/fast + +#============================================================================= +# Target rules for targets named ContinuousUpdate + +# Build rule for target. +ContinuousUpdate: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousUpdate +.PHONY : ContinuousUpdate + +# fast build rule for target. +ContinuousUpdate/fast: + $(MAKE) -f CMakeFiles/ContinuousUpdate.dir/build.make CMakeFiles/ContinuousUpdate.dir/build +.PHONY : ContinuousUpdate/fast + +#============================================================================= +# Target rules for targets named ContinuousStart + +# Build rule for target. +ContinuousStart: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousStart +.PHONY : ContinuousStart + +# fast build rule for target. +ContinuousStart/fast: + $(MAKE) -f CMakeFiles/ContinuousStart.dir/build.make CMakeFiles/ContinuousStart.dir/build +.PHONY : ContinuousStart/fast + +#============================================================================= +# Target rules for targets named ExperimentalSubmit + +# Build rule for target. +ExperimentalSubmit: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalSubmit +.PHONY : ExperimentalSubmit + +# fast build rule for target. +ExperimentalSubmit/fast: + $(MAKE) -f CMakeFiles/ExperimentalSubmit.dir/build.make CMakeFiles/ExperimentalSubmit.dir/build +.PHONY : ExperimentalSubmit/fast + +#============================================================================= +# Target rules for targets named ExperimentalBuild + +# Build rule for target. +ExperimentalBuild: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalBuild +.PHONY : ExperimentalBuild + +# fast build rule for target. +ExperimentalBuild/fast: + $(MAKE) -f CMakeFiles/ExperimentalBuild.dir/build.make CMakeFiles/ExperimentalBuild.dir/build +.PHONY : ExperimentalBuild/fast + +#============================================================================= +# Target rules for targets named ExperimentalCoverage + +# Build rule for target. +ExperimentalCoverage: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalCoverage +.PHONY : ExperimentalCoverage + +# fast build rule for target. +ExperimentalCoverage/fast: + $(MAKE) -f CMakeFiles/ExperimentalCoverage.dir/build.make CMakeFiles/ExperimentalCoverage.dir/build +.PHONY : ExperimentalCoverage/fast + +#============================================================================= +# Target rules for targets named ExperimentalUpdate + +# Build rule for target. +ExperimentalUpdate: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalUpdate +.PHONY : ExperimentalUpdate + +# fast build rule for target. +ExperimentalUpdate/fast: + $(MAKE) -f CMakeFiles/ExperimentalUpdate.dir/build.make CMakeFiles/ExperimentalUpdate.dir/build +.PHONY : ExperimentalUpdate/fast + +#============================================================================= +# Target rules for targets named ExperimentalStart + +# Build rule for target. +ExperimentalStart: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalStart +.PHONY : ExperimentalStart + +# fast build rule for target. +ExperimentalStart/fast: + $(MAKE) -f CMakeFiles/ExperimentalStart.dir/build.make CMakeFiles/ExperimentalStart.dir/build +.PHONY : ExperimentalStart/fast + +#============================================================================= +# Target rules for targets named NightlyMemCheck + +# Build rule for target. +NightlyMemCheck: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyMemCheck +.PHONY : NightlyMemCheck + +# fast build rule for target. +NightlyMemCheck/fast: + $(MAKE) -f CMakeFiles/NightlyMemCheck.dir/build.make CMakeFiles/NightlyMemCheck.dir/build +.PHONY : NightlyMemCheck/fast + +#============================================================================= +# Target rules for targets named ExperimentalConfigure + +# Build rule for target. +ExperimentalConfigure: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalConfigure +.PHONY : ExperimentalConfigure + +# fast build rule for target. +ExperimentalConfigure/fast: + $(MAKE) -f CMakeFiles/ExperimentalConfigure.dir/build.make CMakeFiles/ExperimentalConfigure.dir/build +.PHONY : ExperimentalConfigure/fast + +#============================================================================= +# Target rules for targets named NightlyCoverage + +# Build rule for target. +NightlyCoverage: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyCoverage +.PHONY : NightlyCoverage + +# fast build rule for target. +NightlyCoverage/fast: + $(MAKE) -f CMakeFiles/NightlyCoverage.dir/build.make CMakeFiles/NightlyCoverage.dir/build +.PHONY : NightlyCoverage/fast + +#============================================================================= +# Target rules for targets named NightlyTest + +# Build rule for target. +NightlyTest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyTest +.PHONY : NightlyTest + +# fast build rule for target. +NightlyTest/fast: + $(MAKE) -f CMakeFiles/NightlyTest.dir/build.make CMakeFiles/NightlyTest.dir/build +.PHONY : NightlyTest/fast + +#============================================================================= +# Target rules for targets named NightlyConfigure + +# Build rule for target. +NightlyConfigure: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyConfigure +.PHONY : NightlyConfigure + +# fast build rule for target. +NightlyConfigure/fast: + $(MAKE) -f CMakeFiles/NightlyConfigure.dir/build.make CMakeFiles/NightlyConfigure.dir/build +.PHONY : NightlyConfigure/fast + +#============================================================================= +# Target rules for targets named openmc + +# Build rule for target. +openmc: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 openmc +.PHONY : openmc + +# fast build rule for target. +openmc/fast: + $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/build +.PHONY : openmc/fast + +#============================================================================= +# Target rules for targets named Continuous + +# Build rule for target. +Continuous: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 Continuous +.PHONY : Continuous + +# fast build rule for target. +Continuous/fast: + $(MAKE) -f CMakeFiles/Continuous.dir/build.make CMakeFiles/Continuous.dir/build +.PHONY : Continuous/fast + +#============================================================================= +# Target rules for targets named NightlyStart + +# Build rule for target. +NightlyStart: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyStart +.PHONY : NightlyStart + +# fast build rule for target. +NightlyStart/fast: + $(MAKE) -f CMakeFiles/NightlyStart.dir/build.make CMakeFiles/NightlyStart.dir/build +.PHONY : NightlyStart/fast + +#============================================================================= +# Target rules for targets named Nightly + +# Build rule for target. +Nightly: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 Nightly +.PHONY : Nightly + +# fast build rule for target. +Nightly/fast: + $(MAKE) -f CMakeFiles/Nightly.dir/build.make CMakeFiles/Nightly.dir/build +.PHONY : Nightly/fast + +#============================================================================= +# Target rules for targets named ExperimentalMemCheck + +# Build rule for target. +ExperimentalMemCheck: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalMemCheck +.PHONY : ExperimentalMemCheck + +# fast build rule for target. +ExperimentalMemCheck/fast: + $(MAKE) -f CMakeFiles/ExperimentalMemCheck.dir/build.make CMakeFiles/ExperimentalMemCheck.dir/build +.PHONY : ExperimentalMemCheck/fast + +#============================================================================= +# Target rules for targets named libopenmc + +# Build rule for target. +libopenmc: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 libopenmc +.PHONY : libopenmc + +# fast build rule for target. +libopenmc/fast: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/build +.PHONY : libopenmc/fast + +#============================================================================= +# Target rules for targets named ContinuousConfigure + +# Build rule for target. +ContinuousConfigure: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousConfigure +.PHONY : ContinuousConfigure + +# fast build rule for target. +ContinuousConfigure/fast: + $(MAKE) -f CMakeFiles/ContinuousConfigure.dir/build.make CMakeFiles/ContinuousConfigure.dir/build +.PHONY : ContinuousConfigure/fast + +#============================================================================= +# Target rules for targets named NightlyMemoryCheck + +# Build rule for target. +NightlyMemoryCheck: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyMemoryCheck +.PHONY : NightlyMemoryCheck + +# fast build rule for target. +NightlyMemoryCheck/fast: + $(MAKE) -f CMakeFiles/NightlyMemoryCheck.dir/build.make CMakeFiles/NightlyMemoryCheck.dir/build +.PHONY : NightlyMemoryCheck/fast + +#============================================================================= +# Target rules for targets named Experimental + +# Build rule for target. +Experimental: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 Experimental +.PHONY : Experimental + +# fast build rule for target. +Experimental/fast: + $(MAKE) -f CMakeFiles/Experimental.dir/build.make CMakeFiles/Experimental.dir/build +.PHONY : Experimental/fast + +#============================================================================= +# Target rules for targets named ContinuousSubmit + +# Build rule for target. +ContinuousSubmit: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousSubmit +.PHONY : ContinuousSubmit + +# fast build rule for target. +ContinuousSubmit/fast: + $(MAKE) -f CMakeFiles/ContinuousSubmit.dir/build.make CMakeFiles/ContinuousSubmit.dir/build +.PHONY : ContinuousSubmit/fast + +#============================================================================= +# Target rules for targets named ExperimentalTest + +# Build rule for target. +ExperimentalTest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ExperimentalTest +.PHONY : ExperimentalTest + +# fast build rule for target. +ExperimentalTest/fast: + $(MAKE) -f CMakeFiles/ExperimentalTest.dir/build.make CMakeFiles/ExperimentalTest.dir/build +.PHONY : ExperimentalTest/fast + +#============================================================================= +# Target rules for targets named NightlySubmit + +# Build rule for target. +NightlySubmit: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlySubmit +.PHONY : NightlySubmit + +# fast build rule for target. +NightlySubmit/fast: + $(MAKE) -f CMakeFiles/NightlySubmit.dir/build.make CMakeFiles/NightlySubmit.dir/build +.PHONY : NightlySubmit/fast + +#============================================================================= +# Target rules for targets named ContinuousTest + +# Build rule for target. +ContinuousTest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousTest +.PHONY : ContinuousTest + +# fast build rule for target. +ContinuousTest/fast: + $(MAKE) -f CMakeFiles/ContinuousTest.dir/build.make CMakeFiles/ContinuousTest.dir/build +.PHONY : ContinuousTest/fast + +#============================================================================= +# Target rules for targets named faddeeva + +# Build rule for target. +faddeeva: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 faddeeva +.PHONY : faddeeva + +# fast build rule for target. +faddeeva/fast: + $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/build +.PHONY : faddeeva/fast + +#============================================================================= +# Target rules for targets named ContinuousMemCheck + +# Build rule for target. +ContinuousMemCheck: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 ContinuousMemCheck +.PHONY : ContinuousMemCheck + +# fast build rule for target. +ContinuousMemCheck/fast: + $(MAKE) -f CMakeFiles/ContinuousMemCheck.dir/build.make CMakeFiles/ContinuousMemCheck.dir/build +.PHONY : ContinuousMemCheck/fast + +#============================================================================= +# Target rules for targets named NightlyBuild + +# Build rule for target. +NightlyBuild: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyBuild +.PHONY : NightlyBuild + +# fast build rule for target. +NightlyBuild/fast: + $(MAKE) -f CMakeFiles/NightlyBuild.dir/build.make CMakeFiles/NightlyBuild.dir/build +.PHONY : NightlyBuild/fast + +#============================================================================= +# Target rules for targets named pugixml_fortran + +# Build rule for target. +pugixml_fortran: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pugixml_fortran +.PHONY : pugixml_fortran + +# fast build rule for target. +pugixml_fortran/fast: + $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/build +.PHONY : pugixml_fortran/fast + +#============================================================================= +# Target rules for targets named NightlyUpdate + +# Build rule for target. +NightlyUpdate: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 NightlyUpdate +.PHONY : NightlyUpdate + +# fast build rule for target. +NightlyUpdate/fast: + $(MAKE) -f CMakeFiles/NightlyUpdate.dir/build.make CMakeFiles/NightlyUpdate.dir/build +.PHONY : NightlyUpdate/fast + +#============================================================================= +# Target rules for targets named pugixml + +# Build rule for target. +pugixml: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pugixml +.PHONY : pugixml + +# fast build rule for target. +pugixml/fast: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/build +.PHONY : pugixml/fast + +algorithm.o: algorithm.F90.o + +.PHONY : algorithm.o + +# target to build an object file +algorithm.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.o +.PHONY : algorithm.F90.o + +algorithm.i: algorithm.F90.i + +.PHONY : algorithm.i + +# target to preprocess a source file +algorithm.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.i +.PHONY : algorithm.F90.i + +algorithm.s: algorithm.F90.s + +.PHONY : algorithm.s + +# target to generate assembly for a file +algorithm.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.s +.PHONY : algorithm.F90.s + +angle_distribution.o: angle_distribution.F90.o + +.PHONY : angle_distribution.o + +# target to build an object file +angle_distribution.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.o +.PHONY : angle_distribution.F90.o + +angle_distribution.i: angle_distribution.F90.i + +.PHONY : angle_distribution.i + +# target to preprocess a source file +angle_distribution.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.i +.PHONY : angle_distribution.F90.i + +angle_distribution.s: angle_distribution.F90.s + +.PHONY : angle_distribution.s + +# target to generate assembly for a file +angle_distribution.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.s +.PHONY : angle_distribution.F90.s + +angleenergy_header.o: angleenergy_header.F90.o + +.PHONY : angleenergy_header.o + +# target to build an object file +angleenergy_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.o +.PHONY : angleenergy_header.F90.o + +angleenergy_header.i: angleenergy_header.F90.i + +.PHONY : angleenergy_header.i + +# target to preprocess a source file +angleenergy_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.i +.PHONY : angleenergy_header.F90.i + +angleenergy_header.s: angleenergy_header.F90.s + +.PHONY : angleenergy_header.s + +# target to generate assembly for a file +angleenergy_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.s +.PHONY : angleenergy_header.F90.s + +bank_header.o: bank_header.F90.o + +.PHONY : bank_header.o + +# target to build an object file +bank_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.o +.PHONY : bank_header.F90.o + +bank_header.i: bank_header.F90.i + +.PHONY : bank_header.i + +# target to preprocess a source file +bank_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.i +.PHONY : bank_header.F90.i + +bank_header.s: bank_header.F90.s + +.PHONY : bank_header.s + +# target to generate assembly for a file +bank_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.s +.PHONY : bank_header.F90.s + +cmfd_data.o: cmfd_data.F90.o + +.PHONY : cmfd_data.o + +# target to build an object file +cmfd_data.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.o +.PHONY : cmfd_data.F90.o + +cmfd_data.i: cmfd_data.F90.i + +.PHONY : cmfd_data.i + +# target to preprocess a source file +cmfd_data.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.i +.PHONY : cmfd_data.F90.i + +cmfd_data.s: cmfd_data.F90.s + +.PHONY : cmfd_data.s + +# target to generate assembly for a file +cmfd_data.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.s +.PHONY : cmfd_data.F90.s + +cmfd_execute.o: cmfd_execute.F90.o + +.PHONY : cmfd_execute.o + +# target to build an object file +cmfd_execute.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.o +.PHONY : cmfd_execute.F90.o + +cmfd_execute.i: cmfd_execute.F90.i + +.PHONY : cmfd_execute.i + +# target to preprocess a source file +cmfd_execute.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.i +.PHONY : cmfd_execute.F90.i + +cmfd_execute.s: cmfd_execute.F90.s + +.PHONY : cmfd_execute.s + +# target to generate assembly for a file +cmfd_execute.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.s +.PHONY : cmfd_execute.F90.s + +cmfd_header.o: cmfd_header.F90.o + +.PHONY : cmfd_header.o + +# target to build an object file +cmfd_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.o +.PHONY : cmfd_header.F90.o + +cmfd_header.i: cmfd_header.F90.i + +.PHONY : cmfd_header.i + +# target to preprocess a source file +cmfd_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.i +.PHONY : cmfd_header.F90.i + +cmfd_header.s: cmfd_header.F90.s + +.PHONY : cmfd_header.s + +# target to generate assembly for a file +cmfd_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.s +.PHONY : cmfd_header.F90.s + +cmfd_input.o: cmfd_input.F90.o + +.PHONY : cmfd_input.o + +# target to build an object file +cmfd_input.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.o +.PHONY : cmfd_input.F90.o + +cmfd_input.i: cmfd_input.F90.i + +.PHONY : cmfd_input.i + +# target to preprocess a source file +cmfd_input.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.i +.PHONY : cmfd_input.F90.i + +cmfd_input.s: cmfd_input.F90.s + +.PHONY : cmfd_input.s + +# target to generate assembly for a file +cmfd_input.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.s +.PHONY : cmfd_input.F90.s + +cmfd_loss_operator.o: cmfd_loss_operator.F90.o + +.PHONY : cmfd_loss_operator.o + +# target to build an object file +cmfd_loss_operator.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.o +.PHONY : cmfd_loss_operator.F90.o + +cmfd_loss_operator.i: cmfd_loss_operator.F90.i + +.PHONY : cmfd_loss_operator.i + +# target to preprocess a source file +cmfd_loss_operator.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.i +.PHONY : cmfd_loss_operator.F90.i + +cmfd_loss_operator.s: cmfd_loss_operator.F90.s + +.PHONY : cmfd_loss_operator.s + +# target to generate assembly for a file +cmfd_loss_operator.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.s +.PHONY : cmfd_loss_operator.F90.s + +cmfd_prod_operator.o: cmfd_prod_operator.F90.o + +.PHONY : cmfd_prod_operator.o + +# target to build an object file +cmfd_prod_operator.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.o +.PHONY : cmfd_prod_operator.F90.o + +cmfd_prod_operator.i: cmfd_prod_operator.F90.i + +.PHONY : cmfd_prod_operator.i + +# target to preprocess a source file +cmfd_prod_operator.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.i +.PHONY : cmfd_prod_operator.F90.i + +cmfd_prod_operator.s: cmfd_prod_operator.F90.s + +.PHONY : cmfd_prod_operator.s + +# target to generate assembly for a file +cmfd_prod_operator.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.s +.PHONY : cmfd_prod_operator.F90.s + +cmfd_solver.o: cmfd_solver.F90.o + +.PHONY : cmfd_solver.o + +# target to build an object file +cmfd_solver.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.o +.PHONY : cmfd_solver.F90.o + +cmfd_solver.i: cmfd_solver.F90.i + +.PHONY : cmfd_solver.i + +# target to preprocess a source file +cmfd_solver.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.i +.PHONY : cmfd_solver.F90.i + +cmfd_solver.s: cmfd_solver.F90.s + +.PHONY : cmfd_solver.s + +# target to generate assembly for a file +cmfd_solver.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.s +.PHONY : cmfd_solver.F90.s + +constants.o: constants.F90.o + +.PHONY : constants.o + +# target to build an object file +constants.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.o +.PHONY : constants.F90.o + +constants.i: constants.F90.i + +.PHONY : constants.i + +# target to preprocess a source file +constants.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.i +.PHONY : constants.F90.i + +constants.s: constants.F90.s + +.PHONY : constants.s + +# target to generate assembly for a file +constants.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.s +.PHONY : constants.F90.s + +cross_section.o: cross_section.F90.o + +.PHONY : cross_section.o + +# target to build an object file +cross_section.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.o +.PHONY : cross_section.F90.o + +cross_section.i: cross_section.F90.i + +.PHONY : cross_section.i + +# target to preprocess a source file +cross_section.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.i +.PHONY : cross_section.F90.i + +cross_section.s: cross_section.F90.s + +.PHONY : cross_section.s + +# target to generate assembly for a file +cross_section.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.s +.PHONY : cross_section.F90.s + +dict_header.o: dict_header.F90.o + +.PHONY : dict_header.o + +# target to build an object file +dict_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.o +.PHONY : dict_header.F90.o + +dict_header.i: dict_header.F90.i + +.PHONY : dict_header.i + +# target to preprocess a source file +dict_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.i +.PHONY : dict_header.F90.i + +dict_header.s: dict_header.F90.s + +.PHONY : dict_header.s + +# target to generate assembly for a file +dict_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.s +.PHONY : dict_header.F90.s + +distribution_multivariate.o: distribution_multivariate.F90.o + +.PHONY : distribution_multivariate.o + +# target to build an object file +distribution_multivariate.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.o +.PHONY : distribution_multivariate.F90.o + +distribution_multivariate.i: distribution_multivariate.F90.i + +.PHONY : distribution_multivariate.i + +# target to preprocess a source file +distribution_multivariate.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.i +.PHONY : distribution_multivariate.F90.i + +distribution_multivariate.s: distribution_multivariate.F90.s + +.PHONY : distribution_multivariate.s + +# target to generate assembly for a file +distribution_multivariate.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.s +.PHONY : distribution_multivariate.F90.s + +distribution_univariate.o: distribution_univariate.F90.o + +.PHONY : distribution_univariate.o + +# target to build an object file +distribution_univariate.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.o +.PHONY : distribution_univariate.F90.o + +distribution_univariate.i: distribution_univariate.F90.i + +.PHONY : distribution_univariate.i + +# target to preprocess a source file +distribution_univariate.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.i +.PHONY : distribution_univariate.F90.i + +distribution_univariate.s: distribution_univariate.F90.s + +.PHONY : distribution_univariate.s + +# target to generate assembly for a file +distribution_univariate.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.s +.PHONY : distribution_univariate.F90.s + +doppler.o: doppler.F90.o + +.PHONY : doppler.o + +# target to build an object file +doppler.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.o +.PHONY : doppler.F90.o + +doppler.i: doppler.F90.i + +.PHONY : doppler.i + +# target to preprocess a source file +doppler.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.i +.PHONY : doppler.F90.i + +doppler.s: doppler.F90.s + +.PHONY : doppler.s + +# target to generate assembly for a file +doppler.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.s +.PHONY : doppler.F90.s + +eigenvalue.o: eigenvalue.F90.o + +.PHONY : eigenvalue.o + +# target to build an object file +eigenvalue.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.o +.PHONY : eigenvalue.F90.o + +eigenvalue.i: eigenvalue.F90.i + +.PHONY : eigenvalue.i + +# target to preprocess a source file +eigenvalue.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.i +.PHONY : eigenvalue.F90.i + +eigenvalue.s: eigenvalue.F90.s + +.PHONY : eigenvalue.s + +# target to generate assembly for a file +eigenvalue.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.s +.PHONY : eigenvalue.F90.s + +endf.o: endf.F90.o + +.PHONY : endf.o + +# target to build an object file +endf.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.o +.PHONY : endf.F90.o + +endf.i: endf.F90.i + +.PHONY : endf.i + +# target to preprocess a source file +endf.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.i +.PHONY : endf.F90.i + +endf.s: endf.F90.s + +.PHONY : endf.s + +# target to generate assembly for a file +endf.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.s +.PHONY : endf.F90.s + +endf_header.o: endf_header.F90.o + +.PHONY : endf_header.o + +# target to build an object file +endf_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.o +.PHONY : endf_header.F90.o + +endf_header.i: endf_header.F90.i + +.PHONY : endf_header.i + +# target to preprocess a source file +endf_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.i +.PHONY : endf_header.F90.i + +endf_header.s: endf_header.F90.s + +.PHONY : endf_header.s + +# target to generate assembly for a file +endf_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.s +.PHONY : endf_header.F90.s + +energy_distribution.o: energy_distribution.F90.o + +.PHONY : energy_distribution.o + +# target to build an object file +energy_distribution.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.o +.PHONY : energy_distribution.F90.o + +energy_distribution.i: energy_distribution.F90.i + +.PHONY : energy_distribution.i + +# target to preprocess a source file +energy_distribution.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.i +.PHONY : energy_distribution.F90.i + +energy_distribution.s: energy_distribution.F90.s + +.PHONY : energy_distribution.s + +# target to generate assembly for a file +energy_distribution.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.s +.PHONY : energy_distribution.F90.s + +energy_grid.o: energy_grid.F90.o + +.PHONY : energy_grid.o + +# target to build an object file +energy_grid.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_grid.F90.o +.PHONY : energy_grid.F90.o + +energy_grid.i: energy_grid.F90.i + +.PHONY : energy_grid.i + +# target to preprocess a source file +energy_grid.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_grid.F90.i +.PHONY : energy_grid.F90.i + +energy_grid.s: energy_grid.F90.s + +.PHONY : energy_grid.s + +# target to generate assembly for a file +energy_grid.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_grid.F90.s +.PHONY : energy_grid.F90.s + +error.o: error.F90.o + +.PHONY : error.o + +# target to build an object file +error.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.o +.PHONY : error.F90.o + +error.i: error.F90.i + +.PHONY : error.i + +# target to preprocess a source file +error.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.i +.PHONY : error.F90.i + +error.s: error.F90.s + +.PHONY : error.s + +# target to generate assembly for a file +error.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.s +.PHONY : error.F90.s + +faddeeva/Faddeeva.o: faddeeva/Faddeeva.c.o + +.PHONY : faddeeva/Faddeeva.o + +# target to build an object file +faddeeva/Faddeeva.c.o: + $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.o +.PHONY : faddeeva/Faddeeva.c.o + +faddeeva/Faddeeva.i: faddeeva/Faddeeva.c.i + +.PHONY : faddeeva/Faddeeva.i + +# target to preprocess a source file +faddeeva/Faddeeva.c.i: + $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.i +.PHONY : faddeeva/Faddeeva.c.i + +faddeeva/Faddeeva.s: faddeeva/Faddeeva.c.s + +.PHONY : faddeeva/Faddeeva.s + +# target to generate assembly for a file +faddeeva/Faddeeva.c.s: + $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.s +.PHONY : faddeeva/Faddeeva.c.s + +finalize.o: finalize.F90.o + +.PHONY : finalize.o + +# target to build an object file +finalize.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/finalize.F90.o +.PHONY : finalize.F90.o + +finalize.i: finalize.F90.i + +.PHONY : finalize.i + +# target to preprocess a source file +finalize.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/finalize.F90.i +.PHONY : finalize.F90.i + +finalize.s: finalize.F90.s + +.PHONY : finalize.s + +# target to generate assembly for a file +finalize.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/finalize.F90.s +.PHONY : finalize.F90.s + +geometry.o: geometry.F90.o + +.PHONY : geometry.o + +# target to build an object file +geometry.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.o +.PHONY : geometry.F90.o + +geometry.i: geometry.F90.i + +.PHONY : geometry.i + +# target to preprocess a source file +geometry.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.i +.PHONY : geometry.F90.i + +geometry.s: geometry.F90.s + +.PHONY : geometry.s + +# target to generate assembly for a file +geometry.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.s +.PHONY : geometry.F90.s + +geometry_header.o: geometry_header.F90.o + +.PHONY : geometry_header.o + +# target to build an object file +geometry_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.o +.PHONY : geometry_header.F90.o + +geometry_header.i: geometry_header.F90.i + +.PHONY : geometry_header.i + +# target to preprocess a source file +geometry_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.i +.PHONY : geometry_header.F90.i + +geometry_header.s: geometry_header.F90.s + +.PHONY : geometry_header.s + +# target to generate assembly for a file +geometry_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.s +.PHONY : geometry_header.F90.s + +global.o: global.F90.o + +.PHONY : global.o + +# target to build an object file +global.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.o +.PHONY : global.F90.o + +global.i: global.F90.i + +.PHONY : global.i + +# target to preprocess a source file +global.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.i +.PHONY : global.F90.i + +global.s: global.F90.s + +.PHONY : global.s + +# target to generate assembly for a file +global.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.s +.PHONY : global.F90.s + +hdf5_interface.o: hdf5_interface.F90.o + +.PHONY : hdf5_interface.o + +# target to build an object file +hdf5_interface.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.o +.PHONY : hdf5_interface.F90.o + +hdf5_interface.i: hdf5_interface.F90.i + +.PHONY : hdf5_interface.i + +# target to preprocess a source file +hdf5_interface.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.i +.PHONY : hdf5_interface.F90.i + +hdf5_interface.s: hdf5_interface.F90.s + +.PHONY : hdf5_interface.s + +# target to generate assembly for a file +hdf5_interface.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.s +.PHONY : hdf5_interface.F90.s + +initialize.o: initialize.F90.o + +.PHONY : initialize.o + +# target to build an object file +initialize.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.o +.PHONY : initialize.F90.o + +initialize.i: initialize.F90.i + +.PHONY : initialize.i + +# target to preprocess a source file +initialize.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.i +.PHONY : initialize.F90.i + +initialize.s: initialize.F90.s + +.PHONY : initialize.s + +# target to generate assembly for a file +initialize.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.s +.PHONY : initialize.F90.s + +input_xml.o: input_xml.F90.o + +.PHONY : input_xml.o + +# target to build an object file +input_xml.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.o +.PHONY : input_xml.F90.o + +input_xml.i: input_xml.F90.i + +.PHONY : input_xml.i + +# target to preprocess a source file +input_xml.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.i +.PHONY : input_xml.F90.i + +input_xml.s: input_xml.F90.s + +.PHONY : input_xml.s + +# target to generate assembly for a file +input_xml.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.s +.PHONY : input_xml.F90.s + +list_header.o: list_header.F90.o + +.PHONY : list_header.o + +# target to build an object file +list_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.o +.PHONY : list_header.F90.o + +list_header.i: list_header.F90.i + +.PHONY : list_header.i + +# target to preprocess a source file +list_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.i +.PHONY : list_header.F90.i + +list_header.s: list_header.F90.s + +.PHONY : list_header.s + +# target to generate assembly for a file +list_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.s +.PHONY : list_header.F90.s + +main.o: main.F90.o + +.PHONY : main.o + +# target to build an object file +main.F90.o: + $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.o +.PHONY : main.F90.o + +main.i: main.F90.i + +.PHONY : main.i + +# target to preprocess a source file +main.F90.i: + $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.i +.PHONY : main.F90.i + +main.s: main.F90.s + +.PHONY : main.s + +# target to generate assembly for a file +main.F90.s: + $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.s +.PHONY : main.F90.s + +material_header.o: material_header.F90.o + +.PHONY : material_header.o + +# target to build an object file +material_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.o +.PHONY : material_header.F90.o + +material_header.i: material_header.F90.i + +.PHONY : material_header.i + +# target to preprocess a source file +material_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.i +.PHONY : material_header.F90.i + +material_header.s: material_header.F90.s + +.PHONY : material_header.s + +# target to generate assembly for a file +material_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.s +.PHONY : material_header.F90.s + +math.o: math.F90.o + +.PHONY : math.o + +# target to build an object file +math.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.o +.PHONY : math.F90.o + +math.i: math.F90.i + +.PHONY : math.i + +# target to preprocess a source file +math.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.i +.PHONY : math.F90.i + +math.s: math.F90.s + +.PHONY : math.s + +# target to generate assembly for a file +math.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.s +.PHONY : math.F90.s + +matrix_header.o: matrix_header.F90.o + +.PHONY : matrix_header.o + +# target to build an object file +matrix_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.o +.PHONY : matrix_header.F90.o + +matrix_header.i: matrix_header.F90.i + +.PHONY : matrix_header.i + +# target to preprocess a source file +matrix_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.i +.PHONY : matrix_header.F90.i + +matrix_header.s: matrix_header.F90.s + +.PHONY : matrix_header.s + +# target to generate assembly for a file +matrix_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.s +.PHONY : matrix_header.F90.s + +mesh.o: mesh.F90.o + +.PHONY : mesh.o + +# target to build an object file +mesh.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.o +.PHONY : mesh.F90.o + +mesh.i: mesh.F90.i + +.PHONY : mesh.i + +# target to preprocess a source file +mesh.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.i +.PHONY : mesh.F90.i + +mesh.s: mesh.F90.s + +.PHONY : mesh.s + +# target to generate assembly for a file +mesh.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.s +.PHONY : mesh.F90.s + +mesh_header.o: mesh_header.F90.o + +.PHONY : mesh_header.o + +# target to build an object file +mesh_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.o +.PHONY : mesh_header.F90.o + +mesh_header.i: mesh_header.F90.i + +.PHONY : mesh_header.i + +# target to preprocess a source file +mesh_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.i +.PHONY : mesh_header.F90.i + +mesh_header.s: mesh_header.F90.s + +.PHONY : mesh_header.s + +# target to generate assembly for a file +mesh_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.s +.PHONY : mesh_header.F90.s + +message_passing.o: message_passing.F90.o + +.PHONY : message_passing.o + +# target to build an object file +message_passing.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.o +.PHONY : message_passing.F90.o + +message_passing.i: message_passing.F90.i + +.PHONY : message_passing.i + +# target to preprocess a source file +message_passing.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.i +.PHONY : message_passing.F90.i + +message_passing.s: message_passing.F90.s + +.PHONY : message_passing.s + +# target to generate assembly for a file +message_passing.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.s +.PHONY : message_passing.F90.s + +mgxs_data.o: mgxs_data.F90.o + +.PHONY : mgxs_data.o + +# target to build an object file +mgxs_data.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.o +.PHONY : mgxs_data.F90.o + +mgxs_data.i: mgxs_data.F90.i + +.PHONY : mgxs_data.i + +# target to preprocess a source file +mgxs_data.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.i +.PHONY : mgxs_data.F90.i + +mgxs_data.s: mgxs_data.F90.s + +.PHONY : mgxs_data.s + +# target to generate assembly for a file +mgxs_data.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.s +.PHONY : mgxs_data.F90.s + +mgxs_header.o: mgxs_header.F90.o + +.PHONY : mgxs_header.o + +# target to build an object file +mgxs_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.o +.PHONY : mgxs_header.F90.o + +mgxs_header.i: mgxs_header.F90.i + +.PHONY : mgxs_header.i + +# target to preprocess a source file +mgxs_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.i +.PHONY : mgxs_header.F90.i + +mgxs_header.s: mgxs_header.F90.s + +.PHONY : mgxs_header.s + +# target to generate assembly for a file +mgxs_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.s +.PHONY : mgxs_header.F90.s + +multipole.o: multipole.F90.o + +.PHONY : multipole.o + +# target to build an object file +multipole.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.o +.PHONY : multipole.F90.o + +multipole.i: multipole.F90.i + +.PHONY : multipole.i + +# target to preprocess a source file +multipole.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.i +.PHONY : multipole.F90.i + +multipole.s: multipole.F90.s + +.PHONY : multipole.s + +# target to generate assembly for a file +multipole.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.s +.PHONY : multipole.F90.s + +multipole_header.o: multipole_header.F90.o + +.PHONY : multipole_header.o + +# target to build an object file +multipole_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.o +.PHONY : multipole_header.F90.o + +multipole_header.i: multipole_header.F90.i + +.PHONY : multipole_header.i + +# target to preprocess a source file +multipole_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.i +.PHONY : multipole_header.F90.i + +multipole_header.s: multipole_header.F90.s + +.PHONY : multipole_header.s + +# target to generate assembly for a file +multipole_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.s +.PHONY : multipole_header.F90.s + +nuclide_header.o: nuclide_header.F90.o + +.PHONY : nuclide_header.o + +# target to build an object file +nuclide_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.o +.PHONY : nuclide_header.F90.o + +nuclide_header.i: nuclide_header.F90.i + +.PHONY : nuclide_header.i + +# target to preprocess a source file +nuclide_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.i +.PHONY : nuclide_header.F90.i + +nuclide_header.s: nuclide_header.F90.s + +.PHONY : nuclide_header.s + +# target to generate assembly for a file +nuclide_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.s +.PHONY : nuclide_header.F90.s + +output.o: output.F90.o + +.PHONY : output.o + +# target to build an object file +output.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.o +.PHONY : output.F90.o + +output.i: output.F90.i + +.PHONY : output.i + +# target to preprocess a source file +output.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.i +.PHONY : output.F90.i + +output.s: output.F90.s + +.PHONY : output.s + +# target to generate assembly for a file +output.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.s +.PHONY : output.F90.s + +particle_header.o: particle_header.F90.o + +.PHONY : particle_header.o + +# target to build an object file +particle_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.o +.PHONY : particle_header.F90.o + +particle_header.i: particle_header.F90.i + +.PHONY : particle_header.i + +# target to preprocess a source file +particle_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.i +.PHONY : particle_header.F90.i + +particle_header.s: particle_header.F90.s + +.PHONY : particle_header.s + +# target to generate assembly for a file +particle_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.s +.PHONY : particle_header.F90.s + +particle_restart.o: particle_restart.F90.o + +.PHONY : particle_restart.o + +# target to build an object file +particle_restart.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.o +.PHONY : particle_restart.F90.o + +particle_restart.i: particle_restart.F90.i + +.PHONY : particle_restart.i + +# target to preprocess a source file +particle_restart.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.i +.PHONY : particle_restart.F90.i + +particle_restart.s: particle_restart.F90.s + +.PHONY : particle_restart.s + +# target to generate assembly for a file +particle_restart.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.s +.PHONY : particle_restart.F90.s + +particle_restart_write.o: particle_restart_write.F90.o + +.PHONY : particle_restart_write.o + +# target to build an object file +particle_restart_write.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.o +.PHONY : particle_restart_write.F90.o + +particle_restart_write.i: particle_restart_write.F90.i + +.PHONY : particle_restart_write.i + +# target to preprocess a source file +particle_restart_write.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.i +.PHONY : particle_restart_write.F90.i + +particle_restart_write.s: particle_restart_write.F90.s + +.PHONY : particle_restart_write.s + +# target to generate assembly for a file +particle_restart_write.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.s +.PHONY : particle_restart_write.F90.s + +physics.o: physics.F90.o + +.PHONY : physics.o + +# target to build an object file +physics.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.o +.PHONY : physics.F90.o + +physics.i: physics.F90.i + +.PHONY : physics.i + +# target to preprocess a source file +physics.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.i +.PHONY : physics.F90.i + +physics.s: physics.F90.s + +.PHONY : physics.s + +# target to generate assembly for a file +physics.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.s +.PHONY : physics.F90.s + +physics_common.o: physics_common.F90.o + +.PHONY : physics_common.o + +# target to build an object file +physics_common.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.o +.PHONY : physics_common.F90.o + +physics_common.i: physics_common.F90.i + +.PHONY : physics_common.i + +# target to preprocess a source file +physics_common.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.i +.PHONY : physics_common.F90.i + +physics_common.s: physics_common.F90.s + +.PHONY : physics_common.s + +# target to generate assembly for a file +physics_common.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.s +.PHONY : physics_common.F90.s + +physics_mg.o: physics_mg.F90.o + +.PHONY : physics_mg.o + +# target to build an object file +physics_mg.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.o +.PHONY : physics_mg.F90.o + +physics_mg.i: physics_mg.F90.i + +.PHONY : physics_mg.i + +# target to preprocess a source file +physics_mg.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.i +.PHONY : physics_mg.F90.i + +physics_mg.s: physics_mg.F90.s + +.PHONY : physics_mg.s + +# target to generate assembly for a file +physics_mg.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.s +.PHONY : physics_mg.F90.s + +plot.o: plot.F90.o + +.PHONY : plot.o + +# target to build an object file +plot.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.o +.PHONY : plot.F90.o + +plot.i: plot.F90.i + +.PHONY : plot.i + +# target to preprocess a source file +plot.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.i +.PHONY : plot.F90.i + +plot.s: plot.F90.s + +.PHONY : plot.s + +# target to generate assembly for a file +plot.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.s +.PHONY : plot.F90.s + +plot_header.o: plot_header.F90.o + +.PHONY : plot_header.o + +# target to build an object file +plot_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.o +.PHONY : plot_header.F90.o + +plot_header.i: plot_header.F90.i + +.PHONY : plot_header.i + +# target to preprocess a source file +plot_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.i +.PHONY : plot_header.F90.i + +plot_header.s: plot_header.F90.s + +.PHONY : plot_header.s + +# target to generate assembly for a file +plot_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.s +.PHONY : plot_header.F90.s + +product_header.o: product_header.F90.o + +.PHONY : product_header.o + +# target to build an object file +product_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.o +.PHONY : product_header.F90.o + +product_header.i: product_header.F90.i + +.PHONY : product_header.i + +# target to preprocess a source file +product_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.i +.PHONY : product_header.F90.i + +product_header.s: product_header.F90.s + +.PHONY : product_header.s + +# target to generate assembly for a file +product_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.s +.PHONY : product_header.F90.s + +progress_header.o: progress_header.F90.o + +.PHONY : progress_header.o + +# target to build an object file +progress_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.o +.PHONY : progress_header.F90.o + +progress_header.i: progress_header.F90.i + +.PHONY : progress_header.i + +# target to preprocess a source file +progress_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.i +.PHONY : progress_header.F90.i + +progress_header.s: progress_header.F90.s + +.PHONY : progress_header.s + +# target to generate assembly for a file +progress_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.s +.PHONY : progress_header.F90.s + +pugixml/pugixml.o: pugixml/pugixml.cpp.o + +.PHONY : pugixml/pugixml.o + +# target to build an object file +pugixml/pugixml.cpp.o: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.o +.PHONY : pugixml/pugixml.cpp.o + +pugixml/pugixml.i: pugixml/pugixml.cpp.i + +.PHONY : pugixml/pugixml.i + +# target to preprocess a source file +pugixml/pugixml.cpp.i: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.i +.PHONY : pugixml/pugixml.cpp.i + +pugixml/pugixml.s: pugixml/pugixml.cpp.s + +.PHONY : pugixml/pugixml.s + +# target to generate assembly for a file +pugixml/pugixml.cpp.s: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.s +.PHONY : pugixml/pugixml.cpp.s + +pugixml/pugixml_c.o: pugixml/pugixml_c.cpp.o + +.PHONY : pugixml/pugixml_c.o + +# target to build an object file +pugixml/pugixml_c.cpp.o: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.o +.PHONY : pugixml/pugixml_c.cpp.o + +pugixml/pugixml_c.i: pugixml/pugixml_c.cpp.i + +.PHONY : pugixml/pugixml_c.i + +# target to preprocess a source file +pugixml/pugixml_c.cpp.i: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.i +.PHONY : pugixml/pugixml_c.cpp.i + +pugixml/pugixml_c.s: pugixml/pugixml_c.cpp.s + +.PHONY : pugixml/pugixml_c.s + +# target to generate assembly for a file +pugixml/pugixml_c.cpp.s: + $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.s +.PHONY : pugixml/pugixml_c.cpp.s + +pugixml/pugixml_f.o: pugixml/pugixml_f.F90.o + +.PHONY : pugixml/pugixml_f.o + +# target to build an object file +pugixml/pugixml_f.F90.o: + $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.o +.PHONY : pugixml/pugixml_f.F90.o + +pugixml/pugixml_f.i: pugixml/pugixml_f.F90.i + +.PHONY : pugixml/pugixml_f.i + +# target to preprocess a source file +pugixml/pugixml_f.F90.i: + $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.i +.PHONY : pugixml/pugixml_f.F90.i + +pugixml/pugixml_f.s: pugixml/pugixml_f.F90.s + +.PHONY : pugixml/pugixml_f.s + +# target to generate assembly for a file +pugixml/pugixml_f.F90.s: + $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.s +.PHONY : pugixml/pugixml_f.F90.s + +random_lcg.o: random_lcg.F90.o + +.PHONY : random_lcg.o + +# target to build an object file +random_lcg.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.o +.PHONY : random_lcg.F90.o + +random_lcg.i: random_lcg.F90.i + +.PHONY : random_lcg.i + +# target to preprocess a source file +random_lcg.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.i +.PHONY : random_lcg.F90.i + +random_lcg.s: random_lcg.F90.s + +.PHONY : random_lcg.s + +# target to generate assembly for a file +random_lcg.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.s +.PHONY : random_lcg.F90.s + +reaction_header.o: reaction_header.F90.o + +.PHONY : reaction_header.o + +# target to build an object file +reaction_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.o +.PHONY : reaction_header.F90.o + +reaction_header.i: reaction_header.F90.i + +.PHONY : reaction_header.i + +# target to preprocess a source file +reaction_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.i +.PHONY : reaction_header.F90.i + +reaction_header.s: reaction_header.F90.s + +.PHONY : reaction_header.s + +# target to generate assembly for a file +reaction_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.s +.PHONY : reaction_header.F90.s + +sab_header.o: sab_header.F90.o + +.PHONY : sab_header.o + +# target to build an object file +sab_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.o +.PHONY : sab_header.F90.o + +sab_header.i: sab_header.F90.i + +.PHONY : sab_header.i + +# target to preprocess a source file +sab_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.i +.PHONY : sab_header.F90.i + +sab_header.s: sab_header.F90.s + +.PHONY : sab_header.s + +# target to generate assembly for a file +sab_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.s +.PHONY : sab_header.F90.s + +scattdata_header.o: scattdata_header.F90.o + +.PHONY : scattdata_header.o + +# target to build an object file +scattdata_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.o +.PHONY : scattdata_header.F90.o + +scattdata_header.i: scattdata_header.F90.i + +.PHONY : scattdata_header.i + +# target to preprocess a source file +scattdata_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.i +.PHONY : scattdata_header.F90.i + +scattdata_header.s: scattdata_header.F90.s + +.PHONY : scattdata_header.s + +# target to generate assembly for a file +scattdata_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.s +.PHONY : scattdata_header.F90.s + +secondary_correlated.o: secondary_correlated.F90.o + +.PHONY : secondary_correlated.o + +# target to build an object file +secondary_correlated.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.o +.PHONY : secondary_correlated.F90.o + +secondary_correlated.i: secondary_correlated.F90.i + +.PHONY : secondary_correlated.i + +# target to preprocess a source file +secondary_correlated.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.i +.PHONY : secondary_correlated.F90.i + +secondary_correlated.s: secondary_correlated.F90.s + +.PHONY : secondary_correlated.s + +# target to generate assembly for a file +secondary_correlated.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.s +.PHONY : secondary_correlated.F90.s + +secondary_kalbach.o: secondary_kalbach.F90.o + +.PHONY : secondary_kalbach.o + +# target to build an object file +secondary_kalbach.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.o +.PHONY : secondary_kalbach.F90.o + +secondary_kalbach.i: secondary_kalbach.F90.i + +.PHONY : secondary_kalbach.i + +# target to preprocess a source file +secondary_kalbach.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.i +.PHONY : secondary_kalbach.F90.i + +secondary_kalbach.s: secondary_kalbach.F90.s + +.PHONY : secondary_kalbach.s + +# target to generate assembly for a file +secondary_kalbach.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.s +.PHONY : secondary_kalbach.F90.s + +secondary_nbody.o: secondary_nbody.F90.o + +.PHONY : secondary_nbody.o + +# target to build an object file +secondary_nbody.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.o +.PHONY : secondary_nbody.F90.o + +secondary_nbody.i: secondary_nbody.F90.i + +.PHONY : secondary_nbody.i + +# target to preprocess a source file +secondary_nbody.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.i +.PHONY : secondary_nbody.F90.i + +secondary_nbody.s: secondary_nbody.F90.s + +.PHONY : secondary_nbody.s + +# target to generate assembly for a file +secondary_nbody.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.s +.PHONY : secondary_nbody.F90.s + +secondary_uncorrelated.o: secondary_uncorrelated.F90.o + +.PHONY : secondary_uncorrelated.o + +# target to build an object file +secondary_uncorrelated.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.o +.PHONY : secondary_uncorrelated.F90.o + +secondary_uncorrelated.i: secondary_uncorrelated.F90.i + +.PHONY : secondary_uncorrelated.i + +# target to preprocess a source file +secondary_uncorrelated.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.i +.PHONY : secondary_uncorrelated.F90.i + +secondary_uncorrelated.s: secondary_uncorrelated.F90.s + +.PHONY : secondary_uncorrelated.s + +# target to generate assembly for a file +secondary_uncorrelated.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.s +.PHONY : secondary_uncorrelated.F90.s + +set_header.o: set_header.F90.o + +.PHONY : set_header.o + +# target to build an object file +set_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.o +.PHONY : set_header.F90.o + +set_header.i: set_header.F90.i + +.PHONY : set_header.i + +# target to preprocess a source file +set_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.i +.PHONY : set_header.F90.i + +set_header.s: set_header.F90.s + +.PHONY : set_header.s + +# target to generate assembly for a file +set_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.s +.PHONY : set_header.F90.s + +simulation.o: simulation.F90.o + +.PHONY : simulation.o + +# target to build an object file +simulation.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.o +.PHONY : simulation.F90.o + +simulation.i: simulation.F90.i + +.PHONY : simulation.i + +# target to preprocess a source file +simulation.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.i +.PHONY : simulation.F90.i + +simulation.s: simulation.F90.s + +.PHONY : simulation.s + +# target to generate assembly for a file +simulation.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.s +.PHONY : simulation.F90.s + +source.o: source.F90.o + +.PHONY : source.o + +# target to build an object file +source.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.o +.PHONY : source.F90.o + +source.i: source.F90.i + +.PHONY : source.i + +# target to preprocess a source file +source.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.i +.PHONY : source.F90.i + +source.s: source.F90.s + +.PHONY : source.s + +# target to generate assembly for a file +source.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.s +.PHONY : source.F90.s + +source_header.o: source_header.F90.o + +.PHONY : source_header.o + +# target to build an object file +source_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.o +.PHONY : source_header.F90.o + +source_header.i: source_header.F90.i + +.PHONY : source_header.i + +# target to preprocess a source file +source_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.i +.PHONY : source_header.F90.i + +source_header.s: source_header.F90.s + +.PHONY : source_header.s + +# target to generate assembly for a file +source_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.s +.PHONY : source_header.F90.s + +state_point.o: state_point.F90.o + +.PHONY : state_point.o + +# target to build an object file +state_point.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.o +.PHONY : state_point.F90.o + +state_point.i: state_point.F90.i + +.PHONY : state_point.i + +# target to preprocess a source file +state_point.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.i +.PHONY : state_point.F90.i + +state_point.s: state_point.F90.s + +.PHONY : state_point.s + +# target to generate assembly for a file +state_point.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.s +.PHONY : state_point.F90.s + +stl_vector.o: stl_vector.F90.o + +.PHONY : stl_vector.o + +# target to build an object file +stl_vector.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.o +.PHONY : stl_vector.F90.o + +stl_vector.i: stl_vector.F90.i + +.PHONY : stl_vector.i + +# target to preprocess a source file +stl_vector.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.i +.PHONY : stl_vector.F90.i + +stl_vector.s: stl_vector.F90.s + +.PHONY : stl_vector.s + +# target to generate assembly for a file +stl_vector.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.s +.PHONY : stl_vector.F90.s + +string.o: string.F90.o + +.PHONY : string.o + +# target to build an object file +string.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.o +.PHONY : string.F90.o + +string.i: string.F90.i + +.PHONY : string.i + +# target to preprocess a source file +string.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.i +.PHONY : string.F90.i + +string.s: string.F90.s + +.PHONY : string.s + +# target to generate assembly for a file +string.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.s +.PHONY : string.F90.s + +summary.o: summary.F90.o + +.PHONY : summary.o + +# target to build an object file +summary.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.o +.PHONY : summary.F90.o + +summary.i: summary.F90.i + +.PHONY : summary.i + +# target to preprocess a source file +summary.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.i +.PHONY : summary.F90.i + +summary.s: summary.F90.s + +.PHONY : summary.s + +# target to generate assembly for a file +summary.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.s +.PHONY : summary.F90.s + +surface_header.o: surface_header.F90.o + +.PHONY : surface_header.o + +# target to build an object file +surface_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.o +.PHONY : surface_header.F90.o + +surface_header.i: surface_header.F90.i + +.PHONY : surface_header.i + +# target to preprocess a source file +surface_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.i +.PHONY : surface_header.F90.i + +surface_header.s: surface_header.F90.s + +.PHONY : surface_header.s + +# target to generate assembly for a file +surface_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.s +.PHONY : surface_header.F90.s + +tally.o: tally.F90.o + +.PHONY : tally.o + +# target to build an object file +tally.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.o +.PHONY : tally.F90.o + +tally.i: tally.F90.i + +.PHONY : tally.i + +# target to preprocess a source file +tally.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.i +.PHONY : tally.F90.i + +tally.s: tally.F90.s + +.PHONY : tally.s + +# target to generate assembly for a file +tally.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.s +.PHONY : tally.F90.s + +tally_filter.o: tally_filter.F90.o + +.PHONY : tally_filter.o + +# target to build an object file +tally_filter.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.o +.PHONY : tally_filter.F90.o + +tally_filter.i: tally_filter.F90.i + +.PHONY : tally_filter.i + +# target to preprocess a source file +tally_filter.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.i +.PHONY : tally_filter.F90.i + +tally_filter.s: tally_filter.F90.s + +.PHONY : tally_filter.s + +# target to generate assembly for a file +tally_filter.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.s +.PHONY : tally_filter.F90.s + +tally_filter_header.o: tally_filter_header.F90.o + +.PHONY : tally_filter_header.o + +# target to build an object file +tally_filter_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.o +.PHONY : tally_filter_header.F90.o + +tally_filter_header.i: tally_filter_header.F90.i + +.PHONY : tally_filter_header.i + +# target to preprocess a source file +tally_filter_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.i +.PHONY : tally_filter_header.F90.i + +tally_filter_header.s: tally_filter_header.F90.s + +.PHONY : tally_filter_header.s + +# target to generate assembly for a file +tally_filter_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.s +.PHONY : tally_filter_header.F90.s + +tally_header.o: tally_header.F90.o + +.PHONY : tally_header.o + +# target to build an object file +tally_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.o +.PHONY : tally_header.F90.o + +tally_header.i: tally_header.F90.i + +.PHONY : tally_header.i + +# target to preprocess a source file +tally_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.i +.PHONY : tally_header.F90.i + +tally_header.s: tally_header.F90.s + +.PHONY : tally_header.s + +# target to generate assembly for a file +tally_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.s +.PHONY : tally_header.F90.s + +tally_initialize.o: tally_initialize.F90.o + +.PHONY : tally_initialize.o + +# target to build an object file +tally_initialize.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.o +.PHONY : tally_initialize.F90.o + +tally_initialize.i: tally_initialize.F90.i + +.PHONY : tally_initialize.i + +# target to preprocess a source file +tally_initialize.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.i +.PHONY : tally_initialize.F90.i + +tally_initialize.s: tally_initialize.F90.s + +.PHONY : tally_initialize.s + +# target to generate assembly for a file +tally_initialize.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.s +.PHONY : tally_initialize.F90.s + +timer_header.o: timer_header.F90.o + +.PHONY : timer_header.o + +# target to build an object file +timer_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.o +.PHONY : timer_header.F90.o + +timer_header.i: timer_header.F90.i + +.PHONY : timer_header.i + +# target to preprocess a source file +timer_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.i +.PHONY : timer_header.F90.i + +timer_header.s: timer_header.F90.s + +.PHONY : timer_header.s + +# target to generate assembly for a file +timer_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.s +.PHONY : timer_header.F90.s + +track_output.o: track_output.F90.o + +.PHONY : track_output.o + +# target to build an object file +track_output.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.o +.PHONY : track_output.F90.o + +track_output.i: track_output.F90.i + +.PHONY : track_output.i + +# target to preprocess a source file +track_output.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.i +.PHONY : track_output.F90.i + +track_output.s: track_output.F90.s + +.PHONY : track_output.s + +# target to generate assembly for a file +track_output.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.s +.PHONY : track_output.F90.s + +tracking.o: tracking.F90.o + +.PHONY : tracking.o + +# target to build an object file +tracking.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.o +.PHONY : tracking.F90.o + +tracking.i: tracking.F90.i + +.PHONY : tracking.i + +# target to preprocess a source file +tracking.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.i +.PHONY : tracking.F90.i + +tracking.s: tracking.F90.s + +.PHONY : tracking.s + +# target to generate assembly for a file +tracking.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.s +.PHONY : tracking.F90.s + +trigger.o: trigger.F90.o + +.PHONY : trigger.o + +# target to build an object file +trigger.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.o +.PHONY : trigger.F90.o + +trigger.i: trigger.F90.i + +.PHONY : trigger.i + +# target to preprocess a source file +trigger.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.i +.PHONY : trigger.F90.i + +trigger.s: trigger.F90.s + +.PHONY : trigger.s + +# target to generate assembly for a file +trigger.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.s +.PHONY : trigger.F90.s + +trigger_header.o: trigger_header.F90.o + +.PHONY : trigger_header.o + +# target to build an object file +trigger_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.o +.PHONY : trigger_header.F90.o + +trigger_header.i: trigger_header.F90.i + +.PHONY : trigger_header.i + +# target to preprocess a source file +trigger_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.i +.PHONY : trigger_header.F90.i + +trigger_header.s: trigger_header.F90.s + +.PHONY : trigger_header.s + +# target to generate assembly for a file +trigger_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.s +.PHONY : trigger_header.F90.s + +urr_header.o: urr_header.F90.o + +.PHONY : urr_header.o + +# target to build an object file +urr_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.o +.PHONY : urr_header.F90.o + +urr_header.i: urr_header.F90.i + +.PHONY : urr_header.i + +# target to preprocess a source file +urr_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.i +.PHONY : urr_header.F90.i + +urr_header.s: urr_header.F90.s + +.PHONY : urr_header.s + +# target to generate assembly for a file +urr_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.s +.PHONY : urr_header.F90.s + +vector_header.o: vector_header.F90.o + +.PHONY : vector_header.o + +# target to build an object file +vector_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.o +.PHONY : vector_header.F90.o + +vector_header.i: vector_header.F90.i + +.PHONY : vector_header.i + +# target to preprocess a source file +vector_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.i +.PHONY : vector_header.F90.i + +vector_header.s: vector_header.F90.s + +.PHONY : vector_header.s + +# target to generate assembly for a file +vector_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.s +.PHONY : vector_header.F90.s + +volume_calc.o: volume_calc.F90.o + +.PHONY : volume_calc.o + +# target to build an object file +volume_calc.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.o +.PHONY : volume_calc.F90.o + +volume_calc.i: volume_calc.F90.i + +.PHONY : volume_calc.i + +# target to preprocess a source file +volume_calc.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.i +.PHONY : volume_calc.F90.i + +volume_calc.s: volume_calc.F90.s + +.PHONY : volume_calc.s + +# target to generate assembly for a file +volume_calc.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.s +.PHONY : volume_calc.F90.s + +volume_header.o: volume_header.F90.o + +.PHONY : volume_header.o + +# target to build an object file +volume_header.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.o +.PHONY : volume_header.F90.o + +volume_header.i: volume_header.F90.i + +.PHONY : volume_header.i + +# target to preprocess a source file +volume_header.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.i +.PHONY : volume_header.F90.i + +volume_header.s: volume_header.F90.s + +.PHONY : volume_header.s + +# target to generate assembly for a file +volume_header.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.s +.PHONY : volume_header.F90.s + +xml_interface.o: xml_interface.F90.o + +.PHONY : xml_interface.o + +# target to build an object file +xml_interface.F90.o: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.o +.PHONY : xml_interface.F90.o + +xml_interface.i: xml_interface.F90.i + +.PHONY : xml_interface.i + +# target to preprocess a source file +xml_interface.F90.i: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.i +.PHONY : xml_interface.F90.i + +xml_interface.s: xml_interface.F90.s + +.PHONY : xml_interface.s + +# target to generate assembly for a file +xml_interface.F90.s: + $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.s +.PHONY : xml_interface.F90.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... install/strip" + @echo "... install/local" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... ContinuousCoverage" + @echo "... ContinuousBuild" + @echo "... ContinuousUpdate" + @echo "... ContinuousStart" + @echo "... ExperimentalSubmit" + @echo "... ExperimentalBuild" + @echo "... ExperimentalCoverage" + @echo "... ExperimentalUpdate" + @echo "... install" + @echo "... ExperimentalStart" + @echo "... NightlyMemCheck" + @echo "... test" + @echo "... ExperimentalConfigure" + @echo "... NightlyCoverage" + @echo "... NightlyTest" + @echo "... NightlyConfigure" + @echo "... openmc" + @echo "... Continuous" + @echo "... NightlyStart" + @echo "... Nightly" + @echo "... ExperimentalMemCheck" + @echo "... libopenmc" + @echo "... edit_cache" + @echo "... ContinuousConfigure" + @echo "... NightlyMemoryCheck" + @echo "... Experimental" + @echo "... ContinuousSubmit" + @echo "... ExperimentalTest" + @echo "... NightlySubmit" + @echo "... ContinuousTest" + @echo "... faddeeva" + @echo "... ContinuousMemCheck" + @echo "... NightlyBuild" + @echo "... pugixml_fortran" + @echo "... NightlyUpdate" + @echo "... pugixml" + @echo "... algorithm.o" + @echo "... algorithm.i" + @echo "... algorithm.s" + @echo "... angle_distribution.o" + @echo "... angle_distribution.i" + @echo "... angle_distribution.s" + @echo "... angleenergy_header.o" + @echo "... angleenergy_header.i" + @echo "... angleenergy_header.s" + @echo "... bank_header.o" + @echo "... bank_header.i" + @echo "... bank_header.s" + @echo "... cmfd_data.o" + @echo "... cmfd_data.i" + @echo "... cmfd_data.s" + @echo "... cmfd_execute.o" + @echo "... cmfd_execute.i" + @echo "... cmfd_execute.s" + @echo "... cmfd_header.o" + @echo "... cmfd_header.i" + @echo "... cmfd_header.s" + @echo "... cmfd_input.o" + @echo "... cmfd_input.i" + @echo "... cmfd_input.s" + @echo "... cmfd_loss_operator.o" + @echo "... cmfd_loss_operator.i" + @echo "... cmfd_loss_operator.s" + @echo "... cmfd_prod_operator.o" + @echo "... cmfd_prod_operator.i" + @echo "... cmfd_prod_operator.s" + @echo "... cmfd_solver.o" + @echo "... cmfd_solver.i" + @echo "... cmfd_solver.s" + @echo "... constants.o" + @echo "... constants.i" + @echo "... constants.s" + @echo "... cross_section.o" + @echo "... cross_section.i" + @echo "... cross_section.s" + @echo "... dict_header.o" + @echo "... dict_header.i" + @echo "... dict_header.s" + @echo "... distribution_multivariate.o" + @echo "... distribution_multivariate.i" + @echo "... distribution_multivariate.s" + @echo "... distribution_univariate.o" + @echo "... distribution_univariate.i" + @echo "... distribution_univariate.s" + @echo "... doppler.o" + @echo "... doppler.i" + @echo "... doppler.s" + @echo "... eigenvalue.o" + @echo "... eigenvalue.i" + @echo "... eigenvalue.s" + @echo "... endf.o" + @echo "... endf.i" + @echo "... endf.s" + @echo "... endf_header.o" + @echo "... endf_header.i" + @echo "... endf_header.s" + @echo "... energy_distribution.o" + @echo "... energy_distribution.i" + @echo "... energy_distribution.s" + @echo "... energy_grid.o" + @echo "... energy_grid.i" + @echo "... energy_grid.s" + @echo "... error.o" + @echo "... error.i" + @echo "... error.s" + @echo "... faddeeva/Faddeeva.o" + @echo "... faddeeva/Faddeeva.i" + @echo "... faddeeva/Faddeeva.s" + @echo "... finalize.o" + @echo "... finalize.i" + @echo "... finalize.s" + @echo "... geometry.o" + @echo "... geometry.i" + @echo "... geometry.s" + @echo "... geometry_header.o" + @echo "... geometry_header.i" + @echo "... geometry_header.s" + @echo "... global.o" + @echo "... global.i" + @echo "... global.s" + @echo "... hdf5_interface.o" + @echo "... hdf5_interface.i" + @echo "... hdf5_interface.s" + @echo "... initialize.o" + @echo "... initialize.i" + @echo "... initialize.s" + @echo "... input_xml.o" + @echo "... input_xml.i" + @echo "... input_xml.s" + @echo "... list_header.o" + @echo "... list_header.i" + @echo "... list_header.s" + @echo "... main.o" + @echo "... main.i" + @echo "... main.s" + @echo "... material_header.o" + @echo "... material_header.i" + @echo "... material_header.s" + @echo "... math.o" + @echo "... math.i" + @echo "... math.s" + @echo "... matrix_header.o" + @echo "... matrix_header.i" + @echo "... matrix_header.s" + @echo "... mesh.o" + @echo "... mesh.i" + @echo "... mesh.s" + @echo "... mesh_header.o" + @echo "... mesh_header.i" + @echo "... mesh_header.s" + @echo "... message_passing.o" + @echo "... message_passing.i" + @echo "... message_passing.s" + @echo "... mgxs_data.o" + @echo "... mgxs_data.i" + @echo "... mgxs_data.s" + @echo "... mgxs_header.o" + @echo "... mgxs_header.i" + @echo "... mgxs_header.s" + @echo "... multipole.o" + @echo "... multipole.i" + @echo "... multipole.s" + @echo "... multipole_header.o" + @echo "... multipole_header.i" + @echo "... multipole_header.s" + @echo "... nuclide_header.o" + @echo "... nuclide_header.i" + @echo "... nuclide_header.s" + @echo "... output.o" + @echo "... output.i" + @echo "... output.s" + @echo "... particle_header.o" + @echo "... particle_header.i" + @echo "... particle_header.s" + @echo "... particle_restart.o" + @echo "... particle_restart.i" + @echo "... particle_restart.s" + @echo "... particle_restart_write.o" + @echo "... particle_restart_write.i" + @echo "... particle_restart_write.s" + @echo "... physics.o" + @echo "... physics.i" + @echo "... physics.s" + @echo "... physics_common.o" + @echo "... physics_common.i" + @echo "... physics_common.s" + @echo "... physics_mg.o" + @echo "... physics_mg.i" + @echo "... physics_mg.s" + @echo "... plot.o" + @echo "... plot.i" + @echo "... plot.s" + @echo "... plot_header.o" + @echo "... plot_header.i" + @echo "... plot_header.s" + @echo "... product_header.o" + @echo "... product_header.i" + @echo "... product_header.s" + @echo "... progress_header.o" + @echo "... progress_header.i" + @echo "... progress_header.s" + @echo "... pugixml/pugixml.o" + @echo "... pugixml/pugixml.i" + @echo "... pugixml/pugixml.s" + @echo "... pugixml/pugixml_c.o" + @echo "... pugixml/pugixml_c.i" + @echo "... pugixml/pugixml_c.s" + @echo "... pugixml/pugixml_f.o" + @echo "... pugixml/pugixml_f.i" + @echo "... pugixml/pugixml_f.s" + @echo "... random_lcg.o" + @echo "... random_lcg.i" + @echo "... random_lcg.s" + @echo "... reaction_header.o" + @echo "... reaction_header.i" + @echo "... reaction_header.s" + @echo "... sab_header.o" + @echo "... sab_header.i" + @echo "... sab_header.s" + @echo "... scattdata_header.o" + @echo "... scattdata_header.i" + @echo "... scattdata_header.s" + @echo "... secondary_correlated.o" + @echo "... secondary_correlated.i" + @echo "... secondary_correlated.s" + @echo "... secondary_kalbach.o" + @echo "... secondary_kalbach.i" + @echo "... secondary_kalbach.s" + @echo "... secondary_nbody.o" + @echo "... secondary_nbody.i" + @echo "... secondary_nbody.s" + @echo "... secondary_uncorrelated.o" + @echo "... secondary_uncorrelated.i" + @echo "... secondary_uncorrelated.s" + @echo "... set_header.o" + @echo "... set_header.i" + @echo "... set_header.s" + @echo "... simulation.o" + @echo "... simulation.i" + @echo "... simulation.s" + @echo "... source.o" + @echo "... source.i" + @echo "... source.s" + @echo "... source_header.o" + @echo "... source_header.i" + @echo "... source_header.s" + @echo "... state_point.o" + @echo "... state_point.i" + @echo "... state_point.s" + @echo "... stl_vector.o" + @echo "... stl_vector.i" + @echo "... stl_vector.s" + @echo "... string.o" + @echo "... string.i" + @echo "... string.s" + @echo "... summary.o" + @echo "... summary.i" + @echo "... summary.s" + @echo "... surface_header.o" + @echo "... surface_header.i" + @echo "... surface_header.s" + @echo "... tally.o" + @echo "... tally.i" + @echo "... tally.s" + @echo "... tally_filter.o" + @echo "... tally_filter.i" + @echo "... tally_filter.s" + @echo "... tally_filter_header.o" + @echo "... tally_filter_header.i" + @echo "... tally_filter_header.s" + @echo "... tally_header.o" + @echo "... tally_header.i" + @echo "... tally_header.s" + @echo "... tally_initialize.o" + @echo "... tally_initialize.i" + @echo "... tally_initialize.s" + @echo "... timer_header.o" + @echo "... timer_header.i" + @echo "... timer_header.s" + @echo "... track_output.o" + @echo "... track_output.i" + @echo "... track_output.s" + @echo "... tracking.o" + @echo "... tracking.i" + @echo "... tracking.s" + @echo "... trigger.o" + @echo "... trigger.i" + @echo "... trigger.s" + @echo "... trigger_header.o" + @echo "... trigger_header.i" + @echo "... trigger_header.s" + @echo "... urr_header.o" + @echo "... urr_header.i" + @echo "... urr_header.s" + @echo "... vector_header.o" + @echo "... vector_header.i" + @echo "... vector_header.s" + @echo "... volume_calc.o" + @echo "... volume_calc.i" + @echo "... volume_calc.s" + @echo "... volume_header.o" + @echo "... volume_header.i" + @echo "... volume_header.s" + @echo "... xml_interface.o" + @echo "... xml_interface.i" + @echo "... xml_interface.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/src/tally.F90 b/src/tally.F90 index 0ee041cbe..e542f77b1 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2292,14 +2292,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2452,14 +2446,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2837,14 +2825,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -3013,15 +2995,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do - filter_matches(i_filt) % bins_present = .true. + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) end if ! If there are no valid bins for this filter, then there is nothing to ! score and we can move on to the next tally. @@ -3148,6 +3123,7 @@ contains integer :: i integer :: i_tally + integer :: i_filt integer :: j, k ! loop indices integer :: n_dim ! num dimensions of the mesh integer :: d1 ! dimension index @@ -3237,10 +3213,15 @@ contains ! Determine incoming energy bin. We need to tell the energy filter this ! is a tracklength tally so it uses the pre-collision energy. if (energy_filter) then - call filters(i_filter_energy) % obj % get_next_bin(p, & - ESTIMATOR_TRACKLENGTH, NO_BIN_FOUND, matching_bin, filt_score) - if (matching_bin == NO_BIN_FOUND) cycle + t => tallies(i_tally) + ! Find all valid bins in each filter if they have not already been found + ! for a previous tally. + do j = 1, size(t % filter) + i_filt = t % filter(j) + call filters(i_filter_energy) % obj % get_all_bins(p, & + ESTIMATOR_TRACKLENGTH, filter_matches(i_filt)) filter_matches(i_filter_energy) % bins % data(1) = matching_bin + end do end if ! Bounding coordinates diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index dfb89d433..ec490d1e3 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -13,7 +13,8 @@ module tally_filter mesh_intersects_3d use particle_header, only: Particle use string, only: to_str - use tally_filter_header, only: TallyFilter, TallyFilterContainer + use tally_filter_header, only: TallyFilter, TallyFilterContainer, & + TallyFilterMatch use hdf5, only: HID_T @@ -27,7 +28,7 @@ module tally_filter type, extends(TallyFilter) :: MeshFilter integer :: mesh contains - procedure :: get_next_bin => get_next_bin_mesh + procedure :: get_all_bins => get_all_bins_mesh procedure :: to_statepoint => to_statepoint_mesh procedure :: text_label => text_label_mesh end type MeshFilter @@ -39,7 +40,7 @@ module tally_filter integer, allocatable :: universes(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_universe + procedure :: get_all_bins => get_all_bins_universe procedure :: to_statepoint => to_statepoint_universe procedure :: text_label => text_label_universe procedure :: initialize => initialize_universe @@ -52,7 +53,7 @@ module tally_filter integer, allocatable :: materials(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_material + procedure :: get_all_bins => get_all_bins_material procedure :: to_statepoint => to_statepoint_material procedure :: text_label => text_label_material procedure :: initialize => initialize_material @@ -65,7 +66,7 @@ module tally_filter integer, allocatable :: cells(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_cell + procedure :: get_all_bins => get_all_bins_cell procedure :: to_statepoint => to_statepoint_cell procedure :: text_label => text_label_cell procedure :: initialize => initialize_cell @@ -78,7 +79,7 @@ module tally_filter type, extends(TallyFilter) :: DistribcellFilter integer :: cell contains - procedure :: get_next_bin => get_next_bin_distribcell + procedure :: get_all_bins => get_all_bins_distribcell procedure :: to_statepoint => to_statepoint_distribcell procedure :: text_label => text_label_distribcell procedure :: initialize => initialize_distribcell @@ -91,7 +92,7 @@ module tally_filter integer, allocatable :: cells(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_cellborn + procedure :: get_all_bins => get_all_bins_cellborn procedure :: to_statepoint => to_statepoint_cellborn procedure :: text_label => text_label_cellborn procedure :: initialize => initialize_cellborn @@ -107,7 +108,7 @@ module tally_filter ! True if this filter is used for surface currents logical :: current = .false. contains - procedure :: get_next_bin => get_next_bin_surface + procedure :: get_all_bins => get_all_bins_surface procedure :: to_statepoint => to_statepoint_surface procedure :: text_label => text_label_surface procedure :: initialize => initialize_surface @@ -123,14 +124,14 @@ module tally_filter logical :: matches_transport_groups = .false. contains - procedure :: get_next_bin => get_next_bin_energy + procedure :: get_all_bins => get_all_bins_energy procedure :: to_statepoint => to_statepoint_energy procedure :: text_label => text_label_energy end type EnergyFilter !=============================================================================== ! ENERGYOUTFILTER bins the outgoing neutron energy. Only scattering events use -! the get_next_bin functionality. Nu-fission tallies manually iterate over the +! the get_all_bins functionality. Nu-fission tallies manually iterate over the ! filter bins. !=============================================================================== type, extends(TallyFilter) :: EnergyoutFilter @@ -140,20 +141,20 @@ module tally_filter logical :: matches_transport_groups = .false. contains - procedure :: get_next_bin => get_next_bin_energyout + procedure :: get_all_bins => get_all_bins_energyout procedure :: to_statepoint => to_statepoint_energyout procedure :: text_label => text_label_energyout end type EnergyoutFilter !=============================================================================== ! DELAYEDGROUPFILTER bins outgoing fission neutrons in their delayed groups. -! The get_next_bin functionality is not actually used. The bins are manually +! The get_all_bins functionality is not actually used. The bins are manually ! iterated over in the scoring subroutines. !=============================================================================== type, extends(TallyFilter) :: DelayedGroupFilter integer, allocatable :: groups(:) contains - procedure :: get_next_bin => get_next_bin_dg + procedure :: get_all_bins => get_all_bins_dg procedure :: to_statepoint => to_statepoint_dg procedure :: text_label => text_label_dg end type DelayedGroupFilter @@ -165,7 +166,7 @@ module tally_filter type, extends(TallyFilter) :: MuFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_mu + procedure :: get_all_bins => get_all_bins_mu procedure :: to_statepoint => to_statepoint_mu procedure :: text_label => text_label_mu end type MuFilter @@ -177,7 +178,7 @@ module tally_filter type, extends(TallyFilter) :: PolarFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_polar + procedure :: get_all_bins => get_all_bins_polar procedure :: to_statepoint => to_statepoint_polar procedure :: text_label => text_label_polar end type PolarFilter @@ -189,7 +190,7 @@ module tally_filter type, extends(TallyFilter) :: AzimuthalFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_azimuthal + procedure :: get_all_bins => get_all_bins_azimuthal procedure :: to_statepoint => to_statepoint_azimuthal procedure :: text_label => text_label_azimuthal end type AzimuthalFilter @@ -203,7 +204,7 @@ module tally_filter real(8), allocatable :: y(:) contains - procedure :: get_next_bin => get_next_bin_energyfunction + procedure :: get_all_bins => get_all_bins_energyfunction procedure :: to_statepoint => to_statepoint_energyfunction procedure :: text_label => text_label_energyfunction end type EnergyFunctionFilter @@ -218,14 +219,11 @@ contains !=============================================================================== ! MeshFilter methods !=============================================================================== - subroutine get_next_bin_mesh(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_mesh(this, p, estimator, match) class(MeshFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer, parameter :: MAX_SEARCH_ITER = 100 ! Maximum number of times we can ! can loop while trying to find @@ -235,6 +233,7 @@ contains integer :: ijk0(3) ! indices of starting coordinates integer :: ijk1(3) ! indices of ending coordinates integer :: search_iter ! loop count for intersection search + real(8) :: weight ! weight to be pushed back real(8) :: uvw(3) ! cosine of angle of particle real(8) :: xyz0(3) ! starting/intermediate coordinates real(8) :: xyz1(3) ! ending coordinates of particle @@ -246,20 +245,14 @@ contains logical :: end_in_mesh ! ending coordinates inside mesh? type(RegularMesh), pointer :: m - weight = ERROR_REAL - ! Get a pointer to the mesh. m => meshes(this % mesh) if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. - if (current_bin == NO_BIN_FOUND) then - call get_mesh_bin(m, p % coord(1) % xyz, next_bin) - weight = ONE - else - next_bin = NO_BIN_FOUND - end if + call match % bins % push_back(1) + call match % weights % push_back(ONE) else ! A track can span multiple mesh bins so we need to handle a lot of @@ -279,29 +272,6 @@ contains call get_mesh_indices(m, xyz0, ijk0(:m % n_dimension), start_in_mesh) call get_mesh_indices(m, xyz1, ijk1(:m % n_dimension), end_in_mesh) - ! If this is the first iteration of the filter loop, check if the track - ! intersects any part of the mesh. - if (current_bin == NO_BIN_FOUND) then - if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (m % n_dimension == 1) then - if (.not. mesh_intersects_1d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - else if (m % n_dimension == 2) then - if (.not. mesh_intersects_2d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - else - if (.not. mesh_intersects_3d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - end if - end if - end if - ! ======================================================================== ! Figure out which mesh cell to tally. @@ -313,71 +283,11 @@ contains ! Compute the length of the entire track. total_distance = sqrt(sum((xyz1 - xyz0)**2)) - if (current_bin == NO_BIN_FOUND) then - ! We are looking for the first valid mesh bin. Check to see if the - ! particle starts inside the mesh. - if (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) then - ! The particle does not start in the mesh. Note that we nudged the - ! start and end coordinates by a TINY_BIT each so we will have - ! difficulty resolving tracks that are less than 2*TINY_BIT in length. - ! If the track is that short, it is also insignificant so we can - ! safely ignore it in the tallies. - if (total_distance < 2*TINY_BIT) then - next_bin = NO_BIN_FOUND - return - end if - - ! The particle does not start in the mesh so keep iterating the ijk0 - ! indices to cross the nearest mesh surface until we've found a valid - ! bin. MAX_SEARCH_ITER prevents an infinite loop. - search_iter = 0 - do while (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) - if (search_iter == MAX_SEARCH_ITER) then - call warning("Failed to find a mesh intersection on a tally mesh & - &filter.") - next_bin = NO_BIN_FOUND - return - end if - - do j = 1, m % n_dimension - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:m % n_dimension), 1) - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if - - search_iter = search_iter + 1 - end do - distance = d(j) - xyz0 = xyz0 + distance * uvw - - end if - - else ! We have already scored some mesh bins for this track. Pick up where ! we left off and find the next mesh cell that the particle enters. ! Get the indices to the last bin we scored. - call bin_to_mesh_indices(m, current_bin, ijk0(:m % n_dimension)) - - ! If the particle track ends in that bin, then we are done. - if (all(ijk0(:m % n_dimension) == ijk1(:m % n_dimension))) then - next_bin = NO_BIN_FOUND - return - end if + ! call bin_to_mesh_indices(m, current_bin, ijk0(:m % n_dimension)) ! Figure out which face of the previous mesh cell our track exits, i.e. ! the closest surface of that cell for which @@ -407,14 +317,6 @@ contains else ijk0(j) = ijk0(j) - 1 end if - - ! If the next indices are invalid, then the track has left the mesh and - ! we are done. - if (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) then - next_bin = NO_BIN_FOUND - return - end if end if ! ======================================================================== @@ -442,10 +344,10 @@ contains end if ! Assign the next tally bin and the score. - next_bin = mesh_indices_to_bin(m, ijk0(:m % n_dimension)) + call match % bins % push_back(mesh_indices_to_bin(m, ijk0(:m % n_dimension))) weight = distance / total_distance - endif - end subroutine get_next_bin_mesh + call match % weights % push_back(weight) + end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) class(MeshFilter), intent(in) :: this @@ -481,40 +383,24 @@ contains !=============================================================================== ! UniverseFilter methods !=============================================================================== - subroutine get_next_bin_universe(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_universe(this, p, estimator, match) class(UniverseFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: i, start - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % universe == this % universes(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord + ! Iterate over coordinate levels to see which universes match + do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % universe)) then - next_bin = this % map % get_key(p % coord(i) % universe) - weight = ONE - exit + call match % bins % push_back(this % map % get_key(p % coord(i) & + % universe)) + call match % weights % push_back(ONE) end if end do - end subroutine get_next_bin_universe + + end subroutine get_all_bins_universe subroutine to_statepoint_universe(this, filter_group) class(UniverseFilter), intent(in) :: this @@ -566,24 +452,18 @@ contains !=============================================================================== ! MaterialFilter methods !=============================================================================== - subroutine get_next_bin_material(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_material(this, p, estimator, match) class(MaterialFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then if (this % map % has_key(p % material)) then - next_bin = this % map % get_key(p % material) - weight = ONE + call match % bins % push_back(this % map % get_key(p % material)) + call match % weights % push_back(ONE) end if - end if - end subroutine get_next_bin_material + + end subroutine get_all_bins_material subroutine to_statepoint_material(this, filter_group) class(MaterialFilter), intent(in) :: this @@ -635,40 +515,23 @@ contains !=============================================================================== ! CellFilter methods !=============================================================================== - subroutine get_next_bin_cell(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_cell(this, p, estimator, match) class(CellFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - integer :: i, start + integer :: i - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % cell == this % cells(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord + ! Iterate over coordinate levels to see with cells match + do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % cell)) then - next_bin = this % map % get_key(p % coord(i) % cell) - weight = ONE - exit + call match % bins % push_back(this % map % get_key(p % coord(i) % cell)) + call match % weights % push_back(ONE) end if end do - end subroutine get_next_bin_cell + + end subroutine get_all_bins_cell subroutine to_statepoint_cell(this, filter_group) class(CellFilter), intent(in) :: this @@ -720,18 +583,14 @@ contains !=============================================================================== ! DistribcellFilter methods !=============================================================================== - subroutine get_next_bin_distribcell(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_all_bins_distribcell(this, p, estimator, match) class(DistribcellFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: distribcell_index, offset, i - if (current_bin == NO_BIN_FOUND) then distribcell_index = cells(this % cell) % distribcell_index offset = 0 do i = 1, p % n_coord @@ -752,15 +611,12 @@ contains end if end if if (this % cell == p % coord(i) % cell) then - next_bin = offset + 1 - weight = ONE + call match % bins % push_back(offset + 1) + call match % weights % push_back(ONE) return end if end do - end if - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end subroutine get_next_bin_distribcell + end subroutine get_all_bins_distribcell subroutine to_statepoint_distribcell(this, filter_group) class(DistribcellFilter), intent(in) :: this @@ -804,24 +660,18 @@ contains !=============================================================================== ! CellbornFilter methods !=============================================================================== - subroutine get_next_bin_cellborn(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_cellborn(this, p, estimator, match) class(CellbornFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then if (this % map % has_key(p % cell_born)) then - next_bin = this % map % get_key(p % cell_born) - weight = ONE + call match % bins % push_back(this % map % get_key(p % cell_born)) + call match % weights % push_back(ONE) end if - end if - end subroutine get_next_bin_cellborn + + end subroutine get_all_bins_cellborn subroutine to_statepoint_cellborn(this, filter_group) class(CellbornFilter), intent(in) :: this @@ -872,29 +722,23 @@ contains !=============================================================================== ! SurfaceFilter methods !=============================================================================== - subroutine get_next_bin_surface(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_surface(this, p, estimator, match) class(SurfaceFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: i - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then do i = 1, this % n_bins if (p % surface == this % surfaces(i)) then - next_bin = i - weight = ONE + call match % bins % push_back(i) + call match % weights % push_back(ONE) exit end if end do - end if - end subroutine get_next_bin_surface + + end subroutine get_all_bins_surface subroutine to_statepoint_surface(this, filter_group) class(SurfaceFilter), intent(in) :: this @@ -933,33 +777,26 @@ contains !=============================================================================== ! EnergyFilter methods !=============================================================================== - subroutine get_next_bin_energy(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_energy(this, p, estimator, match) class(EnergyFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: E - if (current_bin == NO_BIN_FOUND) then n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then if (estimator == ESTIMATOR_TRACKLENGTH) then - next_bin = p % g + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) else - next_bin = p % last_g + call match % bins % push_back(num_energy_groups - p % last_g + 1) + call match % weights % push_back(ONE) end if - ! Tallies are ordered in increasing groups, group indices - ! however are the opposite, so switch - next_bin = num_energy_groups - next_bin + 1 - weight = ONE - else ! Make sure the correct energy is used. if (estimator == ESTIMATOR_TRACKLENGTH) then @@ -968,22 +805,11 @@ contains E = p % last_E end if - ! Check if energy of the particle is within energy bins. - if (E < this % bins(1) .or. E > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, E) - weight = ONE - end if + call match % bins % push_back(binary_search(this % bins, n + 1, E)) + call match % weights % push_back(ONE) end if - - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_energy + end subroutine get_all_bins_energy subroutine to_statepoint_energy(this, filter_group) class(EnergyFilter), intent(in) :: this @@ -1010,45 +836,31 @@ contains !=============================================================================== ! EnergyoutFilter methods !=============================================================================== - subroutine get_next_bin_energyout(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_energyout(this, p, estimator, match) class(EnergyoutFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n - if (current_bin == NO_BIN_FOUND) then n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then - next_bin = p % g + call match % bins % push_back(p % g) ! Tallies are ordered in increasing groups, group indices ! however are the opposite, so switch - next_bin = num_energy_groups - next_bin + 1 - weight = ONE + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) else - ! Check if energy of the particle is within energy bins. - if (p % E < this % bins(1) .or. p % E > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, p % E) - weight = ONE - end if - end if - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_energyout + ! Search to find incoming energy bin. + call match % bins % push_back(binary_search(this % bins, n + 1, p % E)) + call match % weights % push_back(ONE) + end if + end subroutine get_all_bins_energyout subroutine to_statepoint_energyout(this, filter_group) class(EnergyoutFilter), intent(in) :: this @@ -1075,22 +887,15 @@ contains !=============================================================================== ! DelayedGroupFilter methods !=============================================================================== - subroutine get_next_bin_dg(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_dg(this, p, estimator, match) class(DelayedGroupFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - if (current_bin == NO_BIN_FOUND) then - next_bin = 1 - weight = ONE - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_dg + call match % bins % push_back(1) + call match % weights % push_back(ONE) + end subroutine get_all_bins_dg subroutine to_statepoint_dg(this, filter_group) class(DelayedGroupFilter), intent(in) :: this @@ -1112,34 +917,20 @@ contains !=============================================================================== ! MuFilter methods !=============================================================================== - subroutine get_next_bin_mu(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_mu(this, p, estimator, match) class(MuFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n - if (current_bin == NO_BIN_FOUND) then n = this % n_bins - ! Check if energy of the particle is within energy bins. - if (p % mu < this % bins(1) .or. p % mu > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, p % mu) - weight = ONE - end if - - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_mu + ! Search to find incoming energy bin. + call match % bins % push_back(binary_search(this % bins, n + 1, p % mu)) + call match % weights % push_back(ONE) + end subroutine get_all_bins_mu subroutine to_statepoint_mu(this, filter_group) class(MuFilter), intent(in) :: this @@ -1166,43 +957,28 @@ contains !=============================================================================== ! PolarFilter methods !=============================================================================== - subroutine get_next_bin_polar(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_polar(this, p, estimator, match) class(PolarFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: theta - if (current_bin == NO_BIN_FOUND) then - n = this % n_bins - - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - theta = acos(p % coord(1) % uvw(3)) - else - theta = acos(p % last_uvw(3)) - end if - - ! Check if particle is within polar angle bins. - if (theta < this % bins(1) .or. theta > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find polar angle bin. - next_bin = binary_search(this % bins, n + 1, theta) - weight = ONE - end if + n = this % n_bins + ! Make sure the correct direction vector is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + theta = acos(p % coord(1) % uvw(3)) else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL + theta = acos(p % last_uvw(3)) end if - end subroutine get_next_bin_polar + + ! Search to find polar angle bin. + call match % bins % push_back(binary_search(this % bins, n + 1, theta)) + call match % weights % push_back(ONE) + end subroutine get_all_bins_polar subroutine to_statepoint_polar(this, filter_group) class(PolarFilter), intent(in) :: this @@ -1229,19 +1005,15 @@ contains !=============================================================================== ! AzimuthalFilter methods !=============================================================================== - subroutine get_next_bin_azimuthal(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_azimuthal(this, p, estimator, match) class(AzimuthalFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: phi - if (current_bin == NO_BIN_FOUND) then n = this % n_bins ! Make sure the correct direction vector is used. @@ -1251,21 +1023,11 @@ contains phi = atan2(p % last_uvw(2), p % last_uvw(1)) end if - ! Check if particle is within azimuthal angle bins. - if (phi < this % bins(1) .or. phi > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find azimuthal angle bin. - next_bin = binary_search(this % bins, n + 1, phi) - weight = ONE - end if + ! Search to find azimuthal angle bin. + call match % bins % push_back(binary_search(this % bins, n + 1, phi)) + call match % weights % push_back(ONE) - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_azimuthal + end subroutine get_all_bins_azimuthal subroutine to_statepoint_azimuthal(this, filter_group) class(AzimuthalFilter), intent(in) :: this @@ -1292,54 +1054,39 @@ contains !=============================================================================== ! EnergyFunctionFilter methods !=============================================================================== - subroutine get_next_bin_energyfunction(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_all_bins_energyfunction(this, p, estimator, match) class(EnergyFunctionFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n, indx - real(8) :: E, f + real(8) :: E, f, weight select type(this) type is (EnergyFunctionFilter) - if (current_bin == NO_BIN_FOUND) then - n = size(this % energy) - - ! Make sure the correct energy is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - - ! Check if energy of the particle is within energy bins. - if (E < this % energy(1) .or. E > this % energy(n)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - - else - ! Search to find incoming energy bin. - indx = binary_search(this % energy, n, E) - - ! Compute an interpolation factor between nearest bins. - f = (E - this % energy(indx)) & - / (this % energy(indx+1) - this % energy(indx)) - - ! Interpolate on the lin-lin grid. - next_bin = 1 - weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) - end if + n = size(this % energy) + ! Make sure the correct energy is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + E = p % E else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL + E = p % last_E end if + + ! Search to find incoming energy bin. + indx = binary_search(this % energy, n, E) + + ! Compute an interpolation factor between nearest bins. + f = (E - this % energy(indx)) & + / (this % energy(indx+1) - this % energy(indx)) + + ! Interpolate on the lin-lin grid. + call match % bins % push_back(1) + weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) + call match % weights % push_back(weight) end select - end subroutine get_next_bin_energyfunction + end subroutine get_all_bins_energyfunction subroutine to_statepoint_energyfunction(this, filter_group) class(EnergyFunctionFilter), intent(in) :: this diff --git a/src/tally_filter_header.F90 b/src/tally_filter_header.F90 index 061642545..d69dd299d 100644 --- a/src/tally_filter_header.F90 +++ b/src/tally_filter_header.F90 @@ -32,7 +32,7 @@ module tally_filter_header integer :: id integer :: n_bins = 0 contains - procedure(get_next_bin_), deferred :: get_next_bin + procedure(get_all_bins_), deferred :: get_all_bins procedure(to_statepoint_), deferred :: to_statepoint procedure(text_label_), deferred :: text_label procedure :: initialize => filter_initialize @@ -49,16 +49,15 @@ module tally_filter_header ! first valid bin should then give the second valid bin, and so on. When there ! are no valid bins left, the next_bin should be NO_VALID_BIN. - subroutine get_next_bin_(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_(this, p, estimator, match) import TallyFilter import Particle + import TallyFilterMatch class(TallyFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight - end subroutine get_next_bin_ + type(TallyFilterMatch), intent(inout) :: match + end subroutine get_all_bins_ !=============================================================================== ! TO_STATEPOINT writes all the information needed to reconstruct the filter to diff --git a/tests/.DS_Store b/tests/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bf690003cba7b9e8f2781f7c45b907fc73049b0b GIT binary patch literal 14340 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 Zf*cuQR{1|Ou>Eg_nA^#!!V$>-{}08l+<5>1 literal 0 HcmV?d00001 From 565064781c597e97d0706c61aecf70bc7d9fdb44 Mon Sep 17 00:00:00 2001 From: Brittany Grayson Date: Fri, 4 Aug 2017 15:15:04 -0600 Subject: [PATCH 090/229] Updating tally.f90 and tally_filter.F90 Updating the final get_next_bin of tally.F90 and changing some of the mesh filter in tally_filter.F90. --- .DS_Store | Bin 10244 -> 10244 bytes src/tally.F90 | 6 +----- src/tally_filter.F90 | 6 ++++-- tests/.DS_Store | Bin 14340 -> 14340 bytes 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.DS_Store b/.DS_Store index 140d256a9a1efe014802c226c6d782f149adf8ab..2022437f8a27e6be3fbddb269934109b4183bca1 100644 GIT binary patch delta 598 zcmZn(XbIThFU)vqa)59Hk7RYVk&%Uwj)I|u!Q|V*vW&APe-M*roIP1m#7;>{N+w=F zI4LnXJH05sG%v+DKPSJ)DW^0wA~QKZFF3O*b#l4*uKIWZ{^E@Ma!;UGKv8O0W@>qK zdQoOda6w{nW?s6o{RajxP<9A_F*G0y0S09VgMmTWVRio7&*%f}VO#UZsJe?UoSYyb7BwRQ%;6AV49UySOXXB{2!Kc{J9tAF3>*yF42}%J z3^5Fa3=Is^85T2aWjM%ij^Q!GSBC$Lyo_RuN{rf!I*g`_=8O)Eo{V0MK8%5kL6gsj zR^#)O^emwHtPCX#sSL$HvN$ujtRN{TKZ${Xar0yY5hYGhQ895*2}vo*$>HL6CM!xx zPxg~g6UKBY=i~_zisk}fSC}x`GTJkG0A1nD7yxud6vPiqj8MPGKxrt&7`^$Gge?2S U2Hwr=3cpw;{}izvPNB9Q0Auox%>V!Z diff --git a/src/tally.F90 b/src/tally.F90 index e542f77b1..b9102270e 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3213,15 +3213,11 @@ contains ! Determine incoming energy bin. We need to tell the energy filter this ! is a tracklength tally so it uses the pre-collision energy. if (energy_filter) then - t => tallies(i_tally) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. - do j = 1, size(t % filter) - i_filt = t % filter(j) call filters(i_filter_energy) % obj % get_all_bins(p, & - ESTIMATOR_TRACKLENGTH, filter_matches(i_filt)) + ESTIMATOR_TRACKLENGTH, filter_matches(i_filter_energy)) filter_matches(i_filter_energy) % bins % data(1) = matching_bin - end do end if ! Bounding coordinates diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index ec490d1e3..fcd2e7b40 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -245,6 +245,8 @@ contains logical :: end_in_mesh ! ending coordinates inside mesh? type(RegularMesh), pointer :: m + weight = ERROR_REAL + ! Get a pointer to the mesh. m => meshes(this % mesh) @@ -287,7 +289,7 @@ contains ! we left off and find the next mesh cell that the particle enters. ! Get the indices to the last bin we scored. - ! call bin_to_mesh_indices(m, current_bin, ijk0(:m % n_dimension)) + call bin_to_mesh_indices(m, 1, ijk0(:m % n_dimension)) ! Figure out which face of the previous mesh cell our track exits, i.e. ! the closest surface of that cell for which @@ -317,7 +319,6 @@ contains else ijk0(j) = ijk0(j) - 1 end if - end if ! ======================================================================== ! Compute the length of the track segment in the appropiate mesh cell and @@ -347,6 +348,7 @@ contains call match % bins % push_back(mesh_indices_to_bin(m, ijk0(:m % n_dimension))) weight = distance / total_distance call match % weights % push_back(weight) + end if end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) diff --git a/tests/.DS_Store b/tests/.DS_Store index bf690003cba7b9e8f2781f7c45b907fc73049b0b..a2057a0df76e3a9ce5cb82846993710fd15b448b 100644 GIT binary patch delta 173 zcmZoEXepTBFPh50z`)GFAi%&-%uvD*&ydTI&QLK~kWqQEfe8yMBT$xQGM}L4)@E}7HO9$ejMkgk4gRtN0C=G-vH$=8 delta 112 zcmV-$0FVEKaD;G>PZeVT0009301yBGa{zPzUjS_YX8>Q55dkBUFf;@O0RR911e5P9 z6_ZjfDw9tjHM0Z(2M+-?lg} Date: Fri, 4 Aug 2017 15:26:26 -0600 Subject: [PATCH 091/229] Update tally.F90 Updates the get_next_bin to get_all_bins --- src/tally.F90 | 49 +++++++++++++------------------------------------ 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 0ee041cbe..b9102270e 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2292,14 +2292,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2452,14 +2446,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2837,14 +2825,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -3013,15 +2995,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - matching_bin = NO_BIN_FOUND - do - call filters(i_filt) % obj % get_next_bin(p, t % estimator, & - matching_bin, matching_bin, filter_weight) - if (matching_bin == NO_BIN_FOUND) exit - call filter_matches(i_filt) % bins % push_back(matching_bin) - call filter_matches(i_filt) % weights % push_back(filter_weight) - end do - filter_matches(i_filt) % bins_present = .true. + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) end if ! If there are no valid bins for this filter, then there is nothing to ! score and we can move on to the next tally. @@ -3148,6 +3123,7 @@ contains integer :: i integer :: i_tally + integer :: i_filt integer :: j, k ! loop indices integer :: n_dim ! num dimensions of the mesh integer :: d1 ! dimension index @@ -3237,9 +3213,10 @@ contains ! Determine incoming energy bin. We need to tell the energy filter this ! is a tracklength tally so it uses the pre-collision energy. if (energy_filter) then - call filters(i_filter_energy) % obj % get_next_bin(p, & - ESTIMATOR_TRACKLENGTH, NO_BIN_FOUND, matching_bin, filt_score) - if (matching_bin == NO_BIN_FOUND) cycle + ! Find all valid bins in each filter if they have not already been found + ! for a previous tally. + call filters(i_filter_energy) % obj % get_all_bins(p, & + ESTIMATOR_TRACKLENGTH, filter_matches(i_filter_energy)) filter_matches(i_filter_energy) % bins % data(1) = matching_bin end if From a401b628c007c24f1c179889fc52d4b4187e1130 Mon Sep 17 00:00:00 2001 From: Brittany Grayson <21345299+graybri3@users.noreply.github.com> Date: Fri, 4 Aug 2017 15:27:55 -0600 Subject: [PATCH 092/229] Update tally_filter.F90 Updates the get_next_bin subroutines to the get_all_bins subroutine --- src/tally_filter.F90 | 527 +++++++++++-------------------------------- 1 file changed, 138 insertions(+), 389 deletions(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index dfb89d433..fcd2e7b40 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -13,7 +13,8 @@ module tally_filter mesh_intersects_3d use particle_header, only: Particle use string, only: to_str - use tally_filter_header, only: TallyFilter, TallyFilterContainer + use tally_filter_header, only: TallyFilter, TallyFilterContainer, & + TallyFilterMatch use hdf5, only: HID_T @@ -27,7 +28,7 @@ module tally_filter type, extends(TallyFilter) :: MeshFilter integer :: mesh contains - procedure :: get_next_bin => get_next_bin_mesh + procedure :: get_all_bins => get_all_bins_mesh procedure :: to_statepoint => to_statepoint_mesh procedure :: text_label => text_label_mesh end type MeshFilter @@ -39,7 +40,7 @@ module tally_filter integer, allocatable :: universes(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_universe + procedure :: get_all_bins => get_all_bins_universe procedure :: to_statepoint => to_statepoint_universe procedure :: text_label => text_label_universe procedure :: initialize => initialize_universe @@ -52,7 +53,7 @@ module tally_filter integer, allocatable :: materials(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_material + procedure :: get_all_bins => get_all_bins_material procedure :: to_statepoint => to_statepoint_material procedure :: text_label => text_label_material procedure :: initialize => initialize_material @@ -65,7 +66,7 @@ module tally_filter integer, allocatable :: cells(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_cell + procedure :: get_all_bins => get_all_bins_cell procedure :: to_statepoint => to_statepoint_cell procedure :: text_label => text_label_cell procedure :: initialize => initialize_cell @@ -78,7 +79,7 @@ module tally_filter type, extends(TallyFilter) :: DistribcellFilter integer :: cell contains - procedure :: get_next_bin => get_next_bin_distribcell + procedure :: get_all_bins => get_all_bins_distribcell procedure :: to_statepoint => to_statepoint_distribcell procedure :: text_label => text_label_distribcell procedure :: initialize => initialize_distribcell @@ -91,7 +92,7 @@ module tally_filter integer, allocatable :: cells(:) type(DictIntInt) :: map contains - procedure :: get_next_bin => get_next_bin_cellborn + procedure :: get_all_bins => get_all_bins_cellborn procedure :: to_statepoint => to_statepoint_cellborn procedure :: text_label => text_label_cellborn procedure :: initialize => initialize_cellborn @@ -107,7 +108,7 @@ module tally_filter ! True if this filter is used for surface currents logical :: current = .false. contains - procedure :: get_next_bin => get_next_bin_surface + procedure :: get_all_bins => get_all_bins_surface procedure :: to_statepoint => to_statepoint_surface procedure :: text_label => text_label_surface procedure :: initialize => initialize_surface @@ -123,14 +124,14 @@ module tally_filter logical :: matches_transport_groups = .false. contains - procedure :: get_next_bin => get_next_bin_energy + procedure :: get_all_bins => get_all_bins_energy procedure :: to_statepoint => to_statepoint_energy procedure :: text_label => text_label_energy end type EnergyFilter !=============================================================================== ! ENERGYOUTFILTER bins the outgoing neutron energy. Only scattering events use -! the get_next_bin functionality. Nu-fission tallies manually iterate over the +! the get_all_bins functionality. Nu-fission tallies manually iterate over the ! filter bins. !=============================================================================== type, extends(TallyFilter) :: EnergyoutFilter @@ -140,20 +141,20 @@ module tally_filter logical :: matches_transport_groups = .false. contains - procedure :: get_next_bin => get_next_bin_energyout + procedure :: get_all_bins => get_all_bins_energyout procedure :: to_statepoint => to_statepoint_energyout procedure :: text_label => text_label_energyout end type EnergyoutFilter !=============================================================================== ! DELAYEDGROUPFILTER bins outgoing fission neutrons in their delayed groups. -! The get_next_bin functionality is not actually used. The bins are manually +! The get_all_bins functionality is not actually used. The bins are manually ! iterated over in the scoring subroutines. !=============================================================================== type, extends(TallyFilter) :: DelayedGroupFilter integer, allocatable :: groups(:) contains - procedure :: get_next_bin => get_next_bin_dg + procedure :: get_all_bins => get_all_bins_dg procedure :: to_statepoint => to_statepoint_dg procedure :: text_label => text_label_dg end type DelayedGroupFilter @@ -165,7 +166,7 @@ module tally_filter type, extends(TallyFilter) :: MuFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_mu + procedure :: get_all_bins => get_all_bins_mu procedure :: to_statepoint => to_statepoint_mu procedure :: text_label => text_label_mu end type MuFilter @@ -177,7 +178,7 @@ module tally_filter type, extends(TallyFilter) :: PolarFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_polar + procedure :: get_all_bins => get_all_bins_polar procedure :: to_statepoint => to_statepoint_polar procedure :: text_label => text_label_polar end type PolarFilter @@ -189,7 +190,7 @@ module tally_filter type, extends(TallyFilter) :: AzimuthalFilter real(8), allocatable :: bins(:) contains - procedure :: get_next_bin => get_next_bin_azimuthal + procedure :: get_all_bins => get_all_bins_azimuthal procedure :: to_statepoint => to_statepoint_azimuthal procedure :: text_label => text_label_azimuthal end type AzimuthalFilter @@ -203,7 +204,7 @@ module tally_filter real(8), allocatable :: y(:) contains - procedure :: get_next_bin => get_next_bin_energyfunction + procedure :: get_all_bins => get_all_bins_energyfunction procedure :: to_statepoint => to_statepoint_energyfunction procedure :: text_label => text_label_energyfunction end type EnergyFunctionFilter @@ -218,14 +219,11 @@ contains !=============================================================================== ! MeshFilter methods !=============================================================================== - subroutine get_next_bin_mesh(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_mesh(this, p, estimator, match) class(MeshFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer, parameter :: MAX_SEARCH_ITER = 100 ! Maximum number of times we can ! can loop while trying to find @@ -235,6 +233,7 @@ contains integer :: ijk0(3) ! indices of starting coordinates integer :: ijk1(3) ! indices of ending coordinates integer :: search_iter ! loop count for intersection search + real(8) :: weight ! weight to be pushed back real(8) :: uvw(3) ! cosine of angle of particle real(8) :: xyz0(3) ! starting/intermediate coordinates real(8) :: xyz1(3) ! ending coordinates of particle @@ -254,12 +253,8 @@ contains if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. - if (current_bin == NO_BIN_FOUND) then - call get_mesh_bin(m, p % coord(1) % xyz, next_bin) - weight = ONE - else - next_bin = NO_BIN_FOUND - end if + call match % bins % push_back(1) + call match % weights % push_back(ONE) else ! A track can span multiple mesh bins so we need to handle a lot of @@ -279,29 +274,6 @@ contains call get_mesh_indices(m, xyz0, ijk0(:m % n_dimension), start_in_mesh) call get_mesh_indices(m, xyz1, ijk1(:m % n_dimension), end_in_mesh) - ! If this is the first iteration of the filter loop, check if the track - ! intersects any part of the mesh. - if (current_bin == NO_BIN_FOUND) then - if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (m % n_dimension == 1) then - if (.not. mesh_intersects_1d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - else if (m % n_dimension == 2) then - if (.not. mesh_intersects_2d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - else - if (.not. mesh_intersects_3d(m, xyz0, xyz1)) then - next_bin = NO_BIN_FOUND - return - end if - end if - end if - end if - ! ======================================================================== ! Figure out which mesh cell to tally. @@ -313,71 +285,11 @@ contains ! Compute the length of the entire track. total_distance = sqrt(sum((xyz1 - xyz0)**2)) - if (current_bin == NO_BIN_FOUND) then - ! We are looking for the first valid mesh bin. Check to see if the - ! particle starts inside the mesh. - if (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) then - ! The particle does not start in the mesh. Note that we nudged the - ! start and end coordinates by a TINY_BIT each so we will have - ! difficulty resolving tracks that are less than 2*TINY_BIT in length. - ! If the track is that short, it is also insignificant so we can - ! safely ignore it in the tallies. - if (total_distance < 2*TINY_BIT) then - next_bin = NO_BIN_FOUND - return - end if - - ! The particle does not start in the mesh so keep iterating the ijk0 - ! indices to cross the nearest mesh surface until we've found a valid - ! bin. MAX_SEARCH_ITER prevents an infinite loop. - search_iter = 0 - do while (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) - if (search_iter == MAX_SEARCH_ITER) then - call warning("Failed to find a mesh intersection on a tally mesh & - &filter.") - next_bin = NO_BIN_FOUND - return - end if - - do j = 1, m % n_dimension - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:m % n_dimension), 1) - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if - - search_iter = search_iter + 1 - end do - distance = d(j) - xyz0 = xyz0 + distance * uvw - - end if - - else ! We have already scored some mesh bins for this track. Pick up where ! we left off and find the next mesh cell that the particle enters. ! Get the indices to the last bin we scored. - call bin_to_mesh_indices(m, current_bin, ijk0(:m % n_dimension)) - - ! If the particle track ends in that bin, then we are done. - if (all(ijk0(:m % n_dimension) == ijk1(:m % n_dimension))) then - next_bin = NO_BIN_FOUND - return - end if + call bin_to_mesh_indices(m, 1, ijk0(:m % n_dimension)) ! Figure out which face of the previous mesh cell our track exits, i.e. ! the closest surface of that cell for which @@ -408,15 +320,6 @@ contains ijk0(j) = ijk0(j) - 1 end if - ! If the next indices are invalid, then the track has left the mesh and - ! we are done. - if (any(ijk0(:m % n_dimension) < 1) & - .or. any(ijk0(:m % n_dimension) > m % dimension)) then - next_bin = NO_BIN_FOUND - return - end if - end if - ! ======================================================================== ! Compute the length of the track segment in the appropiate mesh cell and ! return. @@ -442,10 +345,11 @@ contains end if ! Assign the next tally bin and the score. - next_bin = mesh_indices_to_bin(m, ijk0(:m % n_dimension)) + call match % bins % push_back(mesh_indices_to_bin(m, ijk0(:m % n_dimension))) weight = distance / total_distance - endif - end subroutine get_next_bin_mesh + call match % weights % push_back(weight) + end if + end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) class(MeshFilter), intent(in) :: this @@ -481,40 +385,24 @@ contains !=============================================================================== ! UniverseFilter methods !=============================================================================== - subroutine get_next_bin_universe(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_universe(this, p, estimator, match) class(UniverseFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: i, start - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % universe == this % universes(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord + ! Iterate over coordinate levels to see which universes match + do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % universe)) then - next_bin = this % map % get_key(p % coord(i) % universe) - weight = ONE - exit + call match % bins % push_back(this % map % get_key(p % coord(i) & + % universe)) + call match % weights % push_back(ONE) end if end do - end subroutine get_next_bin_universe + + end subroutine get_all_bins_universe subroutine to_statepoint_universe(this, filter_group) class(UniverseFilter), intent(in) :: this @@ -566,24 +454,18 @@ contains !=============================================================================== ! MaterialFilter methods !=============================================================================== - subroutine get_next_bin_material(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_material(this, p, estimator, match) class(MaterialFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then if (this % map % has_key(p % material)) then - next_bin = this % map % get_key(p % material) - weight = ONE + call match % bins % push_back(this % map % get_key(p % material)) + call match % weights % push_back(ONE) end if - end if - end subroutine get_next_bin_material + + end subroutine get_all_bins_material subroutine to_statepoint_material(this, filter_group) class(MaterialFilter), intent(in) :: this @@ -635,40 +517,23 @@ contains !=============================================================================== ! CellFilter methods !=============================================================================== - subroutine get_next_bin_cell(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_cell(this, p, estimator, match) class(CellFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - integer :: i, start + integer :: i - ! Find the coordinate level of the last bin we found. - if (current_bin == NO_BIN_FOUND) then - start = 1 - else - do i = 1, p % n_coord - if (p % coord(i) % cell == this % cells(current_bin)) then - start = i + 1 - exit - end if - end do - end if - - ! Starting one coordinate level deeper, find the next bin. - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - do i = start, p % n_coord + ! Iterate over coordinate levels to see with cells match + do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % cell)) then - next_bin = this % map % get_key(p % coord(i) % cell) - weight = ONE - exit + call match % bins % push_back(this % map % get_key(p % coord(i) % cell)) + call match % weights % push_back(ONE) end if end do - end subroutine get_next_bin_cell + + end subroutine get_all_bins_cell subroutine to_statepoint_cell(this, filter_group) class(CellFilter), intent(in) :: this @@ -720,18 +585,14 @@ contains !=============================================================================== ! DistribcellFilter methods !=============================================================================== - subroutine get_next_bin_distribcell(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_all_bins_distribcell(this, p, estimator, match) class(DistribcellFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: distribcell_index, offset, i - if (current_bin == NO_BIN_FOUND) then distribcell_index = cells(this % cell) % distribcell_index offset = 0 do i = 1, p % n_coord @@ -752,15 +613,12 @@ contains end if end if if (this % cell == p % coord(i) % cell) then - next_bin = offset + 1 - weight = ONE + call match % bins % push_back(offset + 1) + call match % weights % push_back(ONE) return end if end do - end if - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end subroutine get_next_bin_distribcell + end subroutine get_all_bins_distribcell subroutine to_statepoint_distribcell(this, filter_group) class(DistribcellFilter), intent(in) :: this @@ -804,24 +662,18 @@ contains !=============================================================================== ! CellbornFilter methods !=============================================================================== - subroutine get_next_bin_cellborn(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_cellborn(this, p, estimator, match) class(CellbornFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then if (this % map % has_key(p % cell_born)) then - next_bin = this % map % get_key(p % cell_born) - weight = ONE + call match % bins % push_back(this % map % get_key(p % cell_born)) + call match % weights % push_back(ONE) end if - end if - end subroutine get_next_bin_cellborn + + end subroutine get_all_bins_cellborn subroutine to_statepoint_cellborn(this, filter_group) class(CellbornFilter), intent(in) :: this @@ -872,29 +724,23 @@ contains !=============================================================================== ! SurfaceFilter methods !=============================================================================== - subroutine get_next_bin_surface(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_surface(this, p, estimator, match) class(SurfaceFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: i - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - if (current_bin == NO_BIN_FOUND) then do i = 1, this % n_bins if (p % surface == this % surfaces(i)) then - next_bin = i - weight = ONE + call match % bins % push_back(i) + call match % weights % push_back(ONE) exit end if end do - end if - end subroutine get_next_bin_surface + + end subroutine get_all_bins_surface subroutine to_statepoint_surface(this, filter_group) class(SurfaceFilter), intent(in) :: this @@ -933,33 +779,26 @@ contains !=============================================================================== ! EnergyFilter methods !=============================================================================== - subroutine get_next_bin_energy(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_energy(this, p, estimator, match) class(EnergyFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: E - if (current_bin == NO_BIN_FOUND) then n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then if (estimator == ESTIMATOR_TRACKLENGTH) then - next_bin = p % g + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) else - next_bin = p % last_g + call match % bins % push_back(num_energy_groups - p % last_g + 1) + call match % weights % push_back(ONE) end if - ! Tallies are ordered in increasing groups, group indices - ! however are the opposite, so switch - next_bin = num_energy_groups - next_bin + 1 - weight = ONE - else ! Make sure the correct energy is used. if (estimator == ESTIMATOR_TRACKLENGTH) then @@ -968,22 +807,11 @@ contains E = p % last_E end if - ! Check if energy of the particle is within energy bins. - if (E < this % bins(1) .or. E > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, E) - weight = ONE - end if + call match % bins % push_back(binary_search(this % bins, n + 1, E)) + call match % weights % push_back(ONE) end if - - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_energy + end subroutine get_all_bins_energy subroutine to_statepoint_energy(this, filter_group) class(EnergyFilter), intent(in) :: this @@ -1010,45 +838,31 @@ contains !=============================================================================== ! EnergyoutFilter methods !=============================================================================== - subroutine get_next_bin_energyout(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_energyout(this, p, estimator, match) class(EnergyoutFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n - if (current_bin == NO_BIN_FOUND) then n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then - next_bin = p % g + call match % bins % push_back(p % g) ! Tallies are ordered in increasing groups, group indices ! however are the opposite, so switch - next_bin = num_energy_groups - next_bin + 1 - weight = ONE + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) else - ! Check if energy of the particle is within energy bins. - if (p % E < this % bins(1) .or. p % E > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, p % E) - weight = ONE - end if - end if - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_energyout + ! Search to find incoming energy bin. + call match % bins % push_back(binary_search(this % bins, n + 1, p % E)) + call match % weights % push_back(ONE) + end if + end subroutine get_all_bins_energyout subroutine to_statepoint_energyout(this, filter_group) class(EnergyoutFilter), intent(in) :: this @@ -1075,22 +889,15 @@ contains !=============================================================================== ! DelayedGroupFilter methods !=============================================================================== - subroutine get_next_bin_dg(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_dg(this, p, estimator, match) class(DelayedGroupFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match - if (current_bin == NO_BIN_FOUND) then - next_bin = 1 - weight = ONE - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_dg + call match % bins % push_back(1) + call match % weights % push_back(ONE) + end subroutine get_all_bins_dg subroutine to_statepoint_dg(this, filter_group) class(DelayedGroupFilter), intent(in) :: this @@ -1112,34 +919,20 @@ contains !=============================================================================== ! MuFilter methods !=============================================================================== - subroutine get_next_bin_mu(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_mu(this, p, estimator, match) class(MuFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n - if (current_bin == NO_BIN_FOUND) then n = this % n_bins - ! Check if energy of the particle is within energy bins. - if (p % mu < this % bins(1) .or. p % mu > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find incoming energy bin. - next_bin = binary_search(this % bins, n + 1, p % mu) - weight = ONE - end if - - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_mu + ! Search to find incoming energy bin. + call match % bins % push_back(binary_search(this % bins, n + 1, p % mu)) + call match % weights % push_back(ONE) + end subroutine get_all_bins_mu subroutine to_statepoint_mu(this, filter_group) class(MuFilter), intent(in) :: this @@ -1166,43 +959,28 @@ contains !=============================================================================== ! PolarFilter methods !=============================================================================== - subroutine get_next_bin_polar(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_polar(this, p, estimator, match) class(PolarFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: theta - if (current_bin == NO_BIN_FOUND) then - n = this % n_bins - - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - theta = acos(p % coord(1) % uvw(3)) - else - theta = acos(p % last_uvw(3)) - end if - - ! Check if particle is within polar angle bins. - if (theta < this % bins(1) .or. theta > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find polar angle bin. - next_bin = binary_search(this % bins, n + 1, theta) - weight = ONE - end if + n = this % n_bins + ! Make sure the correct direction vector is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + theta = acos(p % coord(1) % uvw(3)) else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL + theta = acos(p % last_uvw(3)) end if - end subroutine get_next_bin_polar + + ! Search to find polar angle bin. + call match % bins % push_back(binary_search(this % bins, n + 1, theta)) + call match % weights % push_back(ONE) + end subroutine get_all_bins_polar subroutine to_statepoint_polar(this, filter_group) class(PolarFilter), intent(in) :: this @@ -1229,19 +1007,15 @@ contains !=============================================================================== ! AzimuthalFilter methods !=============================================================================== - subroutine get_next_bin_azimuthal(this, p, estimator, current_bin, next_bin, & - weight) + subroutine get_all_bins_azimuthal(this, p, estimator, match) class(AzimuthalFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n real(8) :: phi - if (current_bin == NO_BIN_FOUND) then n = this % n_bins ! Make sure the correct direction vector is used. @@ -1251,21 +1025,11 @@ contains phi = atan2(p % last_uvw(2), p % last_uvw(1)) end if - ! Check if particle is within azimuthal angle bins. - if (phi < this % bins(1) .or. phi > this % bins(n + 1)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - else - ! Search to find azimuthal angle bin. - next_bin = binary_search(this % bins, n + 1, phi) - weight = ONE - end if + ! Search to find azimuthal angle bin. + call match % bins % push_back(binary_search(this % bins, n + 1, phi)) + call match % weights % push_back(ONE) - else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - end if - end subroutine get_next_bin_azimuthal + end subroutine get_all_bins_azimuthal subroutine to_statepoint_azimuthal(this, filter_group) class(AzimuthalFilter), intent(in) :: this @@ -1292,54 +1056,39 @@ contains !=============================================================================== ! EnergyFunctionFilter methods !=============================================================================== - subroutine get_next_bin_energyfunction(this, p, estimator, current_bin, & - next_bin, weight) + subroutine get_all_bins_energyfunction(this, p, estimator, match) class(EnergyFunctionFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight + type(TallyFilterMatch), intent(inout) :: match integer :: n, indx - real(8) :: E, f + real(8) :: E, f, weight select type(this) type is (EnergyFunctionFilter) - if (current_bin == NO_BIN_FOUND) then - n = size(this % energy) - - ! Make sure the correct energy is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - - ! Check if energy of the particle is within energy bins. - if (E < this % energy(1) .or. E > this % energy(n)) then - next_bin = NO_BIN_FOUND - weight = ERROR_REAL - - else - ! Search to find incoming energy bin. - indx = binary_search(this % energy, n, E) - - ! Compute an interpolation factor between nearest bins. - f = (E - this % energy(indx)) & - / (this % energy(indx+1) - this % energy(indx)) - - ! Interpolate on the lin-lin grid. - next_bin = 1 - weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) - end if + n = size(this % energy) + ! Make sure the correct energy is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + E = p % E else - next_bin = NO_BIN_FOUND - weight = ERROR_REAL + E = p % last_E end if + + ! Search to find incoming energy bin. + indx = binary_search(this % energy, n, E) + + ! Compute an interpolation factor between nearest bins. + f = (E - this % energy(indx)) & + / (this % energy(indx+1) - this % energy(indx)) + + ! Interpolate on the lin-lin grid. + call match % bins % push_back(1) + weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) + call match % weights % push_back(weight) end select - end subroutine get_next_bin_energyfunction + end subroutine get_all_bins_energyfunction subroutine to_statepoint_energyfunction(this, filter_group) class(EnergyFunctionFilter), intent(in) :: this From 9c508ab35e1ce7226eae694d5c54b6eb795ff8c9 Mon Sep 17 00:00:00 2001 From: Brittany Grayson <21345299+graybri3@users.noreply.github.com> Date: Fri, 4 Aug 2017 15:29:18 -0600 Subject: [PATCH 093/229] Adds in the get_all_bins subroutine --- src/tally_filter_header.F90 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tally_filter_header.F90 b/src/tally_filter_header.F90 index 061642545..d69dd299d 100644 --- a/src/tally_filter_header.F90 +++ b/src/tally_filter_header.F90 @@ -32,7 +32,7 @@ module tally_filter_header integer :: id integer :: n_bins = 0 contains - procedure(get_next_bin_), deferred :: get_next_bin + procedure(get_all_bins_), deferred :: get_all_bins procedure(to_statepoint_), deferred :: to_statepoint procedure(text_label_), deferred :: text_label procedure :: initialize => filter_initialize @@ -49,16 +49,15 @@ module tally_filter_header ! first valid bin should then give the second valid bin, and so on. When there ! are no valid bins left, the next_bin should be NO_VALID_BIN. - subroutine get_next_bin_(this, p, estimator, current_bin, next_bin, weight) + subroutine get_all_bins_(this, p, estimator, match) import TallyFilter import Particle + import TallyFilterMatch class(TallyFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - integer, value, intent(in) :: current_bin - integer, intent(out) :: next_bin - real(8), intent(out) :: weight - end subroutine get_next_bin_ + type(TallyFilterMatch), intent(inout) :: match + end subroutine get_all_bins_ !=============================================================================== ! TO_STATEPOINT writes all the information needed to reconstruct the filter to From f0c051db5f5779b3b4a7cc7ba987c4eacbdfb276 Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 13:54:03 -0400 Subject: [PATCH 094/229] corrected syntax in PyAPI test, and deleted forgotten cellto options in input handling --- openmc/filter.py | 3 +- src/input_xml.F90 | 2 +- .../test_surface_tally/test_surface_tally.py | 145 ++++++++++-------- 3 files changed, 84 insertions(+), 66 deletions(-) diff --git a/openmc/filter.py b/openmc/filter.py index e822b9553..514e96f26 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -18,8 +18,7 @@ AUTO_FILTER_ID = 10000 _FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', - 'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom', - 'cellto'] + 'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom'] _CURRENT_NAMES = {1: 'x-min out', 2: 'x-min in', 3: 'x-max out', 4: 'x-max in', diff --git a/src/input_xml.F90 b/src/input_xml.F90 index dfc2e853c..cfb80b4fa 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3004,7 +3004,7 @@ contains end if n_words = node_word_count(node_filt, "bins") case ("mesh", "universe", "material", "cell", "distribcell", & - "cellborn", "cellto", "cellfrom", "surface", "delayedgroup") + "cellborn", "cellfrom", "surface", "delayedgroup") if (.not. check_for_node(node_filt, "bins")) then call fatal_error("Bins not set in filter " // trim(to_str(filter_id))) end if diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index cafdd84e2..5ebe30d58 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -8,7 +8,8 @@ import numpy as np import openmc import pandas as pd -class CreateSurfaceTallyTestHarness(PyAPITestHarness): + +class SurfaceTallyTestHarness(PyAPITestHarness): def _build_inputs(self): # Instantiate some Materials and register the appropriate Nuclides uo2 = openmc.Material(name='UO2 fuel at 2.4% wt enrichment') @@ -25,15 +26,15 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): # Instantiate a Materials collection and export to XML materials_file = openmc.Materials([uo2, borated_water]) - materials_file.export_to_xml() # Instantiate ZCylinder surfaces - fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=0.4, name='Fuel OR') - left = openmc.XPlane(surface_id=2, x0=-0.62992, name='left') - right = openmc.XPlane(surface_id=3, x0=0.62992, name='right') - bottom = openmc.YPlane(y0=-0.62992, name='bottom') - top = openmc.YPlane(y0=0.62992, name='top') + fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, R=1, \ + name='Fuel OR') + left = openmc.XPlane(surface_id=2, x0=-2, name='left') + right = openmc.XPlane(surface_id=3, x0=2, name='right') + bottom = openmc.YPlane(y0=-2, name='bottom') + top = openmc.YPlane(y0=2, name='top') left.boundary_type = 'vacuum' right.boundary_type = 'reflective' @@ -49,7 +50,7 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): water.region = +fuel_or & -right & +bottom & -top # Register Materials with Cells - fuel.fill = uo2 + fuel.fill = uo2 water.fill = borated_water # Instantiate pin cell Universe @@ -63,82 +64,101 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): root_univ = openmc.Universe(universe_id=0, name='root universe') root_univ.add_cell(root_cell) - # Instantiate a Geometry, register the root Universe, and export to XML + # Instantiate a Geometry, register the root Universe geometry = openmc.Geometry(root_univ) geometry.export_to_xml() - # Instantiate a Settings object, set all runtime parameters, and export to XML + # Instantiate a Settings object, set all runtime parameters settings_file = openmc.Settings() settings_file.batches = 10 settings_file.inactive = 0 settings_file.particles = 1000 + #settings_file.output = {'tallies': True} - # Create an initial uniform spatial source distribution over fissionable zones + # Create an initial uniform spatial source distribution bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],\ + only_fissionable=True) settings_file.source = openmc.source.Source(space=uniform_dist) settings_file.export_to_xml() # Tallies file tallies_file = openmc.Tallies() - # Cell to cell tallies - # These filters are same for all tallies + # Create partial current tallies from fuel to water + # Filters two_groups = np.array([0., 4, 20.]) * 1e6 - energy_filter = openmc.EnergyFilter(two_groups) - polar_filter = openmc.PolarFilter([0, np.pi / 4, np.pi]) - azimuthal_filter = openmc.AzimuthalFilter([0, np.pi / 4, np.pi]) - - - cell_to_cell_tallies = [] - tally_index = 0 - - for cell1 in pin_cell.get_all_cells(): - for cell2 in pin_cell.get_all_cells(): - - if cell1 != cell2 and abs(abs(cell1-cell2)-1) < 0.1: # no need for cell1 to cell1 - - # Cell to cell filters for partial current - cell_from_filter = openmc.CellFromFilter(cell1) - cell_to_filter = openmc.CellFilter(cell2) - - cell_to_cell_tallies.append(openmc.Tally(tally_id=tally_index, name=str(cell1)+'-'+str(cell2))) - cell_to_cell_tallies[tally_index].filters = [cell_from_filter, cell_to_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[tally_index].scores = ['current'] - tallies_file.append(cell_to_cell_tallies[tally_index]) - tally_index += 1 - - # Cell from + surface filters for partial current - surface_filter = openmc.SurfaceFilter([1]) - cell_to_cell_tallies.append(openmc.Tally(tally_id=tally_index, name=str(cell1)+'-surface1')) - cell_to_cell_tallies[tally_index].filters = [cell_from_filter, surface_filter, energy_filter, polar_filter, azimuthal_filter] - cell_to_cell_tallies[tally_index].scores = ['current'] - tallies_file.append(cell_to_cell_tallies[tally_index]) - tally_index += 1 - - # Surface filter on inner surface, for net current + energy_filter = openmc.EnergyFilter(two_groups) + polar_filter = openmc.PolarFilter([0, np.pi / 4, np.pi]) + azimuthal_filter = openmc.AzimuthalFilter([0, np.pi / 4, np.pi]) surface_filter = openmc.SurfaceFilter([1]) - surf_tally1 = openmc.Tally(tally_id=tally_index, name='net_cylinder') - surf_tally1.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] - surf_tally1.scores = ['current'] + cell_from_filter = openmc.CellFromFilter(fuel) + cell_filter = openmc.CellFilter(water) + + # Use Cell to cell filters for partial current + cell_to_cell_tally = openmc.Tally(name=str('fuel_to_water_1')) + cell_to_cell_tally.filters = [cell_from_filter, cell_filter, \ + energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tally.scores = ['current'] + tallies_file.append(cell_to_cell_tally) + + # Use a Cell from + surface filters for partial current + cell_to_cell_tally = openmc.Tally(name=str('fuel_to_water_2')) + cell_to_cell_tally.filters = [cell_from_filter, surface_filter, \ + energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tally.scores = ['current'] + tallies_file.append(cell_to_cell_tally) + + # Create partial current tallies from water to fuel + # Filters + cell_from_filter = openmc.CellFromFilter(water) + cell_filter = openmc.CellFilter(fuel) + + # Cell to cell filters for partial current + cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_1')) + cell_to_cell_tally.filters = [cell_from_filter, cell_filter, \ + energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tally.scores = ['current'] + tallies_file.append(cell_to_cell_tally) + + # Cell from + surface filters for partial current + cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_2')) + cell_to_cell_tally.filters = [cell_from_filter, surface_filter, \ + energy_filter, polar_filter, azimuthal_filter] + cell_to_cell_tally.scores = ['current'] + tallies_file.append(cell_to_cell_tally) + + # Create a net current tally on inner surface using a surface filter + surface_filter = openmc.SurfaceFilter([1]) + surf_tally1 = openmc.Tally(name='net_cylinder') + surf_tally1.filters = [surface_filter, energy_filter, polar_filter, \ + azimuthal_filter] + surf_tally1.scores = ['current'] tallies_file.append(surf_tally1) - tally_index += 1 - # Surface filter on left surface, vacuum BC, for net current = leakage + # Create a net current tally on left surface using a surface filter + # This surface has a vacuum boundary condition, so leakage is tallied surface_filter = openmc.SurfaceFilter([2]) - surf_tally2 = openmc.Tally(tally_id=tally_index, name='leakage_left') - surf_tally2.filters = [surface_filter, energy_filter, polar_filter, azimuthal_filter] - surf_tally2.scores = ['current'] + surf_tally2 = openmc.Tally(name='leakage_left') + surf_tally2.filters = [surface_filter, energy_filter, polar_filter, \ + azimuthal_filter] + surf_tally2.scores = ['current'] tallies_file.append(surf_tally2) - tally_index += 1 - # Surface filter on right surface, reflective, current tally doesnt pick up the zero net current though + # Create a net current tally on right surface using a surface filter + # This surface has a reflective boundary condition, but the zero + # net current is not picked up because particles are only tallied once surface_filter = openmc.SurfaceFilter([3]) - surf_tally3 = openmc.Tally(tally_id=tally_index, name='net_right') - surf_tally3.filters = [surface_filter, energy_filter] - surf_tally3.scores = ['current'] + surf_tally3 = openmc.Tally(name='net_right') + surf_tally3.filters = [surface_filter, energy_filter] + surf_tally3.scores = ['current'] + tallies_file.append(surf_tally3) + + surface_filter = openmc.SurfaceFilter([3]) + surf_tally3 = openmc.Tally(name='net_right') + surf_tally3.filters = [surface_filter, energy_filter] + surf_tally3.scores = ['current'] tallies_file.append(surf_tally3) - tally_index += 1 tallies_file.export_to_xml() @@ -153,12 +173,11 @@ class CreateSurfaceTallyTestHarness(PyAPITestHarness): df = df.append(t.get_pandas_dataframe(), ignore_index=True) # Extract the relevant data as a CSV string. - cols = ('d_material', 'd_nuclide', 'd_variable', 'score', 'mean', - 'std. dev.') + cols = ('mean', 'std. dev.') return df.to_csv(None, columns=cols, index=False, float_format='%.7e') return outstr if __name__ == '__main__': - harness = CreateSurfaceTallyTestHarness('statepoint.10.h5') + harness = SurfaceTallyTestHarness('statepoint.10.h5') harness.main() From 1c122733637d93b825eb1c53b947fd5ecb668063 Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 14:06:02 -0400 Subject: [PATCH 095/229] updated test_surface_tally results --- tests/test_surface_tally/inputs_true.dat | 50 ++++++----- tests/test_surface_tally/results_true.dat | 104 +++++++++++----------- 2 files changed, 80 insertions(+), 74 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index 213097e8d..7eeb5102f 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -3,11 +3,11 @@ - - - - - + + + + + @@ -44,10 +44,10 @@ - + 10000 - + 10001 @@ -59,7 +59,7 @@ 0.0 0.785398163397 3.14159265359 - + 1 @@ -68,38 +68,42 @@ 10000 - + 2 - + 3 - - 10003 10004 10000 10001 10002 + + 10004 10005 10000 10001 10002 current - - 10003 10005 10000 10001 10002 + + 10004 10003 10000 10001 10002 current - + 10006 10007 10000 10001 10002 current - - 10006 10005 10000 10001 10002 + + 10006 10003 10000 10001 10002 current - - 10005 10000 10001 10002 + + 10003 10000 10001 10002 current - - 10010 10000 10001 10002 + + 10009 10000 10001 10002 current - - 10011 10000 + + 10010 10000 + current + + + 10010 10000 current diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index df8c1597f..8e9f6c390 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -1,51 +1,53 @@ -d_material,d_nuclide,d_variable,score,mean,std. dev. -,,,current,2.4000000e-02,5.6725460e-03 -,,,current,1.0080000e-01,7.0266161e-03 -,,,current,1.2900000e-01,3.1304952e-03 -,,,current,7.2540000e-01,1.4240943e-02 -,,,current,1.8000000e-03,4.1633320e-04 -,,,current,8.3000000e-03,1.4146063e-03 -,,,current,1.5300000e-02,2.9666667e-03 -,,,current,7.9700000e-02,4.3717528e-03 -,,,current,2.4000000e-02,5.6725460e-03 -,,,current,1.0080000e-01,7.0266161e-03 -,,,current,1.2900000e-01,3.1304952e-03 -,,,current,7.2540000e-01,1.4240943e-02 -,,,current,1.8000000e-03,4.1633320e-04 -,,,current,8.3000000e-03,1.4146063e-03 -,,,current,1.5300000e-02,2.9666667e-03 -,,,current,7.9700000e-02,4.3717528e-03 -,,,current,1.5000000e-03,4.0138649e-04 -,,,current,5.7500000e-02,4.1075811e-03 -,,,current,1.0000000e-02,1.3416408e-03 -,,,current,4.5890000e-01,8.6941232e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,4.6000000e-03,1.0241528e-03 -,,,current,2.0000000e-04,1.3333333e-04 -,,,current,4.6700000e-02,3.5654203e-03 -,,,current,-1.5000000e-03,4.0138649e-04 -,,,current,-5.7500000e-02,4.1075811e-03 -,,,current,-1.0000000e-02,1.3416408e-03 -,,,current,-4.5890000e-01,8.6941232e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.6000000e-03,1.0241528e-03 -,,,current,-2.0000000e-04,1.3333333e-04 -,,,current,-4.6700000e-02,3.5654203e-03 -,,,current,2.2500000e-02,5.6651959e-03 -,,,current,4.3300000e-02,4.1714639e-03 -,,,current,1.1900000e-01,2.8635642e-03 -,,,current,2.6650000e-01,1.4426249e-02 -,,,current,1.8000000e-03,4.1633320e-04 -,,,current,3.7000000e-03,1.0333333e-03 -,,,current,1.5100000e-02,2.8691849e-03 -,,,current,3.3000000e-02,1.7448336e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-5.2600000e-02,4.8355167e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-3.9890000e-01,8.1150751e-03 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-4.2000000e-03,7.1180522e-04 -,,,current,0.0000000e+00,0.0000000e+00 -,,,current,-3.9000000e-02,4.1686662e-03 -,,,current,-5.9230000e-01,1.2109730e-02 -,,,current,-5.1900000e-02,3.3381632e-03 +mean,std. dev. +2.2000000e-02,1.8915015e-03 +7.0600000e-02,2.4549270e-03 +1.4900000e-01,4.1150132e-03 +6.1190000e-01,9.6014467e-03 +1.1000000e-03,3.7859389e-04 +5.8000000e-03,9.9777530e-04 +1.0300000e-02,1.5205993e-03 +4.6700000e-02,3.0333333e-03 +2.2000000e-02,1.8915015e-03 +7.0600000e-02,2.4549270e-03 +1.4900000e-01,4.1150132e-03 +6.1190000e-01,9.6014467e-03 +1.1000000e-03,3.7859389e-04 +5.8000000e-03,9.9777530e-04 +1.0300000e-02,1.5205993e-03 +4.6700000e-02,3.0333333e-03 +5.4000000e-03,6.6999171e-04 +4.5000000e-02,1.9436506e-03 +3.2300000e-02,1.4067299e-03 +3.8900000e-01,7.4311656e-03 +0.0000000e+00,0.0000000e+00 +2.6000000e-03,4.7609523e-04 +1.0000000e-04,1.0000000e-04 +1.9300000e-02,1.3337499e-03 +-5.4000000e-03,6.6999171e-04 +-4.5000000e-02,1.9436506e-03 +-3.2300000e-02,1.4067299e-03 +-3.8900000e-01,7.4311656e-03 +0.0000000e+00,0.0000000e+00 +-2.6000000e-03,4.7609523e-04 +-1.0000000e-04,1.0000000e-04 +-1.9300000e-02,1.3337499e-03 +1.6600000e-02,1.9675139e-03 +2.5600000e-02,3.2903900e-03 +1.1670000e-01,3.3100856e-03 +2.2290000e-01,5.8924622e-03 +1.1000000e-03,3.7859389e-04 +3.2000000e-03,6.4635731e-04 +1.0200000e-02,1.5114379e-03 +2.7400000e-02,3.0081371e-03 +0.0000000e+00,0.0000000e+00 +-3.5600000e-02,2.2020193e-03 +0.0000000e+00,0.0000000e+00 +-3.6890000e-01,3.4236108e-03 +0.0000000e+00,0.0000000e+00 +-2.8000000e-03,6.7986927e-04 +0.0000000e+00,0.0000000e+00 +-2.2900000e-02,2.4919872e-03 +-7.9490000e-01,1.2723076e-02 +-3.4600000e-02,2.7414514e-03 +-7.9490000e-01,1.2723076e-02 +-3.4600000e-02,2.7414514e-03 From 368842b5df735f7d00afeb30871da05897e8ec84 Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 14:06:29 -0400 Subject: [PATCH 096/229] tiny deletion in tally.f90 to avoid a merge --- src/tally.F90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 04af19f51..155a31a3e 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -3271,9 +3271,6 @@ contains ! Reset filter matches flag filter_matches(:) % bins_present = .false. - ! Reset tally map positioning - position = 0 - end subroutine score_surface_tally !=============================================================================== From a766aa33f82f6105d6fa71e51e30349e795c23c1 Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 14:19:09 -0400 Subject: [PATCH 097/229] merged with develop then updated surface tally results --- tests/test_surface_tally/inputs_true.dat | 194 +++++++++++------------ 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index 7eeb5102f..4d18ff107 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -1,109 +1,109 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - eigenvalue - 1000 - 10 - 0 - - - -0.62992 -0.62992 -1 0.62992 0.62992 1 - - + eigenvalue + 1000 + 10 + 0 + + + -0.62992 -0.62992 -1 0.62992 0.62992 1 + + - - 10000 - - - 10001 - - - 0.0 4000000.0 20000000.0 - - - 0.0 0.785398163397 3.14159265359 - - - 0.0 0.785398163397 3.14159265359 - - - 1 - - - 10001 - - - 10000 - - - 2 - - - 3 - - - 10004 10005 10000 10001 10002 - current - - - 10004 10003 10000 10001 10002 - current - - - 10006 10007 10000 10001 10002 - current - - - 10006 10003 10000 10001 10002 - current - - - 10003 10000 10001 10002 - current - - - 10009 10000 10001 10002 - current - - - 10010 10000 - current - - - 10010 10000 - current - + + 13 + + + 14 + + + 0.0 4000000.0 20000000.0 + + + 0.0 0.785398163397 3.14159265359 + + + 0.0 0.785398163397 3.14159265359 + + + 1 + + + 14 + + + 13 + + + 2 + + + 3 + + + 5 6 1 2 3 + current + + + 5 4 1 2 3 + current + + + 7 8 1 2 3 + current + + + 7 4 1 2 3 + current + + + 4 1 2 3 + current + + + 10 1 2 3 + current + + + 11 1 + current + + + 11 1 + current + From fa07ddb857ab452a0eda9d4d693efe59f7faca0b Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 15:00:38 -0400 Subject: [PATCH 098/229] pleasing python2 --- tests/test_surface_tally/test_surface_tally.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index 5ebe30d58..928b74100 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -87,7 +87,7 @@ class SurfaceTallyTestHarness(PyAPITestHarness): # Create partial current tallies from fuel to water # Filters - two_groups = np.array([0., 4, 20.]) * 1e6 + two_groups = [0., 4e6, 20e6] energy_filter = openmc.EnergyFilter(two_groups) polar_filter = openmc.PolarFilter([0, np.pi / 4, np.pi]) azimuthal_filter = openmc.AzimuthalFilter([0, np.pi / 4, np.pi]) From 56d8f25f36b2cb70d3a698e0dfc35d349e362aa3 Mon Sep 17 00:00:00 2001 From: guillaume Date: Sun, 6 Aug 2017 15:31:02 -0400 Subject: [PATCH 099/229] pleasing python2: .set_element was not giving the same round offs in python2 and python3 --- tests/test_surface_tally/inputs_true.dat | 22 ++--- tests/test_surface_tally/results_true.dat | 92 +++++++++---------- .../test_surface_tally/test_surface_tally.py | 16 ++-- 3 files changed, 62 insertions(+), 68 deletions(-) diff --git a/tests/test_surface_tally/inputs_true.dat b/tests/test_surface_tally/inputs_true.dat index 4d18ff107..e66d44273 100644 --- a/tests/test_surface_tally/inputs_true.dat +++ b/tests/test_surface_tally/inputs_true.dat @@ -12,22 +12,16 @@ - - - - - - + + + + - - - - - - - - + + + + diff --git a/tests/test_surface_tally/results_true.dat b/tests/test_surface_tally/results_true.dat index 8e9f6c390..51e2d7dc0 100644 --- a/tests/test_surface_tally/results_true.dat +++ b/tests/test_surface_tally/results_true.dat @@ -1,53 +1,53 @@ mean,std. dev. -2.2000000e-02,1.8915015e-03 -7.0600000e-02,2.4549270e-03 -1.4900000e-01,4.1150132e-03 -6.1190000e-01,9.6014467e-03 -1.1000000e-03,3.7859389e-04 -5.8000000e-03,9.9777530e-04 -1.0300000e-02,1.5205993e-03 -4.6700000e-02,3.0333333e-03 -2.2000000e-02,1.8915015e-03 -7.0600000e-02,2.4549270e-03 -1.4900000e-01,4.1150132e-03 -6.1190000e-01,9.6014467e-03 -1.1000000e-03,3.7859389e-04 -5.8000000e-03,9.9777530e-04 -1.0300000e-02,1.5205993e-03 -4.6700000e-02,3.0333333e-03 -5.4000000e-03,6.6999171e-04 -4.5000000e-02,1.9436506e-03 -3.2300000e-02,1.4067299e-03 -3.8900000e-01,7.4311656e-03 +2.1400000e-02,1.1850926e-03 +7.4700000e-02,2.5649345e-03 +1.6090000e-01,4.4433471e-03 +6.4810000e-01,8.6041979e-03 +2.0000000e-03,3.9440532e-04 +4.2000000e-03,8.2731158e-04 +1.1200000e-02,1.0934146e-03 +4.6400000e-02,2.2715633e-03 +2.1400000e-02,1.1850926e-03 +7.4700000e-02,2.5649345e-03 +1.6090000e-01,4.4433471e-03 +6.4810000e-01,8.6041979e-03 +2.0000000e-03,3.9440532e-04 +4.2000000e-03,8.2731158e-04 +1.1200000e-02,1.0934146e-03 +4.6400000e-02,2.2715633e-03 +5.5000000e-03,5.6273143e-04 +4.4300000e-02,1.8502252e-03 +4.5600000e-02,1.2220202e-03 +4.1780000e-01,6.4460151e-03 0.0000000e+00,0.0000000e+00 -2.6000000e-03,4.7609523e-04 -1.0000000e-04,1.0000000e-04 -1.9300000e-02,1.3337499e-03 --5.4000000e-03,6.6999171e-04 --4.5000000e-02,1.9436506e-03 --3.2300000e-02,1.4067299e-03 --3.8900000e-01,7.4311656e-03 +1.4000000e-03,3.3993463e-04 0.0000000e+00,0.0000000e+00 --2.6000000e-03,4.7609523e-04 --1.0000000e-04,1.0000000e-04 --1.9300000e-02,1.3337499e-03 -1.6600000e-02,1.9675139e-03 -2.5600000e-02,3.2903900e-03 -1.1670000e-01,3.3100856e-03 -2.2290000e-01,5.8924622e-03 -1.1000000e-03,3.7859389e-04 -3.2000000e-03,6.4635731e-04 -1.0200000e-02,1.5114379e-03 -2.7400000e-02,3.0081371e-03 +1.6600000e-02,1.0561986e-03 +-5.5000000e-03,5.6273143e-04 +-4.4300000e-02,1.8502252e-03 +-4.5600000e-02,1.2220202e-03 +-4.1780000e-01,6.4460151e-03 0.0000000e+00,0.0000000e+00 --3.5600000e-02,2.2020193e-03 +-1.4000000e-03,3.3993463e-04 0.0000000e+00,0.0000000e+00 --3.6890000e-01,3.4236108e-03 +-1.6600000e-02,1.0561986e-03 +1.5900000e-02,1.1200198e-03 +3.0400000e-02,3.2734623e-03 +1.1530000e-01,3.8327536e-03 +2.3030000e-01,7.2250336e-03 +2.0000000e-03,3.9440532e-04 +2.8000000e-03,7.8598841e-04 +1.1200000e-02,1.0934146e-03 +2.9800000e-02,2.5811281e-03 0.0000000e+00,0.0000000e+00 --2.8000000e-03,6.7986927e-04 +-3.0000000e-02,1.3743685e-03 0.0000000e+00,0.0000000e+00 --2.2900000e-02,2.4919872e-03 --7.9490000e-01,1.2723076e-02 --3.4600000e-02,2.7414514e-03 --7.9490000e-01,1.2723076e-02 --3.4600000e-02,2.7414514e-03 +-3.4810000e-01,5.9711343e-03 +0.0000000e+00,0.0000000e+00 +-3.1000000e-03,6.9041051e-04 +0.0000000e+00,0.0000000e+00 +-2.1900000e-02,2.4241837e-03 +-9.0250000e-01,2.0941320e-02 +-3.5200000e-02,1.2806248e-03 +-9.0250000e-01,2.0941320e-02 +-3.5200000e-02,1.2806248e-03 diff --git a/tests/test_surface_tally/test_surface_tally.py b/tests/test_surface_tally/test_surface_tally.py index 928b74100..ae525a683 100644 --- a/tests/test_surface_tally/test_surface_tally.py +++ b/tests/test_surface_tally/test_surface_tally.py @@ -13,16 +13,16 @@ class SurfaceTallyTestHarness(PyAPITestHarness): def _build_inputs(self): # Instantiate some Materials and register the appropriate Nuclides uo2 = openmc.Material(name='UO2 fuel at 2.4% wt enrichment') - uo2.set_density('g/cm3', 10.29769) - uo2.add_element('U', 1., enrichment=2.4) - uo2.add_element('O', 2.) + uo2.set_density('g/cc', 10.0) + uo2.add_nuclide('U238', 1.0) + uo2.add_nuclide('U235', 0.02) + uo2.add_nuclide('O16', 2.0) borated_water = openmc.Material(name='Borated water') - borated_water.set_density('g/cm3', 0.740582) - borated_water.add_element('B', 4.0e-5) - borated_water.add_element('H', 5.0e-2) - borated_water.add_element('O', 2.4e-2) - borated_water.add_s_alpha_beta('c_H_in_H2O') + borated_water.set_density('g/cm3', 1) + borated_water.add_nuclide('B10', 10e-5) + borated_water.add_nuclide('H1', 2.0) + borated_water.add_nuclide('O16', 1.0) # Instantiate a Materials collection and export to XML materials_file = openmc.Materials([uo2, borated_water]) From 7f8a2acbf27074479a285e4c20ef6e2611c16a27 Mon Sep 17 00:00:00 2001 From: April Novak Date: Mon, 7 Aug 2017 12:55:27 -0500 Subject: [PATCH 100/229] Corrected material_index to account for the fact that the indices are changed in the adjust_indices routine. Refs #908 --- src/api.F90 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index d45360d28..23aa40587 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -100,7 +100,6 @@ contains integer(C_INT) :: err ! error code integer :: j ! looping variable integer :: n ! number of cell instances - integer :: material_ID ! material associated with cell integer :: material_index ! material index in materials array integer :: num_nuclides ! num nuclides in material integer :: nuclide_index ! index of nuclide in nuclides array @@ -121,16 +120,14 @@ contains if (cells(index) % fill /= NONE) then err = E_CELL_NO_MATERIAL else - ! find which material is associated with this cell + ! find which material is associated with this cell (material_index + ! is the index into the materials array) if (present(instance)) then - material_ID = cells(index) % material(instance) + material_index = cells(index) % material(instance) else - material_ID = cells(index) % material(1) + material_index = cells(index) % material(1) end if - ! index of that material into the materials array - material_index = material_dict % get_key(material_ID) - ! number of nuclides associated with this material num_nuclides = size(materials(material_index) % nuclide) From 26a44218ca8cdb78f1cd2e58902773225bee056a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 14:16:06 -0500 Subject: [PATCH 101/229] Reimplement MeshFilter % get_all_bins --- src/tally.F90 | 10 +-- src/tally_filter.F90 | 156 ++++++++++++++++++++++++++++++------------- 2 files changed, 113 insertions(+), 53 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index b9102270e..ad5391356 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2292,8 +2292,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() - call filters(i_filt) % obj % get_all_bins(p, t % estimator, & - filter_matches(i_filt)) + call filters(i_filt) % obj % get_all_bins(p, t % estimator, & + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2447,7 +2447,7 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & - filter_matches(i_filt)) + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2826,7 +2826,7 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & - filter_matches(i_filt)) + filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2996,7 +2996,7 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & - filter_matches(i_filt)) + filter_matches(i_filt)) end if ! If there are no valid bins for this filter, then there is nothing to ! score and we can move on to the next tally. diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index fcd2e7b40..ec7e0bea2 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -230,9 +230,11 @@ contains ! the first intersection. integer :: j ! loop index for direction + integer :: n integer :: ijk0(3) ! indices of starting coordinates integer :: ijk1(3) ! indices of ending coordinates integer :: search_iter ! loop count for intersection search + integer :: bin real(8) :: weight ! weight to be pushed back real(8) :: uvw(3) ! cosine of angle of particle real(8) :: xyz0(3) ! starting/intermediate coordinates @@ -249,52 +251,87 @@ contains ! Get a pointer to the mesh. m => meshes(this % mesh) + n = m % n_dimension if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. - call match % bins % push_back(1) + call get_mesh_bin(m, p % coord(1) % xyz, bin) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) call match % weights % push_back(ONE) + end if + return + end if - else - ! A track can span multiple mesh bins so we need to handle a lot of - ! intersection logic for tracklength tallies. + ! A track can span multiple mesh bins so we need to handle a lot of + ! intersection logic for tracklength tallies. - ! ======================================================================== - ! Determine if the track intersects the tally mesh. + ! ======================================================================== + ! Determine if the track intersects the tally mesh. - ! Copy the starting and ending coordinates of the particle. Offset these - ! just a bit for the purposes of determining if there was an intersection - ! in case the mesh surfaces coincide with lattice/geometric surfaces which - ! might produce finite-precision errors. - xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw - xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw + ! Copy the starting and ending coordinates of the particle. Offset these + ! just a bit for the purposes of determining if there was an intersection + ! in case the mesh surfaces coincide with lattice/geometric surfaces which + ! might produce finite-precision errors. + xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw + xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw - ! Determine indices for starting and ending location. - call get_mesh_indices(m, xyz0, ijk0(:m % n_dimension), start_in_mesh) - call get_mesh_indices(m, xyz1, ijk1(:m % n_dimension), end_in_mesh) + ! Determine indices for starting and ending location. + call get_mesh_indices(m, xyz0, ijk0(:n), start_in_mesh) + call get_mesh_indices(m, xyz1, ijk1(:n), end_in_mesh) - ! ======================================================================== - ! Figure out which mesh cell to tally. + ! If this is the first iteration of the filter loop, check if the track + ! intersects any part of the mesh. + if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then + if (n == 1) then + if (.not. mesh_intersects_1d(m, xyz0, xyz1)) then + return + end if + else if (n == 2) then + if (.not. mesh_intersects_2d(m, xyz0, xyz1)) then + return + end if + else + if (.not. mesh_intersects_3d(m, xyz0, xyz1)) then + return + end if + end if + end if - ! Copy the un-modified coordinates the particle direction. - xyz0 = p % last_xyz - xyz1 = p % coord(1) % xyz - uvw = p % coord(1) % uvw + ! ======================================================================== + ! Figure out which mesh cell to tally. - ! Compute the length of the entire track. - total_distance = sqrt(sum((xyz1 - xyz0)**2)) + ! Copy the un-modified coordinates the particle direction. + xyz0 = p % last_xyz + xyz1 = p % coord(1) % xyz + uvw = p % coord(1) % uvw - ! We have already scored some mesh bins for this track. Pick up where - ! we left off and find the next mesh cell that the particle enters. + ! Compute the length of the entire track. + total_distance = sqrt(sum((xyz1 - xyz0)**2)) - ! Get the indices to the last bin we scored. - call bin_to_mesh_indices(m, 1, ijk0(:m % n_dimension)) + ! We are looking for the first valid mesh bin. Check to see if the + ! particle starts inside the mesh. + if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then + ! The particle does not start in the mesh. Note that we nudged the + ! start and end coordinates by a TINY_BIT each so we will have + ! difficulty resolving tracks that are less than 2*TINY_BIT in length. + ! If the track is that short, it is also insignificant so we can + ! safely ignore it in the tallies. + if (total_distance < 2*TINY_BIT) return - ! Figure out which face of the previous mesh cell our track exits, i.e. - ! the closest surface of that cell for which - ! dot(p % uvw, face_normal) > 0. - do j = 1, m % n_dimension + ! The particle does not start in the mesh so keep iterating the ijk0 + ! indices to cross the nearest mesh surface until we've found a valid + ! bin. MAX_SEARCH_ITER prevents an infinite loop. + search_iter = 0 + do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) + if (search_iter == MAX_SEARCH_ITER) then + call warning("Failed to find a mesh intersection on a tally mesh & + &filter.") + return + end if + + do j = 1, n if (abs(uvw(j)) < FP_PRECISION) then d(j) = INFINITY else if (uvw(j) > 0) then @@ -305,32 +342,32 @@ contains d(j) = (xyz_cross - xyz0(j)) / uvw(j) end if end do - j = minloc(d(:m % n_dimension), 1) - - ! Translate the starting coordintes by the distance to that face. This - ! should be the xyz that we computed the distance to in the last - ! iteration of the filter loop. - distance = d(j) - xyz0 = xyz0 + distance * uvw - - ! Increment the indices into the next mesh cell. + j = minloc(d(:n), 1) if (uvw(j) > ZERO) then ijk0(j) = ijk0(j) + 1 else ijk0(j) = ijk0(j) - 1 end if + search_iter = search_iter + 1 + end do + distance = d(j) + xyz0 = xyz0 + distance * uvw + end if + + do ! ======================================================================== ! Compute the length of the track segment in the appropiate mesh cell and ! return. - if (all(ijk0(:m % n_dimension) == ijk1(:m % n_dimension))) then + if (all(ijk0(:n) == ijk1(:n))) then ! The track ends in this cell. Use the particle end location rather ! than the mesh surface. distance = sqrt(sum((xyz1 - xyz0)**2)) else - ! The track exits this cell. Use the distance to the mesh surface. - do j = 1, m % n_dimension + ! The track exits this cell. Determine the distance to the closest mesh + ! surface. + do j = 1, n if (abs(uvw(j)) < FP_PRECISION) then d(j) = INFINITY else if (uvw(j) > 0) then @@ -341,14 +378,37 @@ contains d(j) = (xyz_cross - xyz0(j)) / uvw(j) end if end do - distance = minval(d(:m % n_dimension)) + j = minloc(d(:n), 1) + distance = d(j) end if ! Assign the next tally bin and the score. - call match % bins % push_back(mesh_indices_to_bin(m, ijk0(:m % n_dimension))) - weight = distance / total_distance - call match % weights % push_back(weight) - end if + bin = mesh_indices_to_bin(m, ijk0(:n)) + call match % bins % push_back(bin) + call match % weights % push_back(distance / total_distance) + + ! Find the next mesh cell that the particle enters. + + ! If the particle track ends in that bin, then we are done. + if (all(ijk0(:n) == ijk1(:n))) exit + + ! Translate the starting coordintes by the distance to that face. This + ! should be the xyz that we computed the distance to in the last + ! iteration of the filter loop. + xyz0 = xyz0 + distance * uvw + + ! Increment the indices into the next mesh cell. + if (uvw(j) > ZERO) then + ijk0(j) = ijk0(j) + 1 + else + ijk0(j) = ijk0(j) - 1 + end if + + ! If the next indices are invalid, then the track has left the mesh and + ! we are done. + if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit + end do + end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) From 7e750fad74a17798b178bbf53954c2cd5377ac88 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 15:41:57 -0500 Subject: [PATCH 102/229] Catch out of bounds values for binary searches in filters --- src/tally_filter.F90 | 56 ++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index ec7e0bea2..8451b803e 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -846,6 +846,7 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: n + integer :: bin real(8) :: E n = this % n_bins @@ -867,9 +868,12 @@ contains E = p % last_E end if - ! Search to find incoming energy bin. - call match % bins % push_back(binary_search(this % bins, n + 1, E)) + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) call match % weights % push_back(ONE) + end if end if end subroutine get_all_bins_energy @@ -905,6 +909,7 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: n + integer :: bin n = this % n_bins @@ -919,8 +924,11 @@ contains else ! Search to find incoming energy bin. - call match % bins % push_back(binary_search(this % bins, n + 1, p % E)) - call match % weights % push_back(ONE) + bin = binary_search(this % bins, n + 1, p % E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if end if end subroutine get_all_bins_energyout @@ -986,12 +994,16 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: n + integer :: bin - n = this % n_bins + n = this % n_bins - ! Search to find incoming energy bin. - call match % bins % push_back(binary_search(this % bins, n + 1, p % mu)) + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, p % mu) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) call match % weights % push_back(ONE) + end if end subroutine get_all_bins_mu subroutine to_statepoint_mu(this, filter_group) @@ -1026,6 +1038,7 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: n + integer :: bin real(8) :: theta n = this % n_bins @@ -1038,8 +1051,11 @@ contains end if ! Search to find polar angle bin. - call match % bins % push_back(binary_search(this % bins, n + 1, theta)) - call match % weights % push_back(ONE) + bin = binary_search(this % bins, n + 1, theta) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if end subroutine get_all_bins_polar subroutine to_statepoint_polar(this, filter_group) @@ -1074,20 +1090,24 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: n + integer :: bin real(8) :: phi - n = this % n_bins + n = this % n_bins - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - phi = atan2(p % coord(1) % uvw(2), p % coord(1) % uvw(1)) - else - phi = atan2(p % last_uvw(2), p % last_uvw(1)) - end if + ! Make sure the correct direction vector is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + phi = atan2(p % coord(1) % uvw(2), p % coord(1) % uvw(1)) + else + phi = atan2(p % last_uvw(2), p % last_uvw(1)) + end if - ! Search to find azimuthal angle bin. - call match % bins % push_back(binary_search(this % bins, n + 1, phi)) + ! Search to find azimuthal angle bin. + bin = binary_search(this % bins, n + 1, phi) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) call match % weights % push_back(ONE) + end if end subroutine get_all_bins_azimuthal From 73751134d58c44e7a3f5042e04965b815c291d83 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 16:04:15 -0500 Subject: [PATCH 103/229] Fix energyout filter and surface current tally --- src/tally.F90 | 7 +++++-- src/tally_filter.F90 | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index ad5391356..b7a8283c6 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2997,6 +2997,7 @@ contains call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & filter_matches(i_filt)) + filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to ! score and we can move on to the next tally. @@ -3213,10 +3214,12 @@ contains ! Determine incoming energy bin. We need to tell the energy filter this ! is a tracklength tally so it uses the pre-collision energy. if (energy_filter) then - ! Find all valid bins in each filter if they have not already been found - ! for a previous tally. + call filter_matches(i_filter_energy) % bins % clear() + call filter_matches(i_filter_energy) % weights % clear() call filters(i_filter_energy) % obj % get_all_bins(p, & ESTIMATOR_TRACKLENGTH, filter_matches(i_filter_energy)) + if (filter_matches(i_filter_energy) % bins % size() == 0) cycle + matching_bin = filter_matches(i_filter_energy) % bins % data(1) filter_matches(i_filter_energy) % bins % data(1) = matching_bin end if diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 8451b803e..2715ce736 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -914,8 +914,6 @@ contains n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then - call match % bins % push_back(p % g) - ! Tallies are ordered in increasing groups, group indices ! however are the opposite, so switch call match % bins % push_back(num_energy_groups - p % g + 1) From cd93df7f4f8c1cf3174888e990a902b09cc9ccd6 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 21:55:24 -0500 Subject: [PATCH 104/229] Fix continuation line in tally_filter module --- src/tally_filter.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 2715ce736..cdad36230 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -457,7 +457,7 @@ contains do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % universe)) then call match % bins % push_back(this % map % get_key(p % coord(i) & - % universe)) + % universe)) call match % weights % push_back(ONE) end if end do From 98fc801aac9d2cd3bcbee3a6987908ae8b878b91 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 8 Aug 2017 06:38:55 -0500 Subject: [PATCH 105/229] Always use pre-collision energy in tallying --- src/physics.F90 | 5 ---- src/tally.F90 | 61 ++++++++------------------------------------ src/tally_filter.F90 | 16 +++--------- src/tracking.F90 | 15 +++++------ 4 files changed, 20 insertions(+), 77 deletions(-) diff --git a/src/physics.F90 b/src/physics.F90 index 3d557b44f..f40b7fd7b 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -33,11 +33,6 @@ contains type(Particle), intent(inout) :: p - ! Store pre-collision particle properties - p % last_wgt = p % wgt - p % last_E = p % E - p % last_uvw = p % coord(1) % uvw - ! Add to collision counter for particle p % n_collision = p % n_collision + 1 diff --git a/src/tally.F90 b/src/tally.F90 index 1bdde1b50..17dd827ba 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -100,6 +100,9 @@ contains real(8) :: score ! analog tally score real(8) :: E ! particle energy + ! Pre-collision energy of particle + E = p % last_E + i = 0 SCORE_LOOP: do q = 1, t % n_user_score_bins i = i + 1 @@ -159,14 +162,6 @@ contains case (SCORE_INVERSE_VELOCITY) - - ! make sure the correct energy is used - if (t % estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - if (t % estimator == ESTIMATOR_ANALOG) then ! All events score to an inverse velocity bin. We actually use a ! collision estimator in place of an analog one since there is no way @@ -256,7 +251,7 @@ contains ! Get yield and apply to score associate (rxn => nuclides(p % event_nuclide) % reactions(m)) score = p % last_wgt * flux & - * rxn % products(1) % yield % evaluate(p % last_E) + * rxn % products(1) % yield % evaluate(E) end associate end if @@ -283,7 +278,7 @@ contains ! Get yield and apply to score associate (rxn => nuclides(p % event_nuclide) % reactions(m)) score = p % last_wgt * flux & - * rxn % products(1) % yield % evaluate(p % last_E) + * rxn % products(1) % yield % evaluate(E) end associate end if @@ -310,7 +305,7 @@ contains ! Get yield and apply to score associate (rxn => nuclides(p%event_nuclide)%reactions(m)) score = p % last_wgt * flux & - * rxn % products(1) % yield % evaluate(p % last_E) + * rxn % products(1) % yield % evaluate(E) end associate end if @@ -413,13 +408,6 @@ contains case (SCORE_PROMPT_NU_FISSION) - ! make sure the correct energy is used - if (t % estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - if (t % estimator == ESTIMATOR_ANALOG) then if (survival_biasing .or. p % fission) then if (t % find_filter(FILTER_ENERGYOUT) > 0) then @@ -481,16 +469,7 @@ contains end if end if - case (SCORE_DELAYED_NU_FISSION) - - ! make sure the correct energy is used - if (t % estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - ! Set the delayedgroup filter index and the number of delayed group bins dg_filter = t % find_filter(FILTER_DELAYEDGROUP) @@ -682,14 +661,6 @@ contains end if case (SCORE_DECAY_RATE) - - ! make sure the correct energy is used - if (t % estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if - ! Set the delayedgroup filter index dg_filter = t % find_filter(FILTER_DELAYEDGROUP) @@ -1065,7 +1036,7 @@ contains if (micro_xs(p % event_nuclide) % absorption > ZERO .and. & allocated(nuc % fission_q_prompt)) then score = p % absorb_wgt & - * nuc % fission_q_prompt % evaluate(p % last_E) & + * nuc % fission_q_prompt % evaluate(E) & * micro_xs(p % event_nuclide) % fission & / micro_xs(p % event_nuclide) % absorption * flux end if @@ -1079,7 +1050,7 @@ contains associate (nuc => nuclides(p % event_nuclide)) if (allocated(nuc % fission_q_prompt)) then score = p % last_wgt & - * nuc % fission_q_prompt % evaluate(p % last_E) & + * nuc % fission_q_prompt % evaluate(E) & * micro_xs(p % event_nuclide) % fission & / micro_xs(p % event_nuclide) % absorption * flux end if @@ -1087,12 +1058,6 @@ contains end if else - if (t % estimator == ESTIMATOR_COLLISION) then - E = p % last_E - else - E = p % E - end if - if (i_nuclide > 0) then if (allocated(nuclides(i_nuclide) % fission_q_prompt)) then score = micro_xs(i_nuclide) % fission * atom_density * flux & @@ -1125,7 +1090,7 @@ contains if (micro_xs(p % event_nuclide) % absorption > ZERO .and. & allocated(nuc % fission_q_recov)) then score = p % absorb_wgt & - * nuc % fission_q_recov % evaluate(p % last_E) & + * nuc % fission_q_recov % evaluate(E) & * micro_xs(p % event_nuclide) % fission & / micro_xs(p % event_nuclide) % absorption * flux end if @@ -1139,7 +1104,7 @@ contains associate (nuc => nuclides(p % event_nuclide)) if (allocated(nuc % fission_q_recov)) then score = p % last_wgt & - * nuc % fission_q_recov % evaluate(p % last_E) & + * nuc % fission_q_recov % evaluate(E) & * micro_xs(p % event_nuclide) % fission & / micro_xs(p % event_nuclide) % absorption * flux end if @@ -1147,12 +1112,6 @@ contains end if else - if (t % estimator == ESTIMATOR_COLLISION) then - E = p % last_E - else - E = p % E - end if - if (i_nuclide > 0) then if (allocated(nuclides(i_nuclide) % fission_q_recov)) then score = micro_xs(i_nuclide) % fission * atom_density * flux & diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 908b6f1a6..30c5d9073 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -1035,12 +1035,8 @@ contains weight = ONE else - ! Make sure the correct energy is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if + ! Pre-collision energy of particle + E = p % last_E ! Check if energy of the particle is within energy bins. if (E < this % bins(1) .or. E > this % bins(n + 1)) then @@ -1383,12 +1379,8 @@ contains if (current_bin == NO_BIN_FOUND) then n = size(this % energy) - ! Make sure the correct energy is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if + ! Get pre-collision energy of particle + E = p % last_E ! Check if energy of the particle is within energy bins. if (E < this % energy(1) .or. E > this % energy(n)) then diff --git a/src/tracking.F90 b/src/tracking.F90 index 546ae3880..90dd9c35e 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -68,6 +68,12 @@ contains if (active_tallies % size() > 0) call zero_flux_derivs() EVENT_LOOP: do + ! Store pre-collision particle properties + p % last_wgt = p % wgt + p % last_E = p % E + p % last_uvw = p % coord(1) % uvw + p % last_xyz = p % coord(1) % xyz + ! If the cell hasn't been determined based on the particle's location, ! initiate a search for the current cell. This generally happens at the ! beginning of the history and again for any secondary particles @@ -132,7 +138,6 @@ contains call score_tracklength_tally(p, distance) end if - ! Score track-length estimate of k-eff if (run_mode == MODE_EIGENVALUE) then global_tally_tracklength = global_tally_tracklength + p % wgt * & @@ -154,11 +159,6 @@ contains end do p % last_n_coord = p % n_coord - ! Update last_ data. This is needed to use the same filters in - ! surface tallies as the ones implemented for regular tallies - p % last_uvw = p % coord(p % n_coord) % uvw - p % last_E = p % E - p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary @@ -237,9 +237,6 @@ contains if (active_tallies % size() > 0) call score_collision_derivative(p) end if - ! Save coordinates for tallying purposes - p % last_xyz = p % coord(1) % xyz - ! If particle has too many events, display warning and kill it n_event = n_event + 1 if (n_event == MAX_EVENTS) then From 9aa9c13528d98461f42e1d994ffd17959a2b27e9 Mon Sep 17 00:00:00 2001 From: Brittany Grayson Date: Wed, 23 Aug 2017 13:55:59 -0600 Subject: [PATCH 106/229] commits tally and tally_filter updates --- src/tally.F90 | 24 ----------- src/tally_filter.F90 | 100 ------------------------------------------- 2 files changed, 124 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 5f26f21b7..b7a8283c6 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2292,13 +2292,8 @@ contains if (.not. filter_matches(i_filt) % bins_present) then call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() -<<<<<<< HEAD - call filters(i_filt) % obj % get_all_bins(p, t % estimator, & - filter_matches(i_filt)) -======= call filters(i_filt) % obj % get_all_bins(p, t % estimator, & filter_matches(i_filt)) ->>>>>>> get_all_bins filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2452,11 +2447,7 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & -<<<<<<< HEAD - filter_matches(i_filt)) -======= filter_matches(i_filt)) ->>>>>>> get_all_bins filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -2835,11 +2826,7 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & -<<<<<<< HEAD - filter_matches(i_filt)) -======= filter_matches(i_filt)) ->>>>>>> get_all_bins filter_matches(i_filt) % bins_present = .true. end if ! If there are no valid bins for this filter, then there is nothing to @@ -3009,12 +2996,8 @@ contains call filter_matches(i_filt) % bins % clear() call filter_matches(i_filt) % weights % clear() call filters(i_filt) % obj % get_all_bins(p, t % estimator, & -<<<<<<< HEAD - filter_matches(i_filt)) -======= filter_matches(i_filt)) filter_matches(i_filt) % bins_present = .true. ->>>>>>> get_all_bins end if ! If there are no valid bins for this filter, then there is nothing to ! score and we can move on to the next tally. @@ -3231,19 +3214,12 @@ contains ! Determine incoming energy bin. We need to tell the energy filter this ! is a tracklength tally so it uses the pre-collision energy. if (energy_filter) then -<<<<<<< HEAD - ! Find all valid bins in each filter if they have not already been found - ! for a previous tally. - call filters(i_filter_energy) % obj % get_all_bins(p, & - ESTIMATOR_TRACKLENGTH, filter_matches(i_filter_energy)) -======= call filter_matches(i_filter_energy) % bins % clear() call filter_matches(i_filter_energy) % weights % clear() call filters(i_filter_energy) % obj % get_all_bins(p, & ESTIMATOR_TRACKLENGTH, filter_matches(i_filter_energy)) if (filter_matches(i_filter_energy) % bins % size() == 0) cycle matching_bin = filter_matches(i_filter_energy) % bins % data(1) ->>>>>>> get_all_bins filter_matches(i_filter_energy) % bins % data(1) = matching_bin end if diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index ab3ef0c2d..cdad36230 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -234,10 +234,7 @@ contains integer :: ijk0(3) ! indices of starting coordinates integer :: ijk1(3) ! indices of ending coordinates integer :: search_iter ! loop count for intersection search -<<<<<<< HEAD -======= integer :: bin ->>>>>>> get_all_bins real(8) :: weight ! weight to be pushed back real(8) :: uvw(3) ! cosine of angle of particle real(8) :: xyz0(3) ! starting/intermediate coordinates @@ -259,10 +256,6 @@ contains if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. -<<<<<<< HEAD - call match % bins % push_back(1) - call match % weights % push_back(ONE) -======= call get_mesh_bin(m, p % coord(1) % xyz, bin) if (bin /= NO_BIN_FOUND) then call match % bins % push_back(bin) @@ -270,43 +263,10 @@ contains end if return end if ->>>>>>> get_all_bins ! A track can span multiple mesh bins so we need to handle a lot of ! intersection logic for tracklength tallies. -<<<<<<< HEAD - ! ======================================================================== - ! Determine if the track intersects the tally mesh. - - ! Copy the starting and ending coordinates of the particle. Offset these - ! just a bit for the purposes of determining if there was an intersection - ! in case the mesh surfaces coincide with lattice/geometric surfaces which - ! might produce finite-precision errors. - xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw - xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw - - ! Determine indices for starting and ending location. - call get_mesh_indices(m, xyz0, ijk0(:m % n_dimension), start_in_mesh) - call get_mesh_indices(m, xyz1, ijk1(:m % n_dimension), end_in_mesh) - - ! ======================================================================== - ! Figure out which mesh cell to tally. - - ! Copy the un-modified coordinates the particle direction. - xyz0 = p % last_xyz - xyz1 = p % coord(1) % xyz - uvw = p % coord(1) % uvw - - ! Compute the length of the entire track. - total_distance = sqrt(sum((xyz1 - xyz0)**2)) - - ! We have already scored some mesh bins for this track. Pick up where - ! we left off and find the next mesh cell that the particle enters. - - ! Get the indices to the last bin we scored. - call bin_to_mesh_indices(m, 1, ijk0(:m % n_dimension)) -======= ! ======================================================================== ! Determine if the track intersects the tally mesh. @@ -370,7 +330,6 @@ contains &filter.") return end if ->>>>>>> get_all_bins do j = 1, n if (abs(uvw(j)) < FP_PRECISION) then @@ -390,8 +349,6 @@ contains ijk0(j) = ijk0(j) - 1 end if -<<<<<<< HEAD -======= search_iter = search_iter + 1 end do distance = d(j) @@ -399,7 +356,6 @@ contains end if do ->>>>>>> get_all_bins ! ======================================================================== ! Compute the length of the track segment in the appropiate mesh cell and ! return. @@ -427,12 +383,6 @@ contains end if ! Assign the next tally bin and the score. -<<<<<<< HEAD - call match % bins % push_back(mesh_indices_to_bin(m, ijk0(:m % n_dimension))) - weight = distance / total_distance - call match % weights % push_back(weight) - end if -======= bin = mesh_indices_to_bin(m, ijk0(:n)) call match % bins % push_back(bin) call match % weights % push_back(distance / total_distance) @@ -459,7 +409,6 @@ contains if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit end do ->>>>>>> get_all_bins end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) @@ -508,11 +457,7 @@ contains do i = 1, p % n_coord if (this % map % has_key(p % coord(i) % universe)) then call match % bins % push_back(this % map % get_key(p % coord(i) & -<<<<<<< HEAD - % universe)) -======= % universe)) ->>>>>>> get_all_bins call match % weights % push_back(ONE) end if end do @@ -923,18 +868,12 @@ contains E = p % last_E end if -<<<<<<< HEAD - ! Search to find incoming energy bin. - call match % bins % push_back(binary_search(this % bins, n + 1, E)) - call match % weights % push_back(ONE) -======= ! Search to find incoming energy bin. bin = binary_search(this % bins, n + 1, E) if (bin /= NO_BIN_FOUND) then call match % bins % push_back(bin) call match % weights % push_back(ONE) end if ->>>>>>> get_all_bins end if end subroutine get_all_bins_energy @@ -975,11 +914,6 @@ contains n = this % n_bins if ((.not. run_CE) .and. this % matches_transport_groups) then -<<<<<<< HEAD - call match % bins % push_back(p % g) - -======= ->>>>>>> get_all_bins ! Tallies are ordered in increasing groups, group indices ! however are the opposite, so switch call match % bins % push_back(num_energy_groups - p % g + 1) @@ -988,16 +922,11 @@ contains else ! Search to find incoming energy bin. -<<<<<<< HEAD - call match % bins % push_back(binary_search(this % bins, n + 1, p % E)) - call match % weights % push_back(ONE) -======= bin = binary_search(this % bins, n + 1, p % E) if (bin /= NO_BIN_FOUND) then call match % bins % push_back(bin) call match % weights % push_back(ONE) end if ->>>>>>> get_all_bins end if end subroutine get_all_bins_energyout @@ -1065,13 +994,6 @@ contains integer :: n integer :: bin -<<<<<<< HEAD - n = this % n_bins - - ! Search to find incoming energy bin. - call match % bins % push_back(binary_search(this % bins, n + 1, p % mu)) - call match % weights % push_back(ONE) -======= n = this % n_bins ! Search to find incoming energy bin. @@ -1080,7 +1002,6 @@ contains call match % bins % push_back(bin) call match % weights % push_back(ONE) end if ->>>>>>> get_all_bins end subroutine get_all_bins_mu subroutine to_statepoint_mu(this, filter_group) @@ -1128,16 +1049,11 @@ contains end if ! Search to find polar angle bin. -<<<<<<< HEAD - call match % bins % push_back(binary_search(this % bins, n + 1, theta)) - call match % weights % push_back(ONE) -======= bin = binary_search(this % bins, n + 1, theta) if (bin /= NO_BIN_FOUND) then call match % bins % push_back(bin) call match % weights % push_back(ONE) end if ->>>>>>> get_all_bins end subroutine get_all_bins_polar subroutine to_statepoint_polar(this, filter_group) @@ -1175,21 +1091,6 @@ contains integer :: bin real(8) :: phi -<<<<<<< HEAD - n = this % n_bins - - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - phi = atan2(p % coord(1) % uvw(2), p % coord(1) % uvw(1)) - else - phi = atan2(p % last_uvw(2), p % last_uvw(1)) - end if - - ! Search to find azimuthal angle bin. - call match % bins % push_back(binary_search(this % bins, n + 1, phi)) - call match % weights % push_back(ONE) - -======= n = this % n_bins ! Make sure the correct direction vector is used. @@ -1206,7 +1107,6 @@ contains call match % weights % push_back(ONE) end if ->>>>>>> get_all_bins end subroutine get_all_bins_azimuthal subroutine to_statepoint_azimuthal(this, filter_group) From 8bbe2dc213ff47cff32384a975318b16eeaed9ad Mon Sep 17 00:00:00 2001 From: Brittany Grayson Date: Thu, 24 Aug 2017 12:51:57 -0600 Subject: [PATCH 107/229] Adds in the absolute values --- src/tally_filter.F90 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 0d31033db..7ce449235 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -850,9 +850,13 @@ contains integer :: i do i = 1, this % n_bins - if (p % surface == this % surfaces(i)) then + if (abs(p % surface) == this % surfaces(i)) then call match % bins % push_back(i) - call match % weights % push_back(ONE) + if (p % surface < 0) then + call match % weights % push_back(-ONE) + else + call match % weights % push_back(ONE) + end if exit end if end do From 67774302bdb16103ab30faa987de9d45a81e527b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 14:39:11 -0500 Subject: [PATCH 108/229] Remove files that were accidentally added, remove trailing whitespace --- .DS_Store | Bin 10244 -> 0 bytes examples/jupyter/pincell.ipynb | 380 ++-- src/CTestTestfile.cmake | 172 -- src/DartConfiguration.tcl | 112 -- src/Makefile | 3328 -------------------------------- src/tally_filter.F90 | 2 +- tests/.DS_Store | Bin 14340 -> 0 bytes 7 files changed, 273 insertions(+), 3721 deletions(-) delete mode 100644 .DS_Store delete mode 100644 src/CTestTestfile.cmake delete mode 100644 src/DartConfiguration.tcl delete mode 100644 src/Makefile delete mode 100644 tests/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 2022437f8a27e6be3fbddb269934109b4183bca1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMYiu0V6+Xw0c!q4^aqxpINxZP+0Wro20UT(^W}P%KNr;IziJb(@?9R14&Fsu} zX4a3SK}Lv&psIMJh&Muj08y2=%9x< z0+4N>Y;jSV&H=(F71&H*XQUObRHr;WVBm_u5d)<=m8UqIY$mWX(n@zg=?)mQjKK*7 zMeF335^%tbwDB`$AZB1T1N`jX2ze-j30BSdoiC(|Xdz8~EiU2O2n8sD4u^n+PWk~7 zR)vrYp$~RSBJ>7jt0Oq67zF)I1tliTY|2x)8zg@rAL?VJz{?i0v^rn|i~!cOu@z zb`6UsflD4baaknWO>Z>Y5g*P_xW)N|DZn`4xt_Q(rYL3AdI|k0A*PyymrMOBaXm%Q z#1n?m3ZWU{%7pHwd%70S8LPq96W*PRtGQ75Nv{-q>3S_+vP{qK>3JLL>Khv8H7Tm9 zs0)Kh9IKkv^LtG;Iij`pIkvBxHgiMpgZoU|a3-@( z*)}{;&w%caldouKL|c61$lA5NYr9fwdV7v`rH)*1K~Goeymjl39#xc%xDyOF7IofV>xctDzhQ8;MjxaVK(HmDW4}sv_%ozZf0EZO;&EY zM3~lZGDKZlUB>JKW3FlJ8XfhRKQy8>dj;3AtO3U}ebcdrL#4w9J(_@ipB4Msb#;4;Wv4H<^gOe6*;&W;ogzo_+GrpHF5@+cmIh0D!L-NH z8$XgHrZWST#44H4AT1LB>CD~ZBCTkcvmKkMYC5w$C{C9Z(zw=R{$guWL$>ADUOoo9L46=|LfO)Nw#l-1OryMLGzv|4q-bcr=eRyaHL7ex)5;#( z&8RMOf^DW6sj4}mRXWonC(+0`9_LXw(VA%AH(`2a-eP+uO~W4_ z*1ZC=4GK>C=|{)*%~6xNY72I$Ia@EX=wiP_XP zA41=RTWm_ud4B5=2BPzy>zV1@vRM94Znr^;aPYAUWC`+ zEqD+92_M2|@Hu=5Um>81i?9{jDExL}ie#9^9$b$X;zhU>2Pg~=iZGnV0x}%ML+E1} zCvgg|!t3z{yb*80+wdN|7w^MI@JW0MpTTGGulNT34d2GU<2(2-{189EPvyK;gZK{l zUU}l@l&TeS@Z(%}Y;GZU3L&pJ;f4H;+(WdswRfbJpVfVC?}lu3?jzG(Bge1?h3urR zgx)H8k~$}ipSomeqH_-^kxfO{MrF-tO?+i2$2t16(>psgt~dF*Vr6GSLs}22C|$jh zO6!8Mb9$((o}@3!)}5E=)EY_U(sTWViGF)%-%=_C+A4mRV!uHhBESH QEI$ALaNoX8(DVQQ0J09aD*ylh diff --git a/examples/jupyter/pincell.ipynb b/examples/jupyter/pincell.ipynb index 6c02f3648..163429688 100644 --- a/examples/jupyter/pincell.ipynb +++ b/examples/jupyter/pincell.ipynb @@ -10,7 +10,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "%matplotlib inline\n", @@ -29,7 +31,9 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "u235 = openmc.Nuclide('U235')\n", @@ -49,7 +53,9 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -82,7 +88,9 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -115,7 +123,9 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -193,7 +203,9 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "zirconium = openmc.Material(2, \"zirconium\")\n", @@ -216,7 +228,9 @@ { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "water.add_s_alpha_beta('c_H_in_H2O')" @@ -272,7 +286,9 @@ { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -302,7 +318,9 @@ { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -357,7 +375,9 @@ { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -419,7 +439,9 @@ { "cell_type": "code", "execution_count": 15, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -442,7 +464,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", "\n" @@ -467,7 +489,9 @@ { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "uo2_three = openmc.Material()\n", @@ -518,7 +542,9 @@ { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "inside_sphere = -sph\n", @@ -535,7 +561,9 @@ { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -580,7 +608,9 @@ { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -607,7 +637,9 @@ { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "cell = openmc.Cell()\n", @@ -674,13 +706,15 @@ { "cell_type": "code", "execution_count": 25, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -701,13 +735,15 @@ { "cell_type": "code", "execution_count": 26, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { - "image/png": "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\nUWSzAAAAAElFTkSuQmCC\n", + "image/png": "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\nkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw\n8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUp\nCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNf\nkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpIw8CUpCQNfkpJoNPAj4qkRcUNETEfEYxGxMSKW\nL3DMbRGxt+WxJyKuarKfkpTBwQ2//o3ACuA04EnANcDVwPp5jinAJ4H3AVFv29VcFyUph8YCPyJW\nAeuAsVLKnfW2PwJuiYh3lVJ2zHP4rlLKI031TZIyanJKZy3w2EzY1zZTVfDPW+DYsyPikYj4RkRc\nHBFPaayXkpREk1M6K4GHWzeUUvZExA/rfXO5AXgAeAg4Efgw8GzgrIb6KUkptB34EXEJcOE8TQqw\nutMOlVI2tjy9JyJ2AJsj4rhSyn1zHbdhwwZGRkb22TY+Ps74+HinXZGkxk1MTDAxMbHPtunp6Ube\nK0op7R0Q8TTgaQs0+w7wJuAjpZSft42IZcDjwFmllM8v8v0OA/4XWFdK+dJ+9o8Ck5OTk4yOji7y\nU0hS/5qammJsbAyqa6BTS/W6bVf4pZRHgUcXahcRW4AjI2JNyzz+aVQrb+5o4y3XUP3W8P12+ypJ\n+oXGLtqWUrYDm4BPRcSpEfFC4C+BiZkVOhHxjIjYFhGn1M+fFRHvjYjRiDgmIs4ErgW+Wkr596b6\nKkkZNL0O/43Ax6lW5+wF/h54Z8v+Q6guyB5WP/8p8LK6zXLgv4C/Az7UcD8laeg1GvillP9mnj+y\nKqU8ACxref4g8JIm+yRJWXkvHUlKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElK\nwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCX\npCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQM\nfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElKwsCXpCQMfElK\n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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -728,13 +764,15 @@ { "cell_type": "code", "execution_count": 27, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { - "image/png": "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\nSUVORK5CYII=\n", + "image/png": "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\nEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+\nJCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh\n4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCVh4EtSEga+JCXRaOBHxNMj4uaImIuI\nxyJia0SsXmafOyPiYMvtQERsabKfkpTBUQ0//y3AGuA84MnA9cB1wKYl9inAx4D3AFFv29dcFyUp\nh8YCPyJOBzYCE6WUe+ptfwzcHhHvKKXsXmL3faWUvU31TZIyanJKZwPw2HzY17ZTVfDPW2bfiyNi\nb0R8LSI+GBFPbayXkpREk1M6a4EftG4opRyIiB/Vjy3mZuA7wCPAmcCHgWcDFzXUT0lKoe3Aj4ir\ngHcu0aQA6zrtUClla8vdr0fEbmB7RJxSSnlwsf2mpqYYGxs7ZNvk5CSTk5OddkWSGjc9Pc309PQh\n2+bm5hp5rSiltLdDxDOAZyzT7NvAG4CPlFJ+0TYiVgGPAxeVUj6zwtc7FvhfYGMp5fOHeXwcmJmZ\nmWF8fHyF70KSBtfs7CwTExNQnQOd7dbztl3hl1IeBR5drl1E7ACOj4j1LfP451GtvLm7jZdcT/Wt\n4fvt9lWS9EuNnbQtpdwPbAM+HhHnRsQLgb8CpudX6ETEMyNiV0ScU98/NSLeHRHjEXFSRFwI3AB8\nqZTyH031VZIyaHod/uuBv6ZanXMQ+Cfg7S2PH011QvbY+v7PgJfVbVYD/wX8I/CBhvspSSOv0cAv\npfw3S/ySVSnlO8CqlvsPAy9psk+SlJXX0pGkJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8\nSUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrC\nwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJek\nJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8\nSUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrCwJekJAx8SUrC\n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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -853,7 +891,9 @@ { "cell_type": "code", "execution_count": 32, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "water_region = +left & -right & +bottom & -top & +clad_or\n", @@ -873,7 +913,9 @@ { "cell_type": "code", "execution_count": 33, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -920,7 +962,9 @@ { "cell_type": "code", "execution_count": 35, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -1001,7 +1045,9 @@ { "cell_type": "code", "execution_count": 38, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -1064,7 +1110,9 @@ { "cell_type": "code", "execution_count": 40, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "t.nuclides = ['U235']\n", @@ -1081,7 +1129,9 @@ { "cell_type": "code", "execution_count": 41, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -1117,6 +1167,7 @@ "cell_type": "code", "execution_count": 42, "metadata": { + "collapsed": false, "scrolled": true }, "outputs": [ @@ -1152,9 +1203,9 @@ " | The OpenMC Monte Carlo Code\n", " Copyright | 2011-2017 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.9.0\n", - " Git SHA1 | a8bee7757465e4617eb76e0c72f20cdf57771dd9\n", - " Date/Time | 2017-08-03 13:37:33\n", + " Version | 0.8.0\n", + " Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n", + " Date/Time | 2017-04-13 17:17:32\n", " MPI Processes | 1\n", " OpenMP Threads | 4\n", "\n", @@ -1162,33 +1213,159 @@ " Reading geometry XML file...\n", " Reading materials XML file...\n", " Reading cross sections XML file...\n", - " Reading U235 from /Users/brittanygrayson/nndc_hdf5/U235.h5\n", - " Reading U238 from /Users/brittanygrayson/nndc_hdf5/U238.h5\n", - " Reading O16 from /Users/brittanygrayson/nndc_hdf5/O16.h5\n", - " Reading Zr90 from /Users/brittanygrayson/nndc_hdf5/Zr90.h5\n", - " Reading Zr91 from /Users/brittanygrayson/nndc_hdf5/Zr91.h5\n", - " Reading Zr92 from /Users/brittanygrayson/nndc_hdf5/Zr92.h5\n", - " Reading Zr94 from /Users/brittanygrayson/nndc_hdf5/Zr94.h5\n", - " Reading Zr96 from /Users/brittanygrayson/nndc_hdf5/Zr96.h5\n", - " Reading H1 from /Users/brittanygrayson/nndc_hdf5/H1.h5\n", - " Reading O17 from /Users/brittanygrayson/nndc_hdf5/O17.h5\n", - " Reading c_H_in_H2O from /Users/brittanygrayson/nndc_hdf5/c_H_in_H2O.h5\n", + " Reading U235 from /home/smharper/openmc/data/nndc_hdf5/U235.h5\n", + " Reading U238 from /home/smharper/openmc/data/nndc_hdf5/U238.h5\n", + " Reading O16 from /home/smharper/openmc/data/nndc_hdf5/O16.h5\n", + " Reading Zr90 from /home/smharper/openmc/data/nndc_hdf5/Zr90.h5\n", + " Reading Zr91 from /home/smharper/openmc/data/nndc_hdf5/Zr91.h5\n", + " Reading Zr92 from /home/smharper/openmc/data/nndc_hdf5/Zr92.h5\n", + " Reading Zr94 from /home/smharper/openmc/data/nndc_hdf5/Zr94.h5\n", + " Reading Zr96 from /home/smharper/openmc/data/nndc_hdf5/Zr96.h5\n", + " Reading H1 from /home/smharper/openmc/data/nndc_hdf5/H1.h5\n", + " Reading O17 from /home/smharper/openmc/data/nndc_hdf5/O17.h5\n", + " Reading c_H_in_H2O from /home/smharper/openmc/data/nndc_hdf5/c_H_in_H2O.h5\n", " Maximum neutron transport energy: 2.00000E+07 eV for U235\n", " Reading tallies XML file...\n", - " ERROR: Tally filters must be specified independently of tallies in a \n", - " element. The element itself should have a list of filters that\n", - " apply, e.g., 1 2 where 1 and 2 are the IDs of filters\n", - " specified outside of .\n", - "application called MPI_Abort(MPI_COMM_WORLD, -1) - process 0\n", - "[unset]: write_line error; fd=-1 buf=:cmd=abort exitcode=-1\n", - ":\n", - "system msg for write_line failure : Bad file descriptor\n" + " Building neighboring cells lists for each surface...\n", + " Initializing source particles...\n", + "\n", + " ====================> K EIGENVALUE SIMULATION <====================\n", + "\n", + " Bat./Gen. k Average k \n", + " ========= ======== ==================== \n", + " 1/1 1.32572 \n", + " 2/1 1.46138 \n", + " 3/1 1.46068 \n", + " 4/1 1.39592 \n", + " 5/1 1.37519 \n", + " 6/1 1.38777 \n", + " 7/1 1.50242 \n", + " 8/1 1.42042 \n", + " 9/1 1.47458 \n", + " 10/1 1.49148 \n", + " 11/1 1.39339 \n", + " 12/1 1.40637 1.39988 +/- 0.00649\n", + " 13/1 1.42972 1.40983 +/- 0.01063\n", + " 14/1 1.46319 1.42317 +/- 0.01531\n", + " 15/1 1.41538 1.42161 +/- 0.01196\n", + " 16/1 1.38163 1.41494 +/- 0.01182\n", + " 17/1 1.41257 1.41461 +/- 0.01000\n", + " 18/1 1.43455 1.41710 +/- 0.00901\n", + " 19/1 1.33136 1.40757 +/- 0.01241\n", + " 20/1 1.41560 1.40837 +/- 0.01113\n", + " 21/1 1.38911 1.40662 +/- 0.01021\n", + " 22/1 1.28621 1.39659 +/- 0.01370\n", + " 23/1 1.45693 1.40123 +/- 0.01343\n", + " 24/1 1.46839 1.40603 +/- 0.01333\n", + " 25/1 1.46738 1.41012 +/- 0.01306\n", + " 26/1 1.43977 1.41197 +/- 0.01236\n", + " 27/1 1.44066 1.41366 +/- 0.01173\n", + " 28/1 1.39358 1.41254 +/- 0.01112\n", + " 29/1 1.39142 1.41143 +/- 0.01057\n", + " 30/1 1.38525 1.41012 +/- 0.01012\n", + " 31/1 1.38025 1.40870 +/- 0.00973\n", + " 32/1 1.45348 1.41074 +/- 0.00949\n", + " 33/1 1.35893 1.40848 +/- 0.00935\n", + " 34/1 1.32332 1.40493 +/- 0.00963\n", + " 35/1 1.46285 1.40725 +/- 0.00952\n", + " 36/1 1.33760 1.40457 +/- 0.00953\n", + " 37/1 1.41117 1.40482 +/- 0.00917\n", + " 38/1 1.45574 1.40664 +/- 0.00903\n", + " 39/1 1.43472 1.40760 +/- 0.00876\n", + " 40/1 1.30110 1.40405 +/- 0.00918\n", + " 41/1 1.41765 1.40449 +/- 0.00889\n", + " 42/1 1.45300 1.40601 +/- 0.00874\n", + " 43/1 1.40491 1.40597 +/- 0.00847\n", + " 44/1 1.42053 1.40640 +/- 0.00823\n", + " 45/1 1.38805 1.40588 +/- 0.00801\n", + " 46/1 1.34293 1.40413 +/- 0.00798\n", + " 47/1 1.35441 1.40279 +/- 0.00787\n", + " 48/1 1.29370 1.39991 +/- 0.00818\n", + " 49/1 1.48467 1.40209 +/- 0.00826\n", + " 50/1 1.41759 1.40248 +/- 0.00806\n", + " 51/1 1.37151 1.40172 +/- 0.00790\n", + " 52/1 1.42403 1.40225 +/- 0.00773\n", + " 53/1 1.38826 1.40193 +/- 0.00755\n", + " 54/1 1.48944 1.40392 +/- 0.00764\n", + " 55/1 1.41452 1.40415 +/- 0.00747\n", + " 56/1 1.47337 1.40566 +/- 0.00746\n", + " 57/1 1.35700 1.40462 +/- 0.00738\n", + " 58/1 1.40305 1.40459 +/- 0.00722\n", + " 59/1 1.41608 1.40482 +/- 0.00708\n", + " 60/1 1.47254 1.40618 +/- 0.00706\n", + " 61/1 1.36847 1.40544 +/- 0.00696\n", + " 62/1 1.34103 1.40420 +/- 0.00694\n", + " 63/1 1.39510 1.40403 +/- 0.00681\n", + " 64/1 1.40228 1.40399 +/- 0.00668\n", + " 65/1 1.29401 1.40200 +/- 0.00686\n", + " 66/1 1.42693 1.40244 +/- 0.00675\n", + " 67/1 1.36447 1.40177 +/- 0.00666\n", + " 68/1 1.37498 1.40131 +/- 0.00656\n", + " 69/1 1.36958 1.40077 +/- 0.00647\n", + " 70/1 1.38585 1.40053 +/- 0.00637\n", + " 71/1 1.42133 1.40087 +/- 0.00627\n", + " 72/1 1.44900 1.40164 +/- 0.00622\n", + " 73/1 1.37696 1.40125 +/- 0.00613\n", + " 74/1 1.48851 1.40261 +/- 0.00619\n", + " 75/1 1.38933 1.40241 +/- 0.00610\n", + " 76/1 1.41780 1.40264 +/- 0.00601\n", + " 77/1 1.41054 1.40276 +/- 0.00592\n", + " 78/1 1.38194 1.40246 +/- 0.00584\n", + " 79/1 1.38446 1.40219 +/- 0.00576\n", + " 80/1 1.37504 1.40181 +/- 0.00569\n", + " 81/1 1.40550 1.40186 +/- 0.00561\n", + " 82/1 1.49785 1.40319 +/- 0.00569\n", + " 83/1 1.35613 1.40255 +/- 0.00565\n", + " 84/1 1.41786 1.40275 +/- 0.00557\n", + " 85/1 1.38444 1.40251 +/- 0.00550\n", + " 86/1 1.40459 1.40254 +/- 0.00543\n", + " 87/1 1.39923 1.40249 +/- 0.00536\n", + " 88/1 1.44540 1.40304 +/- 0.00532\n", + " 89/1 1.45962 1.40376 +/- 0.00530\n", + " 90/1 1.37057 1.40335 +/- 0.00525\n", + " 91/1 1.38115 1.40307 +/- 0.00519\n", + " 92/1 1.35758 1.40252 +/- 0.00516\n", + " 93/1 1.34508 1.40182 +/- 0.00514\n", + " 94/1 1.31471 1.40079 +/- 0.00519\n", + " 95/1 1.41434 1.40095 +/- 0.00513\n", + " 96/1 1.33895 1.40023 +/- 0.00512\n", + " 97/1 1.44716 1.40077 +/- 0.00509\n", + " 98/1 1.38455 1.40058 +/- 0.00503\n", + " 99/1 1.52127 1.40194 +/- 0.00516\n", + " 100/1 1.35488 1.40141 +/- 0.00513\n", + " Creating state point statepoint.100.h5...\n", + "\n", + " =======================> TIMING STATISTICS <=======================\n", + "\n", + " Total time for initialization = 5.3000E-01 seconds\n", + " Reading cross sections = 4.7425E-01 seconds\n", + " Total time in simulation = 5.9503E+00 seconds\n", + " Time in transport only = 5.6693E+00 seconds\n", + " Time in inactive batches = 5.9508E-01 seconds\n", + " Time in active batches = 5.3552E+00 seconds\n", + " Time synchronizing fission bank = 4.5385E-03 seconds\n", + " Sampling source sites = 2.4558E-03 seconds\n", + " SEND/RECV source sites = 1.0922E-03 seconds\n", + " Time accumulating tallies = 4.2963E-04 seconds\n", + " Total time for finalization = 4.4542E-04 seconds\n", + " Total time elapsed = 6.4846E+00 seconds\n", + " Calculation Rate (inactive) = 16804.5 neutrons/second\n", + " Calculation Rate (active) = 16806.1 neutrons/second\n", + "\n", + " ============================> RESULTS <============================\n", + "\n", + " k-effective (Collision) = 1.39737 +/- 0.00470\n", + " k-effective (Track-length) = 1.40141 +/- 0.00513\n", + " k-effective (Absorption) = 1.39596 +/- 0.00308\n", + " Combined k-effective = 1.39719 +/- 0.00286\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", + "\n" ] }, { "data": { "text/plain": [ - "255" + "0" ] }, "execution_count": 42, @@ -1210,13 +1387,23 @@ { "cell_type": "code", "execution_count": 43, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "cat: tallies.out: No such file or directory\r\n" + "\r\n", + " ============================> TALLY 1 <============================\r\n", + "\r\n", + " Cell 1\r\n", + " U235\r\n", + " Total Reaction Rate 0.731003 +/- 2.53759E-03\r\n", + " Fission Rate 0.547587 +/- 2.10114E-03\r\n", + " Absorption Rate 0.657406 +/- 2.45390E-03\r\n", + " (n,gamma) 0.109821 +/- 3.68054E-04\r\n" ] } ], @@ -1259,7 +1446,9 @@ { "cell_type": "code", "execution_count": 45, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -1294,7 +1483,9 @@ { "cell_type": "code", "execution_count": 46, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "name": "stdout", @@ -1328,9 +1519,9 @@ " | The OpenMC Monte Carlo Code\n", " Copyright | 2011-2017 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.9.0\n", - " Git SHA1 | a8bee7757465e4617eb76e0c72f20cdf57771dd9\n", - " Date/Time | 2017-08-03 13:37:50\n", + " Version | 0.8.0\n", + " Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n", + " Date/Time | 2017-04-13 17:18:01\n", " MPI Processes | 1\n", " OpenMP Threads | 4\n", "\n", @@ -1382,16 +1573,10 @@ { "cell_type": "code", "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/bin/sh: convert: command not found\r\n" - ] - } - ], + "metadata": { + "collapsed": false + }, + "outputs": [], "source": [ "!convert pinplot.ppm pinplot.png" ] @@ -1407,12 +1592,13 @@ "cell_type": "code", "execution_count": 48, "metadata": { + "collapsed": false, "scrolled": false }, "outputs": [ { "data": { - "image/png": "pinplot.png", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///8AAP9yEhL//wDh\n3HbeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUSBp1cqOcAAAKHSURBVGje7dlLjoJAEAZgMrNj\n4z28hKcYFhzBU5hwAFfsTQwJcIqJyzkNcU3SAw2j/agq4Zegk3Rv9Ut3VSt0V0XR/PE1ewQSSCCB\nBHIfSTGT1Hrk00lSj6OYTOrbyCeS/Z3U00hqiLqaQpLaGsUEsrdJ/Zg4kxDTRI8m8afxyPi9Q/ca\nZRLtkiFd5fDqjcmkRdQkZbRR3WhHk4tkCD7aqWFEWyIBDtHBHzaj6OYhEuAQvaxPdRtN7K/MJnpd\nB2WMb39lNunzVW5M0sZezmziTTJOk7Mk8SYZpylY0q/rtLOJ+nBXZpE+xZ+OUM3WSbNF+nW5kygV\nO8GYJPGD/0tAwZCUWtewsoohe3Jdw8p4ciKEuvCk+ySjSGPHb5A++g1F2q0Vv0FSJhQdTEUSLhQ3\nGJtkNGk4woUyBJMTJGFD0cEUNGFC0cFQJJVJRZOMIw1N9mz0Q/wE6RLGRa+UmTKTlDyJKSIlzE7Z\nM0RKmJ0ykxx50lJEyrGdZZPwCdNZJkgpkZgg3bYIQv3cN8YgJ4lcSHKWyNUnibgtemOKRchRIq1P\nUnEn9V5WixBpJ/vtd8mDzTe3/zkiiv4XswQ5yeTikXoCyRcgZ5lcX0YymTSBWOTR08J8XqxK3jZj\n70ze9l+5xkMJeFqu9Rhf45UEvCvXeYkDp4t1jj3AeQw79c0+WwInWOicPPs0Dpz5gZvFOlce4C6G\n3PiAeyVwewXuyMBNHLjvA1UFpHYBVEiAOgxQ7QFqSkjlCqiPAVU4oNYHVBSRuiVQHQVqsEClF6kn\nA1VroDaOVOCBOj/QTUB6FkBnBOm/AF0eoJeEdKyAvhjSfUN6fEgnEehX6pkK7pP/1+ENJJBAAnkF\n+QXfoOhE52QgVwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNC0xM1QxNzoxODowMS0wNDowMJXP\nFDgAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDQtMTNUMTc6MTg6MDEtMDQ6MDDkkqyEAAAAAElF\nTkSuQmCC\n", "text/plain": [ "" ] @@ -1437,46 +1623,24 @@ { "cell_type": "code", "execution_count": 49, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { - "ename": "FileNotFoundError", - "evalue": "[Errno 2] No such file or directory: 'convert'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mopenmc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot_inline\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/Users/brittanygrayson/openmc/openmc/executor.py\u001b[0m in \u001b[0;36mplot_inline\u001b[0;34m(plots, openmc_exec, cwd, convert_exec)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0mppm_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'plot_{}.ppm'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0mpng_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mppm_file\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreplace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'.ppm'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'.png'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mconvert_exec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mppm_file\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpng_file\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 87\u001b[0m \u001b[0mimages\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mImage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpng_file\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mimages\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36mcheck_call\u001b[0;34m(*popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 284\u001b[0m \u001b[0mcheck_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"ls\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-l\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 285\u001b[0m \"\"\"\n\u001b[0;32m--> 286\u001b[0;31m \u001b[0mretcode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mpopenargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 287\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mretcode\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 288\u001b[0m \u001b[0mcmd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"args\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36mcall\u001b[0;34m(timeout, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 265\u001b[0m \u001b[0mretcode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"ls\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"-l\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 266\u001b[0m \"\"\"\n\u001b[0;32m--> 267\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mPopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mpopenargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 268\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 269\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)\u001b[0m\n\u001b[1;32m 705\u001b[0m \u001b[0mc2pread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc2pwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 706\u001b[0m \u001b[0merrread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merrwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 707\u001b[0;31m restore_signals, start_new_session)\n\u001b[0m\u001b[1;32m 708\u001b[0m \u001b[0;32mexcept\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 709\u001b[0m \u001b[0;31m# Cleanup if the child failed starting.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/brittanygrayson/miniconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)\u001b[0m\n\u001b[1;32m 1324\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1325\u001b[0m \u001b[0merr_msg\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m': '\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0morig_executable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1326\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrno_num\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1327\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1328\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'convert'" - ] + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///8AAP9yEhL//wDh\n3HbeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUSCQ3jtXYAAAKHSURBVGje7dlLjoJAEAZgMrNj\n4z28hKcYFhzBU5hwAFfsTQwJcIqJyzkNcU3SAw2j/agq4Zegk3Rv9Ut3VSt0V0XR/PE1ewQSSCCB\nBHIfSTGT1Hrk00lSj6OYTOrbyCeS/Z3U00hqiLqaQpLaGsUEsrdJ/Zg4kxDTRI8m8afxyPi9Q/ca\nZRLtkiFd5fDqjcmkRdQkZbRR3WhHk4tkCD7aqWFEWyIBDtHBHzaj6OYhEuAQvaxPdRtN7K/MJnpd\nB2WMb39lNunzVW5M0sZezmziTTJOk7Mk8SYZpylY0q/rtLOJ+nBXZpE+xZ+OUM3WSbNF+nW5kygV\nO8GYJPGD/0tAwZCUWtewsoohe3Jdw8p4ciKEuvCk+ySjSGPHb5A++g1F2q0Vv0FSJhQdTEUSLhQ3\nGJtkNGk4woUyBJMTJGFD0cEUNGFC0cFQJJVJRZOMIw1N9mz0Q/wE6RLGRa+UmTKTlDyJKSIlzE7Z\nM0RKmJ0ykxx50lJEyrGdZZPwCdNZJkgpkZgg3bYIQv3cN8YgJ4lcSHKWyNUnibgtemOKRchRIq1P\nUnEn9V5WixBpJ/vtd8mDzTe3/zkiiv4XswQ5yeTikXoCyRcgZ5lcX0YymTSBWOTR08J8XqxK3jZj\n70ze9l+5xkMJeFqu9Rhf45UEvCvXeYkDp4t1jj3AeQw79c0+WwInWOicPPs0Dpz5gZvFOlce4C6G\n3PiAeyVwewXuyMBNHLjvA1UFpHYBVEiAOgxQ7QFqSkjlCqiPAVU4oNYHVBSRuiVQHQVqsEClF6kn\nA1VroDaOVOCBOj/QTUB6FkBnBOm/AF0eoJeEdKyAvhjSfUN6fEgnEehX6pkK7pP/1+ENJJBAAnkF\n+QXfoOhE52QgVwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNC0xM1QxNzoxODowOS0wNDowMKYg\nWl8AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDQtMTNUMTc6MTg6MDktMDQ6MDDXfeLjAAAAAElF\nTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ "openmc.plot_inline(p)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -1496,9 +1660,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.0" + "version": "3.5.2" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 0 } diff --git a/src/CTestTestfile.cmake b/src/CTestTestfile.cmake deleted file mode 100644 index fe4bf415a..000000000 --- a/src/CTestTestfile.cmake +++ /dev/null @@ -1,172 +0,0 @@ -# CMake generated Testfile for -# Source directory: /Users/brittanygrayson/openmc_develop/OpenMC -# Build directory: /Users/brittanygrayson/openmc_develop/OpenMC/src -# -# This file includes the relevant testing commands required for -# testing this directory and lists subdirectories to be tested as well. -add_test(test_asymmetric_lattice.py "/Users/brittanygrayson/miniconda3/bin/python" "test_asymmetric_lattice.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_asymmetric_lattice.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_asymmetric_lattice") -add_test(test_cmfd_feed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_cmfd_feed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_cmfd_feed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_cmfd_feed") -add_test(test_cmfd_nofeed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_cmfd_nofeed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_cmfd_nofeed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_cmfd_nofeed") -add_test(test_complex_cell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_complex_cell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_complex_cell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_complex_cell") -add_test(test_confidence_intervals.py "/Users/brittanygrayson/miniconda3/bin/python" "test_confidence_intervals.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_confidence_intervals.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_confidence_intervals") -add_test(test_create_fission_neutrons.py "/Users/brittanygrayson/miniconda3/bin/python" "test_create_fission_neutrons.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_create_fission_neutrons.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_create_fission_neutrons") -add_test(test_density.py "/Users/brittanygrayson/miniconda3/bin/python" "test_density.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_density.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_density") -add_test(test_diff_tally.py "/Users/brittanygrayson/miniconda3/bin/python" "test_diff_tally.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_diff_tally.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_diff_tally") -add_test(test_distribmat.py "/Users/brittanygrayson/miniconda3/bin/python" "test_distribmat.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_distribmat.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_distribmat") -add_test(test_eigenvalue_genperbatch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_eigenvalue_genperbatch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_eigenvalue_genperbatch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_eigenvalue_genperbatch") -add_test(test_eigenvalue_no_inactive.py "/Users/brittanygrayson/miniconda3/bin/python" "test_eigenvalue_no_inactive.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_eigenvalue_no_inactive.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_eigenvalue_no_inactive") -add_test(test_element_wo.py "/Users/brittanygrayson/miniconda3/bin/python" "test_element_wo.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_element_wo.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_element_wo") -add_test(test_energy_cutoff.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_cutoff.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_energy_cutoff.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_cutoff") -add_test(test_energy_grid.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_grid.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_energy_grid.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_grid") -add_test(test_energy_laws.py "/Users/brittanygrayson/miniconda3/bin/python" "test_energy_laws.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_energy_laws.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_energy_laws") -add_test(test_enrichment.py "/Users/brittanygrayson/miniconda3/bin/python" "test_enrichment.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_enrichment.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_enrichment") -add_test(test_entropy.py "/Users/brittanygrayson/miniconda3/bin/python" "test_entropy.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_entropy.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_entropy") -add_test(test_filter_distribcell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_distribcell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_filter_distribcell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_distribcell") -add_test(test_filter_energyfun.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_energyfun.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_filter_energyfun.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_energyfun") -add_test(test_filter_mesh.py "/Users/brittanygrayson/miniconda3/bin/python" "test_filter_mesh.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_filter_mesh.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_filter_mesh") -add_test(test_fixed_source.py "/Users/brittanygrayson/miniconda3/bin/python" "test_fixed_source.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_fixed_source.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_fixed_source") -add_test(test_infinite_cell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_infinite_cell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_infinite_cell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_infinite_cell") -add_test(test_iso_in_lab.py "/Users/brittanygrayson/miniconda3/bin/python" "test_iso_in_lab.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_iso_in_lab.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_iso_in_lab") -add_test(test_lattice.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_lattice.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice") -add_test(test_lattice_hex.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_hex.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_lattice_hex.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_hex") -add_test(test_lattice_mixed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_mixed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_lattice_mixed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_mixed") -add_test(test_lattice_multiple.py "/Users/brittanygrayson/miniconda3/bin/python" "test_lattice_multiple.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_lattice_multiple.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_lattice_multiple") -add_test(test_mg_basic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_basic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_basic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_basic") -add_test(test_mg_convert.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_convert.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_convert.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_convert") -add_test(test_mg_legendre.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_legendre.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_legendre.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_legendre") -add_test(test_mg_max_order.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_max_order.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_max_order.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_max_order") -add_test(test_mg_nuclide.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_nuclide.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_nuclide.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_nuclide") -add_test(test_mg_survival_biasing.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_survival_biasing.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_survival_biasing.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_survival_biasing") -add_test(test_mg_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mg_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mg_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mg_tallies") -add_test(test_mgxs_library_ce_to_mg.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_ce_to_mg.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_ce_to_mg.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_ce_to_mg") -add_test(test_mgxs_library_condense.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_condense.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_condense.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_condense") -add_test(test_mgxs_library_distribcell.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_distribcell.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_distribcell.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_distribcell") -add_test(test_mgxs_library_hdf5.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_hdf5.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_hdf5.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_hdf5") -add_test(test_mgxs_library_mesh.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_mesh.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_mesh.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_mesh") -add_test(test_mgxs_library_no_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_no_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_no_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_no_nuclides") -add_test(test_mgxs_library_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_mgxs_library_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_mgxs_library_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_mgxs_library_nuclides") -add_test(test_multipole.py "/Users/brittanygrayson/miniconda3/bin/python" "test_multipole.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_multipole.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_multipole") -add_test(test_output.py "/Users/brittanygrayson/miniconda3/bin/python" "test_output.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_output.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_output") -add_test(test_particle_restart_eigval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_particle_restart_eigval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_particle_restart_eigval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_particle_restart_eigval") -add_test(test_particle_restart_fixed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_particle_restart_fixed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_particle_restart_fixed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_particle_restart_fixed") -add_test(test_periodic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_periodic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_periodic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_periodic") -add_test(test_plot.py "/Users/brittanygrayson/miniconda3/bin/python" "test_plot.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_plot.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_plot") -add_test(test_ptables_off.py "/Users/brittanygrayson/miniconda3/bin/python" "test_ptables_off.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_ptables_off.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_ptables_off") -add_test(test_quadric_surfaces.py "/Users/brittanygrayson/miniconda3/bin/python" "test_quadric_surfaces.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_quadric_surfaces.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_quadric_surfaces") -add_test(test_reflective_plane.py "/Users/brittanygrayson/miniconda3/bin/python" "test_reflective_plane.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_reflective_plane.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_reflective_plane") -add_test(test_resonance_scattering.py "/Users/brittanygrayson/miniconda3/bin/python" "test_resonance_scattering.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_resonance_scattering.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_resonance_scattering") -add_test(test_rotation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_rotation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_rotation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_rotation") -add_test(test_salphabeta.py "/Users/brittanygrayson/miniconda3/bin/python" "test_salphabeta.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_salphabeta.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_salphabeta") -add_test(test_score_current.py "/Users/brittanygrayson/miniconda3/bin/python" "test_score_current.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_score_current.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_score_current") -add_test(test_seed.py "/Users/brittanygrayson/miniconda3/bin/python" "test_seed.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_seed.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_seed") -add_test(test_source.py "/Users/brittanygrayson/miniconda3/bin/python" "test_source.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_source.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_source") -add_test(test_source_file.py "/Users/brittanygrayson/miniconda3/bin/python" "test_source_file.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_source_file.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_source_file") -add_test(test_sourcepoint_batch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_batch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_sourcepoint_batch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_batch") -add_test(test_sourcepoint_latest.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_latest.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_sourcepoint_latest.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_latest") -add_test(test_sourcepoint_restart.py "/Users/brittanygrayson/miniconda3/bin/python" "test_sourcepoint_restart.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_sourcepoint_restart.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_sourcepoint_restart") -add_test(test_statepoint_batch.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_batch.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_statepoint_batch.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_batch") -add_test(test_statepoint_restart.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_restart.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_statepoint_restart.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_restart") -add_test(test_statepoint_sourcesep.py "/Users/brittanygrayson/miniconda3/bin/python" "test_statepoint_sourcesep.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_statepoint_sourcesep.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_statepoint_sourcesep") -add_test(test_surface_tally.py "/Users/brittanygrayson/miniconda3/bin/python" "test_surface_tally.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_surface_tally.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_surface_tally") -add_test(test_survival_biasing.py "/Users/brittanygrayson/miniconda3/bin/python" "test_survival_biasing.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_survival_biasing.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_survival_biasing") -add_test(test_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tallies") -add_test(test_tally_aggregation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_aggregation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tally_aggregation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_aggregation") -add_test(test_tally_arithmetic.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_arithmetic.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tally_arithmetic.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_arithmetic") -add_test(test_tally_assumesep.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_assumesep.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tally_assumesep.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_assumesep") -add_test(test_tally_nuclides.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_nuclides.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tally_nuclides.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_nuclides") -add_test(test_tally_slice_merge.py "/Users/brittanygrayson/miniconda3/bin/python" "test_tally_slice_merge.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_tally_slice_merge.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_tally_slice_merge") -add_test(test_trace.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trace.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_trace.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trace") -add_test(test_track_output.py "/Users/brittanygrayson/miniconda3/bin/python" "test_track_output.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_track_output.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_track_output") -add_test(test_translation.py "/Users/brittanygrayson/miniconda3/bin/python" "test_translation.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_translation.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_translation") -add_test(test_trigger_batch_interval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_batch_interval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_trigger_batch_interval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_batch_interval") -add_test(test_trigger_no_batch_interval.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_no_batch_interval.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_trigger_no_batch_interval.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_no_batch_interval") -add_test(test_trigger_no_status.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_no_status.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_trigger_no_status.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_no_status") -add_test(test_trigger_tallies.py "/Users/brittanygrayson/miniconda3/bin/python" "test_trigger_tallies.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_trigger_tallies.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_trigger_tallies") -add_test(test_triso.py "/Users/brittanygrayson/miniconda3/bin/python" "test_triso.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_triso.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_triso") -add_test(test_uniform_fs.py "/Users/brittanygrayson/miniconda3/bin/python" "test_uniform_fs.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_uniform_fs.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_uniform_fs") -add_test(test_universe.py "/Users/brittanygrayson/miniconda3/bin/python" "test_universe.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_universe.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_universe") -add_test(test_void.py "/Users/brittanygrayson/miniconda3/bin/python" "test_void.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_void.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_void") -add_test(test_volume_calc.py "/Users/brittanygrayson/miniconda3/bin/python" "test_volume_calc.py" "--exe" "/Users/brittanygrayson/openmc_develop/OpenMC/src/bin/openmc" "--mpi_exec" "/bin/mpiexec") -set_tests_properties(test_volume_calc.py PROPERTIES WORKING_DIRECTORY "/Users/brittanygrayson/openmc_develop/OpenMC/tests/test_volume_calc") diff --git a/src/DartConfiguration.tcl b/src/DartConfiguration.tcl deleted file mode 100644 index 7534bcf7e..000000000 --- a/src/DartConfiguration.tcl +++ /dev/null @@ -1,112 +0,0 @@ -# This file is configured by CMake automatically as DartConfiguration.tcl -# If you choose not to use CMake, this file may be hand configured, by -# filling in the required variables. - - -# Configuration directories and files -SourceDirectory: /Users/brittanygrayson/openmc_develop/OpenMC -BuildDirectory: /Users/brittanygrayson/openmc_develop/OpenMC/src - -# Where to place the cost data store -CostDataFile: - -# Site is something like machine.domain, i.e. pragmatic.crd -Site: Brittanys-Air.PK5001Z - -# Build name is osname-revision-compiler, i.e. Linux-2.4.2-2smp-c++ -BuildName: Darwin-mpicxx - -# Submission information -IsCDash: TRUE -CDashVersion: -QueryCDashVersion: -DropSite: openmc.mit.edu -DropLocation: /cdash/submit.php?project=OpenMC -DropSiteUser: -DropSitePassword: -DropSiteMode: -DropMethod: http -TriggerSite: -ScpCommand: /usr/bin/scp - -# Dashboard start time -NightlyStartTime: 01:00:00 UTC - -# Commands for the build/test/submit cycle -ConfigureCommand: "/Applications/CMake.app/Contents/bin/cmake" "/Users/brittanygrayson/openmc_develop/OpenMC" -MakeCommand: /Applications/CMake.app/Contents/bin/cmake --build . --config "${CTEST_CONFIGURATION_TYPE}" -- -i -DefaultCTestConfigurationType: Release - -# version control -UpdateVersionOnly: - -# CVS options -# Default is "-d -P -A" -CVSCommand: CVSCOMMAND-NOTFOUND -CVSUpdateOptions: -d -A -P - -# Subversion options -SVNCommand: /usr/bin/svn -SVNOptions: -SVNUpdateOptions: - -# Git options -GITCommand: /usr/bin/git -GITInitSubmodules: -GITUpdateOptions: -GITUpdateCustom: - -# Perforce options -P4Command: P4COMMAND-NOTFOUND -P4Client: -P4Options: -P4UpdateOptions: -P4UpdateCustom: - -# Generic update command -UpdateCommand: /usr/bin/git -UpdateOptions: -UpdateType: git - -# Compiler info -Compiler: /Users/brittanygrayson/miniconda3/bin/mpicxx -CompilerVersion: 3.9.0 - -# Dynamic analysis (MemCheck) -PurifyCommand: -ValgrindCommand: -ValgrindCommandOptions: -MemoryCheckType: -MemoryCheckSanitizerOptions: -MemoryCheckCommand: MEMORYCHECK_COMMAND-NOTFOUND -MemoryCheckCommandOptions: -MemoryCheckSuppressionFile: - -# Coverage -CoverageCommand: /Users/brittanygrayson/miniconda3/bin/gcov -CoverageExtraFlags: -l - -# Cluster commands -SlurmBatchCommand: SLURM_SBATCH_COMMAND-NOTFOUND -SlurmRunCommand: SLURM_SRUN_COMMAND-NOTFOUND - -# Testing options -# TimeOut is the amount of time in seconds to wait for processes -# to complete during testing. After TimeOut seconds, the -# process will be summarily terminated. -# Currently set to 25 minutes -TimeOut: 1500 - -# During parallel testing CTest will not start a new test if doing -# so would cause the system load to exceed this value. -TestLoad: - -UseLaunchers: -CurlOptions: -# warning, if you add new options here that have to do with submit, -# you have to update cmCTestSubmitCommand.cxx - -# For CTest submissions that timeout, these options -# specify behavior for retrying the submission -CTestSubmitRetryDelay: 5 -CTestSubmitRetryCount: 3 diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index f14ff0dc3..000000000 --- a/src/Makefile +++ /dev/null @@ -1,3328 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.8 - -# Default target executed when no arguments are given to make. -default_target: all - -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - - -# Remove some rules from gmake that .SUFFIXES does not remove. -SUFFIXES = - -.SUFFIXES: .hpux_make_needs_suffix_list - - -# Suppress display of executed commands. -$(VERBOSE).SILENT: - - -# A target that is always out of date. -cmake_force: - -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /Applications/CMake.app/Contents/bin/cmake - -# The command to remove a file. -RM = /Applications/CMake.app/Contents/bin/cmake -E remove -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /Users/brittanygrayson/openmc_develop/OpenMC - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /Users/brittanygrayson/openmc_develop/OpenMC/src - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target install/strip -install/strip: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip - -# Special rule for the target install/strip -install/strip/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip/fast - -# Special rule for the target install/local -install/local: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local - -# Special rule for the target install/local -install/local/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /Applications/CMake.app/Contents/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local/fast - -# Special rule for the target list_install_components -list_install_components: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" -.PHONY : list_install_components - -# Special rule for the target list_install_components -list_install_components/fast: list_install_components - -.PHONY : list_install_components/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." - /Applications/CMake.app/Contents/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache - -.PHONY : rebuild_cache/fast - -# Special rule for the target install -install: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /Applications/CMake.app/Contents/bin/cmake -P cmake_install.cmake -.PHONY : install - -# Special rule for the target install -install/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /Applications/CMake.app/Contents/bin/cmake -P cmake_install.cmake -.PHONY : install/fast - -# Special rule for the target test -test: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." - /Applications/CMake.app/Contents/bin/ctest --force-new-ctest-process $(ARGS) -.PHONY : test - -# Special rule for the target test -test/fast: test - -.PHONY : test/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." - /Applications/CMake.app/Contents/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache - -.PHONY : edit_cache/fast - -# The main all target -all: cmake_check_build_system - $(CMAKE_COMMAND) -E cmake_progress_start /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles/progress.marks - $(MAKE) -f CMakeFiles/Makefile2 all - $(CMAKE_COMMAND) -E cmake_progress_start /Users/brittanygrayson/openmc_develop/OpenMC/src/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - $(MAKE) -f CMakeFiles/Makefile2 clean -.PHONY : clean - -# The main clean target -clean/fast: clean - -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - $(MAKE) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - $(MAKE) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -#============================================================================= -# Target rules for targets named ContinuousCoverage - -# Build rule for target. -ContinuousCoverage: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousCoverage -.PHONY : ContinuousCoverage - -# fast build rule for target. -ContinuousCoverage/fast: - $(MAKE) -f CMakeFiles/ContinuousCoverage.dir/build.make CMakeFiles/ContinuousCoverage.dir/build -.PHONY : ContinuousCoverage/fast - -#============================================================================= -# Target rules for targets named ContinuousBuild - -# Build rule for target. -ContinuousBuild: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousBuild -.PHONY : ContinuousBuild - -# fast build rule for target. -ContinuousBuild/fast: - $(MAKE) -f CMakeFiles/ContinuousBuild.dir/build.make CMakeFiles/ContinuousBuild.dir/build -.PHONY : ContinuousBuild/fast - -#============================================================================= -# Target rules for targets named ContinuousUpdate - -# Build rule for target. -ContinuousUpdate: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousUpdate -.PHONY : ContinuousUpdate - -# fast build rule for target. -ContinuousUpdate/fast: - $(MAKE) -f CMakeFiles/ContinuousUpdate.dir/build.make CMakeFiles/ContinuousUpdate.dir/build -.PHONY : ContinuousUpdate/fast - -#============================================================================= -# Target rules for targets named ContinuousStart - -# Build rule for target. -ContinuousStart: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousStart -.PHONY : ContinuousStart - -# fast build rule for target. -ContinuousStart/fast: - $(MAKE) -f CMakeFiles/ContinuousStart.dir/build.make CMakeFiles/ContinuousStart.dir/build -.PHONY : ContinuousStart/fast - -#============================================================================= -# Target rules for targets named ExperimentalSubmit - -# Build rule for target. -ExperimentalSubmit: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalSubmit -.PHONY : ExperimentalSubmit - -# fast build rule for target. -ExperimentalSubmit/fast: - $(MAKE) -f CMakeFiles/ExperimentalSubmit.dir/build.make CMakeFiles/ExperimentalSubmit.dir/build -.PHONY : ExperimentalSubmit/fast - -#============================================================================= -# Target rules for targets named ExperimentalBuild - -# Build rule for target. -ExperimentalBuild: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalBuild -.PHONY : ExperimentalBuild - -# fast build rule for target. -ExperimentalBuild/fast: - $(MAKE) -f CMakeFiles/ExperimentalBuild.dir/build.make CMakeFiles/ExperimentalBuild.dir/build -.PHONY : ExperimentalBuild/fast - -#============================================================================= -# Target rules for targets named ExperimentalCoverage - -# Build rule for target. -ExperimentalCoverage: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalCoverage -.PHONY : ExperimentalCoverage - -# fast build rule for target. -ExperimentalCoverage/fast: - $(MAKE) -f CMakeFiles/ExperimentalCoverage.dir/build.make CMakeFiles/ExperimentalCoverage.dir/build -.PHONY : ExperimentalCoverage/fast - -#============================================================================= -# Target rules for targets named ExperimentalUpdate - -# Build rule for target. -ExperimentalUpdate: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalUpdate -.PHONY : ExperimentalUpdate - -# fast build rule for target. -ExperimentalUpdate/fast: - $(MAKE) -f CMakeFiles/ExperimentalUpdate.dir/build.make CMakeFiles/ExperimentalUpdate.dir/build -.PHONY : ExperimentalUpdate/fast - -#============================================================================= -# Target rules for targets named ExperimentalStart - -# Build rule for target. -ExperimentalStart: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalStart -.PHONY : ExperimentalStart - -# fast build rule for target. -ExperimentalStart/fast: - $(MAKE) -f CMakeFiles/ExperimentalStart.dir/build.make CMakeFiles/ExperimentalStart.dir/build -.PHONY : ExperimentalStart/fast - -#============================================================================= -# Target rules for targets named NightlyMemCheck - -# Build rule for target. -NightlyMemCheck: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyMemCheck -.PHONY : NightlyMemCheck - -# fast build rule for target. -NightlyMemCheck/fast: - $(MAKE) -f CMakeFiles/NightlyMemCheck.dir/build.make CMakeFiles/NightlyMemCheck.dir/build -.PHONY : NightlyMemCheck/fast - -#============================================================================= -# Target rules for targets named ExperimentalConfigure - -# Build rule for target. -ExperimentalConfigure: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalConfigure -.PHONY : ExperimentalConfigure - -# fast build rule for target. -ExperimentalConfigure/fast: - $(MAKE) -f CMakeFiles/ExperimentalConfigure.dir/build.make CMakeFiles/ExperimentalConfigure.dir/build -.PHONY : ExperimentalConfigure/fast - -#============================================================================= -# Target rules for targets named NightlyCoverage - -# Build rule for target. -NightlyCoverage: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyCoverage -.PHONY : NightlyCoverage - -# fast build rule for target. -NightlyCoverage/fast: - $(MAKE) -f CMakeFiles/NightlyCoverage.dir/build.make CMakeFiles/NightlyCoverage.dir/build -.PHONY : NightlyCoverage/fast - -#============================================================================= -# Target rules for targets named NightlyTest - -# Build rule for target. -NightlyTest: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyTest -.PHONY : NightlyTest - -# fast build rule for target. -NightlyTest/fast: - $(MAKE) -f CMakeFiles/NightlyTest.dir/build.make CMakeFiles/NightlyTest.dir/build -.PHONY : NightlyTest/fast - -#============================================================================= -# Target rules for targets named NightlyConfigure - -# Build rule for target. -NightlyConfigure: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyConfigure -.PHONY : NightlyConfigure - -# fast build rule for target. -NightlyConfigure/fast: - $(MAKE) -f CMakeFiles/NightlyConfigure.dir/build.make CMakeFiles/NightlyConfigure.dir/build -.PHONY : NightlyConfigure/fast - -#============================================================================= -# Target rules for targets named openmc - -# Build rule for target. -openmc: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 openmc -.PHONY : openmc - -# fast build rule for target. -openmc/fast: - $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/build -.PHONY : openmc/fast - -#============================================================================= -# Target rules for targets named Continuous - -# Build rule for target. -Continuous: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 Continuous -.PHONY : Continuous - -# fast build rule for target. -Continuous/fast: - $(MAKE) -f CMakeFiles/Continuous.dir/build.make CMakeFiles/Continuous.dir/build -.PHONY : Continuous/fast - -#============================================================================= -# Target rules for targets named NightlyStart - -# Build rule for target. -NightlyStart: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyStart -.PHONY : NightlyStart - -# fast build rule for target. -NightlyStart/fast: - $(MAKE) -f CMakeFiles/NightlyStart.dir/build.make CMakeFiles/NightlyStart.dir/build -.PHONY : NightlyStart/fast - -#============================================================================= -# Target rules for targets named Nightly - -# Build rule for target. -Nightly: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 Nightly -.PHONY : Nightly - -# fast build rule for target. -Nightly/fast: - $(MAKE) -f CMakeFiles/Nightly.dir/build.make CMakeFiles/Nightly.dir/build -.PHONY : Nightly/fast - -#============================================================================= -# Target rules for targets named ExperimentalMemCheck - -# Build rule for target. -ExperimentalMemCheck: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalMemCheck -.PHONY : ExperimentalMemCheck - -# fast build rule for target. -ExperimentalMemCheck/fast: - $(MAKE) -f CMakeFiles/ExperimentalMemCheck.dir/build.make CMakeFiles/ExperimentalMemCheck.dir/build -.PHONY : ExperimentalMemCheck/fast - -#============================================================================= -# Target rules for targets named libopenmc - -# Build rule for target. -libopenmc: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 libopenmc -.PHONY : libopenmc - -# fast build rule for target. -libopenmc/fast: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/build -.PHONY : libopenmc/fast - -#============================================================================= -# Target rules for targets named ContinuousConfigure - -# Build rule for target. -ContinuousConfigure: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousConfigure -.PHONY : ContinuousConfigure - -# fast build rule for target. -ContinuousConfigure/fast: - $(MAKE) -f CMakeFiles/ContinuousConfigure.dir/build.make CMakeFiles/ContinuousConfigure.dir/build -.PHONY : ContinuousConfigure/fast - -#============================================================================= -# Target rules for targets named NightlyMemoryCheck - -# Build rule for target. -NightlyMemoryCheck: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyMemoryCheck -.PHONY : NightlyMemoryCheck - -# fast build rule for target. -NightlyMemoryCheck/fast: - $(MAKE) -f CMakeFiles/NightlyMemoryCheck.dir/build.make CMakeFiles/NightlyMemoryCheck.dir/build -.PHONY : NightlyMemoryCheck/fast - -#============================================================================= -# Target rules for targets named Experimental - -# Build rule for target. -Experimental: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 Experimental -.PHONY : Experimental - -# fast build rule for target. -Experimental/fast: - $(MAKE) -f CMakeFiles/Experimental.dir/build.make CMakeFiles/Experimental.dir/build -.PHONY : Experimental/fast - -#============================================================================= -# Target rules for targets named ContinuousSubmit - -# Build rule for target. -ContinuousSubmit: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousSubmit -.PHONY : ContinuousSubmit - -# fast build rule for target. -ContinuousSubmit/fast: - $(MAKE) -f CMakeFiles/ContinuousSubmit.dir/build.make CMakeFiles/ContinuousSubmit.dir/build -.PHONY : ContinuousSubmit/fast - -#============================================================================= -# Target rules for targets named ExperimentalTest - -# Build rule for target. -ExperimentalTest: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ExperimentalTest -.PHONY : ExperimentalTest - -# fast build rule for target. -ExperimentalTest/fast: - $(MAKE) -f CMakeFiles/ExperimentalTest.dir/build.make CMakeFiles/ExperimentalTest.dir/build -.PHONY : ExperimentalTest/fast - -#============================================================================= -# Target rules for targets named NightlySubmit - -# Build rule for target. -NightlySubmit: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlySubmit -.PHONY : NightlySubmit - -# fast build rule for target. -NightlySubmit/fast: - $(MAKE) -f CMakeFiles/NightlySubmit.dir/build.make CMakeFiles/NightlySubmit.dir/build -.PHONY : NightlySubmit/fast - -#============================================================================= -# Target rules for targets named ContinuousTest - -# Build rule for target. -ContinuousTest: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousTest -.PHONY : ContinuousTest - -# fast build rule for target. -ContinuousTest/fast: - $(MAKE) -f CMakeFiles/ContinuousTest.dir/build.make CMakeFiles/ContinuousTest.dir/build -.PHONY : ContinuousTest/fast - -#============================================================================= -# Target rules for targets named faddeeva - -# Build rule for target. -faddeeva: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 faddeeva -.PHONY : faddeeva - -# fast build rule for target. -faddeeva/fast: - $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/build -.PHONY : faddeeva/fast - -#============================================================================= -# Target rules for targets named ContinuousMemCheck - -# Build rule for target. -ContinuousMemCheck: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 ContinuousMemCheck -.PHONY : ContinuousMemCheck - -# fast build rule for target. -ContinuousMemCheck/fast: - $(MAKE) -f CMakeFiles/ContinuousMemCheck.dir/build.make CMakeFiles/ContinuousMemCheck.dir/build -.PHONY : ContinuousMemCheck/fast - -#============================================================================= -# Target rules for targets named NightlyBuild - -# Build rule for target. -NightlyBuild: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyBuild -.PHONY : NightlyBuild - -# fast build rule for target. -NightlyBuild/fast: - $(MAKE) -f CMakeFiles/NightlyBuild.dir/build.make CMakeFiles/NightlyBuild.dir/build -.PHONY : NightlyBuild/fast - -#============================================================================= -# Target rules for targets named pugixml_fortran - -# Build rule for target. -pugixml_fortran: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 pugixml_fortran -.PHONY : pugixml_fortran - -# fast build rule for target. -pugixml_fortran/fast: - $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/build -.PHONY : pugixml_fortran/fast - -#============================================================================= -# Target rules for targets named NightlyUpdate - -# Build rule for target. -NightlyUpdate: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 NightlyUpdate -.PHONY : NightlyUpdate - -# fast build rule for target. -NightlyUpdate/fast: - $(MAKE) -f CMakeFiles/NightlyUpdate.dir/build.make CMakeFiles/NightlyUpdate.dir/build -.PHONY : NightlyUpdate/fast - -#============================================================================= -# Target rules for targets named pugixml - -# Build rule for target. -pugixml: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 pugixml -.PHONY : pugixml - -# fast build rule for target. -pugixml/fast: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/build -.PHONY : pugixml/fast - -algorithm.o: algorithm.F90.o - -.PHONY : algorithm.o - -# target to build an object file -algorithm.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.o -.PHONY : algorithm.F90.o - -algorithm.i: algorithm.F90.i - -.PHONY : algorithm.i - -# target to preprocess a source file -algorithm.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.i -.PHONY : algorithm.F90.i - -algorithm.s: algorithm.F90.s - -.PHONY : algorithm.s - -# target to generate assembly for a file -algorithm.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/algorithm.F90.s -.PHONY : algorithm.F90.s - -angle_distribution.o: angle_distribution.F90.o - -.PHONY : angle_distribution.o - -# target to build an object file -angle_distribution.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.o -.PHONY : angle_distribution.F90.o - -angle_distribution.i: angle_distribution.F90.i - -.PHONY : angle_distribution.i - -# target to preprocess a source file -angle_distribution.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.i -.PHONY : angle_distribution.F90.i - -angle_distribution.s: angle_distribution.F90.s - -.PHONY : angle_distribution.s - -# target to generate assembly for a file -angle_distribution.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angle_distribution.F90.s -.PHONY : angle_distribution.F90.s - -angleenergy_header.o: angleenergy_header.F90.o - -.PHONY : angleenergy_header.o - -# target to build an object file -angleenergy_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.o -.PHONY : angleenergy_header.F90.o - -angleenergy_header.i: angleenergy_header.F90.i - -.PHONY : angleenergy_header.i - -# target to preprocess a source file -angleenergy_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.i -.PHONY : angleenergy_header.F90.i - -angleenergy_header.s: angleenergy_header.F90.s - -.PHONY : angleenergy_header.s - -# target to generate assembly for a file -angleenergy_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/angleenergy_header.F90.s -.PHONY : angleenergy_header.F90.s - -api.o: api.F90.o - -.PHONY : api.o - -# target to build an object file -api.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/api.F90.o -.PHONY : api.F90.o - -api.i: api.F90.i - -.PHONY : api.i - -# target to preprocess a source file -api.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/api.F90.i -.PHONY : api.F90.i - -api.s: api.F90.s - -.PHONY : api.s - -# target to generate assembly for a file -api.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/api.F90.s -.PHONY : api.F90.s - -bank_header.o: bank_header.F90.o - -.PHONY : bank_header.o - -# target to build an object file -bank_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.o -.PHONY : bank_header.F90.o - -bank_header.i: bank_header.F90.i - -.PHONY : bank_header.i - -# target to preprocess a source file -bank_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.i -.PHONY : bank_header.F90.i - -bank_header.s: bank_header.F90.s - -.PHONY : bank_header.s - -# target to generate assembly for a file -bank_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/bank_header.F90.s -.PHONY : bank_header.F90.s - -cmfd_data.o: cmfd_data.F90.o - -.PHONY : cmfd_data.o - -# target to build an object file -cmfd_data.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.o -.PHONY : cmfd_data.F90.o - -cmfd_data.i: cmfd_data.F90.i - -.PHONY : cmfd_data.i - -# target to preprocess a source file -cmfd_data.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.i -.PHONY : cmfd_data.F90.i - -cmfd_data.s: cmfd_data.F90.s - -.PHONY : cmfd_data.s - -# target to generate assembly for a file -cmfd_data.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_data.F90.s -.PHONY : cmfd_data.F90.s - -cmfd_execute.o: cmfd_execute.F90.o - -.PHONY : cmfd_execute.o - -# target to build an object file -cmfd_execute.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.o -.PHONY : cmfd_execute.F90.o - -cmfd_execute.i: cmfd_execute.F90.i - -.PHONY : cmfd_execute.i - -# target to preprocess a source file -cmfd_execute.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.i -.PHONY : cmfd_execute.F90.i - -cmfd_execute.s: cmfd_execute.F90.s - -.PHONY : cmfd_execute.s - -# target to generate assembly for a file -cmfd_execute.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_execute.F90.s -.PHONY : cmfd_execute.F90.s - -cmfd_header.o: cmfd_header.F90.o - -.PHONY : cmfd_header.o - -# target to build an object file -cmfd_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.o -.PHONY : cmfd_header.F90.o - -cmfd_header.i: cmfd_header.F90.i - -.PHONY : cmfd_header.i - -# target to preprocess a source file -cmfd_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.i -.PHONY : cmfd_header.F90.i - -cmfd_header.s: cmfd_header.F90.s - -.PHONY : cmfd_header.s - -# target to generate assembly for a file -cmfd_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_header.F90.s -.PHONY : cmfd_header.F90.s - -cmfd_input.o: cmfd_input.F90.o - -.PHONY : cmfd_input.o - -# target to build an object file -cmfd_input.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.o -.PHONY : cmfd_input.F90.o - -cmfd_input.i: cmfd_input.F90.i - -.PHONY : cmfd_input.i - -# target to preprocess a source file -cmfd_input.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.i -.PHONY : cmfd_input.F90.i - -cmfd_input.s: cmfd_input.F90.s - -.PHONY : cmfd_input.s - -# target to generate assembly for a file -cmfd_input.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_input.F90.s -.PHONY : cmfd_input.F90.s - -cmfd_loss_operator.o: cmfd_loss_operator.F90.o - -.PHONY : cmfd_loss_operator.o - -# target to build an object file -cmfd_loss_operator.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.o -.PHONY : cmfd_loss_operator.F90.o - -cmfd_loss_operator.i: cmfd_loss_operator.F90.i - -.PHONY : cmfd_loss_operator.i - -# target to preprocess a source file -cmfd_loss_operator.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.i -.PHONY : cmfd_loss_operator.F90.i - -cmfd_loss_operator.s: cmfd_loss_operator.F90.s - -.PHONY : cmfd_loss_operator.s - -# target to generate assembly for a file -cmfd_loss_operator.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_loss_operator.F90.s -.PHONY : cmfd_loss_operator.F90.s - -cmfd_prod_operator.o: cmfd_prod_operator.F90.o - -.PHONY : cmfd_prod_operator.o - -# target to build an object file -cmfd_prod_operator.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.o -.PHONY : cmfd_prod_operator.F90.o - -cmfd_prod_operator.i: cmfd_prod_operator.F90.i - -.PHONY : cmfd_prod_operator.i - -# target to preprocess a source file -cmfd_prod_operator.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.i -.PHONY : cmfd_prod_operator.F90.i - -cmfd_prod_operator.s: cmfd_prod_operator.F90.s - -.PHONY : cmfd_prod_operator.s - -# target to generate assembly for a file -cmfd_prod_operator.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_prod_operator.F90.s -.PHONY : cmfd_prod_operator.F90.s - -cmfd_solver.o: cmfd_solver.F90.o - -.PHONY : cmfd_solver.o - -# target to build an object file -cmfd_solver.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.o -.PHONY : cmfd_solver.F90.o - -cmfd_solver.i: cmfd_solver.F90.i - -.PHONY : cmfd_solver.i - -# target to preprocess a source file -cmfd_solver.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.i -.PHONY : cmfd_solver.F90.i - -cmfd_solver.s: cmfd_solver.F90.s - -.PHONY : cmfd_solver.s - -# target to generate assembly for a file -cmfd_solver.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cmfd_solver.F90.s -.PHONY : cmfd_solver.F90.s - -constants.o: constants.F90.o - -.PHONY : constants.o - -# target to build an object file -constants.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.o -.PHONY : constants.F90.o - -constants.i: constants.F90.i - -.PHONY : constants.i - -# target to preprocess a source file -constants.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.i -.PHONY : constants.F90.i - -constants.s: constants.F90.s - -.PHONY : constants.s - -# target to generate assembly for a file -constants.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/constants.F90.s -.PHONY : constants.F90.s - -cross_section.o: cross_section.F90.o - -.PHONY : cross_section.o - -# target to build an object file -cross_section.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.o -.PHONY : cross_section.F90.o - -cross_section.i: cross_section.F90.i - -.PHONY : cross_section.i - -# target to preprocess a source file -cross_section.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.i -.PHONY : cross_section.F90.i - -cross_section.s: cross_section.F90.s - -.PHONY : cross_section.s - -# target to generate assembly for a file -cross_section.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/cross_section.F90.s -.PHONY : cross_section.F90.s - -dict_header.o: dict_header.F90.o - -.PHONY : dict_header.o - -# target to build an object file -dict_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.o -.PHONY : dict_header.F90.o - -dict_header.i: dict_header.F90.i - -.PHONY : dict_header.i - -# target to preprocess a source file -dict_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.i -.PHONY : dict_header.F90.i - -dict_header.s: dict_header.F90.s - -.PHONY : dict_header.s - -# target to generate assembly for a file -dict_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/dict_header.F90.s -.PHONY : dict_header.F90.s - -distribution_multivariate.o: distribution_multivariate.F90.o - -.PHONY : distribution_multivariate.o - -# target to build an object file -distribution_multivariate.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.o -.PHONY : distribution_multivariate.F90.o - -distribution_multivariate.i: distribution_multivariate.F90.i - -.PHONY : distribution_multivariate.i - -# target to preprocess a source file -distribution_multivariate.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.i -.PHONY : distribution_multivariate.F90.i - -distribution_multivariate.s: distribution_multivariate.F90.s - -.PHONY : distribution_multivariate.s - -# target to generate assembly for a file -distribution_multivariate.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_multivariate.F90.s -.PHONY : distribution_multivariate.F90.s - -distribution_univariate.o: distribution_univariate.F90.o - -.PHONY : distribution_univariate.o - -# target to build an object file -distribution_univariate.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.o -.PHONY : distribution_univariate.F90.o - -distribution_univariate.i: distribution_univariate.F90.i - -.PHONY : distribution_univariate.i - -# target to preprocess a source file -distribution_univariate.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.i -.PHONY : distribution_univariate.F90.i - -distribution_univariate.s: distribution_univariate.F90.s - -.PHONY : distribution_univariate.s - -# target to generate assembly for a file -distribution_univariate.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/distribution_univariate.F90.s -.PHONY : distribution_univariate.F90.s - -doppler.o: doppler.F90.o - -.PHONY : doppler.o - -# target to build an object file -doppler.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.o -.PHONY : doppler.F90.o - -doppler.i: doppler.F90.i - -.PHONY : doppler.i - -# target to preprocess a source file -doppler.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.i -.PHONY : doppler.F90.i - -doppler.s: doppler.F90.s - -.PHONY : doppler.s - -# target to generate assembly for a file -doppler.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/doppler.F90.s -.PHONY : doppler.F90.s - -eigenvalue.o: eigenvalue.F90.o - -.PHONY : eigenvalue.o - -# target to build an object file -eigenvalue.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.o -.PHONY : eigenvalue.F90.o - -eigenvalue.i: eigenvalue.F90.i - -.PHONY : eigenvalue.i - -# target to preprocess a source file -eigenvalue.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.i -.PHONY : eigenvalue.F90.i - -eigenvalue.s: eigenvalue.F90.s - -.PHONY : eigenvalue.s - -# target to generate assembly for a file -eigenvalue.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/eigenvalue.F90.s -.PHONY : eigenvalue.F90.s - -endf.o: endf.F90.o - -.PHONY : endf.o - -# target to build an object file -endf.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.o -.PHONY : endf.F90.o - -endf.i: endf.F90.i - -.PHONY : endf.i - -# target to preprocess a source file -endf.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.i -.PHONY : endf.F90.i - -endf.s: endf.F90.s - -.PHONY : endf.s - -# target to generate assembly for a file -endf.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf.F90.s -.PHONY : endf.F90.s - -endf_header.o: endf_header.F90.o - -.PHONY : endf_header.o - -# target to build an object file -endf_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.o -.PHONY : endf_header.F90.o - -endf_header.i: endf_header.F90.i - -.PHONY : endf_header.i - -# target to preprocess a source file -endf_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.i -.PHONY : endf_header.F90.i - -endf_header.s: endf_header.F90.s - -.PHONY : endf_header.s - -# target to generate assembly for a file -endf_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/endf_header.F90.s -.PHONY : endf_header.F90.s - -energy_distribution.o: energy_distribution.F90.o - -.PHONY : energy_distribution.o - -# target to build an object file -energy_distribution.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.o -.PHONY : energy_distribution.F90.o - -energy_distribution.i: energy_distribution.F90.i - -.PHONY : energy_distribution.i - -# target to preprocess a source file -energy_distribution.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.i -.PHONY : energy_distribution.F90.i - -energy_distribution.s: energy_distribution.F90.s - -.PHONY : energy_distribution.s - -# target to generate assembly for a file -energy_distribution.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/energy_distribution.F90.s -.PHONY : energy_distribution.F90.s - -error.o: error.F90.o - -.PHONY : error.o - -# target to build an object file -error.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.o -.PHONY : error.F90.o - -error.i: error.F90.i - -.PHONY : error.i - -# target to preprocess a source file -error.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.i -.PHONY : error.F90.i - -error.s: error.F90.s - -.PHONY : error.s - -# target to generate assembly for a file -error.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/error.F90.s -.PHONY : error.F90.s - -faddeeva/Faddeeva.o: faddeeva/Faddeeva.c.o - -.PHONY : faddeeva/Faddeeva.o - -# target to build an object file -faddeeva/Faddeeva.c.o: - $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.o -.PHONY : faddeeva/Faddeeva.c.o - -faddeeva/Faddeeva.i: faddeeva/Faddeeva.c.i - -.PHONY : faddeeva/Faddeeva.i - -# target to preprocess a source file -faddeeva/Faddeeva.c.i: - $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.i -.PHONY : faddeeva/Faddeeva.c.i - -faddeeva/Faddeeva.s: faddeeva/Faddeeva.c.s - -.PHONY : faddeeva/Faddeeva.s - -# target to generate assembly for a file -faddeeva/Faddeeva.c.s: - $(MAKE) -f CMakeFiles/faddeeva.dir/build.make CMakeFiles/faddeeva.dir/faddeeva/Faddeeva.c.s -.PHONY : faddeeva/Faddeeva.c.s - -geometry.o: geometry.F90.o - -.PHONY : geometry.o - -# target to build an object file -geometry.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.o -.PHONY : geometry.F90.o - -geometry.i: geometry.F90.i - -.PHONY : geometry.i - -# target to preprocess a source file -geometry.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.i -.PHONY : geometry.F90.i - -geometry.s: geometry.F90.s - -.PHONY : geometry.s - -# target to generate assembly for a file -geometry.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry.F90.s -.PHONY : geometry.F90.s - -geometry_header.o: geometry_header.F90.o - -.PHONY : geometry_header.o - -# target to build an object file -geometry_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.o -.PHONY : geometry_header.F90.o - -geometry_header.i: geometry_header.F90.i - -.PHONY : geometry_header.i - -# target to preprocess a source file -geometry_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.i -.PHONY : geometry_header.F90.i - -geometry_header.s: geometry_header.F90.s - -.PHONY : geometry_header.s - -# target to generate assembly for a file -geometry_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/geometry_header.F90.s -.PHONY : geometry_header.F90.s - -global.o: global.F90.o - -.PHONY : global.o - -# target to build an object file -global.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.o -.PHONY : global.F90.o - -global.i: global.F90.i - -.PHONY : global.i - -# target to preprocess a source file -global.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.i -.PHONY : global.F90.i - -global.s: global.F90.s - -.PHONY : global.s - -# target to generate assembly for a file -global.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/global.F90.s -.PHONY : global.F90.s - -hdf5_interface.o: hdf5_interface.F90.o - -.PHONY : hdf5_interface.o - -# target to build an object file -hdf5_interface.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.o -.PHONY : hdf5_interface.F90.o - -hdf5_interface.i: hdf5_interface.F90.i - -.PHONY : hdf5_interface.i - -# target to preprocess a source file -hdf5_interface.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.i -.PHONY : hdf5_interface.F90.i - -hdf5_interface.s: hdf5_interface.F90.s - -.PHONY : hdf5_interface.s - -# target to generate assembly for a file -hdf5_interface.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/hdf5_interface.F90.s -.PHONY : hdf5_interface.F90.s - -initialize.o: initialize.F90.o - -.PHONY : initialize.o - -# target to build an object file -initialize.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.o -.PHONY : initialize.F90.o - -initialize.i: initialize.F90.i - -.PHONY : initialize.i - -# target to preprocess a source file -initialize.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.i -.PHONY : initialize.F90.i - -initialize.s: initialize.F90.s - -.PHONY : initialize.s - -# target to generate assembly for a file -initialize.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/initialize.F90.s -.PHONY : initialize.F90.s - -input_xml.o: input_xml.F90.o - -.PHONY : input_xml.o - -# target to build an object file -input_xml.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.o -.PHONY : input_xml.F90.o - -input_xml.i: input_xml.F90.i - -.PHONY : input_xml.i - -# target to preprocess a source file -input_xml.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.i -.PHONY : input_xml.F90.i - -input_xml.s: input_xml.F90.s - -.PHONY : input_xml.s - -# target to generate assembly for a file -input_xml.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/input_xml.F90.s -.PHONY : input_xml.F90.s - -list_header.o: list_header.F90.o - -.PHONY : list_header.o - -# target to build an object file -list_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.o -.PHONY : list_header.F90.o - -list_header.i: list_header.F90.i - -.PHONY : list_header.i - -# target to preprocess a source file -list_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.i -.PHONY : list_header.F90.i - -list_header.s: list_header.F90.s - -.PHONY : list_header.s - -# target to generate assembly for a file -list_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/list_header.F90.s -.PHONY : list_header.F90.s - -main.o: main.F90.o - -.PHONY : main.o - -# target to build an object file -main.F90.o: - $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.o -.PHONY : main.F90.o - -main.i: main.F90.i - -.PHONY : main.i - -# target to preprocess a source file -main.F90.i: - $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.i -.PHONY : main.F90.i - -main.s: main.F90.s - -.PHONY : main.s - -# target to generate assembly for a file -main.F90.s: - $(MAKE) -f CMakeFiles/openmc.dir/build.make CMakeFiles/openmc.dir/main.F90.s -.PHONY : main.F90.s - -material_header.o: material_header.F90.o - -.PHONY : material_header.o - -# target to build an object file -material_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.o -.PHONY : material_header.F90.o - -material_header.i: material_header.F90.i - -.PHONY : material_header.i - -# target to preprocess a source file -material_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.i -.PHONY : material_header.F90.i - -material_header.s: material_header.F90.s - -.PHONY : material_header.s - -# target to generate assembly for a file -material_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/material_header.F90.s -.PHONY : material_header.F90.s - -math.o: math.F90.o - -.PHONY : math.o - -# target to build an object file -math.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.o -.PHONY : math.F90.o - -math.i: math.F90.i - -.PHONY : math.i - -# target to preprocess a source file -math.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.i -.PHONY : math.F90.i - -math.s: math.F90.s - -.PHONY : math.s - -# target to generate assembly for a file -math.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/math.F90.s -.PHONY : math.F90.s - -matrix_header.o: matrix_header.F90.o - -.PHONY : matrix_header.o - -# target to build an object file -matrix_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.o -.PHONY : matrix_header.F90.o - -matrix_header.i: matrix_header.F90.i - -.PHONY : matrix_header.i - -# target to preprocess a source file -matrix_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.i -.PHONY : matrix_header.F90.i - -matrix_header.s: matrix_header.F90.s - -.PHONY : matrix_header.s - -# target to generate assembly for a file -matrix_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/matrix_header.F90.s -.PHONY : matrix_header.F90.s - -mesh.o: mesh.F90.o - -.PHONY : mesh.o - -# target to build an object file -mesh.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.o -.PHONY : mesh.F90.o - -mesh.i: mesh.F90.i - -.PHONY : mesh.i - -# target to preprocess a source file -mesh.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.i -.PHONY : mesh.F90.i - -mesh.s: mesh.F90.s - -.PHONY : mesh.s - -# target to generate assembly for a file -mesh.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh.F90.s -.PHONY : mesh.F90.s - -mesh_header.o: mesh_header.F90.o - -.PHONY : mesh_header.o - -# target to build an object file -mesh_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.o -.PHONY : mesh_header.F90.o - -mesh_header.i: mesh_header.F90.i - -.PHONY : mesh_header.i - -# target to preprocess a source file -mesh_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.i -.PHONY : mesh_header.F90.i - -mesh_header.s: mesh_header.F90.s - -.PHONY : mesh_header.s - -# target to generate assembly for a file -mesh_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mesh_header.F90.s -.PHONY : mesh_header.F90.s - -message_passing.o: message_passing.F90.o - -.PHONY : message_passing.o - -# target to build an object file -message_passing.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.o -.PHONY : message_passing.F90.o - -message_passing.i: message_passing.F90.i - -.PHONY : message_passing.i - -# target to preprocess a source file -message_passing.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.i -.PHONY : message_passing.F90.i - -message_passing.s: message_passing.F90.s - -.PHONY : message_passing.s - -# target to generate assembly for a file -message_passing.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/message_passing.F90.s -.PHONY : message_passing.F90.s - -mgxs_data.o: mgxs_data.F90.o - -.PHONY : mgxs_data.o - -# target to build an object file -mgxs_data.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.o -.PHONY : mgxs_data.F90.o - -mgxs_data.i: mgxs_data.F90.i - -.PHONY : mgxs_data.i - -# target to preprocess a source file -mgxs_data.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.i -.PHONY : mgxs_data.F90.i - -mgxs_data.s: mgxs_data.F90.s - -.PHONY : mgxs_data.s - -# target to generate assembly for a file -mgxs_data.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_data.F90.s -.PHONY : mgxs_data.F90.s - -mgxs_header.o: mgxs_header.F90.o - -.PHONY : mgxs_header.o - -# target to build an object file -mgxs_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.o -.PHONY : mgxs_header.F90.o - -mgxs_header.i: mgxs_header.F90.i - -.PHONY : mgxs_header.i - -# target to preprocess a source file -mgxs_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.i -.PHONY : mgxs_header.F90.i - -mgxs_header.s: mgxs_header.F90.s - -.PHONY : mgxs_header.s - -# target to generate assembly for a file -mgxs_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/mgxs_header.F90.s -.PHONY : mgxs_header.F90.s - -multipole.o: multipole.F90.o - -.PHONY : multipole.o - -# target to build an object file -multipole.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.o -.PHONY : multipole.F90.o - -multipole.i: multipole.F90.i - -.PHONY : multipole.i - -# target to preprocess a source file -multipole.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.i -.PHONY : multipole.F90.i - -multipole.s: multipole.F90.s - -.PHONY : multipole.s - -# target to generate assembly for a file -multipole.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole.F90.s -.PHONY : multipole.F90.s - -multipole_header.o: multipole_header.F90.o - -.PHONY : multipole_header.o - -# target to build an object file -multipole_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.o -.PHONY : multipole_header.F90.o - -multipole_header.i: multipole_header.F90.i - -.PHONY : multipole_header.i - -# target to preprocess a source file -multipole_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.i -.PHONY : multipole_header.F90.i - -multipole_header.s: multipole_header.F90.s - -.PHONY : multipole_header.s - -# target to generate assembly for a file -multipole_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/multipole_header.F90.s -.PHONY : multipole_header.F90.s - -nuclide_header.o: nuclide_header.F90.o - -.PHONY : nuclide_header.o - -# target to build an object file -nuclide_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.o -.PHONY : nuclide_header.F90.o - -nuclide_header.i: nuclide_header.F90.i - -.PHONY : nuclide_header.i - -# target to preprocess a source file -nuclide_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.i -.PHONY : nuclide_header.F90.i - -nuclide_header.s: nuclide_header.F90.s - -.PHONY : nuclide_header.s - -# target to generate assembly for a file -nuclide_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/nuclide_header.F90.s -.PHONY : nuclide_header.F90.s - -output.o: output.F90.o - -.PHONY : output.o - -# target to build an object file -output.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.o -.PHONY : output.F90.o - -output.i: output.F90.i - -.PHONY : output.i - -# target to preprocess a source file -output.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.i -.PHONY : output.F90.i - -output.s: output.F90.s - -.PHONY : output.s - -# target to generate assembly for a file -output.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/output.F90.s -.PHONY : output.F90.s - -particle_header.o: particle_header.F90.o - -.PHONY : particle_header.o - -# target to build an object file -particle_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.o -.PHONY : particle_header.F90.o - -particle_header.i: particle_header.F90.i - -.PHONY : particle_header.i - -# target to preprocess a source file -particle_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.i -.PHONY : particle_header.F90.i - -particle_header.s: particle_header.F90.s - -.PHONY : particle_header.s - -# target to generate assembly for a file -particle_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_header.F90.s -.PHONY : particle_header.F90.s - -particle_restart.o: particle_restart.F90.o - -.PHONY : particle_restart.o - -# target to build an object file -particle_restart.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.o -.PHONY : particle_restart.F90.o - -particle_restart.i: particle_restart.F90.i - -.PHONY : particle_restart.i - -# target to preprocess a source file -particle_restart.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.i -.PHONY : particle_restart.F90.i - -particle_restart.s: particle_restart.F90.s - -.PHONY : particle_restart.s - -# target to generate assembly for a file -particle_restart.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart.F90.s -.PHONY : particle_restart.F90.s - -particle_restart_write.o: particle_restart_write.F90.o - -.PHONY : particle_restart_write.o - -# target to build an object file -particle_restart_write.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.o -.PHONY : particle_restart_write.F90.o - -particle_restart_write.i: particle_restart_write.F90.i - -.PHONY : particle_restart_write.i - -# target to preprocess a source file -particle_restart_write.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.i -.PHONY : particle_restart_write.F90.i - -particle_restart_write.s: particle_restart_write.F90.s - -.PHONY : particle_restart_write.s - -# target to generate assembly for a file -particle_restart_write.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/particle_restart_write.F90.s -.PHONY : particle_restart_write.F90.s - -physics.o: physics.F90.o - -.PHONY : physics.o - -# target to build an object file -physics.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.o -.PHONY : physics.F90.o - -physics.i: physics.F90.i - -.PHONY : physics.i - -# target to preprocess a source file -physics.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.i -.PHONY : physics.F90.i - -physics.s: physics.F90.s - -.PHONY : physics.s - -# target to generate assembly for a file -physics.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics.F90.s -.PHONY : physics.F90.s - -physics_common.o: physics_common.F90.o - -.PHONY : physics_common.o - -# target to build an object file -physics_common.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.o -.PHONY : physics_common.F90.o - -physics_common.i: physics_common.F90.i - -.PHONY : physics_common.i - -# target to preprocess a source file -physics_common.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.i -.PHONY : physics_common.F90.i - -physics_common.s: physics_common.F90.s - -.PHONY : physics_common.s - -# target to generate assembly for a file -physics_common.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_common.F90.s -.PHONY : physics_common.F90.s - -physics_mg.o: physics_mg.F90.o - -.PHONY : physics_mg.o - -# target to build an object file -physics_mg.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.o -.PHONY : physics_mg.F90.o - -physics_mg.i: physics_mg.F90.i - -.PHONY : physics_mg.i - -# target to preprocess a source file -physics_mg.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.i -.PHONY : physics_mg.F90.i - -physics_mg.s: physics_mg.F90.s - -.PHONY : physics_mg.s - -# target to generate assembly for a file -physics_mg.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/physics_mg.F90.s -.PHONY : physics_mg.F90.s - -plot.o: plot.F90.o - -.PHONY : plot.o - -# target to build an object file -plot.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.o -.PHONY : plot.F90.o - -plot.i: plot.F90.i - -.PHONY : plot.i - -# target to preprocess a source file -plot.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.i -.PHONY : plot.F90.i - -plot.s: plot.F90.s - -.PHONY : plot.s - -# target to generate assembly for a file -plot.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot.F90.s -.PHONY : plot.F90.s - -plot_header.o: plot_header.F90.o - -.PHONY : plot_header.o - -# target to build an object file -plot_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.o -.PHONY : plot_header.F90.o - -plot_header.i: plot_header.F90.i - -.PHONY : plot_header.i - -# target to preprocess a source file -plot_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.i -.PHONY : plot_header.F90.i - -plot_header.s: plot_header.F90.s - -.PHONY : plot_header.s - -# target to generate assembly for a file -plot_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/plot_header.F90.s -.PHONY : plot_header.F90.s - -product_header.o: product_header.F90.o - -.PHONY : product_header.o - -# target to build an object file -product_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.o -.PHONY : product_header.F90.o - -product_header.i: product_header.F90.i - -.PHONY : product_header.i - -# target to preprocess a source file -product_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.i -.PHONY : product_header.F90.i - -product_header.s: product_header.F90.s - -.PHONY : product_header.s - -# target to generate assembly for a file -product_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/product_header.F90.s -.PHONY : product_header.F90.s - -progress_header.o: progress_header.F90.o - -.PHONY : progress_header.o - -# target to build an object file -progress_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.o -.PHONY : progress_header.F90.o - -progress_header.i: progress_header.F90.i - -.PHONY : progress_header.i - -# target to preprocess a source file -progress_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.i -.PHONY : progress_header.F90.i - -progress_header.s: progress_header.F90.s - -.PHONY : progress_header.s - -# target to generate assembly for a file -progress_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/progress_header.F90.s -.PHONY : progress_header.F90.s - -pugixml/pugixml.o: pugixml/pugixml.cpp.o - -.PHONY : pugixml/pugixml.o - -# target to build an object file -pugixml/pugixml.cpp.o: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.o -.PHONY : pugixml/pugixml.cpp.o - -pugixml/pugixml.i: pugixml/pugixml.cpp.i - -.PHONY : pugixml/pugixml.i - -# target to preprocess a source file -pugixml/pugixml.cpp.i: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.i -.PHONY : pugixml/pugixml.cpp.i - -pugixml/pugixml.s: pugixml/pugixml.cpp.s - -.PHONY : pugixml/pugixml.s - -# target to generate assembly for a file -pugixml/pugixml.cpp.s: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml.cpp.s -.PHONY : pugixml/pugixml.cpp.s - -pugixml/pugixml_c.o: pugixml/pugixml_c.cpp.o - -.PHONY : pugixml/pugixml_c.o - -# target to build an object file -pugixml/pugixml_c.cpp.o: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.o -.PHONY : pugixml/pugixml_c.cpp.o - -pugixml/pugixml_c.i: pugixml/pugixml_c.cpp.i - -.PHONY : pugixml/pugixml_c.i - -# target to preprocess a source file -pugixml/pugixml_c.cpp.i: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.i -.PHONY : pugixml/pugixml_c.cpp.i - -pugixml/pugixml_c.s: pugixml/pugixml_c.cpp.s - -.PHONY : pugixml/pugixml_c.s - -# target to generate assembly for a file -pugixml/pugixml_c.cpp.s: - $(MAKE) -f CMakeFiles/pugixml.dir/build.make CMakeFiles/pugixml.dir/pugixml/pugixml_c.cpp.s -.PHONY : pugixml/pugixml_c.cpp.s - -pugixml/pugixml_f.o: pugixml/pugixml_f.F90.o - -.PHONY : pugixml/pugixml_f.o - -# target to build an object file -pugixml/pugixml_f.F90.o: - $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.o -.PHONY : pugixml/pugixml_f.F90.o - -pugixml/pugixml_f.i: pugixml/pugixml_f.F90.i - -.PHONY : pugixml/pugixml_f.i - -# target to preprocess a source file -pugixml/pugixml_f.F90.i: - $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.i -.PHONY : pugixml/pugixml_f.F90.i - -pugixml/pugixml_f.s: pugixml/pugixml_f.F90.s - -.PHONY : pugixml/pugixml_f.s - -# target to generate assembly for a file -pugixml/pugixml_f.F90.s: - $(MAKE) -f CMakeFiles/pugixml_fortran.dir/build.make CMakeFiles/pugixml_fortran.dir/pugixml/pugixml_f.F90.s -.PHONY : pugixml/pugixml_f.F90.s - -random_lcg.o: random_lcg.F90.o - -.PHONY : random_lcg.o - -# target to build an object file -random_lcg.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.o -.PHONY : random_lcg.F90.o - -random_lcg.i: random_lcg.F90.i - -.PHONY : random_lcg.i - -# target to preprocess a source file -random_lcg.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.i -.PHONY : random_lcg.F90.i - -random_lcg.s: random_lcg.F90.s - -.PHONY : random_lcg.s - -# target to generate assembly for a file -random_lcg.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/random_lcg.F90.s -.PHONY : random_lcg.F90.s - -reaction_header.o: reaction_header.F90.o - -.PHONY : reaction_header.o - -# target to build an object file -reaction_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.o -.PHONY : reaction_header.F90.o - -reaction_header.i: reaction_header.F90.i - -.PHONY : reaction_header.i - -# target to preprocess a source file -reaction_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.i -.PHONY : reaction_header.F90.i - -reaction_header.s: reaction_header.F90.s - -.PHONY : reaction_header.s - -# target to generate assembly for a file -reaction_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/reaction_header.F90.s -.PHONY : reaction_header.F90.s - -sab_header.o: sab_header.F90.o - -.PHONY : sab_header.o - -# target to build an object file -sab_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.o -.PHONY : sab_header.F90.o - -sab_header.i: sab_header.F90.i - -.PHONY : sab_header.i - -# target to preprocess a source file -sab_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.i -.PHONY : sab_header.F90.i - -sab_header.s: sab_header.F90.s - -.PHONY : sab_header.s - -# target to generate assembly for a file -sab_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/sab_header.F90.s -.PHONY : sab_header.F90.s - -scattdata_header.o: scattdata_header.F90.o - -.PHONY : scattdata_header.o - -# target to build an object file -scattdata_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.o -.PHONY : scattdata_header.F90.o - -scattdata_header.i: scattdata_header.F90.i - -.PHONY : scattdata_header.i - -# target to preprocess a source file -scattdata_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.i -.PHONY : scattdata_header.F90.i - -scattdata_header.s: scattdata_header.F90.s - -.PHONY : scattdata_header.s - -# target to generate assembly for a file -scattdata_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/scattdata_header.F90.s -.PHONY : scattdata_header.F90.s - -secondary_correlated.o: secondary_correlated.F90.o - -.PHONY : secondary_correlated.o - -# target to build an object file -secondary_correlated.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.o -.PHONY : secondary_correlated.F90.o - -secondary_correlated.i: secondary_correlated.F90.i - -.PHONY : secondary_correlated.i - -# target to preprocess a source file -secondary_correlated.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.i -.PHONY : secondary_correlated.F90.i - -secondary_correlated.s: secondary_correlated.F90.s - -.PHONY : secondary_correlated.s - -# target to generate assembly for a file -secondary_correlated.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_correlated.F90.s -.PHONY : secondary_correlated.F90.s - -secondary_kalbach.o: secondary_kalbach.F90.o - -.PHONY : secondary_kalbach.o - -# target to build an object file -secondary_kalbach.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.o -.PHONY : secondary_kalbach.F90.o - -secondary_kalbach.i: secondary_kalbach.F90.i - -.PHONY : secondary_kalbach.i - -# target to preprocess a source file -secondary_kalbach.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.i -.PHONY : secondary_kalbach.F90.i - -secondary_kalbach.s: secondary_kalbach.F90.s - -.PHONY : secondary_kalbach.s - -# target to generate assembly for a file -secondary_kalbach.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_kalbach.F90.s -.PHONY : secondary_kalbach.F90.s - -secondary_nbody.o: secondary_nbody.F90.o - -.PHONY : secondary_nbody.o - -# target to build an object file -secondary_nbody.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.o -.PHONY : secondary_nbody.F90.o - -secondary_nbody.i: secondary_nbody.F90.i - -.PHONY : secondary_nbody.i - -# target to preprocess a source file -secondary_nbody.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.i -.PHONY : secondary_nbody.F90.i - -secondary_nbody.s: secondary_nbody.F90.s - -.PHONY : secondary_nbody.s - -# target to generate assembly for a file -secondary_nbody.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_nbody.F90.s -.PHONY : secondary_nbody.F90.s - -secondary_uncorrelated.o: secondary_uncorrelated.F90.o - -.PHONY : secondary_uncorrelated.o - -# target to build an object file -secondary_uncorrelated.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.o -.PHONY : secondary_uncorrelated.F90.o - -secondary_uncorrelated.i: secondary_uncorrelated.F90.i - -.PHONY : secondary_uncorrelated.i - -# target to preprocess a source file -secondary_uncorrelated.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.i -.PHONY : secondary_uncorrelated.F90.i - -secondary_uncorrelated.s: secondary_uncorrelated.F90.s - -.PHONY : secondary_uncorrelated.s - -# target to generate assembly for a file -secondary_uncorrelated.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/secondary_uncorrelated.F90.s -.PHONY : secondary_uncorrelated.F90.s - -set_header.o: set_header.F90.o - -.PHONY : set_header.o - -# target to build an object file -set_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.o -.PHONY : set_header.F90.o - -set_header.i: set_header.F90.i - -.PHONY : set_header.i - -# target to preprocess a source file -set_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.i -.PHONY : set_header.F90.i - -set_header.s: set_header.F90.s - -.PHONY : set_header.s - -# target to generate assembly for a file -set_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/set_header.F90.s -.PHONY : set_header.F90.s - -simulation.o: simulation.F90.o - -.PHONY : simulation.o - -# target to build an object file -simulation.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.o -.PHONY : simulation.F90.o - -simulation.i: simulation.F90.i - -.PHONY : simulation.i - -# target to preprocess a source file -simulation.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.i -.PHONY : simulation.F90.i - -simulation.s: simulation.F90.s - -.PHONY : simulation.s - -# target to generate assembly for a file -simulation.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/simulation.F90.s -.PHONY : simulation.F90.s - -source.o: source.F90.o - -.PHONY : source.o - -# target to build an object file -source.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.o -.PHONY : source.F90.o - -source.i: source.F90.i - -.PHONY : source.i - -# target to preprocess a source file -source.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.i -.PHONY : source.F90.i - -source.s: source.F90.s - -.PHONY : source.s - -# target to generate assembly for a file -source.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source.F90.s -.PHONY : source.F90.s - -source_header.o: source_header.F90.o - -.PHONY : source_header.o - -# target to build an object file -source_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.o -.PHONY : source_header.F90.o - -source_header.i: source_header.F90.i - -.PHONY : source_header.i - -# target to preprocess a source file -source_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.i -.PHONY : source_header.F90.i - -source_header.s: source_header.F90.s - -.PHONY : source_header.s - -# target to generate assembly for a file -source_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/source_header.F90.s -.PHONY : source_header.F90.s - -state_point.o: state_point.F90.o - -.PHONY : state_point.o - -# target to build an object file -state_point.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.o -.PHONY : state_point.F90.o - -state_point.i: state_point.F90.i - -.PHONY : state_point.i - -# target to preprocess a source file -state_point.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.i -.PHONY : state_point.F90.i - -state_point.s: state_point.F90.s - -.PHONY : state_point.s - -# target to generate assembly for a file -state_point.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/state_point.F90.s -.PHONY : state_point.F90.s - -stl_vector.o: stl_vector.F90.o - -.PHONY : stl_vector.o - -# target to build an object file -stl_vector.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.o -.PHONY : stl_vector.F90.o - -stl_vector.i: stl_vector.F90.i - -.PHONY : stl_vector.i - -# target to preprocess a source file -stl_vector.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.i -.PHONY : stl_vector.F90.i - -stl_vector.s: stl_vector.F90.s - -.PHONY : stl_vector.s - -# target to generate assembly for a file -stl_vector.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/stl_vector.F90.s -.PHONY : stl_vector.F90.s - -string.o: string.F90.o - -.PHONY : string.o - -# target to build an object file -string.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.o -.PHONY : string.F90.o - -string.i: string.F90.i - -.PHONY : string.i - -# target to preprocess a source file -string.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.i -.PHONY : string.F90.i - -string.s: string.F90.s - -.PHONY : string.s - -# target to generate assembly for a file -string.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/string.F90.s -.PHONY : string.F90.s - -summary.o: summary.F90.o - -.PHONY : summary.o - -# target to build an object file -summary.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.o -.PHONY : summary.F90.o - -summary.i: summary.F90.i - -.PHONY : summary.i - -# target to preprocess a source file -summary.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.i -.PHONY : summary.F90.i - -summary.s: summary.F90.s - -.PHONY : summary.s - -# target to generate assembly for a file -summary.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/summary.F90.s -.PHONY : summary.F90.s - -surface_header.o: surface_header.F90.o - -.PHONY : surface_header.o - -# target to build an object file -surface_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.o -.PHONY : surface_header.F90.o - -surface_header.i: surface_header.F90.i - -.PHONY : surface_header.i - -# target to preprocess a source file -surface_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.i -.PHONY : surface_header.F90.i - -surface_header.s: surface_header.F90.s - -.PHONY : surface_header.s - -# target to generate assembly for a file -surface_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/surface_header.F90.s -.PHONY : surface_header.F90.s - -tally.o: tally.F90.o - -.PHONY : tally.o - -# target to build an object file -tally.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.o -.PHONY : tally.F90.o - -tally.i: tally.F90.i - -.PHONY : tally.i - -# target to preprocess a source file -tally.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.i -.PHONY : tally.F90.i - -tally.s: tally.F90.s - -.PHONY : tally.s - -# target to generate assembly for a file -tally.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally.F90.s -.PHONY : tally.F90.s - -tally_filter.o: tally_filter.F90.o - -.PHONY : tally_filter.o - -# target to build an object file -tally_filter.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.o -.PHONY : tally_filter.F90.o - -tally_filter.i: tally_filter.F90.i - -.PHONY : tally_filter.i - -# target to preprocess a source file -tally_filter.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.i -.PHONY : tally_filter.F90.i - -tally_filter.s: tally_filter.F90.s - -.PHONY : tally_filter.s - -# target to generate assembly for a file -tally_filter.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter.F90.s -.PHONY : tally_filter.F90.s - -tally_filter_header.o: tally_filter_header.F90.o - -.PHONY : tally_filter_header.o - -# target to build an object file -tally_filter_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.o -.PHONY : tally_filter_header.F90.o - -tally_filter_header.i: tally_filter_header.F90.i - -.PHONY : tally_filter_header.i - -# target to preprocess a source file -tally_filter_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.i -.PHONY : tally_filter_header.F90.i - -tally_filter_header.s: tally_filter_header.F90.s - -.PHONY : tally_filter_header.s - -# target to generate assembly for a file -tally_filter_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_filter_header.F90.s -.PHONY : tally_filter_header.F90.s - -tally_header.o: tally_header.F90.o - -.PHONY : tally_header.o - -# target to build an object file -tally_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.o -.PHONY : tally_header.F90.o - -tally_header.i: tally_header.F90.i - -.PHONY : tally_header.i - -# target to preprocess a source file -tally_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.i -.PHONY : tally_header.F90.i - -tally_header.s: tally_header.F90.s - -.PHONY : tally_header.s - -# target to generate assembly for a file -tally_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_header.F90.s -.PHONY : tally_header.F90.s - -tally_initialize.o: tally_initialize.F90.o - -.PHONY : tally_initialize.o - -# target to build an object file -tally_initialize.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.o -.PHONY : tally_initialize.F90.o - -tally_initialize.i: tally_initialize.F90.i - -.PHONY : tally_initialize.i - -# target to preprocess a source file -tally_initialize.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.i -.PHONY : tally_initialize.F90.i - -tally_initialize.s: tally_initialize.F90.s - -.PHONY : tally_initialize.s - -# target to generate assembly for a file -tally_initialize.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tally_initialize.F90.s -.PHONY : tally_initialize.F90.s - -timer_header.o: timer_header.F90.o - -.PHONY : timer_header.o - -# target to build an object file -timer_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.o -.PHONY : timer_header.F90.o - -timer_header.i: timer_header.F90.i - -.PHONY : timer_header.i - -# target to preprocess a source file -timer_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.i -.PHONY : timer_header.F90.i - -timer_header.s: timer_header.F90.s - -.PHONY : timer_header.s - -# target to generate assembly for a file -timer_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/timer_header.F90.s -.PHONY : timer_header.F90.s - -track_output.o: track_output.F90.o - -.PHONY : track_output.o - -# target to build an object file -track_output.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.o -.PHONY : track_output.F90.o - -track_output.i: track_output.F90.i - -.PHONY : track_output.i - -# target to preprocess a source file -track_output.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.i -.PHONY : track_output.F90.i - -track_output.s: track_output.F90.s - -.PHONY : track_output.s - -# target to generate assembly for a file -track_output.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/track_output.F90.s -.PHONY : track_output.F90.s - -tracking.o: tracking.F90.o - -.PHONY : tracking.o - -# target to build an object file -tracking.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.o -.PHONY : tracking.F90.o - -tracking.i: tracking.F90.i - -.PHONY : tracking.i - -# target to preprocess a source file -tracking.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.i -.PHONY : tracking.F90.i - -tracking.s: tracking.F90.s - -.PHONY : tracking.s - -# target to generate assembly for a file -tracking.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/tracking.F90.s -.PHONY : tracking.F90.s - -trigger.o: trigger.F90.o - -.PHONY : trigger.o - -# target to build an object file -trigger.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.o -.PHONY : trigger.F90.o - -trigger.i: trigger.F90.i - -.PHONY : trigger.i - -# target to preprocess a source file -trigger.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.i -.PHONY : trigger.F90.i - -trigger.s: trigger.F90.s - -.PHONY : trigger.s - -# target to generate assembly for a file -trigger.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger.F90.s -.PHONY : trigger.F90.s - -trigger_header.o: trigger_header.F90.o - -.PHONY : trigger_header.o - -# target to build an object file -trigger_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.o -.PHONY : trigger_header.F90.o - -trigger_header.i: trigger_header.F90.i - -.PHONY : trigger_header.i - -# target to preprocess a source file -trigger_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.i -.PHONY : trigger_header.F90.i - -trigger_header.s: trigger_header.F90.s - -.PHONY : trigger_header.s - -# target to generate assembly for a file -trigger_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/trigger_header.F90.s -.PHONY : trigger_header.F90.s - -urr_header.o: urr_header.F90.o - -.PHONY : urr_header.o - -# target to build an object file -urr_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.o -.PHONY : urr_header.F90.o - -urr_header.i: urr_header.F90.i - -.PHONY : urr_header.i - -# target to preprocess a source file -urr_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.i -.PHONY : urr_header.F90.i - -urr_header.s: urr_header.F90.s - -.PHONY : urr_header.s - -# target to generate assembly for a file -urr_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/urr_header.F90.s -.PHONY : urr_header.F90.s - -vector_header.o: vector_header.F90.o - -.PHONY : vector_header.o - -# target to build an object file -vector_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.o -.PHONY : vector_header.F90.o - -vector_header.i: vector_header.F90.i - -.PHONY : vector_header.i - -# target to preprocess a source file -vector_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.i -.PHONY : vector_header.F90.i - -vector_header.s: vector_header.F90.s - -.PHONY : vector_header.s - -# target to generate assembly for a file -vector_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/vector_header.F90.s -.PHONY : vector_header.F90.s - -volume_calc.o: volume_calc.F90.o - -.PHONY : volume_calc.o - -# target to build an object file -volume_calc.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.o -.PHONY : volume_calc.F90.o - -volume_calc.i: volume_calc.F90.i - -.PHONY : volume_calc.i - -# target to preprocess a source file -volume_calc.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.i -.PHONY : volume_calc.F90.i - -volume_calc.s: volume_calc.F90.s - -.PHONY : volume_calc.s - -# target to generate assembly for a file -volume_calc.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_calc.F90.s -.PHONY : volume_calc.F90.s - -volume_header.o: volume_header.F90.o - -.PHONY : volume_header.o - -# target to build an object file -volume_header.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.o -.PHONY : volume_header.F90.o - -volume_header.i: volume_header.F90.i - -.PHONY : volume_header.i - -# target to preprocess a source file -volume_header.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.i -.PHONY : volume_header.F90.i - -volume_header.s: volume_header.F90.s - -.PHONY : volume_header.s - -# target to generate assembly for a file -volume_header.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/volume_header.F90.s -.PHONY : volume_header.F90.s - -xml_interface.o: xml_interface.F90.o - -.PHONY : xml_interface.o - -# target to build an object file -xml_interface.F90.o: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.o -.PHONY : xml_interface.F90.o - -xml_interface.i: xml_interface.F90.i - -.PHONY : xml_interface.i - -# target to preprocess a source file -xml_interface.F90.i: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.i -.PHONY : xml_interface.F90.i - -xml_interface.s: xml_interface.F90.s - -.PHONY : xml_interface.s - -# target to generate assembly for a file -xml_interface.F90.s: - $(MAKE) -f CMakeFiles/libopenmc.dir/build.make CMakeFiles/libopenmc.dir/xml_interface.F90.s -.PHONY : xml_interface.F90.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... install/strip" - @echo "... install/local" - @echo "... list_install_components" - @echo "... rebuild_cache" - @echo "... ContinuousCoverage" - @echo "... ContinuousBuild" - @echo "... ContinuousUpdate" - @echo "... ContinuousStart" - @echo "... ExperimentalSubmit" - @echo "... ExperimentalBuild" - @echo "... ExperimentalCoverage" - @echo "... ExperimentalUpdate" - @echo "... install" - @echo "... ExperimentalStart" - @echo "... NightlyMemCheck" - @echo "... test" - @echo "... ExperimentalConfigure" - @echo "... NightlyCoverage" - @echo "... NightlyTest" - @echo "... NightlyConfigure" - @echo "... openmc" - @echo "... Continuous" - @echo "... NightlyStart" - @echo "... Nightly" - @echo "... ExperimentalMemCheck" - @echo "... libopenmc" - @echo "... edit_cache" - @echo "... ContinuousConfigure" - @echo "... NightlyMemoryCheck" - @echo "... Experimental" - @echo "... ContinuousSubmit" - @echo "... ExperimentalTest" - @echo "... NightlySubmit" - @echo "... ContinuousTest" - @echo "... faddeeva" - @echo "... ContinuousMemCheck" - @echo "... NightlyBuild" - @echo "... pugixml_fortran" - @echo "... NightlyUpdate" - @echo "... pugixml" - @echo "... algorithm.o" - @echo "... algorithm.i" - @echo "... algorithm.s" - @echo "... angle_distribution.o" - @echo "... angle_distribution.i" - @echo "... angle_distribution.s" - @echo "... angleenergy_header.o" - @echo "... angleenergy_header.i" - @echo "... angleenergy_header.s" - @echo "... api.o" - @echo "... api.i" - @echo "... api.s" - @echo "... bank_header.o" - @echo "... bank_header.i" - @echo "... bank_header.s" - @echo "... cmfd_data.o" - @echo "... cmfd_data.i" - @echo "... cmfd_data.s" - @echo "... cmfd_execute.o" - @echo "... cmfd_execute.i" - @echo "... cmfd_execute.s" - @echo "... cmfd_header.o" - @echo "... cmfd_header.i" - @echo "... cmfd_header.s" - @echo "... cmfd_input.o" - @echo "... cmfd_input.i" - @echo "... cmfd_input.s" - @echo "... cmfd_loss_operator.o" - @echo "... cmfd_loss_operator.i" - @echo "... cmfd_loss_operator.s" - @echo "... cmfd_prod_operator.o" - @echo "... cmfd_prod_operator.i" - @echo "... cmfd_prod_operator.s" - @echo "... cmfd_solver.o" - @echo "... cmfd_solver.i" - @echo "... cmfd_solver.s" - @echo "... constants.o" - @echo "... constants.i" - @echo "... constants.s" - @echo "... cross_section.o" - @echo "... cross_section.i" - @echo "... cross_section.s" - @echo "... dict_header.o" - @echo "... dict_header.i" - @echo "... dict_header.s" - @echo "... distribution_multivariate.o" - @echo "... distribution_multivariate.i" - @echo "... distribution_multivariate.s" - @echo "... distribution_univariate.o" - @echo "... distribution_univariate.i" - @echo "... distribution_univariate.s" - @echo "... doppler.o" - @echo "... doppler.i" - @echo "... doppler.s" - @echo "... eigenvalue.o" - @echo "... eigenvalue.i" - @echo "... eigenvalue.s" - @echo "... endf.o" - @echo "... endf.i" - @echo "... endf.s" - @echo "... endf_header.o" - @echo "... endf_header.i" - @echo "... endf_header.s" - @echo "... energy_distribution.o" - @echo "... energy_distribution.i" - @echo "... energy_distribution.s" - @echo "... error.o" - @echo "... error.i" - @echo "... error.s" - @echo "... faddeeva/Faddeeva.o" - @echo "... faddeeva/Faddeeva.i" - @echo "... faddeeva/Faddeeva.s" - @echo "... geometry.o" - @echo "... geometry.i" - @echo "... geometry.s" - @echo "... geometry_header.o" - @echo "... geometry_header.i" - @echo "... geometry_header.s" - @echo "... global.o" - @echo "... global.i" - @echo "... global.s" - @echo "... hdf5_interface.o" - @echo "... hdf5_interface.i" - @echo "... hdf5_interface.s" - @echo "... initialize.o" - @echo "... initialize.i" - @echo "... initialize.s" - @echo "... input_xml.o" - @echo "... input_xml.i" - @echo "... input_xml.s" - @echo "... list_header.o" - @echo "... list_header.i" - @echo "... list_header.s" - @echo "... main.o" - @echo "... main.i" - @echo "... main.s" - @echo "... material_header.o" - @echo "... material_header.i" - @echo "... material_header.s" - @echo "... math.o" - @echo "... math.i" - @echo "... math.s" - @echo "... matrix_header.o" - @echo "... matrix_header.i" - @echo "... matrix_header.s" - @echo "... mesh.o" - @echo "... mesh.i" - @echo "... mesh.s" - @echo "... mesh_header.o" - @echo "... mesh_header.i" - @echo "... mesh_header.s" - @echo "... message_passing.o" - @echo "... message_passing.i" - @echo "... message_passing.s" - @echo "... mgxs_data.o" - @echo "... mgxs_data.i" - @echo "... mgxs_data.s" - @echo "... mgxs_header.o" - @echo "... mgxs_header.i" - @echo "... mgxs_header.s" - @echo "... multipole.o" - @echo "... multipole.i" - @echo "... multipole.s" - @echo "... multipole_header.o" - @echo "... multipole_header.i" - @echo "... multipole_header.s" - @echo "... nuclide_header.o" - @echo "... nuclide_header.i" - @echo "... nuclide_header.s" - @echo "... output.o" - @echo "... output.i" - @echo "... output.s" - @echo "... particle_header.o" - @echo "... particle_header.i" - @echo "... particle_header.s" - @echo "... particle_restart.o" - @echo "... particle_restart.i" - @echo "... particle_restart.s" - @echo "... particle_restart_write.o" - @echo "... particle_restart_write.i" - @echo "... particle_restart_write.s" - @echo "... physics.o" - @echo "... physics.i" - @echo "... physics.s" - @echo "... physics_common.o" - @echo "... physics_common.i" - @echo "... physics_common.s" - @echo "... physics_mg.o" - @echo "... physics_mg.i" - @echo "... physics_mg.s" - @echo "... plot.o" - @echo "... plot.i" - @echo "... plot.s" - @echo "... plot_header.o" - @echo "... plot_header.i" - @echo "... plot_header.s" - @echo "... product_header.o" - @echo "... product_header.i" - @echo "... product_header.s" - @echo "... progress_header.o" - @echo "... progress_header.i" - @echo "... progress_header.s" - @echo "... pugixml/pugixml.o" - @echo "... pugixml/pugixml.i" - @echo "... pugixml/pugixml.s" - @echo "... pugixml/pugixml_c.o" - @echo "... pugixml/pugixml_c.i" - @echo "... pugixml/pugixml_c.s" - @echo "... pugixml/pugixml_f.o" - @echo "... pugixml/pugixml_f.i" - @echo "... pugixml/pugixml_f.s" - @echo "... random_lcg.o" - @echo "... random_lcg.i" - @echo "... random_lcg.s" - @echo "... reaction_header.o" - @echo "... reaction_header.i" - @echo "... reaction_header.s" - @echo "... sab_header.o" - @echo "... sab_header.i" - @echo "... sab_header.s" - @echo "... scattdata_header.o" - @echo "... scattdata_header.i" - @echo "... scattdata_header.s" - @echo "... secondary_correlated.o" - @echo "... secondary_correlated.i" - @echo "... secondary_correlated.s" - @echo "... secondary_kalbach.o" - @echo "... secondary_kalbach.i" - @echo "... secondary_kalbach.s" - @echo "... secondary_nbody.o" - @echo "... secondary_nbody.i" - @echo "... secondary_nbody.s" - @echo "... secondary_uncorrelated.o" - @echo "... secondary_uncorrelated.i" - @echo "... secondary_uncorrelated.s" - @echo "... set_header.o" - @echo "... set_header.i" - @echo "... set_header.s" - @echo "... simulation.o" - @echo "... simulation.i" - @echo "... simulation.s" - @echo "... source.o" - @echo "... source.i" - @echo "... source.s" - @echo "... source_header.o" - @echo "... source_header.i" - @echo "... source_header.s" - @echo "... state_point.o" - @echo "... state_point.i" - @echo "... state_point.s" - @echo "... stl_vector.o" - @echo "... stl_vector.i" - @echo "... stl_vector.s" - @echo "... string.o" - @echo "... string.i" - @echo "... string.s" - @echo "... summary.o" - @echo "... summary.i" - @echo "... summary.s" - @echo "... surface_header.o" - @echo "... surface_header.i" - @echo "... surface_header.s" - @echo "... tally.o" - @echo "... tally.i" - @echo "... tally.s" - @echo "... tally_filter.o" - @echo "... tally_filter.i" - @echo "... tally_filter.s" - @echo "... tally_filter_header.o" - @echo "... tally_filter_header.i" - @echo "... tally_filter_header.s" - @echo "... tally_header.o" - @echo "... tally_header.i" - @echo "... tally_header.s" - @echo "... tally_initialize.o" - @echo "... tally_initialize.i" - @echo "... tally_initialize.s" - @echo "... timer_header.o" - @echo "... timer_header.i" - @echo "... timer_header.s" - @echo "... track_output.o" - @echo "... track_output.i" - @echo "... track_output.s" - @echo "... tracking.o" - @echo "... tracking.i" - @echo "... tracking.s" - @echo "... trigger.o" - @echo "... trigger.i" - @echo "... trigger.s" - @echo "... trigger_header.o" - @echo "... trigger_header.i" - @echo "... trigger_header.s" - @echo "... urr_header.o" - @echo "... urr_header.i" - @echo "... urr_header.s" - @echo "... vector_header.o" - @echo "... vector_header.i" - @echo "... vector_header.s" - @echo "... volume_calc.o" - @echo "... volume_calc.i" - @echo "... volume_calc.s" - @echo "... volume_header.o" - @echo "... volume_header.i" - @echo "... volume_header.s" - @echo "... xml_interface.o" - @echo "... xml_interface.i" - @echo "... xml_interface.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 7ce449235..cde8341b9 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -856,7 +856,7 @@ contains call match % weights % push_back(-ONE) else call match % weights % push_back(ONE) - end if + end if exit end if end do diff --git a/tests/.DS_Store b/tests/.DS_Store deleted file mode 100644 index a2057a0df76e3a9ce5cb82846993710fd15b448b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14340 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 G|9=4Wu;L2< From 3bc700062c6213e8c64f6088230b52c23b2ba668 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 14:44:45 -0500 Subject: [PATCH 109/229] Remove unused variables --- src/tally.F90 | 7 ------- src/tally_filter.F90 | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/tally.F90 b/src/tally.F90 index 9cdf4c3c8..ee2fc992f 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2227,7 +2227,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array - integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations type(TallyObject), pointer :: t @@ -2372,7 +2371,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array - integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters real(8) :: atom_density logical :: finished ! found all valid bin combinations @@ -2748,7 +2746,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) - integer :: matching_bin ! next valid filter bin real(8) :: flux ! tracklength estimate of flux real(8) :: atom_density ! atom density of single nuclide in atom/b-cm real(8) :: filter_weight ! combined weight of all filters @@ -2909,7 +2906,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) - integer :: matching_bin ! next valid filter bin real(8) :: flux ! collision estimate of flux real(8) :: atom_density ! atom density of single nuclide ! in atom/b-cm @@ -3075,7 +3071,6 @@ contains integer :: score_index ! scoring bin index integer :: j ! loop index for scoring bins integer :: filter_index ! single index for single bin - integer :: matching_bin ! next valid filter bin real(8) :: flux ! collision estimate of flux real(8) :: filter_weight ! combined weight of all filters real(8) :: score ! analog tally score @@ -3197,7 +3192,6 @@ contains integer :: i integer :: i_tally - integer :: i_filt integer :: j, k ! loop indices integer :: n_dim ! num dimensions of the mesh integer :: d1 ! dimension index @@ -3216,7 +3210,6 @@ contains real(8) :: xyz_cross(3) ! coordinates of bounding surfaces real(8) :: d(3) ! distance to each bounding surface real(8) :: distance ! actual distance traveled - real(8) :: filt_score ! score applied by filters integer :: matching_bin ! next valid filter bin logical :: start_in_mesh ! particle's starting xyz in mesh? logical :: end_in_mesh ! particle's ending xyz in mesh? diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index cde8341b9..eb83b319c 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -461,7 +461,7 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - integer :: i, start + integer :: i ! Iterate over coordinate levels to see which universes match do i = 1, p % n_coord From 01245c3e961329285142f0d441c25bae36059d7b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 14:56:53 -0500 Subject: [PATCH 110/229] Move error codes to error module --- src/api.F90 | 21 +-------------------- src/error.F90 | 27 ++++++++++++++++++++++++++- src/material_header.F90 | 4 ++-- src/tally.F90 | 6 ++++++ src/tally_filter.F90 | 15 +++++---------- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 23aa40587..4f99066d2 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -6,6 +6,7 @@ module openmc_api use constants, only: K_BOLTZMANN use eigenvalue, only: k_sum, openmc_get_keff + use error use geometry, only: find_cell use geometry_header, only: root_universe use global @@ -49,26 +50,6 @@ module openmc_api public :: openmc_tally_results public :: openmc_tally_set_nuclides - ! Error codes - integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1 - integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -2 - integer(C_INT), public, bind(C) :: E_CELL_NOT_ALLOCATED = -3 - integer(C_INT), public, bind(C) :: E_CELL_INVALID_ID = -4 - integer(C_INT), public, bind(C) :: E_CELL_NOT_FOUND = -5 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_ALLOCATED = -6 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_LOADED = -7 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -8 - integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -9 - integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -10 - integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -11 - integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 - integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 - integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 - - ! Warning codes - integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 - integer(C_INT), public, bind(C) :: W_ABOVE_MAX_BOUND = 2 - contains !=============================================================================== diff --git a/src/error.F90 b/src/error.F90 index 1bb6b5257..9dec93147 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -1,12 +1,37 @@ module error + use, intrinsic :: ISO_C_BINDING use, intrinsic :: ISO_FORTRAN_ENV - use constants + use constants use message_passing implicit none + private + public :: fatal_error + public :: warning + + ! Error codes + integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1 + integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -2 + integer(C_INT), public, bind(C) :: E_CELL_NOT_ALLOCATED = -3 + integer(C_INT), public, bind(C) :: E_CELL_INVALID_ID = -4 + integer(C_INT), public, bind(C) :: E_CELL_NOT_FOUND = -5 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_ALLOCATED = -6 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_LOADED = -7 + integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -8 + integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -9 + integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -10 + integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -11 + integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 + integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 + integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 + + ! Warning codes + integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 + integer(C_INT), public, bind(C) :: W_ABOVE_MAX_BOUND = 2 + contains !=============================================================================== diff --git a/src/material_header.F90 b/src/material_header.F90 index 5d45c40d6..b73f372ba 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -1,7 +1,7 @@ module material_header use constants - use error, only: fatal_error + use error use nuclide_header, only: Nuclide use sab_header, only: SAlphaBeta use stl_vector, only: VectorReal, VectorInt @@ -67,7 +67,7 @@ contains real(8) :: sum_percent real(8) :: awr - err = -1 + err = E_UNASSIGNED if (allocated(m % atom_density)) then ! Set total density based on value provided m % density = density diff --git a/src/tally.F90 b/src/tally.F90 index ee2fc992f..fae764602 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2227,6 +2227,7 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array + integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations type(TallyObject), pointer :: t @@ -2371,6 +2372,7 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array + integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters real(8) :: atom_density logical :: finished ! found all valid bin combinations @@ -2746,6 +2748,7 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) + integer :: matching_bin ! next valid filter bin real(8) :: flux ! tracklength estimate of flux real(8) :: atom_density ! atom density of single nuclide in atom/b-cm real(8) :: filter_weight ! combined weight of all filters @@ -2906,6 +2909,7 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) + integer :: matching_bin ! next valid filter bin real(8) :: flux ! collision estimate of flux real(8) :: atom_density ! atom density of single nuclide ! in atom/b-cm @@ -3192,6 +3196,7 @@ contains integer :: i integer :: i_tally + integer :: i_filt integer :: j, k ! loop indices integer :: n_dim ! num dimensions of the mesh integer :: d1 ! dimension index @@ -3210,6 +3215,7 @@ contains real(8) :: xyz_cross(3) ! coordinates of bounding surfaces real(8) :: d(3) ! distance to each bounding surface real(8) :: distance ! actual distance traveled + real(8) :: filt_score ! score applied by filters integer :: matching_bin ! next valid filter bin logical :: start_in_mesh ! particle's starting xyz in mesh? logical :: end_in_mesh ! particle's ending xyz in mesh? diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index eb83b319c..0a7ce23cd 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -461,7 +461,7 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - integer :: i + integer :: i, start ! Iterate over coordinate levels to see which universes match do i = 1, p % n_coord @@ -663,12 +663,12 @@ contains integer :: i - ! Iterate over coordinate levels to see with cells match - + ! Starting one coordinate level deeper, find the next bin. do i = 1, p % last_n_coord if (this % map % has_key(p % last_cell(i))) then call match % bins % push_back(this % map % get_key(p % last_cell(i))) call match % weights % push_back(ONE) + exit end if end do @@ -1202,15 +1202,10 @@ contains select type(this) type is (EnergyFunctionFilter) - n = size(this % energy) - ! Make sure the correct energy is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - E = p % E - else - E = p % last_E - end if + ! Get pre-collision energy of particle + E = p % last_E ! Search to find incoming energy bin. indx = binary_search(this % energy, n, E) From 56021e1e4225cbfc83d21323bba862160292513c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 11:40:14 -0500 Subject: [PATCH 111/229] Allocate filter_matches at beginning of simulation --- src/global.F90 | 1 - src/output.F90 | 37 ++++++++++++++++++++++--------------- src/simulation.F90 | 5 ++++- src/tally_initialize.F90 | 5 ----- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index 8343b49ac..04e3eff89 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -508,7 +508,6 @@ contains ! Deallocate fission and source bank and entropy !$omp parallel if (allocated(fission_bank)) deallocate(fission_bank) - if (allocated(filter_matches)) deallocate(filter_matches) if (allocated(tally_derivs)) deallocate(tally_derivs) !$omp end parallel #ifdef _OPENMP diff --git a/src/output.F90 b/src/output.F90 index b239a4c79..b4e620e13 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -21,6 +21,7 @@ module output use string, only: to_upper, to_str use tally_header, only: TallyObject use tally_filter + use tally_filter_header, only: TallyFilterMatch implicit none @@ -730,10 +731,13 @@ contains character(36) :: score_name ! names of scoring function ! to be applied at write-time type(TallyObject), pointer :: t + type(TallyfilterMatch), allocatable :: matches(:) ! Skip if there are no tallies if (n_tallies == 0) return + allocate(matches(n_filters)) + ! Initialize names for scores score_names(abs(SCORE_FLUX)) = "Flux" score_names(abs(SCORE_TOTAL)) = "Total Reaction Rate" @@ -830,8 +834,8 @@ contains ! Initialize bins, filter level, and indentation do h = 1, size(t % filter) - call filter_matches(t % filter(h)) % bins % clear() - call filter_matches(t % filter(h)) % bins % push_back(0) + call matches(t % filter(h)) % bins % clear() + call matches(t % filter(h)) % bins % push_back(0) end do j = 1 indent = 0 @@ -842,18 +846,18 @@ contains if (size(t % filter) == 0) exit find_bin ! Increment bin combination - filter_matches(t % filter(j)) % bins % data(1) = & - filter_matches(t % filter(j)) % bins % data(1) + 1 + matches(t % filter(j)) % bins % data(1) = & + matches(t % filter(j)) % bins % data(1) + 1 ! ================================================================= ! REACHED END OF BINS FOR THIS FILTER, MOVE TO NEXT FILTER - if (filter_matches(t % filter(j)) % bins % data(1) > & + if (matches(t % filter(j)) % bins % data(1) > & filters(t % filter(j)) % obj % n_bins) then ! If this is the first filter, then exit if (j == 1) exit print_bin - filter_matches(t % filter(j)) % bins % data(1) = 0 + matches(t % filter(j)) % bins % data(1) = 0 j = j - 1 indent = indent - 2 @@ -867,7 +871,7 @@ contains ! Print current filter information write(UNIT=unit_tally, FMT='(1X,2A)') repeat(" ", indent), & trim(filters(t % filter(j)) % obj % & - text_label(filter_matches(t % filter(j)) % bins % data(1))) + text_label(matches(t % filter(j)) % bins % data(1))) indent = indent + 2 j = j + 1 end if @@ -878,7 +882,7 @@ contains if (size(t % filter) > 0) then write(UNIT=unit_tally, FMT='(1X,2A)') repeat(" ", indent), & trim(filters(t % filter(j)) % obj % & - text_label(filter_matches(t % filter(j)) % bins % data(1))) + text_label(matches(t % filter(j)) % bins % data(1))) end if ! Determine scoring index for this bin combination -- note that unlike @@ -887,7 +891,7 @@ contains filter_index = 1 do h = 1, size(t % filter) - filter_index = filter_index + (max(filter_matches(t % filter(h)) & + filter_index = filter_index + (max(matches(t % filter(h)) & % bins % data(1),1) - 1) * t % stride(h) end do @@ -1009,6 +1013,9 @@ contains logical :: energy_filters ! energy filters present character(MAX_LINE_LEN) :: string type(RegularMesh), pointer :: m + type(TallyFilterMatch), allocatable :: matches(:) + + allocate(matches(n_filters)) nr = t % n_realizations @@ -1025,8 +1032,8 @@ contains ! initialize bins array do j = 1, size(t % filter) - call filter_matches(t % filter(j)) % bins % clear() - call filter_matches(t % filter(j)) % bins % push_back(1) + call matches(t % filter(j)) % bins % clear() + call matches(t % filter(j)) % bins % push_back(1) end do ! determine how many energy in bins there are @@ -1049,7 +1056,7 @@ contains ! Get the indices for this cell call bin_to_mesh_indices(m, i, ijk) - filter_matches(i_filter_mesh) % bins % data(1) = i + matches(i_filter_mesh) % bins % data(1) = i ! Write the header for this cell if (n_dim == 1) then @@ -1067,18 +1074,18 @@ contains do l = 1, n if (print_ebin) then ! Set incoming energy bin - filter_matches(i_filter_ein) % bins % data(1) = l + matches(i_filter_ein) % bins % data(1) = l ! Write incoming energy bin write(UNIT=unit_tally, FMT='(3X,A)') & trim(filters(i_filter_ein) % obj % text_label( & - filter_matches(i_filter_ein) % bins % data(1))) + matches(i_filter_ein) % bins % data(1))) end if filter_index = 1 do j = 1, size(t % filter) if (t % filter(j) == i_filter_surf) cycle - filter_index = filter_index + (filter_matches(t % filter(j)) & + filter_index = filter_index + (matches(t % filter(j)) & % bins % data(1) - 1) * t % stride(j) end do diff --git a/src/simulation.F90 b/src/simulation.F90 index 7427443bb..8da913b5a 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -371,6 +371,9 @@ contains !$omp parallel allocate(micro_xs(n_nuclides_total)) + + ! Allocate array for matching filter bins + allocate(filter_matches(n_filters)) !$omp end parallel if (.not. restart_run) call initialize_source() @@ -403,7 +406,7 @@ contains #endif !$omp parallel - deallocate(micro_xs) + deallocate(micro_xs, filter_matches) !$omp end parallel ! Increment total number of generations diff --git a/src/tally_initialize.F90 b/src/tally_initialize.F90 index 46c028364..84ef43534 100644 --- a/src/tally_initialize.F90 +++ b/src/tally_initialize.F90 @@ -67,11 +67,6 @@ contains end do TALLY_LOOP - ! Allocate array for matching filter bins -!$omp parallel - allocate(filter_matches(n_filters)) -!$omp end parallel - end subroutine setup_tally_arrays !=============================================================================== From 286491540979bed49b8dea732e27a05994549e9c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 12:10:10 -0500 Subject: [PATCH 112/229] Move nuclide and S(a,b) table arrays to their respective modules --- src/api.F90 | 10 +++++----- src/geometry_header.F90 | 17 +++++++---------- src/global.F90 | 32 ++++---------------------------- src/input_xml.F90 | 24 +++++++++++------------- src/material_header.F90 | 11 ++++------- src/mgxs_data.F90 | 5 ++--- src/nuclide_header.F90 | 17 +++++++++++++++-- src/particle_restart.F90 | 2 +- src/sab_header.F90 | 7 ++++++- src/simulation.F90 | 2 +- src/summary.F90 | 8 ++++---- src/tally.F90 | 4 ++-- 12 files changed, 62 insertions(+), 77 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 4f99066d2..50d702b31 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -424,7 +424,7 @@ contains if (.not. nuclide_dict % has_key(to_lower(name_))) then if (library_dict % has_key(to_lower(name_))) then ! allocate extra space in nuclides array - n = n_nuclides_total + n = n_nuclides allocate(new_nuclides(n + 1)) new_nuclides(1:n) = nuclides(:) call move_alloc(FROM=new_nuclides, TO=nuclides) @@ -446,7 +446,7 @@ contains ! Add entry to nuclide dictionary call nuclide_dict % add_key(to_lower(name_), n) - n_nuclides_total = n + n_nuclides = n ! Assign resonant scattering data if (res_scat_on) call assign_0K_elastic_scattering(nuclides(n)) @@ -585,7 +585,7 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(materials)) then associate (m => materials(index)) - err = m % set_density(density, nuclides) + err = m % set_density(density) end associate else err = E_OUT_OF_BOUNDS @@ -636,10 +636,10 @@ contains m % p0(:) = .false. ! Set total density to the sum of the vector - err = m % set_density(sum(density), nuclides) + err = m % set_density(sum(density)) ! Assign S(a,b) tables - call m % assign_sab_tables(nuclides, sab_tables) + call m % assign_sab_tables() end associate else err = E_OUT_OF_BOUNDS diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 0d3ae2640..b9eab0ad0 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -4,7 +4,9 @@ module geometry_header use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & MATERIAL_VOID, NONE use dict_header, only: DictCharInt, DictIntInt + use nuclide_header use material_header, only: Material + use sab_header use stl_vector, only: VectorReal use string, only: to_lower @@ -330,16 +332,12 @@ contains ! temperatures to read (which may be different if interpolation is used) !=============================================================================== - subroutine get_temperatures(cells, materials, material_dict, nuclide_dict, & - n_nucs, nuc_temps, sab_dict, n_sabs, sab_temps) + subroutine get_temperatures(cells, materials, material_dict, & + nuc_temps, sab_temps) type(Cell), allocatable, intent(in) :: cells(:) type(Material), allocatable, intent(in) :: materials(:) type(DictIntInt), intent(in) :: material_dict - type(DictCharInt), intent(in) :: nuclide_dict - integer, intent(in) :: n_nucs type(VectorReal), allocatable, intent(out) :: nuc_temps(:) - type(DictCharInt), optional, intent(in) :: sab_dict - integer, optional, intent(in) :: n_sabs type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:) integer :: i, j, k @@ -348,8 +346,8 @@ contains integer :: i_material real(8) :: temperature ! temperature in Kelvin - allocate(nuc_temps(n_nucs)) - if (present(n_sabs) .and. present(sab_temps)) allocate(sab_temps(n_sabs)) + allocate(nuc_temps(n_nuclides)) + if (present(sab_temps)) allocate(sab_temps(n_sab_tables)) do i = 1, size(cells) do j = 1, size(cells(i) % material) @@ -376,8 +374,7 @@ contains end if end do NUC_NAMES_LOOP - if (present(sab_temps) .and. present(sab_dict) .and. & - mat % n_sab > 0) then + if (present(sab_temps) .and. mat % n_sab > 0) then SAB_NAMES_LOOP: do k = 1, size(mat % sab_names) ! Get index in nuc_temps array i_sab = sab_dict % get_key(to_lower(mat % sab_names(k))) diff --git a/src/global.F90 b/src/global.F90 index 04e3eff89..9e2ca1c25 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -14,9 +14,7 @@ module global use material_header, only: Material use mesh_header, only: RegularMesh use mgxs_header, only: Mgxs, MgxsContainer - use nuclide_header use plot_header, only: ObjectPlot - use sab_header, only: SAlphaBeta use set_header, only: SetInt use stl_vector, only: VectorInt use surface_header, only: SurfaceContainer @@ -27,6 +25,10 @@ module global use timer_header, only: Timer use volume_header, only: VolumeCalculation + ! Inherit module variables from nuclide/S(a,b) modules + use nuclide_header + use sab_header + implicit none ! ============================================================================ @@ -70,39 +72,13 @@ module global ! ENERGY TREATMENT RELATED VARIABLES logical :: run_CE = .true. ! Run in CE mode? - ! ============================================================================ - ! CROSS SECTION RELATED VARIABLES NEEDED REGARDLESS OF CE OR MG - - ! Number of nuclide cross section tables - integer(C_INT), bind(C, name='n_nuclides') :: n_nuclides_total - ! Cross section caches type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide type(MaterialMacroXS) :: material_xs ! Cache for current material - ! Dictionaries to look up cross sections and listings - type(DictCharInt) :: nuclide_dict - type(DictCharInt) :: library_dict - - ! Cross section libraries - type(Library), allocatable :: libraries(:) - ! ============================================================================ ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES - ! Cross section arrays - type(Nuclide), allocatable, target :: nuclides(:) ! Nuclide cross-sections - type(SAlphaBeta), allocatable, target :: sab_tables(:) ! S(a,b) tables - - integer :: n_sab_tables ! Number of S(a,b) thermal scattering tables - - ! Minimum/maximum energies - real(8) :: energy_min_neutron = ZERO - real(8) :: energy_max_neutron = INFINITY - - ! Dictionaries to look up cross sections and listings - type(DictCharInt) :: sab_dict - ! Unreoslved resonance probablity tables logical :: urr_ptables_on = .true. diff --git a/src/input_xml.F90 b/src/input_xml.F90 index efdc3e523..cde7e21e0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2187,9 +2187,7 @@ contains call assign_temperatures(material_temps) ! Determine desired temperatures for each nuclide and S(a,b) table - call get_temperatures(cells, materials, material_dict, nuclide_dict, & - n_nuclides_total, nuc_temps, sab_dict, & - n_sab_tables, sab_temps) + call get_temperatures(cells, materials, material_dict, nuc_temps, sab_temps) ! Read continuous-energy cross sections if (run_CE .and. run_mode /= MODE_PLOTTING) then @@ -2617,8 +2615,8 @@ contains end do ! Set total number of nuclides and S(a,b) tables - n_nuclides_total = index_nuclide - n_sab_tables = index_sab + n_nuclides = index_nuclide + n_sab_tables = index_sab ! Close materials XML file call doc % clear() @@ -3464,15 +3462,15 @@ contains if (trim(sarray(1)) == 'all') then ! Handle special case all - allocate(t % nuclide_bins(n_nuclides_total + 1)) + allocate(t % nuclide_bins(n_nuclides + 1)) - ! Set bins to 1, 2, 3, ..., n_nuclides_total, -1 - t % nuclide_bins(1:n_nuclides_total) = & - (/ (j, j=1, n_nuclides_total) /) - t % nuclide_bins(n_nuclides_total + 1) = -1 + ! Set bins to 1, 2, 3, ..., n_nuclides, -1 + t % nuclide_bins(1:n_nuclides) = & + (/ (j, j=1, n_nuclides) /) + t % nuclide_bins(n_nuclides + 1) = -1 ! Set number of nuclide bins - t % n_nuclide_bins = n_nuclides_total + 1 + t % n_nuclide_bins = n_nuclides + 1 ! Set flag so we can treat this case specially t % all_nuclides = .true. @@ -5183,7 +5181,7 @@ contains character(MAX_WORD_LEN) :: name type(SetChar) :: already_read - allocate(nuclides(n_nuclides_total)) + allocate(nuclides(n_nuclides)) allocate(sab_tables(n_sab_tables)) ! Read cross sections @@ -5275,7 +5273,7 @@ contains end do ! Associate S(a,b) tables with specific nuclides - call materials(i) % assign_sab_tables(nuclides, sab_tables) + call materials(i) % assign_sab_tables() end do ! Show which nuclide results in lowest energy for neutron transport diff --git a/src/material_header.F90 b/src/material_header.F90 index b73f372ba..1308810e2 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -2,8 +2,8 @@ module material_header use constants use error - use nuclide_header, only: Nuclide - use sab_header, only: SAlphaBeta + use nuclide_header + use sab_header use stl_vector, only: VectorReal, VectorInt use string, only: to_str @@ -57,10 +57,9 @@ contains ! MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm. !=============================================================================== - function material_set_density(m, density, nuclides) result(err) + function material_set_density(m, density) result(err) class(Material), intent(inout) :: m real(8), intent(in) :: density - type(Nuclide), intent(in) :: nuclides(:) integer :: err integer :: i @@ -95,10 +94,8 @@ contains ! materials so the code knows when to apply bound thermal scattering data !=============================================================================== - subroutine material_assign_sab_tables(this, nuclides, sab_tables) + subroutine material_assign_sab_tables(this) class(Material), intent(inout) :: this - type(Nuclide), intent(in) :: nuclides(:) - type(SAlphaBeta), intent(in) :: sab_tables(:) integer :: j ! index over nuclides in material integer :: k ! index over S(a,b) tables in material diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index ad20aca83..bbea3c4b3 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -51,8 +51,7 @@ contains call write_message("Loading cross section data...", 5) ! Get temperatures - call get_temperatures(cells, materials, material_dict, nuclide_dict, & - n_nuclides_total, temps) + call get_temperatures(cells, materials, material_dict, temps) ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) @@ -72,7 +71,7 @@ contains end if ! allocate arrays for MGXS storage and cross section cache - allocate(nuclides_MG(n_nuclides_total)) + allocate(nuclides_MG(n_nuclides)) ! ========================================================================== ! READ ALL MGXS CROSS SECTION TABLES diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index bf1ea97b2..68759115b 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -7,7 +7,7 @@ module nuclide_header use algorithm, only: sort, find use constants - use dict_header, only: DictIntInt + use dict_header, only: DictIntInt, DictCharInt use endf, only: reaction_name, is_fission, is_disappearance use endf_header, only: Function1D, Polynomial, Tabulated1D use error, only: fatal_error, warning @@ -157,7 +157,20 @@ module nuclide_header character(MAX_FILE_LEN) :: path end type Library - contains + ! Cross section libraries + type(Library), allocatable :: libraries(:) + type(DictCharInt) :: library_dict + + ! Nuclear data for each nuclide + type(Nuclide), allocatable, target :: nuclides(:) + integer(C_INT), bind(C) :: n_nuclides + type(DictCharInt) :: nuclide_dict + + ! Minimum/maximum energies + real(8) :: energy_min_neutron = ZERO + real(8) :: energy_max_neutron = INFINITY + +contains !=============================================================================== ! NUCLIDE_CLEAR resets and deallocates data in Nuclide diff --git a/src/particle_restart.F90 b/src/particle_restart.F90 index 4438c48c0..35b16224d 100644 --- a/src/particle_restart.F90 +++ b/src/particle_restart.F90 @@ -32,7 +32,7 @@ contains ! Set verbosity high verbosity = 10 - allocate(micro_xs(n_nuclides_total)) + allocate(micro_xs(n_nuclides)) ! Initialize the particle to be tracked call p % initialize() diff --git a/src/sab_header.F90 b/src/sab_header.F90 index e0b79f248..8e783a741 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -4,7 +4,7 @@ module sab_header use algorithm, only: find, sort use constants - use dict_header, only: DictIntInt + use dict_header, only: DictIntInt, DictCharInt use distribution_univariate, only: Tabular use error, only: warning, fatal_error use hdf5, only: HID_T, HSIZE_T, SIZE_T @@ -78,6 +78,11 @@ module sab_header procedure :: from_hdf5 => salphabeta_from_hdf5 end type SAlphaBeta + ! S(a,b) tables + type(SAlphaBeta), allocatable, target :: sab_tables(:) + integer :: n_sab_tables + type(DictCharInt) :: sab_dict + contains subroutine salphabeta_from_hdf5(this, group_id, temperature, method, & diff --git a/src/simulation.F90 b/src/simulation.F90 index 8da913b5a..64632a343 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -370,7 +370,7 @@ contains subroutine initialize_simulation() !$omp parallel - allocate(micro_xs(n_nuclides_total)) + allocate(micro_xs(n_nuclides)) ! Allocate array for matching filter bins allocate(filter_matches(n_filters)) diff --git a/src/summary.F90 b/src/summary.F90 index 9c952fe70..e4263d8d0 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -79,12 +79,12 @@ contains ! Write useful data from nuclide objects nuclide_group = create_group(file_id, "nuclides") - call write_attribute(nuclide_group, "n_nuclides", n_nuclides_total) + call write_attribute(nuclide_group, "n_nuclides", n_nuclides) ! Build array of nuclide names and awrs - allocate(nucnames(n_nuclides_total)) - allocate(awrs(n_nuclides_total)) - do i = 1, n_nuclides_total + allocate(nucnames(n_nuclides)) + allocate(awrs(n_nuclides)) + do i = 1, n_nuclides if (run_CE) then nucnames(i) = nuclides(i) % name awrs(i) = nuclides(i) % awr diff --git a/src/tally.F90 b/src/tally.F90 index fae764602..338362c69 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -2205,7 +2205,7 @@ contains atom_density = ZERO ! Determine score for each bin - call score_general(p, t, n_nuclides_total*t % n_score_bins, filter_index, & + call score_general(p, t, n_nuclides*t % n_score_bins, filter_index, & i_nuclide, atom_density, flux) end subroutine score_all_nuclides @@ -2300,7 +2300,7 @@ contains elseif (k == p % event_nuclide + 1) then ! After we've tallied the individual nuclide bin, we also need ! to contribute to the total material bin which is the last bin - k = n_nuclides_total + 1 + k = n_nuclides + 1 else ! After we've tallied in both the individual nuclide bin and the ! total material bin, we're done From d2d70a3d42764291a68caf7a4c968e2fbe78b6e7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Aug 2017 13:40:49 -0500 Subject: [PATCH 113/229] Move most of mesh module into mesh_header as type-bound procedures --- src/cmfd_data.F90 | 7 +- src/cmfd_execute.F90 | 4 +- src/mesh.F90 | 334 +--------------------------------------- src/mesh_header.F90 | 359 +++++++++++++++++++++++++++++++++++++++++++ src/output.F90 | 3 +- src/physics.F90 | 3 +- src/physics_mg.F90 | 3 +- src/plot.F90 | 6 +- src/tally.F90 | 24 +-- src/tally_filter.F90 | 28 +--- src/trigger.F90 | 3 +- 11 files changed, 384 insertions(+), 390 deletions(-) diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index 177f140b6..c873b1beb 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -58,7 +58,6 @@ contains use error, only: fatal_error use global, only: cmfd, n_cmfd_tallies, cmfd_tallies, meshes, & filters, filter_matches - use mesh, only: mesh_indices_to_bin use mesh_header, only: RegularMesh use string, only: to_str use tally_header, only: TallyObject @@ -166,7 +165,7 @@ contains ! Get bin number for mesh indices filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m,ijk) + m % get_bin_from_indices(ijk) ! Apply energy in filter if (energy_filters) then @@ -217,7 +216,7 @@ contains ! Get bin number for mesh indices filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m,ijk) + m % get_bin_from_indices(ijk) if (energy_filters) then ! Apply energy in filter @@ -266,7 +265,7 @@ contains ! Get the bin for this mesh cell filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m, (/ i, j, k /)) + m % get_bin_from_indices([ i, j, k ]) score_index = 1 do l = 1, size(t % filter) diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index e87bff930..b9aae0da5 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -218,7 +218,7 @@ contains use error, only: warning, fatal_error use global, only: meshes, source_bank, work, n_user_meshes, cmfd use mesh_header, only: RegularMesh - use mesh, only: count_bank_sites, get_mesh_indices + use mesh, only: count_bank_sites use message_passing use string, only: to_str @@ -295,7 +295,7 @@ contains do i = 1, int(work,4) ! Determine spatial bin - call get_mesh_indices(m, source_bank(i) % xyz, ijk, in_mesh) + call m % get_indices(source_bank(i) % xyz, ijk, in_mesh) ! Determine energy bin n_groups = size(cmfd % egrid) - 1 diff --git a/src/mesh.F90 b/src/mesh.F90 index c25e3f7a6..6d94ffba4 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -10,116 +10,6 @@ module mesh contains -!=============================================================================== -! GET_MESH_BIN determines the tally bin for a particle in a structured mesh -!=============================================================================== - - pure subroutine get_mesh_bin(m, xyz, bin) - type(RegularMesh), intent(in) :: m ! mesh pointer - real(8), intent(in) :: xyz(:) ! coordinates - integer, intent(out) :: bin ! tally bin - - integer :: n ! size of mesh - integer :: d ! mesh dimension index - integer :: ijk(3) ! indices in mesh - logical :: in_mesh ! was given coordinate in mesh at all? - - ! Get number of dimensions - n = m % n_dimension - - ! Loop over the dimensions of the mesh - do d = 1, n - - ! Check for cases where particle is outside of mesh - if (xyz(d) < m % lower_left(d)) then - bin = NO_BIN_FOUND - return - elseif (xyz(d) > m % upper_right(d)) then - bin = NO_BIN_FOUND - return - end if - end do - - ! Determine indices - call get_mesh_indices(m, xyz, ijk, in_mesh) - - ! Convert indices to bin - if (in_mesh) then - bin = mesh_indices_to_bin(m, ijk) - else - bin = NO_BIN_FOUND - end if - - end subroutine get_mesh_bin - -!=============================================================================== -! GET_MESH_INDICES determines the indices of a particle in a structured mesh -!=============================================================================== - - pure subroutine get_mesh_indices(m, xyz, ijk, in_mesh) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz(:) ! coordinates to check - integer, intent(out) :: ijk(:) ! indices in mesh - logical, intent(out) :: in_mesh ! were given coords in mesh? - - ! Find particle in mesh - ijk(:m % n_dimension) = ceiling((xyz(:m % n_dimension) - m % lower_left)/m % width) - - ! Determine if particle is in mesh - if (any(ijk(:m % n_dimension) < 1) .or. & - any(ijk(:m % n_dimension) > m % dimension)) then - in_mesh = .false. - else - in_mesh = .true. - end if - - end subroutine get_mesh_indices - -!=============================================================================== -! MESH_INDICES_TO_BIN maps (i), (i,j), or (i,j,k) indices to a single bin number -! for use in a TallyObject results array -!=============================================================================== - - pure function mesh_indices_to_bin(m, ijk) result(bin) - type(RegularMesh), intent(in) :: m - integer, intent(in) :: ijk(:) - integer :: bin - - if (m % n_dimension == 1) then - bin = ijk(1) - elseif (m % n_dimension == 2) then - bin = (ijk(2) - 1) * m % dimension(1) + ijk(1) - elseif (m % n_dimension == 3) then - bin = ((ijk(3) - 1) * m % dimension(2) + (ijk(2) - 1)) & - * m % dimension(1) + ijk(1) - end if - - end function mesh_indices_to_bin - -!=============================================================================== -! BIN_TO_MESH_INDICES maps a single mesh bin from a TallyObject results array to -! (i), (i,j), or (i,j,k) indices -!=============================================================================== - - pure subroutine bin_to_mesh_indices(m, bin, ijk) - type(RegularMesh), intent(in) :: m - integer, intent(in) :: bin - integer, intent(out) :: ijk(:) - - if (m % n_dimension == 1) then - ijk(1) = bin - else if (m % n_dimension == 2) then - ijk(1) = mod(bin - 1, m % dimension(1)) + 1 - ijk(2) = (bin - 1)/m % dimension(1) + 1 - else if (m % n_dimension == 3) then - ijk(1) = mod(bin - 1, m % dimension(1)) + 1 - ijk(2) = mod(bin - 1, m % dimension(1) * m % dimension(2)) & - / m % dimension(1) + 1 - ijk(3) = (bin - 1)/(m % dimension(1) * m % dimension(2)) + 1 - end if - - end subroutine bin_to_mesh_indices - !=============================================================================== ! COUNT_BANK_SITES determines the number of fission bank sites in each cell of a ! given mesh as well as an optional energy group structure. This can be used for @@ -172,7 +62,7 @@ contains ! loop over fission sites and count how many are in each mesh box FISSION_SITES: do i = 1, n_sites ! determine scoring bin for entropy mesh - call get_mesh_indices(m, bank_array(i) % xyz, ijk, in_mesh) + call m % get_indices(bank_array(i) % xyz, ijk, in_mesh) ! if outside mesh, skip particle if (.not. in_mesh) then @@ -215,226 +105,4 @@ contains end subroutine count_bank_sites -!=============================================================================== -! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the -! outer boundary of the given mesh. This is important for determining whether a -! track will score to a mesh tally. -!=============================================================================== - - pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(1) - real(8), intent(in) :: xyz1(1) - logical :: intersects - - real(8) :: x0 ! track start point - real(8) :: x1 ! track end point - real(8) :: xm0 ! lower-left coordinates of mesh - real(8) :: xm1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - - ! Copy coordinates of ending point - x1 = xyz1(1) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - intersects = .true. - return - end if - - ! Check if line intersects right surface - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - intersects = .true. - return - end if - - end function mesh_intersects_1d - - pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(2) - real(8), intent(in) :: xyz1(2) - logical :: intersects - - real(8) :: x0, y0 ! track start point - real(8) :: x1, y1 ! track end point - real(8) :: xi, yi ! track intersection point with mesh - real(8) :: xm0, ym0 ! lower-left coordinates of mesh - real(8) :: xm1, ym1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - y0 = xyz0(2) - - ! Copy coordinates of ending point - x1 = xyz1(1) - y1 = xyz1(2) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - ym0 = m % lower_left(2) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - ym1 = m % upper_right(2) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface -- calculate the intersection point - ! y - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects back surface -- calculate the intersection point - ! x - if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then - xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects right surface -- calculate the intersection - ! point y - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects front surface -- calculate the intersection point - ! x - if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then - xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1) then - intersects = .true. - return - end if - end if - - end function mesh_intersects_2d - - pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(3) - real(8), intent(in) :: xyz1(3) - logical :: intersects - - real(8) :: x0, y0, z0 ! track start point - real(8) :: x1, y1, z1 ! track end point - real(8) :: xi, yi, zi ! track intersection point with mesh - real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh - real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - y0 = xyz0(2) - z0 = xyz0(3) - - ! Copy coordinates of ending point - x1 = xyz1(1) - y1 = xyz1(2) - z1 = xyz1(3) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - ym0 = m % lower_left(2) - zm0 = m % lower_left(3) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - ym1 = m % upper_right(2) - zm1 = m % upper_right(3) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface -- calculate the intersection point - ! (y,z) - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) - zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects back surface -- calculate the intersection point - ! (x,z) - if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then - xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) - zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects bottom surface -- calculate the intersection - ! point (x,y) - if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then - xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0) - yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0) - if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects right surface -- calculate the intersection point - ! (y,z) - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) - zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects front surface -- calculate the intersection point - ! (x,z) - if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then - xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) - zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects top surface -- calculate the intersection point - ! (x,y) - if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then - xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0) - yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0) - if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - end function mesh_intersects_3d - end module mesh diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 9da06f813..9c40ccbef 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -1,5 +1,7 @@ module mesh_header + use constants, only: NO_BIN_FOUND + implicit none !=============================================================================== @@ -16,6 +18,363 @@ module mesh_header real(8), allocatable :: lower_left(:) ! lower-left corner of mesh real(8), allocatable :: upper_right(:) ! upper-right corner of mesh real(8), allocatable :: width(:) ! width of each mesh cell + contains + procedure :: get_bin => regular_get_bin + procedure :: get_indices => regular_get_indices + procedure :: get_bin_from_indices => regular_get_bin_from_indices + procedure :: get_indices_from_bin => regular_get_indices_from_bin + procedure :: intersects => regular_intersects end type RegularMesh +contains + +!=============================================================================== +! GET_MESH_BIN determines the tally bin for a particle in a structured mesh +!=============================================================================== + + pure subroutine regular_get_bin(this, xyz, bin) + class(RegularMesh), intent(in) :: this + real(8), intent(in) :: xyz(:) ! coordinates + integer, intent(out) :: bin ! tally bin + + integer :: n ! size of mesh + integer :: d ! mesh dimension index + integer :: ijk(3) ! indices in mesh + logical :: in_mesh ! was given coordinate in mesh at all? + + ! Get number of dimensions + n = this % n_dimension + + ! Loop over the dimensions of the mesh + do d = 1, n + + ! Check for cases where particle is outside of mesh + if (xyz(d) < this % lower_left(d)) then + bin = NO_BIN_FOUND + return + elseif (xyz(d) > this % upper_right(d)) then + bin = NO_BIN_FOUND + return + end if + end do + + ! Determine indices + call this % get_indices(xyz, ijk, in_mesh) + + ! Convert indices to bin + if (in_mesh) then + bin = this % get_bin_from_indices(ijk) + else + bin = NO_BIN_FOUND + end if + + end subroutine regular_get_bin + +!=============================================================================== +! GET_MESH_INDICES determines the indices of a particle in a structured mesh +!=============================================================================== + + pure subroutine regular_get_indices(this, xyz, ijk, in_mesh) + class(RegularMesh), intent(in) :: this + real(8), intent(in) :: xyz(:) ! coordinates to check + integer, intent(out) :: ijk(:) ! indices in mesh + logical, intent(out) :: in_mesh ! were given coords in mesh? + + ! Find particle in mesh + ijk(:this % n_dimension) = ceiling((xyz(:this % n_dimension) - & + this % lower_left)/this % width) + + ! Determine if particle is in mesh + if (any(ijk(:this % n_dimension) < 1) .or. & + any(ijk(:this % n_dimension) > this % dimension)) then + in_mesh = .false. + else + in_mesh = .true. + end if + + end subroutine regular_get_indices + +!=============================================================================== +! MESH_INDICES_TO_BIN maps (i), (i,j), or (i,j,k) indices to a single bin number +! for use in a TallyObject results array +!=============================================================================== + + pure function regular_get_bin_from_indices(this, ijk) result(bin) + class(RegularMesh), intent(in) :: this + integer, intent(in) :: ijk(:) + integer :: bin + + if (this % n_dimension == 1) then + bin = ijk(1) + elseif (this % n_dimension == 2) then + bin = (ijk(2) - 1) * this % dimension(1) + ijk(1) + elseif (this % n_dimension == 3) then + bin = ((ijk(3) - 1) * this % dimension(2) + (ijk(2) - 1)) & + * this % dimension(1) + ijk(1) + end if + + end function regular_get_bin_from_indices + +!=============================================================================== +! BIN_TO_MESH_INDICES maps a single mesh bin from a TallyObject results array to +! (i), (i,j), or (i,j,k) indices +!=============================================================================== + + pure subroutine regular_get_indices_from_bin(this, bin, ijk) + class(RegularMesh), intent(in) :: this + integer, intent(in) :: bin + integer, intent(out) :: ijk(:) + + if (this % n_dimension == 1) then + ijk(1) = bin + else if (this % n_dimension == 2) then + ijk(1) = mod(bin - 1, this % dimension(1)) + 1 + ijk(2) = (bin - 1)/this % dimension(1) + 1 + else if (this % n_dimension == 3) then + ijk(1) = mod(bin - 1, this % dimension(1)) + 1 + ijk(2) = mod(bin - 1, this % dimension(1) * this % dimension(2)) & + / this % dimension(1) + 1 + ijk(3) = (bin - 1)/(this % dimension(1) * this % dimension(2)) + 1 + end if + + end subroutine regular_get_indices_from_bin + +!=============================================================================== +! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the +! outer boundary of the given mesh. This is important for determining whether a +! track will score to a mesh tally. +!=============================================================================== + + pure function regular_intersects(this, xyz0, xyz1) result(intersects) + class(RegularMesh), intent(in) :: this + real(8), intent(in) :: xyz0(1) + real(8), intent(in) :: xyz1(1) + logical :: intersects + + select case(this % n_dimension) + case (1) + intersects = mesh_intersects_1d(this, xyz0, xyz1) + case (2) + intersects = mesh_intersects_2d(this, xyz0, xyz1) + case (3) + intersects = mesh_intersects_3d(this, xyz0, xyz1) + end select + end function regular_intersects + + pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects) + type(RegularMesh), intent(in) :: m + real(8), intent(in) :: xyz0(:) + real(8), intent(in) :: xyz1(:) + logical :: intersects + + real(8) :: x0 ! track start point + real(8) :: x1 ! track end point + real(8) :: xm0 ! lower-left coordinates of mesh + real(8) :: xm1 ! upper-right coordinates of mesh + + ! Copy coordinates of starting point + x0 = xyz0(1) + + ! Copy coordinates of ending point + x1 = xyz1(1) + + ! Copy coordinates of mesh lower_left + xm0 = m % lower_left(1) + + ! Copy coordinates of mesh upper_right + xm1 = m % upper_right(1) + + ! Set default value for intersects + intersects = .false. + + ! Check if line intersects left surface + if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then + intersects = .true. + return + end if + + ! Check if line intersects right surface + if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then + intersects = .true. + return + end if + + end function mesh_intersects_1d + + pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects) + type(RegularMesh), intent(in) :: m + real(8), intent(in) :: xyz0(:) + real(8), intent(in) :: xyz1(:) + logical :: intersects + + real(8) :: x0, y0 ! track start point + real(8) :: x1, y1 ! track end point + real(8) :: xi, yi ! track intersection point with mesh + real(8) :: xm0, ym0 ! lower-left coordinates of mesh + real(8) :: xm1, ym1 ! upper-right coordinates of mesh + + ! Copy coordinates of starting point + x0 = xyz0(1) + y0 = xyz0(2) + + ! Copy coordinates of ending point + x1 = xyz1(1) + y1 = xyz1(2) + + ! Copy coordinates of mesh lower_left + xm0 = m % lower_left(1) + ym0 = m % lower_left(2) + + ! Copy coordinates of mesh upper_right + xm1 = m % upper_right(1) + ym1 = m % upper_right(2) + + ! Set default value for intersects + intersects = .false. + + ! Check if line intersects left surface -- calculate the intersection point + ! y + if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then + yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) + if (yi >= ym0 .and. yi < ym1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects back surface -- calculate the intersection point + ! x + if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then + xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) + if (xi >= xm0 .and. xi < xm1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects right surface -- calculate the intersection + ! point y + if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then + yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) + if (yi >= ym0 .and. yi < ym1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects front surface -- calculate the intersection point + ! x + if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then + xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) + if (xi >= xm0 .and. xi < xm1) then + intersects = .true. + return + end if + end if + + end function mesh_intersects_2d + + pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects) + type(RegularMesh), intent(in) :: m + real(8), intent(in) :: xyz0(:) + real(8), intent(in) :: xyz1(:) + logical :: intersects + + real(8) :: x0, y0, z0 ! track start point + real(8) :: x1, y1, z1 ! track end point + real(8) :: xi, yi, zi ! track intersection point with mesh + real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh + real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh + + ! Copy coordinates of starting point + x0 = xyz0(1) + y0 = xyz0(2) + z0 = xyz0(3) + + ! Copy coordinates of ending point + x1 = xyz1(1) + y1 = xyz1(2) + z1 = xyz1(3) + + ! Copy coordinates of mesh lower_left + xm0 = m % lower_left(1) + ym0 = m % lower_left(2) + zm0 = m % lower_left(3) + + ! Copy coordinates of mesh upper_right + xm1 = m % upper_right(1) + ym1 = m % upper_right(2) + zm1 = m % upper_right(3) + + ! Set default value for intersects + intersects = .false. + + ! Check if line intersects left surface -- calculate the intersection point + ! (y,z) + if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then + yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) + zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0) + if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects back surface -- calculate the intersection point + ! (x,z) + if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then + xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) + zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0) + if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects bottom surface -- calculate the intersection + ! point (x,y) + if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then + xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0) + yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0) + if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects right surface -- calculate the intersection point + ! (y,z) + if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then + yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) + zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0) + if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects front surface -- calculate the intersection point + ! (x,z) + if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then + xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) + zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0) + if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then + intersects = .true. + return + end if + end if + + ! Check if line intersects top surface -- calculate the intersection point + ! (x,y) + if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then + xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0) + yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0) + if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then + intersects = .true. + return + end if + end if + + end function mesh_intersects_3d + end module mesh_header diff --git a/src/output.F90 b/src/output.F90 index b4e620e13..4ea581041 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -12,7 +12,6 @@ module output use global use math, only: t_percentile use mesh_header, only: RegularMesh - use mesh, only: mesh_indices_to_bin, bin_to_mesh_indices use message_passing, only: master, n_procs use nuclide_header use particle_header, only: LocalCoord, Particle @@ -1055,7 +1054,7 @@ contains do i = 1, n_cells ! Get the indices for this cell - call bin_to_mesh_indices(m, i, ijk) + call m % get_indices_from_bin(i, ijk) matches(i_filter_mesh) % bins % data(1) = i ! Write the header for this cell diff --git a/src/physics.F90 b/src/physics.F90 index f40b7fd7b..8081aebcb 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -8,7 +8,6 @@ module physics use global use material_header, only: Material use math - use mesh, only: get_mesh_indices use message_passing use nuclide_header use output, only: write_message @@ -1090,7 +1089,7 @@ contains if (ufs) then ! Determine indices on ufs mesh for current location - call get_mesh_indices(ufs_mesh, p % coord(1) % xyz, ijk, in_mesh) + call ufs_mesh % get_indices(p % coord(1) % xyz, ijk, in_mesh) if (.not. in_mesh) then call write_particle_restart(p) call fatal_error("Source site outside UFS mesh!") diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index b5d34838c..c412e9e32 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -8,7 +8,6 @@ module physics_mg use material_header, only: Material use math, only: rotate_angle use mgxs_header, only: Mgxs, MgxsContainer - use mesh, only: get_mesh_indices use message_passing use output, only: write_message use particle_header, only: Particle @@ -196,7 +195,7 @@ contains if (ufs) then ! Determine indices on ufs mesh for current location - call get_mesh_indices(ufs_mesh, p % coord(1) % xyz, ijk, in_mesh) + call ufs_mesh % get_indices(p % coord(1) % xyz, ijk, in_mesh) if (.not. in_mesh) then call write_particle_restart(p) diff --git a/src/plot.F90 b/src/plot.F90 index 067d0c56f..b8ac3cfe6 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -10,8 +10,6 @@ module plot use geometry_header, only: Cell, root_universe use global use hdf5_interface - use mesh, only: get_mesh_indices - use mesh_header, only: RegularMesh use output, only: write_message, time_stamp use particle_header, only: LocalCoord, Particle use plot_header @@ -241,8 +239,8 @@ contains width = xyz_ur_plot - xyz_ll_plot associate (m => pl % meshlines_mesh) - call get_mesh_indices(m, xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh) - call get_mesh_indices(m, xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh) + call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh) + call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh) ! sweep through all meshbins on this plane and draw borders do i = ijk_ll(outer), ijk_ur(outer) diff --git a/src/tally.F90 b/src/tally.F90 index 338362c69..cccf79d04 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -9,10 +9,6 @@ module tally use geometry_header use global use math, only: t_percentile, calc_pn, calc_rn - use mesh, only: get_mesh_bin, bin_to_mesh_indices, & - get_mesh_indices, mesh_indices_to_bin, & - mesh_intersects_1d, mesh_intersects_2d, & - mesh_intersects_3d use mesh_header, only: RegularMesh use message_passing use output, only: header @@ -3259,19 +3255,13 @@ contains n_dim = m % n_dimension ! Determine indices for starting and ending location - call get_mesh_indices(m, xyz0, ijk0, start_in_mesh) - call get_mesh_indices(m, xyz1, ijk1, end_in_mesh) + call m % get_indices(xyz0, ijk0, start_in_mesh) + call m % get_indices(xyz1, ijk1, end_in_mesh) ! Check to see if start or end is in mesh -- if not, check if track still ! intersects with mesh if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (n_dim == 1) then - if (.not. mesh_intersects_1d(m, xyz0, xyz1)) cycle - else if (n_dim == 2) then - if (.not. mesh_intersects_2d(m, xyz0, xyz1)) cycle - else - if (.not. mesh_intersects_3d(m, xyz0, xyz1)) cycle - end if + if (.not. m % intersects(xyz0, xyz1)) cycle end if ! Calculate number of surface crossings @@ -3350,7 +3340,7 @@ contains all(ijk0(:n_dim) <= m % dimension)) then filter_matches(i_filter_surf) % bins % data(1) = d1 * 4 - 1 filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m, ijk0) + m % get_bin_from_indices(ijk0) filter_index = 1 do k = 1, size(t % filter) filter_index = filter_index + (filter_matches(t % & @@ -3389,7 +3379,7 @@ contains ijk0(d1) = ijk0(d1) + 1 filter_matches(i_filter_surf) % bins % data(1) = d1 * 4 - 2 filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m, ijk0) + m % get_bin_from_indices(ijk0) filter_index = 1 do k = 1, size(t % filter) filter_index = filter_index + (filter_matches(t % & @@ -3412,7 +3402,7 @@ contains all(ijk0(:n_dim) <= m % dimension)) then filter_matches(i_filter_surf) % bins % data(1) = d1 * 4 - 3 filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m, ijk0) + m % get_bin_from_indices(ijk0) filter_index = 1 do k = 1, size(t % filter) filter_index = filter_index + (filter_matches(t % & @@ -3451,7 +3441,7 @@ contains ijk0(d1) = ijk0(d1) - 1 filter_matches(i_filter_surf) % bins % data(1) = d1 * 4 filter_matches(i_filter_mesh) % bins % data(1) = & - mesh_indices_to_bin(m, ijk0) + m % get_bin_from_indices(ijk0) filter_index = 1 do k = 1, size(t % filter) filter_index = filter_index + (filter_matches(t % & diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 0a7ce23cd..f8283c071 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -7,10 +7,6 @@ module tally_filter use global use hdf5_interface use mesh_header, only: RegularMesh - use mesh, only: get_mesh_bin, bin_to_mesh_indices, & - get_mesh_indices, mesh_indices_to_bin, & - mesh_intersects_1d, mesh_intersects_2d, & - mesh_intersects_3d use particle_header, only: Particle use string, only: to_str use tally_filter_header, only: TallyFilter, TallyFilterContainer, & @@ -266,7 +262,7 @@ contains if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. - call get_mesh_bin(m, p % coord(1) % xyz, bin) + call m % get_bin(p % coord(1) % xyz, bin) if (bin /= NO_BIN_FOUND) then call match % bins % push_back(bin) call match % weights % push_back(ONE) @@ -288,25 +284,13 @@ contains xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw ! Determine indices for starting and ending location. - call get_mesh_indices(m, xyz0, ijk0(:n), start_in_mesh) - call get_mesh_indices(m, xyz1, ijk1(:n), end_in_mesh) + call m % get_indices(xyz0, ijk0(:n), start_in_mesh) + call m % get_indices(xyz1, ijk1(:n), end_in_mesh) ! If this is the first iteration of the filter loop, check if the track ! intersects any part of the mesh. if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (n == 1) then - if (.not. mesh_intersects_1d(m, xyz0, xyz1)) then - return - end if - else if (n == 2) then - if (.not. mesh_intersects_2d(m, xyz0, xyz1)) then - return - end if - else - if (.not. mesh_intersects_3d(m, xyz0, xyz1)) then - return - end if - end if + if (.not. m % intersects(xyz0, xyz1)) return end if ! ======================================================================== @@ -393,7 +377,7 @@ contains end if ! Assign the next tally bin and the score. - bin = mesh_indices_to_bin(m, ijk0(:n)) + bin = m % get_bin_from_indices(ijk0(:n)) call match % bins % push_back(bin) call match % weights % push_back(distance / total_distance) @@ -440,7 +424,7 @@ contains m => meshes(this % mesh) allocate(ijk(m % n_dimension)) - call bin_to_mesh_indices(m, bin, ijk) + call m % get_indices_from_bin(bin, ijk) if (m % n_dimension == 1) then label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" elseif (m % n_dimension == 2) then diff --git a/src/trigger.F90 b/src/trigger.F90 index cb5f2c4c8..2927aea6c 100644 --- a/src/trigger.F90 +++ b/src/trigger.F90 @@ -11,7 +11,6 @@ module trigger use global use string, only: to_str use output, only: warning, write_message - use mesh, only: bin_to_mesh_indices use mesh_header, only: RegularMesh use message_passing, only: master use trigger_header, only: TriggerObject @@ -344,7 +343,7 @@ contains do i = 1, n_cells ! Get the indices for this cell - call bin_to_mesh_indices(m, i, ijk) + call m % get_indices_from_bin(i, ijk) filter_matches(i_filter_mesh) % bins % data(1) = i do l = 1, n From 2caf3fe856ae824b62ce96bc6fdddab01b21043e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Aug 2017 10:57:36 -0500 Subject: [PATCH 114/229] Move tally modules into tallies subdirectory --- CMakeLists.txt | 17 +++++++++-------- src/{ => tallies}/tally.F90 | 0 src/{ => tallies}/tally_filter.F90 | 0 src/{ => tallies}/tally_filter_header.F90 | 0 src/{ => tallies}/tally_header.F90 | 0 src/{ => tallies}/tally_initialize.F90 | 0 src/{ => tallies}/trigger.F90 | 0 src/{ => tallies}/trigger_header.F90 | 0 8 files changed, 9 insertions(+), 8 deletions(-) rename src/{ => tallies}/tally.F90 (100%) rename src/{ => tallies}/tally_filter.F90 (100%) rename src/{ => tallies}/tally_filter_header.F90 (100%) rename src/{ => tallies}/tally_header.F90 (100%) rename src/{ => tallies}/tally_initialize.F90 (100%) rename src/{ => tallies}/trigger.F90 (100%) rename src/{ => tallies}/trigger_header.F90 (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c21b44cc1..73d967b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -367,21 +367,22 @@ set(LIBOPENMC_FORTRAN_SRC src/string.F90 src/summary.F90 src/surface_header.F90 - src/tally.F90 - src/tally_filter.F90 - src/tally_filter_header.F90 - src/tally_header.F90 - src/tally_initialize.F90 src/timer_header.F90 src/tracking.F90 src/track_output.F90 - src/trigger.F90 - src/trigger_header.F90 src/urr_header.F90 src/vector_header.F90 src/volume_calc.F90 src/volume_header.F90 - src/xml_interface.F90) + src/xml_interface.F90 + src/tallies/tally.F90 + src/tallies/tally_filter.F90 + src/tallies/tally_filter_header.F90 + src/tallies/tally_header.F90 + src/tallies/tally_initialize.F90 + src/tallies/trigger.F90 + src/tallies/trigger_header.F90 +) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) add_executable(${program} src/main.F90) diff --git a/src/tally.F90 b/src/tallies/tally.F90 similarity index 100% rename from src/tally.F90 rename to src/tallies/tally.F90 diff --git a/src/tally_filter.F90 b/src/tallies/tally_filter.F90 similarity index 100% rename from src/tally_filter.F90 rename to src/tallies/tally_filter.F90 diff --git a/src/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 similarity index 100% rename from src/tally_filter_header.F90 rename to src/tallies/tally_filter_header.F90 diff --git a/src/tally_header.F90 b/src/tallies/tally_header.F90 similarity index 100% rename from src/tally_header.F90 rename to src/tallies/tally_header.F90 diff --git a/src/tally_initialize.F90 b/src/tallies/tally_initialize.F90 similarity index 100% rename from src/tally_initialize.F90 rename to src/tallies/tally_initialize.F90 diff --git a/src/trigger.F90 b/src/tallies/trigger.F90 similarity index 100% rename from src/trigger.F90 rename to src/tallies/trigger.F90 diff --git a/src/trigger_header.F90 b/src/tallies/trigger_header.F90 similarity index 100% rename from src/trigger_header.F90 rename to src/tallies/trigger_header.F90 From 8d2700004363379869e7c3a212b941b450b7888e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Aug 2017 11:30:17 -0500 Subject: [PATCH 115/229] Move mesh filter into its own module --- CMakeLists.txt | 1 + src/cmfd_data.F90 | 2 +- src/cmfd_input.F90 | 1 + src/input_xml.F90 | 1 + src/output.F90 | 1 + src/tallies/tally.F90 | 1 + src/tallies/tally_filter.F90 | 232 +--------------------------- src/tallies/tally_filter_mesh.F90 | 246 ++++++++++++++++++++++++++++++ src/tallies/trigger.F90 | 2 +- 9 files changed, 255 insertions(+), 232 deletions(-) create mode 100644 src/tallies/tally_filter_mesh.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 73d967b3f..a7e8da55a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally.F90 src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 + src/tallies/tally_filter_mesh.F90 src/tallies/tally_header.F90 src/tallies/tally_initialize.F90 src/tallies/trigger.F90 diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index c873b1beb..b93b4860f 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -6,7 +6,7 @@ module cmfd_data !============================================================================== use constants - use tally_filter, only: MeshFilter + use tally_filter_mesh, only: MeshFilter implicit none private diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 68cd94aa6..7394157d2 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -254,6 +254,7 @@ contains use tally_header, only: TallyObject use tally_filter_header use tally_filter + use tally_filter_mesh, only: MeshFilter use tally_initialize, only: add_tallies use xml_interface diff --git a/src/input_xml.F90 b/src/input_xml.F90 index cde7e21e0..67678af8b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -29,6 +29,7 @@ module input_xml use tally_header, only: TallyObject use tally_filter_header, only: TallyFilterContainer use tally_filter + use tally_filter_mesh, only: MeshFilter use tally_initialize, only: add_tallies use xml_interface diff --git a/src/output.F90 b/src/output.F90 index 4ea581041..ec47070ef 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -20,6 +20,7 @@ module output use string, only: to_upper, to_str use tally_header, only: TallyObject use tally_filter + use tally_filter_mesh, only: MeshFilter use tally_filter_header, only: TallyFilterMatch implicit none diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index cccf79d04..1ed2005e1 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -15,6 +15,7 @@ module tally use particle_header, only: LocalCoord, Particle use string, only: to_str use tally_filter + use tally_filter_mesh, only: MeshFilter implicit none diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index f8283c071..cf8e49b81 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -1,34 +1,20 @@ module tally_filter + use hdf5, only: HID_T + use algorithm, only: binary_search use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION, ERROR_REAL use dict_header, only: DictIntInt use geometry_header, only: root_universe, RectLattice, HexLattice use global use hdf5_interface - use mesh_header, only: RegularMesh use particle_header, only: Particle use string, only: to_str use tally_filter_header, only: TallyFilter, TallyFilterContainer, & TallyFilterMatch - use hdf5, only: HID_T - implicit none -!=============================================================================== -! MESHFILTER indexes the location of particle events to a regular mesh. For -! tracklength tallies, it will produce multiple valid bins and the bin weight -! will correspond to the fraction of the track length that lies in that bin. -!=============================================================================== - type, extends(TallyFilter) :: MeshFilter - integer :: mesh - contains - procedure :: get_all_bins => get_all_bins_mesh - procedure :: to_statepoint => to_statepoint_mesh - procedure :: text_label => text_label_mesh - end type MeshFilter - !=============================================================================== ! UNIVERSEFILTER specifies which geometric universes tally events reside in. !=============================================================================== @@ -222,220 +208,6 @@ contains ! the abstract TallyFilter class. !=============================================================================== -!=============================================================================== -! MeshFilter methods -!=============================================================================== - subroutine get_all_bins_mesh(this, p, estimator, match) - class(MeshFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer, parameter :: MAX_SEARCH_ITER = 100 ! Maximum number of times we can - ! can loop while trying to find - ! the first intersection. - - integer :: j ! loop index for direction - integer :: n - integer :: ijk0(3) ! indices of starting coordinates - integer :: ijk1(3) ! indices of ending coordinates - integer :: search_iter ! loop count for intersection search - integer :: bin - real(8) :: weight ! weight to be pushed back - real(8) :: uvw(3) ! cosine of angle of particle - real(8) :: xyz0(3) ! starting/intermediate coordinates - real(8) :: xyz1(3) ! ending coordinates of particle - real(8) :: xyz_cross ! coordinates of next boundary - real(8) :: d(3) ! distance to each bounding surface - real(8) :: total_distance ! distance of entire particle track - real(8) :: distance ! distance traveled in mesh cell - logical :: start_in_mesh ! starting coordinates inside mesh? - logical :: end_in_mesh ! ending coordinates inside mesh? - type(RegularMesh), pointer :: m - - weight = ERROR_REAL - - ! Get a pointer to the mesh. - m => meshes(this % mesh) - n = m % n_dimension - - if (estimator /= ESTIMATOR_TRACKLENGTH) then - ! If this is an analog or collision tally, then there can only be one - ! valid mesh bin. - call m % get_bin(p % coord(1) % xyz, bin) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - return - end if - - ! A track can span multiple mesh bins so we need to handle a lot of - ! intersection logic for tracklength tallies. - - ! ======================================================================== - ! Determine if the track intersects the tally mesh. - - ! Copy the starting and ending coordinates of the particle. Offset these - ! just a bit for the purposes of determining if there was an intersection - ! in case the mesh surfaces coincide with lattice/geometric surfaces which - ! might produce finite-precision errors. - xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw - xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw - - ! Determine indices for starting and ending location. - call m % get_indices(xyz0, ijk0(:n), start_in_mesh) - call m % get_indices(xyz1, ijk1(:n), end_in_mesh) - - ! If this is the first iteration of the filter loop, check if the track - ! intersects any part of the mesh. - if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (.not. m % intersects(xyz0, xyz1)) return - end if - - ! ======================================================================== - ! Figure out which mesh cell to tally. - - ! Copy the un-modified coordinates the particle direction. - xyz0 = p % last_xyz - xyz1 = p % coord(1) % xyz - uvw = p % coord(1) % uvw - - ! Compute the length of the entire track. - total_distance = sqrt(sum((xyz1 - xyz0)**2)) - - ! We are looking for the first valid mesh bin. Check to see if the - ! particle starts inside the mesh. - if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then - ! The particle does not start in the mesh. Note that we nudged the - ! start and end coordinates by a TINY_BIT each so we will have - ! difficulty resolving tracks that are less than 2*TINY_BIT in length. - ! If the track is that short, it is also insignificant so we can - ! safely ignore it in the tallies. - if (total_distance < 2*TINY_BIT) return - - ! The particle does not start in the mesh so keep iterating the ijk0 - ! indices to cross the nearest mesh surface until we've found a valid - ! bin. MAX_SEARCH_ITER prevents an infinite loop. - search_iter = 0 - do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) - if (search_iter == MAX_SEARCH_ITER) then - call warning("Failed to find a mesh intersection on a tally mesh & - &filter.") - return - end if - - do j = 1, n - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:n), 1) - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if - - search_iter = search_iter + 1 - end do - distance = d(j) - xyz0 = xyz0 + distance * uvw - end if - - do - ! ======================================================================== - ! Compute the length of the track segment in the appropiate mesh cell and - ! return. - - if (all(ijk0(:n) == ijk1(:n))) then - ! The track ends in this cell. Use the particle end location rather - ! than the mesh surface. - distance = sqrt(sum((xyz1 - xyz0)**2)) - else - ! The track exits this cell. Determine the distance to the closest mesh - ! surface. - do j = 1, n - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:n), 1) - distance = d(j) - end if - - ! Assign the next tally bin and the score. - bin = m % get_bin_from_indices(ijk0(:n)) - call match % bins % push_back(bin) - call match % weights % push_back(distance / total_distance) - - ! Find the next mesh cell that the particle enters. - - ! If the particle track ends in that bin, then we are done. - if (all(ijk0(:n) == ijk1(:n))) exit - - ! Translate the starting coordintes by the distance to that face. This - ! should be the xyz that we computed the distance to in the last - ! iteration of the filter loop. - xyz0 = xyz0 + distance * uvw - - ! Increment the indices into the next mesh cell. - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if - - ! If the next indices are invalid, then the track has left the mesh and - ! we are done. - if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit - end do - - end subroutine get_all_bins_mesh - - subroutine to_statepoint_mesh(this, filter_group) - class(MeshFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "mesh") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", meshes(this % mesh) % id) - end subroutine to_statepoint_mesh - - function text_label_mesh(this, bin) result(label) - class(MeshFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - integer, allocatable :: ijk(:) - type(RegularMesh), pointer :: m - - m => meshes(this % mesh) - allocate(ijk(m % n_dimension)) - call m % get_indices_from_bin(bin, ijk) - if (m % n_dimension == 1) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" - elseif (m % n_dimension == 2) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ")" - elseif (m % n_dimension == 3) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" - end if - end function text_label_mesh - !=============================================================================== ! UniverseFilter methods !=============================================================================== diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 new file mode 100644 index 000000000..fc0fdc4eb --- /dev/null +++ b/src/tallies/tally_filter_mesh.F90 @@ -0,0 +1,246 @@ +module tally_filter_mesh + + use hdf5 + + use constants + use error, only: warning + use mesh_header + use global, only: meshes + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header, only: TallyFilter, TallyFilterMatch + + implicit none + + private + public :: MeshFilter + +!=============================================================================== +! MESHFILTER indexes the location of particle events to a regular mesh. For +! tracklength tallies, it will produce multiple valid bins and the bin weight +! will correspond to the fraction of the track length that lies in that bin. +!=============================================================================== + + type, extends(TallyFilter) :: MeshFilter + integer :: mesh + contains + procedure :: get_all_bins => get_all_bins_mesh + procedure :: to_statepoint => to_statepoint_mesh + procedure :: text_label => text_label_mesh + end type MeshFilter + +contains + + subroutine get_all_bins_mesh(this, p, estimator, match) + class(MeshFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer, parameter :: MAX_SEARCH_ITER = 100 ! Maximum number of times we can + ! can loop while trying to find + ! the first intersection. + + integer :: j ! loop index for direction + integer :: n + integer :: ijk0(3) ! indices of starting coordinates + integer :: ijk1(3) ! indices of ending coordinates + integer :: search_iter ! loop count for intersection search + integer :: bin + real(8) :: weight ! weight to be pushed back + real(8) :: uvw(3) ! cosine of angle of particle + real(8) :: xyz0(3) ! starting/intermediate coordinates + real(8) :: xyz1(3) ! ending coordinates of particle + real(8) :: xyz_cross ! coordinates of next boundary + real(8) :: d(3) ! distance to each bounding surface + real(8) :: total_distance ! distance of entire particle track + real(8) :: distance ! distance traveled in mesh cell + logical :: start_in_mesh ! starting coordinates inside mesh? + logical :: end_in_mesh ! ending coordinates inside mesh? + type(RegularMesh), pointer :: m + + weight = ERROR_REAL + + ! Get a pointer to the mesh. + m => meshes(this % mesh) + n = m % n_dimension + + if (estimator /= ESTIMATOR_TRACKLENGTH) then + ! If this is an analog or collision tally, then there can only be one + ! valid mesh bin. + call m % get_bin(p % coord(1) % xyz, bin) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + return + end if + + ! A track can span multiple mesh bins so we need to handle a lot of + ! intersection logic for tracklength tallies. + + ! ======================================================================== + ! Determine if the track intersects the tally mesh. + + ! Copy the starting and ending coordinates of the particle. Offset these + ! just a bit for the purposes of determining if there was an intersection + ! in case the mesh surfaces coincide with lattice/geometric surfaces which + ! might produce finite-precision errors. + xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw + xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw + + ! Determine indices for starting and ending location. + call m % get_indices(xyz0, ijk0(:n), start_in_mesh) + call m % get_indices(xyz1, ijk1(:n), end_in_mesh) + + ! If this is the first iteration of the filter loop, check if the track + ! intersects any part of the mesh. + if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then + if (.not. m % intersects(xyz0, xyz1)) return + end if + + ! ======================================================================== + ! Figure out which mesh cell to tally. + + ! Copy the un-modified coordinates the particle direction. + xyz0 = p % last_xyz + xyz1 = p % coord(1) % xyz + uvw = p % coord(1) % uvw + + ! Compute the length of the entire track. + total_distance = sqrt(sum((xyz1 - xyz0)**2)) + + ! We are looking for the first valid mesh bin. Check to see if the + ! particle starts inside the mesh. + if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then + ! The particle does not start in the mesh. Note that we nudged the + ! start and end coordinates by a TINY_BIT each so we will have + ! difficulty resolving tracks that are less than 2*TINY_BIT in length. + ! If the track is that short, it is also insignificant so we can + ! safely ignore it in the tallies. + if (total_distance < 2*TINY_BIT) return + + ! The particle does not start in the mesh so keep iterating the ijk0 + ! indices to cross the nearest mesh surface until we've found a valid + ! bin. MAX_SEARCH_ITER prevents an infinite loop. + search_iter = 0 + do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) + if (search_iter == MAX_SEARCH_ITER) then + call warning("Failed to find a mesh intersection on a tally mesh & + &filter.") + return + end if + + do j = 1, n + if (abs(uvw(j)) < FP_PRECISION) then + d(j) = INFINITY + else if (uvw(j) > 0) then + xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) + d(j) = (xyz_cross - xyz0(j)) / uvw(j) + else + xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) + d(j) = (xyz_cross - xyz0(j)) / uvw(j) + end if + end do + j = minloc(d(:n), 1) + if (uvw(j) > ZERO) then + ijk0(j) = ijk0(j) + 1 + else + ijk0(j) = ijk0(j) - 1 + end if + + search_iter = search_iter + 1 + end do + distance = d(j) + xyz0 = xyz0 + distance * uvw + end if + + do + ! ======================================================================== + ! Compute the length of the track segment in the appropiate mesh cell and + ! return. + + if (all(ijk0(:n) == ijk1(:n))) then + ! The track ends in this cell. Use the particle end location rather + ! than the mesh surface. + distance = sqrt(sum((xyz1 - xyz0)**2)) + else + ! The track exits this cell. Determine the distance to the closest mesh + ! surface. + do j = 1, n + if (abs(uvw(j)) < FP_PRECISION) then + d(j) = INFINITY + else if (uvw(j) > 0) then + xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) + d(j) = (xyz_cross - xyz0(j)) / uvw(j) + else + xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) + d(j) = (xyz_cross - xyz0(j)) / uvw(j) + end if + end do + j = minloc(d(:n), 1) + distance = d(j) + end if + + ! Assign the next tally bin and the score. + bin = m % get_bin_from_indices(ijk0(:n)) + call match % bins % push_back(bin) + call match % weights % push_back(distance / total_distance) + + ! Find the next mesh cell that the particle enters. + + ! If the particle track ends in that bin, then we are done. + if (all(ijk0(:n) == ijk1(:n))) exit + + ! Translate the starting coordintes by the distance to that face. This + ! should be the xyz that we computed the distance to in the last + ! iteration of the filter loop. + xyz0 = xyz0 + distance * uvw + + ! Increment the indices into the next mesh cell. + if (uvw(j) > ZERO) then + ijk0(j) = ijk0(j) + 1 + else + ijk0(j) = ijk0(j) - 1 + end if + + ! If the next indices are invalid, then the track has left the mesh and + ! we are done. + if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit + end do + + end subroutine get_all_bins_mesh + + subroutine to_statepoint_mesh(this, filter_group) + class(MeshFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "mesh") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", meshes(this % mesh) % id) + end subroutine to_statepoint_mesh + + function text_label_mesh(this, bin) result(label) + class(MeshFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + integer, allocatable :: ijk(:) + + associate (m => meshes(this % mesh)) + allocate(ijk(m % n_dimension)) + call m % get_indices_from_bin(bin, ijk) + if (m % n_dimension == 1) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" + elseif (m % n_dimension == 2) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ")" + elseif (m % n_dimension == 3) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" + end if + end associate + end function text_label_mesh + +end module tally_filter_mesh diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 2927aea6c..7fee92fb8 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -15,7 +15,7 @@ module trigger use message_passing, only: master use trigger_header, only: TriggerObject use tally, only: TallyObject - use tally_filter, only: MeshFilter + use tally_filter_mesh, only: MeshFilter implicit none From 6e82c34a58e7aabd627bc8b66fcb4019a78bd893 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Aug 2017 12:14:56 -0500 Subject: [PATCH 116/229] Remove tally_filter_mesh -> global dependence --- src/global.F90 | 5 +++-- src/mesh_header.F90 | 2 ++ src/tallies/tally_filter_mesh.F90 | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index 9e2ca1c25..628d69c31 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -12,7 +12,6 @@ module global use dict_header, only: DictCharInt, DictIntInt use geometry_header, only: Cell, Universe, Lattice, LatticeContainer use material_header, only: Material - use mesh_header, only: RegularMesh use mgxs_header, only: Mgxs, MgxsContainer use plot_header, only: ObjectPlot use set_header, only: SetInt @@ -29,6 +28,9 @@ module global use nuclide_header use sab_header + ! Inherit meshes array + use mesh_header + implicit none ! ============================================================================ @@ -125,7 +127,6 @@ module global ! ============================================================================ ! TALLY-RELATED VARIABLES - type(RegularMesh), allocatable, target :: meshes(:) type(TallyObject), allocatable, target :: tallies(:) type(TallyFilterContainer), allocatable, target :: filters(:) type(TallyFilterMatch), allocatable :: filter_matches(:) diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 9c40ccbef..97dd24838 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -26,6 +26,8 @@ module mesh_header procedure :: intersects => regular_intersects end type RegularMesh + type(RegularMesh), allocatable, target :: meshes(:) + contains !=============================================================================== diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index fc0fdc4eb..576ab6dbd 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -5,7 +5,6 @@ module tally_filter_mesh use constants use error, only: warning use mesh_header - use global, only: meshes use hdf5_interface use particle_header, only: Particle use string, only: to_str From 01fcdf9acd3b8d38a1d1ae4ef168476432f6e8a0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Aug 2017 12:49:27 -0500 Subject: [PATCH 117/229] Add to_hdf5 type-bound procedure to RegularMesh --- src/mesh_header.F90 | 29 +++++++++++++++++++++++++++++ src/state_point.F90 | 18 ++---------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 97dd24838..f112eb23f 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -1,9 +1,16 @@ module mesh_header + use hdf5 + use constants, only: NO_BIN_FOUND + use hdf5_interface + use string, only: to_str implicit none + private + public :: RegularMesh, meshes + !=============================================================================== ! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by ! congruent squares or cubes @@ -24,6 +31,7 @@ module mesh_header procedure :: get_bin_from_indices => regular_get_bin_from_indices procedure :: get_indices_from_bin => regular_get_indices_from_bin procedure :: intersects => regular_intersects + procedure :: to_hdf5 => regular_to_hdf5 end type RegularMesh type(RegularMesh), allocatable, target :: meshes(:) @@ -379,4 +387,25 @@ contains end function mesh_intersects_3d +!=============================================================================== +! TO_HDF5 writes the mesh data to an HDF5 group +!=============================================================================== + + subroutine regular_to_hdf5(this, group) + class(RegularMesh), intent(in) :: this + integer(HID_T), intent(in) :: group + + integer(HID_T) :: mesh_group + + mesh_group = create_group(group, "mesh " // trim(to_str(this % id))) + + call write_dataset(mesh_group, "type", "regular") + call write_dataset(mesh_group, "dimension", this % dimension) + call write_dataset(mesh_group, "lower_left", this % lower_left) + call write_dataset(mesh_group, "upper_right", this % upper_right) + call write_dataset(mesh_group, "width", this % width) + + call close_group(mesh_group) + end subroutine regular_to_hdf5 + end module mesh_header diff --git a/src/state_point.F90 b/src/state_point.F90 index e2a476e7e..3705f90e3 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -45,7 +45,7 @@ contains integer, allocatable :: id_array(:) integer(HID_T) :: file_id integer(HID_T) :: cmfd_group, tallies_group, tally_group, meshes_group, & - mesh_group, filters_group, filter_group, derivs_group, & + filters_group, filter_group, derivs_group, & deriv_group, runtime_group integer(C_INT) :: err real(C_DOUBLE) :: k_combined(2) @@ -158,21 +158,7 @@ contains ! Write information for meshes MESH_LOOP: do i = 1, n_meshes - associate (m => meshes(i)) - mesh_group = create_group(meshes_group, "mesh " & - // trim(to_str(m % id))) - - select case (m % type) - case (MESH_REGULAR) - call write_dataset(mesh_group, "type", "regular") - end select - call write_dataset(mesh_group, "dimension", m % dimension) - call write_dataset(mesh_group, "lower_left", m % lower_left) - call write_dataset(mesh_group, "upper_right", m % upper_right) - call write_dataset(mesh_group, "width", m % width) - - call close_group(mesh_group) - end associate + call meshes(i) % to_hdf5(meshes_group) end do MESH_LOOP end if From fd1d6faf0f70898f1f798644eb969df01a9f75a4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Aug 2017 15:53:30 -0500 Subject: [PATCH 118/229] Have mesh filter store a pointer to a mesh rather than the index --- src/cmfd_data.F90 | 6 ++---- src/cmfd_input.F90 | 4 ++-- src/input_xml.F90 | 11 ++++------- src/output.F90 | 2 +- src/tallies/tally.F90 | 2 +- src/tallies/tally_filter_mesh.F90 | 10 +++++----- src/tallies/trigger.F90 | 2 +- 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index b93b4860f..779c350d7 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -102,9 +102,8 @@ contains i_filt = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filt) % obj) type is (MeshFilter) - i_mesh = filt % mesh + m => filt % mesh end select - m => meshes(i_mesh) ! Set mesh widths cmfd % hxyz(1,:,:,:) = m % width(1) ! set x width @@ -121,9 +120,8 @@ contains i_filt = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filt) % obj) type is (MeshFilter) - i_mesh = filt % mesh + m => filt % mesh end select - m => meshes(i_mesh) ! Check for energy filters energy_filters = (t % find_filter(FILTER_ENERGYIN) > 0) diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 7394157d2..55862cd52 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -391,7 +391,7 @@ contains type is (MeshFilter) filt % id = i_filt filt % n_bins = product(m % dimension) - filt % mesh = n_user_meshes + 1 + filt % mesh => meshes(n_user_meshes + 1) ! Add filter to dictionary call filter_dict % add_key(filt % id, i_filt) end select @@ -436,7 +436,7 @@ contains ! We need to increase the dimension by one since we also need ! currents coming into and out of the boundary mesh cells. filt % n_bins = product(m % dimension + 1) - filt % mesh = n_user_meshes + 1 + filt % mesh => meshes(n_user_meshes + 1) ! Add filter to dictionary call filter_dict % add_key(filt % id, i_filt) end select diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 67678af8b..93a75d61c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3117,7 +3117,7 @@ contains filt % n_bins = product(m % dimension) ! Store the index of the mesh - filt % mesh = i_mesh + filt % mesh => meshes(i_mesh) end select case ('energy') @@ -3859,8 +3859,7 @@ contains ! Get pointer to mesh select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - i_mesh = filt % mesh - m => meshes(i_mesh) + m => filt % mesh end select ! Copy filter indices to temporary array @@ -3888,7 +3887,7 @@ contains select type(filt => filters(i_filt) % obj) type is (MeshFilter) filt % id = i_filt - filt % mesh = i_mesh + filt % mesh => m ! We need to increase the dimension by one since we also need ! currents coming into and out of the boundary mesh cells. @@ -4347,7 +4346,6 @@ contains integer :: i, j integer :: n_cols, col_id, n_comp, n_masks, n_meshlines integer :: meshid - integer :: i_mesh integer, allocatable :: iarray(:) logical :: file_exists ! does plots.xml file exist? character(MAX_LINE_LEN) :: filename ! absolute path to plots.xml @@ -4682,9 +4680,8 @@ contains select type(filt => filters(cmfd_tallies(1) % & filter(cmfd_tallies(1) % find_filter(FILTER_MESH))) % obj) type is (MeshFilter) - i_mesh = filt % mesh + pl % meshlines_mesh => filt % mesh end select - pl % meshlines_mesh => meshes(i_mesh) case ('entropy') diff --git a/src/output.F90 b/src/output.F90 index ec47070ef..2b69906b2 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -1023,7 +1023,7 @@ contains i_filter_mesh = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => meshes(filt % mesh) + m => filt % mesh end select ! Get surface filter index and stride diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 1ed2005e1..404a1a487 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3250,7 +3250,7 @@ contains ! Get pointer to mesh select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => meshes(filt % mesh) + m => filt % mesh end select n_dim = m % n_dimension diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index 576ab6dbd..5c8c3ba09 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -4,7 +4,7 @@ module tally_filter_mesh use constants use error, only: warning - use mesh_header + use mesh_header, only: RegularMesh use hdf5_interface use particle_header, only: Particle use string, only: to_str @@ -22,7 +22,7 @@ module tally_filter_mesh !=============================================================================== type, extends(TallyFilter) :: MeshFilter - integer :: mesh + type(RegularMesh), pointer :: mesh => null() contains procedure :: get_all_bins => get_all_bins_mesh procedure :: to_statepoint => to_statepoint_mesh @@ -62,7 +62,7 @@ contains weight = ERROR_REAL ! Get a pointer to the mesh. - m => meshes(this % mesh) + m => this % mesh n = m % n_dimension if (estimator /= ESTIMATOR_TRACKLENGTH) then @@ -217,7 +217,7 @@ contains call write_dataset(filter_group, "type", "mesh") call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", meshes(this % mesh) % id) + call write_dataset(filter_group, "bins", this % mesh % id) end subroutine to_statepoint_mesh function text_label_mesh(this, bin) result(label) @@ -227,7 +227,7 @@ contains integer, allocatable :: ijk(:) - associate (m => meshes(this % mesh)) + associate (m => this % mesh) allocate(ijk(m % n_dimension)) call m % get_indices_from_bin(bin, ijk) if (m % n_dimension == 1) then diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 7fee92fb8..d8a0f078c 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -315,7 +315,7 @@ contains i_filter_surf = t % filter(t % find_filter(FILTER_SURFACE)) select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => meshes(filt % mesh) + m => filt % mesh end select ! initialize bins array From 472d808e9732631cda9fc799601517d99ace72ed Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 10:49:17 -0500 Subject: [PATCH 119/229] Move MGXS-related module variables to mgxs_header --- src/global.F90 | 20 +---------- src/input_xml.F90 | 1 + src/mgxs_header.F90 | 20 ++++++++++- src/particle_header.F90 | 3 +- src/tallies/tally_filter.F90 | 66 ++++++++++++++++++------------------ 5 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index 628d69c31..27c28b040 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -12,7 +12,7 @@ module global use dict_header, only: DictCharInt, DictIntInt use geometry_header, only: Cell, Universe, Lattice, LatticeContainer use material_header, only: Material - use mgxs_header, only: Mgxs, MgxsContainer + use mgxs_header use plot_header, only: ObjectPlot use set_header, only: SetInt use stl_vector, only: VectorInt @@ -97,24 +97,6 @@ module global ! ============================================================================ ! MULTI-GROUP CROSS SECTION RELATED VARIABLES - ! Cross section arrays - type(MgxsContainer), allocatable, target :: nuclides_MG(:) - - ! Cross section caches - type(MgxsContainer), target, allocatable :: macro_xs(:) - - ! Number of energy groups - integer :: num_energy_groups - - ! Number of delayed groups - integer :: num_delayed_groups - - ! Energy group structure - real(8), allocatable :: energy_bins(:) - - ! Midpoint of the energy group structure - real(8), allocatable :: energy_bin_avg(:) - ! Maximum Data Order integer :: max_order diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 93a75d61c..6923b3934 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -16,6 +16,7 @@ module input_xml use mesh_header, only: RegularMesh use message_passing use mgxs_data, only: create_macro_xs, read_mgxs + use mgxs_header use multipole, only: multipole_read use output, only: write_message, title, header use plot_header diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index faf0fbaff..a00a3756d 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -209,7 +209,25 @@ module mgxs_header procedure :: calculate_xs => mgxsang_calculate_xs end type MgxsAngle - contains + ! Cross section arrays + type(MgxsContainer), allocatable, target :: nuclides_MG(:) + + ! Cross section caches + type(MgxsContainer), target, allocatable :: macro_xs(:) + + ! Number of energy groups + integer :: num_energy_groups + + ! Number of delayed groups + integer :: num_delayed_groups + + ! Energy group structure + real(8), allocatable :: energy_bins(:) + + ! Midpoint of the energy group structure + real(8), allocatable :: energy_bin_avg(:) + +contains !=============================================================================== ! MGXS*_FROM_HDF5 reads in the data from the HDF5 Library. At the point of entry diff --git a/src/particle_header.F90 b/src/particle_header.F90 index 3f4680c2f..bda7f03b4 100644 --- a/src/particle_header.F90 +++ b/src/particle_header.F90 @@ -147,7 +147,7 @@ contains this % fission = .false. this % delayed_group = 0 this % n_delayed_bank(:) = 0 - this % g = 1 + this % g = NONE ! Set up base level coordinates this % coord(1) % universe = root_universe @@ -214,6 +214,7 @@ contains this % last_uvw = src % uvw if (run_CE) then this % E = src % E + this % g = NONE else this % g = int(src % E) this % last_g = int(src % E) diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index cf8e49b81..a718202b7 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -666,28 +666,28 @@ contains integer :: bin real(8) :: E - n = this % n_bins - - if ((.not. run_CE) .and. this % matches_transport_groups) then - if (estimator == ESTIMATOR_TRACKLENGTH) then - call match % bins % push_back(num_energy_groups - p % g + 1) - call match % weights % push_back(ONE) - else - call match % bins % push_back(num_energy_groups - p % last_g + 1) - call match % weights % push_back(ONE) - end if + n = this % n_bins + if (p % g /= NONE .and. this % matches_transport_groups) then + if (estimator == ESTIMATOR_TRACKLENGTH) then + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) else - ! Pre-collision energy of particle - E = p % last_E - - ! Search to find incoming energy bin. - bin = binary_search(this % bins, n + 1, E) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if + call match % bins % push_back(num_energy_groups - p % last_g + 1) + call match % weights % push_back(ONE) end if + + else + ! Pre-collision energy of particle + E = p % last_E + + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + end if end subroutine get_all_bins_energy subroutine to_statepoint_energy(this, filter_group) @@ -724,23 +724,23 @@ contains integer :: n integer :: bin - n = this % n_bins + n = this % n_bins - if ((.not. run_CE) .and. this % matches_transport_groups) then - ! Tallies are ordered in increasing groups, group indices - ! however are the opposite, so switch - call match % bins % push_back(num_energy_groups - p % g + 1) + if (p % g /= NONE .and. this % matches_transport_groups) then + ! Tallies are ordered in increasing groups, group indices + ! however are the opposite, so switch + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) + + else + + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, p % E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) call match % weights % push_back(ONE) - - else - - ! Search to find incoming energy bin. - bin = binary_search(this % bins, n + 1, p % E) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if end if + end if end subroutine get_all_bins_energyout subroutine to_statepoint_energyout(this, filter_group) From dc3944c91260c078d4b3a88f4d686ab99692ec18 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 11:08:13 -0500 Subject: [PATCH 120/229] Separate energy filters into separate module --- CMakeLists.txt | 1 + src/cmfd_input.F90 | 1 - src/input_xml.F90 | 1 - src/tallies/tally.F90 | 1 - src/tallies/tally_filter.F90 | 150 +------------------------- src/tallies/tally_filter_energy.F90 | 160 ++++++++++++++++++++++++++++ src/tallies/tally_filter_mesh.F90 | 4 +- 7 files changed, 167 insertions(+), 151 deletions(-) create mode 100644 src/tallies/tally_filter_energy.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index a7e8da55a..100e14868 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally.F90 src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 + src/tallies/tally_filter_energy.F90 src/tallies/tally_filter_mesh.F90 src/tallies/tally_header.F90 src/tallies/tally_initialize.F90 diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 55862cd52..2a9f1da30 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -254,7 +254,6 @@ contains use tally_header, only: TallyObject use tally_filter_header use tally_filter - use tally_filter_mesh, only: MeshFilter use tally_initialize, only: add_tallies use xml_interface diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6923b3934..911d2fe55 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -30,7 +30,6 @@ module input_xml use tally_header, only: TallyObject use tally_filter_header, only: TallyFilterContainer use tally_filter - use tally_filter_mesh, only: MeshFilter use tally_initialize, only: add_tallies use xml_interface diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 404a1a487..247214365 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -15,7 +15,6 @@ module tally use particle_header, only: LocalCoord, Particle use string, only: to_str use tally_filter - use tally_filter_mesh, only: MeshFilter implicit none diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index a718202b7..4b1e5acb9 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -11,7 +11,11 @@ module tally_filter use particle_header, only: Particle use string, only: to_str use tally_filter_header, only: TallyFilter, TallyFilterContainer, & - TallyFilterMatch + TallyFilterMatch + + ! Inherit other filters + use tally_filter_energy + use tally_filter_mesh implicit none @@ -106,38 +110,6 @@ module tally_filter procedure :: initialize => initialize_surface end type SurfaceFilter -!=============================================================================== -! ENERGYFILTER bins the incident neutron energy. -!=============================================================================== - type, extends(TallyFilter) :: EnergyFilter - real(8), allocatable :: bins(:) - - ! True if transport group number can be used directly to get bin number - logical :: matches_transport_groups = .false. - - contains - procedure :: get_all_bins => get_all_bins_energy - procedure :: to_statepoint => to_statepoint_energy - procedure :: text_label => text_label_energy - end type EnergyFilter - -!=============================================================================== -! ENERGYOUTFILTER bins the outgoing neutron energy. Only scattering events use -! the get_all_bins functionality. Nu-fission tallies manually iterate over the -! filter bins. -!=============================================================================== - type, extends(TallyFilter) :: EnergyoutFilter - real(8), allocatable :: bins(:) - - ! True if transport group number can be used directly to get bin number - logical :: matches_transport_groups = .false. - - contains - procedure :: get_all_bins => get_all_bins_energyout - procedure :: to_statepoint => to_statepoint_energyout - procedure :: text_label => text_label_energyout - end type EnergyoutFilter - !=============================================================================== ! DELAYEDGROUPFILTER bins outgoing fission neutrons in their delayed groups. ! The get_all_bins functionality is not actually used. The bins are manually @@ -653,118 +625,6 @@ contains label = "Surface " // to_str(surfaces(this % surfaces(bin)) % obj % id) end function text_label_surface -!=============================================================================== -! EnergyFilter methods -!=============================================================================== - subroutine get_all_bins_energy(this, p, estimator, match) - class(EnergyFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n - integer :: bin - real(8) :: E - - n = this % n_bins - - if (p % g /= NONE .and. this % matches_transport_groups) then - if (estimator == ESTIMATOR_TRACKLENGTH) then - call match % bins % push_back(num_energy_groups - p % g + 1) - call match % weights % push_back(ONE) - else - call match % bins % push_back(num_energy_groups - p % last_g + 1) - call match % weights % push_back(ONE) - end if - - else - ! Pre-collision energy of particle - E = p % last_E - - ! Search to find incoming energy bin. - bin = binary_search(this % bins, n + 1, E) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - end if - end subroutine get_all_bins_energy - - subroutine to_statepoint_energy(this, filter_group) - class(EnergyFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "energy") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % bins) - end subroutine to_statepoint_energy - - function text_label_energy(this, bin) result(label) - class(EnergyFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - real(8) :: E0, E1 - - E0 = this % bins(bin) - E1 = this % bins(bin + 1) - label = "Incoming Energy [" // trim(to_str(E0)) // ", " & - // trim(to_str(E1)) // ")" - end function text_label_energy - -!=============================================================================== -! EnergyoutFilter methods -!=============================================================================== - subroutine get_all_bins_energyout(this, p, estimator, match) - class(EnergyoutFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n - integer :: bin - - n = this % n_bins - - if (p % g /= NONE .and. this % matches_transport_groups) then - ! Tallies are ordered in increasing groups, group indices - ! however are the opposite, so switch - call match % bins % push_back(num_energy_groups - p % g + 1) - call match % weights % push_back(ONE) - - else - - ! Search to find incoming energy bin. - bin = binary_search(this % bins, n + 1, p % E) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - end if - end subroutine get_all_bins_energyout - - subroutine to_statepoint_energyout(this, filter_group) - class(EnergyoutFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "energyout") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % bins) - end subroutine to_statepoint_energyout - - function text_label_energyout(this, bin) result(label) - class(EnergyoutFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - real(8) :: E0, E1 - - E0 = this % bins(bin) - E1 = this % bins(bin + 1) - label = "Outgoing Energy [" // trim(to_str(E0)) // ", " & - // trim(to_str(E1)) // ")" - end function text_label_energyout - !=============================================================================== ! DelayedGroupFilter methods !=============================================================================== diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 new file mode 100644 index 000000000..29a203d17 --- /dev/null +++ b/src/tallies/tally_filter_energy.F90 @@ -0,0 +1,160 @@ +module tally_filter_energy + + use hdf5, only: HID_T + + use algorithm, only: binary_search + use constants + use hdf5_interface + use mgxs_header, only: num_energy_groups + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header, only: TallyFilter, TallyFilterMatch + + implicit none + private + +!=============================================================================== +! ENERGYFILTER bins the incident neutron energy. +!=============================================================================== + + type, public, extends(TallyFilter) :: EnergyFilter + real(8), allocatable :: bins(:) + + ! True if transport group number can be used directly to get bin number + logical :: matches_transport_groups = .false. + contains + procedure :: get_all_bins => get_all_bins_energy + procedure :: to_statepoint => to_statepoint_energy + procedure :: text_label => text_label_energy + end type EnergyFilter + +!=============================================================================== +! ENERGYOUTFILTER bins the outgoing neutron energy. Only scattering events use +! the get_all_bins functionality. Nu-fission tallies manually iterate over the +! filter bins. +!=============================================================================== + + type, public, extends(EnergyFilter) :: EnergyoutFilter + contains + procedure :: get_all_bins => get_all_bins_energyout + procedure :: to_statepoint => to_statepoint_energyout + procedure :: text_label => text_label_energyout + end type EnergyoutFilter + +contains + +!=============================================================================== +! EnergyFilter methods +!=============================================================================== + + subroutine get_all_bins_energy(this, p, estimator, match) + class(EnergyFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n + integer :: bin + real(8) :: E + + n = this % n_bins + + if (p % g /= NONE .and. this % matches_transport_groups) then + if (estimator == ESTIMATOR_TRACKLENGTH) then + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) + else + call match % bins % push_back(num_energy_groups - p % last_g + 1) + call match % weights % push_back(ONE) + end if + + else + ! Pre-collision energy of particle + E = p % last_E + + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + end if + end subroutine get_all_bins_energy + + subroutine to_statepoint_energy(this, filter_group) + class(EnergyFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "energy") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % bins) + end subroutine to_statepoint_energy + + function text_label_energy(this, bin) result(label) + class(EnergyFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + real(8) :: E0, E1 + + E0 = this % bins(bin) + E1 = this % bins(bin + 1) + label = "Incoming Energy [" // trim(to_str(E0)) // ", " & + // trim(to_str(E1)) // ")" + end function text_label_energy + +!=============================================================================== +! EnergyoutFilter methods +!=============================================================================== + + subroutine get_all_bins_energyout(this, p, estimator, match) + class(EnergyoutFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n + integer :: bin + + n = this % n_bins + + if (p % g /= NONE .and. this % matches_transport_groups) then + ! Tallies are ordered in increasing groups, group indices + ! however are the opposite, so switch + call match % bins % push_back(num_energy_groups - p % g + 1) + call match % weights % push_back(ONE) + + else + + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, p % E) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + end if + end subroutine get_all_bins_energyout + + subroutine to_statepoint_energyout(this, filter_group) + class(EnergyoutFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "energyout") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % bins) + end subroutine to_statepoint_energyout + + function text_label_energyout(this, bin) result(label) + class(EnergyoutFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + real(8) :: E0, E1 + + E0 = this % bins(bin) + E1 = this % bins(bin + 1) + label = "Outgoing Energy [" // trim(to_str(E0)) // ", " & + // trim(to_str(E1)) // ")" + end function text_label_energyout + +end module tally_filter_energy diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index 5c8c3ba09..f1c8615f5 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -11,9 +11,7 @@ module tally_filter_mesh use tally_filter_header, only: TallyFilter, TallyFilterMatch implicit none - private - public :: MeshFilter !=============================================================================== ! MESHFILTER indexes the location of particle events to a regular mesh. For @@ -21,7 +19,7 @@ module tally_filter_mesh ! will correspond to the fraction of the track length that lies in that bin. !=============================================================================== - type, extends(TallyFilter) :: MeshFilter + type, public, extends(TallyFilter) :: MeshFilter type(RegularMesh), pointer :: mesh => null() contains procedure :: get_all_bins => get_all_bins_mesh From c063b8d9dbcf8cebae3307564291eb331acd6b4b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 11:42:55 -0500 Subject: [PATCH 121/229] Move most important arrays out of global module and into their respective headers --- src/geometry_header.F90 | 15 ++++++ src/global.F90 | 72 +++++------------------------ src/material_header.F90 | 10 ++++ src/mesh_header.F90 | 13 ++++-- src/nuclide_header.F90 | 4 ++ src/plot_header.F90 | 12 ++++- src/surface_header.F90 | 10 ++++ src/tallies/tally_filter_header.F90 | 12 +++++ src/tallies/tally_header.F90 | 11 +++++ src/volume_header.F90 | 2 + 10 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index b9eab0ad0..f4eb9b662 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -1,5 +1,7 @@ module geometry_header + use, intrinsic :: ISO_C_BINDING + use algorithm, only: find use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & MATERIAL_VOID, NONE @@ -157,6 +159,19 @@ module geometry_header ! array index of the root universe integer :: root_universe = -1 + integer(C_INT32_T), bind(C) :: n_cells ! # of cells + integer(C_INT32_T), bind(C) :: n_universes ! # of universes + integer(C_INT32_T), bind(C) :: n_lattices ! # of lattices + + type(Cell), allocatable, target :: cells(:) + type(Universe), allocatable, target :: universes(:) + type(LatticeContainer), allocatable, target :: lattices(:) + + ! Dictionaries which map user IDs to indices in the global arrays + type(DictIntInt) :: cell_dict + type(DictIntInt) :: universe_dict + type(DictIntInt) :: lattice_dict + contains !=============================================================================== diff --git a/src/global.F90 b/src/global.F90 index 27c28b040..0f1ca48c7 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -9,64 +9,30 @@ module global use bank_header, only: Bank use cmfd_header use constants - use dict_header, only: DictCharInt, DictIntInt - use geometry_header, only: Cell, Universe, Lattice, LatticeContainer - use material_header, only: Material - use mgxs_header - use plot_header, only: ObjectPlot use set_header, only: SetInt use stl_vector, only: VectorInt - use surface_header, only: SurfaceContainer use source_header, only: SourceDistribution - use tally_header, only: TallyObject, TallyDerivative - use tally_filter_header, only: TallyFilterContainer, TallyFilterMatch use trigger_header, only: KTrigger use timer_header, only: Timer - use volume_header, only: VolumeCalculation - ! Inherit module variables from nuclide/S(a,b) modules - use nuclide_header - use sab_header - - ! Inherit meshes array + ! Inherit module variables from other modules + use geometry_header + use material_header use mesh_header + use mgxs_header + use nuclide_header + use plot_header + use sab_header + use surface_header + use tally_filter_header + use tally_header + use volume_header implicit none ! ============================================================================ ! GEOMETRY-RELATED VARIABLES - ! Main arrays - type(Cell), allocatable, target :: cells(:) - type(Universe), allocatable, target :: universes(:) - type(LatticeContainer), allocatable, target :: lattices(:) - type(SurfaceContainer), allocatable, target :: surfaces(:) - type(Material), allocatable, target :: materials(:) - type(ObjectPlot), allocatable, target :: plots(:) - - type(VolumeCalculation), allocatable :: volume_calcs(:) - - ! Size of main arrays - integer(C_INT32_T), bind(C) :: n_cells ! # of cells - integer :: n_universes ! # of universes - integer :: n_lattices ! # of lattices - integer :: n_surfaces ! # of surfaces - integer(C_INT32_T), bind(C) :: n_materials ! # of materials - integer :: n_plots ! # of plots - - ! These dictionaries provide a fast lookup mechanism -- the key is the - ! user-specified identifier and the value is the index in the corresponding - ! array - type(DictIntInt) :: cell_dict - type(DictIntInt) :: universe_dict - type(DictIntInt) :: lattice_dict - type(DictIntInt) :: surface_dict - type(DictIntInt) :: material_dict - type(DictIntInt) :: mesh_dict - type(DictIntInt) :: filter_dict - type(DictIntInt) :: tally_dict - type(DictIntInt) :: plot_dict - ! Number of lost particles integer :: n_lost_particles @@ -74,10 +40,6 @@ module global ! ENERGY TREATMENT RELATED VARIABLES logical :: run_CE = .true. ! Run in CE mode? - ! Cross section caches - type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide - type(MaterialMacroXS) :: material_xs ! Cache for current material - ! ============================================================================ ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES @@ -109,9 +71,6 @@ module global ! ============================================================================ ! TALLY-RELATED VARIABLES - type(TallyObject), allocatable, target :: tallies(:) - type(TallyFilterContainer), allocatable, target :: filters(:) - type(TallyFilterMatch), allocatable :: filter_matches(:) ! Pointers for different tallies type(TallyObject), pointer :: user_tallies(:) => null() @@ -149,17 +108,10 @@ module global !$omp threadprivate(global_tally_collision, global_tally_absorption, & !$omp& global_tally_tracklength, global_tally_leakage) - integer :: n_meshes = 0 ! # of structured meshes integer :: n_user_meshes = 0 ! # of structured user meshes - integer :: n_filters = 0 ! # of filters integer :: n_user_filters = 0 ! # of user filters - integer(C_INT32_T), bind(C) :: n_tallies = 0 ! # of tallies integer :: n_user_tallies = 0 ! # of user tallies - ! Tally derivatives - type(TallyDerivative), allocatable :: tally_derivs(:) -!$omp threadprivate(tally_derivs) - ! Normalization for statistics integer :: n_realizations = 0 ! # of independent realizations real(8) :: total_weight ! total starting particle weight in realization @@ -407,7 +359,7 @@ module global character(10), allocatable :: res_scat_nuclides(:) !$omp threadprivate(micro_xs, material_xs, fission_bank, n_bank, & -!$omp& trace, thread_id, current_work, filter_matches) +!$omp& trace, thread_id, current_work) contains diff --git a/src/material_header.F90 b/src/material_header.F90 index 1308810e2..f80c36b5c 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -1,6 +1,9 @@ module material_header + use, intrinsic :: ISO_C_BINDING + use constants + use dict_header, only: DictIntInt use error use nuclide_header use sab_header @@ -51,6 +54,13 @@ module material_header procedure :: assign_sab_tables => material_assign_sab_tables end type Material + integer(C_INT32_T), bind(C) :: n_materials ! # of materials + + type(Material), allocatable, target :: materials(:) + + ! Dictionary that maps user IDs to indices in 'materials' + type(DictIntInt) :: material_dict + contains !=============================================================================== diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index f112eb23f..d94189161 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -1,22 +1,24 @@ module mesh_header + use, intrinsic :: ISO_C_BINDING + use hdf5 use constants, only: NO_BIN_FOUND + use dict_header, only: DictIntInt use hdf5_interface use string, only: to_str implicit none - private - public :: RegularMesh, meshes + public :: RegularMesh, meshes, n_meshes, mesh_dict !=============================================================================== ! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by ! congruent squares or cubes !=============================================================================== - type RegularMesh + type, public :: RegularMesh integer :: id ! user-specified id integer :: type ! rectangular, hexagonal integer :: n_dimension ! rank of mesh @@ -34,8 +36,13 @@ module mesh_header procedure :: to_hdf5 => regular_to_hdf5 end type RegularMesh + integer(C_INT32_T), bind(C) :: n_meshes = 0 ! # of structured meshes + type(RegularMesh), allocatable, target :: meshes(:) + ! Dictionary that maps user IDs to indices in 'meshes' + type(DictIntInt) :: mesh_dict + contains !=============================================================================== diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 68759115b..784888172 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -166,6 +166,10 @@ module nuclide_header integer(C_INT), bind(C) :: n_nuclides type(DictCharInt) :: nuclide_dict + ! Cross section caches + type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide + type(MaterialMacroXS) :: material_xs ! Cache for current material + ! Minimum/maximum energies real(8) :: energy_min_neutron = ZERO real(8) :: energy_max_neutron = INFINITY diff --git a/src/plot_header.F90 b/src/plot_header.F90 index a6ea9a580..06b4919ad 100644 --- a/src/plot_header.F90 +++ b/src/plot_header.F90 @@ -1,7 +1,10 @@ module plot_header + use, intrinsic :: ISO_C_BINDING + use constants - use mesh_header, only: RegularMesh + use dict_header, only: DictIntInt + use mesh_header, only: RegularMesh implicit none @@ -50,4 +53,11 @@ module plot_header integer, parameter :: PLOT_COLOR_CELLS = 1 integer, parameter :: PLOT_COLOR_MATS = 2 + integer(C_INT32_T), bind(C) :: n_plots ! # of plots + + type(ObjectPlot), allocatable, target :: plots(:) + + ! Dictionary that maps user IDs to indices in 'plots' + type(DictIntInt) :: plot_dict + end module plot_header diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 68e5144b7..d1c045233 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -1,6 +1,9 @@ module surface_header + use, intrinsic :: ISO_C_BINDING + use constants, only: NONE, ONE, TWO, ZERO, HALF, INFINITY, FP_COINCIDENT + use dict_header, only: DictIntInt implicit none @@ -193,6 +196,13 @@ module surface_header procedure :: normal => quadric_normal end type SurfaceQuadric + integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces + + type(SurfaceContainer), allocatable, target :: surfaces(:) + + ! Dictionary that maps user IDs to indices in 'surfaces' + type(DictIntInt) :: surface_dict + contains !=============================================================================== diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index d69dd299d..155357695 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -1,6 +1,9 @@ module tally_filter_header + use, intrinsic :: ISO_C_BINDING + use constants, only: MAX_LINE_LEN + use dict_header, only: DictIntInt use particle_header, only: Particle use stl_vector, only: VectorInt, VectorReal @@ -94,6 +97,15 @@ module tally_filter_header class(TallyFilter), allocatable :: obj end type TallyFilterContainer + integer :: n_filters = 0 ! # of filters + + type(TallyFilterContainer), allocatable, target :: filters(:) + type(TallyFilterMatch), allocatable :: filter_matches(:) +!$omp threadprivate(filter_matches) + + ! Dictionary that maps user IDs to indices in 'filters' + type(DictIntInt) :: filter_dict + contains !=============================================================================== diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 76e3d143f..2f712c5f8 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -5,6 +5,7 @@ module tally_header use hdf5 use constants, only: NONE, N_FILTER_TYPES + use dict_header, only: DictIntInt use tally_filter_header, only: TallyFilterContainer use trigger_header, only: TriggerObject @@ -93,6 +94,16 @@ module tally_header procedure :: read_results_hdf5 end type TallyObject + integer(C_INT32_T), bind(C) :: n_tallies = 0 ! # of tallies + + type(TallyObject), allocatable, target :: tallies(:) + type(TallyDerivative), allocatable :: tally_derivs(:) +!$omp threadprivate(tally_derivs) + + ! Dictionary that maps user IDs to indices in 'tallies' + type(DictIntInt) :: tally_dict + + contains subroutine write_results_hdf5(this, group_id) diff --git a/src/volume_header.F90 b/src/volume_header.F90 index a01b664df..13c3299bb 100644 --- a/src/volume_header.F90 +++ b/src/volume_header.F90 @@ -16,6 +16,8 @@ module volume_header procedure :: from_xml => volume_from_xml end type VolumeCalculation + type(VolumeCalculation), allocatable :: volume_calcs(:) + contains subroutine volume_from_xml(this, node_vol) From 3cc5ac38c56939482ce0c9f6e1fb864eff5ec89b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 11:45:55 -0500 Subject: [PATCH 122/229] Remove two arguments on get_temperatures --- src/geometry_header.F90 | 7 ++----- src/input_xml.F90 | 2 +- src/mgxs_data.F90 | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index f4eb9b662..ba6992d47 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -6,8 +6,8 @@ module geometry_header use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & MATERIAL_VOID, NONE use dict_header, only: DictCharInt, DictIntInt + use material_header, only: Material, materials, material_dict use nuclide_header - use material_header, only: Material use sab_header use stl_vector, only: VectorReal use string, only: to_lower @@ -347,11 +347,8 @@ contains ! temperatures to read (which may be different if interpolation is used) !=============================================================================== - subroutine get_temperatures(cells, materials, material_dict, & - nuc_temps, sab_temps) + subroutine get_temperatures(cells, nuc_temps, sab_temps) type(Cell), allocatable, intent(in) :: cells(:) - type(Material), allocatable, intent(in) :: materials(:) - type(DictIntInt), intent(in) :: material_dict type(VectorReal), allocatable, intent(out) :: nuc_temps(:) type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 911d2fe55..5927b9263 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2188,7 +2188,7 @@ contains call assign_temperatures(material_temps) ! Determine desired temperatures for each nuclide and S(a,b) table - call get_temperatures(cells, materials, material_dict, nuc_temps, sab_temps) + call get_temperatures(cells, nuc_temps, sab_temps) ! Read continuous-energy cross sections if (run_CE .and. run_mode /= MODE_PLOTTING) then diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index bbea3c4b3..623ad2ee8 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -51,7 +51,7 @@ contains call write_message("Loading cross section data...", 5) ! Get temperatures - call get_temperatures(cells, materials, material_dict, temps) + call get_temperatures(cells, temps) ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) From d0f989b4cacd419347c50f21f64550cd02751cf8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 11:47:58 -0500 Subject: [PATCH 123/229] Tally filters no longer depend on global module --- src/tallies/tally_filter.F90 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 4b1e5acb9..4a6f35b01 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -5,13 +5,12 @@ module tally_filter use algorithm, only: binary_search use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION, ERROR_REAL use dict_header, only: DictIntInt - use geometry_header, only: root_universe, RectLattice, HexLattice - use global + use geometry_header use hdf5_interface use particle_header, only: Particle + use surface_header use string, only: to_str - use tally_filter_header, only: TallyFilter, TallyFilterContainer, & - TallyFilterMatch + use tally_filter_header ! Inherit other filters use tally_filter_energy From fbe3bd8762f75471732826e5c84fbd6bc9035317 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 15:07:11 -0500 Subject: [PATCH 124/229] Add openmc_extend_tallies C API function --- openmc/capi/tally.py | 3 + src/api.F90 | 168 +----------------------------- src/cmfd_input.F90 | 12 ++- src/input_xml.F90 | 13 ++- src/string.F90 | 24 +++++ src/tallies/tally_header.F90 | 170 ++++++++++++++++++++++++++++++- src/tallies/tally_initialize.F90 | 51 ---------- 7 files changed, 215 insertions(+), 226 deletions(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 611f1ce87..f2498ed90 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -14,6 +14,9 @@ __all__ = ['TallyView', 'tallies'] _dll.openmc_get_tally.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_tally.restype = c_int _dll.openmc_get_tally.errcheck = _error_handler +_dll.openmc_extend_tallies.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] +_dll.openmc_extend_tallies.restype = c_int +_dll.openmc_extend_tallies.errcheck = _error_handler _dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_id.restype = c_int _dll.openmc_tally_get_id.errcheck = _error_handler diff --git a/src/api.F90 b/src/api.F90 index 50d702b31..04b6cd391 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -17,7 +17,9 @@ module openmc_api use particle_header, only: Particle use plot, only: openmc_plot_geometry use random_lcg, only: seed, initialize_prng + use tally_header use simulation, only: openmc_run + use string, only: to_f_string use volume_calc, only: openmc_calculate_volumes implicit none @@ -360,28 +362,6 @@ contains end if end function openmc_get_nuclide -!=============================================================================== -! OPENMC_GET_TALLY returns the index in the tallies array of a tally -! with a given ID -!=============================================================================== - - function openmc_get_tally(id, index) result(err) bind(C) - integer(C_INT32_T), value :: id - integer(C_INT32_T), intent(out) :: index - integer(C_INT) :: err - - if (allocated(tallies)) then - if (tally_dict % has_key(id)) then - index = tally_dict % get_key(id) - err = 0 - else - err = E_TALLY_INVALID_ID - end if - else - err = E_TALLY_NOT_ALLOCATED - end if - end function openmc_get_tally - !=============================================================================== ! OPENMC_HARD_RESET reset tallies and timers as well as the pseudorandom ! generator state @@ -726,148 +706,4 @@ contains end subroutine openmc_reset -!=============================================================================== -! OPENMC_TALLY_GET_ID returns the ID of a tally -!=============================================================================== - - function openmc_tally_get_id(index, id) result(err) bind(C) - integer(C_INT32_T), value :: index - integer(C_INT32_T), intent(out) :: id - integer(C_INT) :: err - - if (index >= 1 .and. index <= size(tallies)) then - id = tallies(index) % id - err = 0 - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_tally_get_id - -!=============================================================================== -! OPENMC_TALLY_NUCLIDES returns the list of nuclides assigned to a tally -!=============================================================================== - - function openmc_tally_get_nuclides(index, nuclides, n) result(err) bind(C) - integer(C_INT32_T), value :: index - type(C_PTR), intent(out) :: nuclides - integer(C_INT), intent(out) :: n - integer(C_INT) :: err - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) - if (allocated(t % nuclide_bins)) then - nuclides = C_LOC(t % nuclide_bins(1)) - n = size(t % nuclide_bins) - err = 0 - end if - end associate - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_tally_get_nuclides - -!=============================================================================== -! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its -! shape. This allows a user to obtain in-memory tally results from Python -! directly. -!=============================================================================== - - function openmc_tally_results(index, ptr, shape_) result(err) bind(C) - integer(C_INT32_T), intent(in), value :: index - type(C_PTR), intent(out) :: ptr - integer(C_INT), intent(out) :: shape_(3) - integer(C_INT) :: err - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(tallies)) then - if (allocated(tallies(index) % results)) then - ptr = C_LOC(tallies(index) % results(1,1,1)) - shape_(:) = shape(tallies(index) % results) - err = 0 - end if - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_tally_results - -!=============================================================================== -! OPENMC_TALLY_SET_NUCLIDES sets the nuclides in the tally which results should -! be scored for -!=============================================================================== - - function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) - integer(C_INT32_T), value :: index - integer(C_INT), value :: n - type(C_PTR), intent(in) :: nuclides(n) - integer(C_INT) :: err - - integer :: i - character(C_CHAR), pointer :: string(:) - character(len=:, kind=C_CHAR), allocatable :: nuclide_ - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) - if (allocated(t % nuclide_bins)) deallocate(t % nuclide_bins) - allocate(t % nuclide_bins(n)) - t % n_nuclide_bins = n - - do i = 1, n - ! Convert C string to Fortran string - call c_f_pointer(nuclides(i), string, [10]) - nuclide_ = to_lower(to_f_string(string)) - - select case (nuclide_) - case ('total') - t % nuclide_bins(i) = -1 - case default - if (nuclide_dict % has_key(nuclide_)) then - t % nuclide_bins(i) = nuclide_dict % get_key(nuclide_) - else - err = E_NUCLIDE_NOT_LOADED - return - end if - end select - end do - - ! Recalculate total number of scoring bins - t % total_score_bins = t % n_score_bins * t % n_nuclide_bins - - ! (Re)allocate results array - if (allocated(t % results)) deallocate(t % results) - allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) - t % results(:,:,:) = ZERO - - err = 0 - end associate - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_tally_set_nuclides - -!=============================================================================== -! TO_F_STRING takes a null-terminated array of C chars and turns it into a -! deferred-length character string. Yay Fortran 2003! -!=============================================================================== - - function to_f_string(c_string) result(f_string) - character(kind=C_CHAR), intent(in) :: c_string(*) - character(:), allocatable :: f_string - - integer :: i, n - - ! Determine length of original string - n = 0 - do while (c_string(n + 1) /= C_NULL_CHAR) - n = n + 1 - end do - - ! Copy C string character by character - allocate(character(len=n) :: f_string) - do i = 1, n - f_string(i:i) = c_string(i) - end do - end function to_f_string - end module openmc_api diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 2a9f1da30..e7e256996 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -1,5 +1,7 @@ module cmfd_input + use, intrinsic :: ISO_C_BINDING + use global implicit none @@ -251,10 +253,10 @@ contains use mesh_header, only: RegularMesh use string use tally, only: setup_active_cmfdtallies - use tally_header, only: TallyObject + use tally_header, only: TallyObject, openmc_extend_tallies use tally_filter_header use tally_filter - use tally_initialize, only: add_tallies + use tally_initialize use xml_interface type(XMLNode), intent(in) :: root ! XML root element @@ -264,6 +266,8 @@ contains integer :: n ! size of arrays in mesh specification integer :: ng ! number of energy groups (default 1) integer :: n_filter ! number of filters + integer :: i_start, i_end + integer(C_INT) :: err integer :: i_filt ! index in filters array integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array @@ -462,7 +466,9 @@ contains end select ! Allocate tallies - call add_tallies("cmfd", n_cmfd_tallies) + i_cmfd_tallies = n_tallies + err = openmc_extend_tallies(n_cmfd_tallies, i_start, i_end) + cmfd_tallies => tallies(i_start:i_end) ! Begin loop around tallies do i = 1, n_cmfd_tallies diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 5927b9263..6a2d6ded3 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1,5 +1,7 @@ module input_xml + use, intrinsic :: ISO_C_BINDING + use algorithm, only: find use cmfd_input, only: configure_cmfd use constants @@ -27,10 +29,9 @@ module input_xml use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & zero_padded - use tally_header, only: TallyObject + use tally_header, only: TallyObject, openmc_extend_tallies use tally_filter_header, only: TallyFilterContainer use tally_filter - use tally_initialize, only: add_tallies use xml_interface implicit none @@ -2650,6 +2651,8 @@ contains integer :: n_user_trig ! number of user-specified tally triggers integer :: trig_ind ! index of triggers array for each tally integer :: user_trig_ind ! index of user-specified triggers for each tally + integer :: i_start, i_end + integer(C_INT) :: err real(8) :: threshold ! trigger convergence threshold integer :: n_order ! moment order requested integer :: n_order_pos ! oosition of Scattering order in score name string @@ -2743,9 +2746,11 @@ contains if (master) call warning("No tallies present in tallies.xml file!") end if - ! Allocate tally array + ! Allocate user tallies if (n_user_tallies > 0 .and. run_mode /= MODE_PLOTTING) then - call add_tallies("user", n_user_tallies) + i_user_tallies = n_tallies + err = openmc_extend_tallies(n_user_tallies, i_start, i_end) + user_tallies => tallies(i_start:i_end) end if ! Check for setting diff --git a/src/string.F90 b/src/string.F90 index efb0dd982..2a69eec98 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -514,4 +514,28 @@ contains if (inword) n = n + 1 end function word_count +!=============================================================================== +! TO_F_STRING takes a null-terminated array of C chars and turns it into a +! deferred-length character string. Yay Fortran 2003! +!=============================================================================== + + function to_f_string(c_string) result(f_string) + character(kind=C_CHAR), intent(in) :: c_string(*) + character(:), allocatable :: f_string + + integer :: i, n + + ! Determine length of original string + n = 0 + do while (c_string(n + 1) /= C_NULL_CHAR) + n = n + 1 + end do + + ! Copy C string character by character + allocate(character(len=n) :: f_string) + do i = 1, n + f_string(i:i) = c_string(i) + end do + end function to_f_string + end module string diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 2f712c5f8..28069affe 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -4,8 +4,11 @@ module tally_header use hdf5 - use constants, only: NONE, N_FILTER_TYPES + use constants, only: NONE, N_FILTER_TYPES, ZERO + use error use dict_header, only: DictIntInt + use nuclide_header, only: nuclide_dict + use string, only: to_lower, to_f_string use tally_filter_header, only: TallyFilterContainer use trigger_header, only: TriggerObject @@ -103,7 +106,6 @@ module tally_header ! Dictionary that maps user IDs to indices in 'tallies' type(DictIntInt) :: tally_dict - contains subroutine write_results_hdf5(this, group_id) @@ -173,4 +175,168 @@ contains call h5sclose_f(dspace, hdf5_err) end subroutine read_results_hdf5 +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_extend_tallies(n, index_start, index_end) result(err) bind(C) + ! Extend the tallies array by n elements + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), intent(out) :: index_start + integer(C_INT32_T), intent(out) :: index_end + integer(C_INT) :: err + + type(TallyObject), allocatable :: temp(:) ! temporary tallies array + + if (n_tallies == 0) then + ! Allocate tallies array + allocate(tallies(n)) + else + ! Allocate tallies array with increased size + allocate(temp(n_tallies + n)) + + ! Copy original tallies to temporary array + temp(1:n_tallies) = tallies + + ! Move allocation from temporary array + call move_alloc(FROM=temp, TO=tallies) + end if + + ! Return indices in tallies array + index_start = n_tallies + 1 + index_end = n_tallies + n + n_tallies = index_end + + err = 0 + end function openmc_extend_tallies + + + function openmc_get_tally(id, index) result(err) bind(C) + ! Returns the index in the tallies array of a tally with a given ID + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(tallies)) then + if (tally_dict % has_key(id)) then + index = tally_dict % get_key(id) + err = 0 + else + err = E_TALLY_INVALID_ID + end if + else + err = E_TALLY_NOT_ALLOCATED + end if + end function openmc_get_tally + + + function openmc_tally_get_id(index, id) result(err) bind(C) + ! Return the ID of a tally + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(tallies)) then + id = tallies(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_get_id + + + function openmc_tally_get_nuclides(index, nuclides, n) result(err) bind(C) + ! Return the list of nuclides assigned to a tally + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: nuclides + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % nuclide_bins)) then + nuclides = C_LOC(t % nuclide_bins(1)) + n = size(t % nuclide_bins) + err = 0 + end if + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_get_nuclides + + + function openmc_tally_results(index, ptr, shape_) result(err) bind(C) + ! Returns a pointer to a tally results array along with its shape. This + ! allows a user to obtain in-memory tally results from Python directly. + integer(C_INT32_T), intent(in), value :: index + type(C_PTR), intent(out) :: ptr + integer(C_INT), intent(out) :: shape_(3) + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + if (allocated(tallies(index) % results)) then + ptr = C_LOC(tallies(index) % results(1,1,1)) + shape_(:) = shape(tallies(index) % results) + err = 0 + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_results + + + function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) + ! Sets the nuclides in the tally which results should be scored for + integer(C_INT32_T), value :: index + integer(C_INT), value :: n + type(C_PTR), intent(in) :: nuclides(n) + integer(C_INT) :: err + + integer :: i + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: nuclide_ + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % nuclide_bins)) deallocate(t % nuclide_bins) + allocate(t % nuclide_bins(n)) + t % n_nuclide_bins = n + + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(nuclides(i), string, [10]) + nuclide_ = to_lower(to_f_string(string)) + + select case (nuclide_) + case ('total') + t % nuclide_bins(i) = -1 + case default + if (nuclide_dict % has_key(nuclide_)) then + t % nuclide_bins(i) = nuclide_dict % get_key(nuclide_) + else + err = E_NUCLIDE_NOT_LOADED + return + end if + end select + end do + + ! Recalculate total number of scoring bins + t % total_score_bins = t % n_score_bins * t % n_nuclide_bins + + ! (Re)allocate results array + if (allocated(t % results)) deallocate(t % results) + allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) + t % results(:,:,:) = ZERO + + err = 0 + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_nuclides + end module tally_header diff --git a/src/tallies/tally_initialize.F90 b/src/tallies/tally_initialize.F90 index 84ef43534..637476b0c 100644 --- a/src/tallies/tally_initialize.F90 +++ b/src/tallies/tally_initialize.F90 @@ -7,7 +7,6 @@ module tally_initialize implicit none private public :: configure_tallies - public :: add_tallies contains @@ -69,54 +68,4 @@ contains end subroutine setup_tally_arrays -!=============================================================================== -! ADD_TALLIES extends the tallies array with a new group of tallies and assigns -! pointers to each group. This is called once for user tallies, once for CMFD -! tallies, etc. -!=============================================================================== - - subroutine add_tallies(tally_group, n) - - character(*), intent(in) :: tally_group ! name of tally group - integer, intent(in) :: n ! number of tallies to add - - type(TallyObject), allocatable :: temp(:) ! temporary tallies array - - if (n_tallies == 0) then - ! Allocate tallies array - allocate(tallies(n)) - else - ! Allocate tallies array with increased size - allocate(temp(n_tallies + n)) - - ! Copy original tallies to temporary array - temp(1:n_tallies) = tallies - - ! Move allocation from temporary array - call move_alloc(FROM=temp, TO=tallies) - - end if - - ! Set index for ths tally group - select case(tally_group) - case ("user") - i_user_tallies = n_tallies - case ("cmfd") - i_cmfd_tallies = n_tallies - end select - - ! Set n_tallies - n_tallies = size(tallies) - - ! Reassign pointers for each group -- after the call to move_alloc, any - ! pointers that were associated with tallies before become unassociated - if (i_user_tallies >= 0) then - user_tallies => tallies(i_user_tallies+1 : i_user_tallies+n_user_tallies) - end if - if (i_cmfd_tallies >= 0) then - cmfd_tallies => tallies(i_cmfd_tallies+1 : i_cmfd_tallies+n_cmfd_tallies) - end if - - end subroutine add_tallies - end module tally_initialize From 34a7445c81507bb2e4e67e0834a32101772fb2df Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 15:41:17 -0500 Subject: [PATCH 125/229] Move setup_arrays and configure_tallies to tally_header module --- CMakeLists.txt | 1 - src/cmfd_input.F90 | 1 - src/global.F90 | 21 ----- src/initialize.F90 | 3 +- src/tallies/tally_header.F90 | 129 +++++++++++++++++++++++++------ src/tallies/tally_initialize.F90 | 71 ----------------- src/tallies/trigger.F90 | 2 +- 7 files changed, 109 insertions(+), 119 deletions(-) delete mode 100644 src/tallies/tally_initialize.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 100e14868..9a47cfa1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,6 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally_filter_energy.F90 src/tallies/tally_filter_mesh.F90 src/tallies/tally_header.F90 - src/tallies/tally_initialize.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 ) diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index e7e256996..8327ac32a 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -256,7 +256,6 @@ contains use tally_header, only: TallyObject, openmc_extend_tallies use tally_filter_header use tally_filter - use tally_initialize use xml_interface type(XMLNode), intent(in) :: root ! XML root element diff --git a/src/global.F90 b/src/global.F90 index 0f1ca48c7..b6c92b13a 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -71,7 +71,6 @@ module global ! ============================================================================ ! TALLY-RELATED VARIABLES - ! Pointers for different tallies type(TallyObject), pointer :: user_tallies(:) => null() type(TallyObject), pointer :: cmfd_tallies(:) => null() @@ -88,26 +87,6 @@ module global type(VectorInt) :: active_tallies type(VectorInt) :: active_surface_tallies - ! Global tallies - ! 1) collision estimate of k-eff - ! 2) absorption estimate of k-eff - ! 3) track-length estimate of k-eff - ! 4) leakage fraction - - real(C_DOUBLE), allocatable, target :: global_tallies(:,:) - - ! It is possible to protect accumulate operations on global tallies by using - ! an atomic update. However, when multiple threads accumulate to the same - ! global tally, it can cause a higher cache miss rate due to - ! invalidation. Thus, we use threadprivate variables to accumulate global - ! tallies and then reduce at the end of a generation. - real(8) :: global_tally_collision = ZERO - real(8) :: global_tally_absorption = ZERO - real(8) :: global_tally_tracklength = ZERO - real(8) :: global_tally_leakage = ZERO -!$omp threadprivate(global_tally_collision, global_tally_absorption, & -!$omp& global_tally_tracklength, global_tally_leakage) - integer :: n_user_meshes = 0 ! # of structured user meshes integer :: n_user_filters = 0 ! # of user filters integer :: n_user_tallies = 0 ! # of user tallies diff --git a/src/initialize.F90 b/src/initialize.F90 index 1e29c638c..92273a6ca 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -29,8 +29,7 @@ module initialize use state_point, only: load_state_point use string, only: to_str, starts_with, ends_with, str_to_int use summary, only: write_summary - use tally_header, only: TallyObject - use tally_initialize,only: configure_tallies + use tally_header, only: TallyObject, configure_tallies use tally_filter use tally, only: init_tally_routines diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 28069affe..ffad1700b 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -4,22 +4,30 @@ module tally_header use hdf5 - use constants, only: NONE, N_FILTER_TYPES, ZERO + use constants, only: NONE, N_FILTER_TYPES, ZERO, N_GLOBAL_TALLIES use error use dict_header, only: DictIntInt use nuclide_header, only: nuclide_dict use string, only: to_lower, to_f_string - use tally_filter_header, only: TallyFilterContainer + use tally_filter_header, only: TallyFilterContainer, filters use trigger_header, only: TriggerObject implicit none + private + public :: configure_tallies + public :: openmc_extend_tallies + public :: openmc_get_tally + public :: openmc_tally_get_id + public :: openmc_tally_get_nuclides + public :: openmc_tally_results + public :: openmc_tally_set_nuclides !=============================================================================== ! TALLYDERIVATIVE describes a first-order derivative that can be applied to ! tallies. !=============================================================================== - type TallyDerivative + type, public :: TallyDerivative integer :: id integer :: variable integer :: diff_material @@ -33,7 +41,7 @@ module tally_header ! TallyResult array. !=============================================================================== - type TallyObject + type, public :: TallyObject ! Basic data integer :: id ! user-defined identifier @@ -75,7 +83,7 @@ module tally_header ! second dimension of the array is for the combination of filters ! (e.g. specific cell, specific energy group, etc.) - integer :: total_filter_bins + integer :: n_filter_bins integer :: total_score_bins real(C_DOUBLE), allocatable :: results(:,:,:) @@ -93,22 +101,43 @@ module tally_header integer :: deriv = NONE contains - procedure :: write_results_hdf5 - procedure :: read_results_hdf5 + procedure :: read_results_hdf5 => tally_read_results_hdf5 + procedure :: write_results_hdf5 => tally_write_results_hdf5 + procedure :: setup_arrays => tally_setup_arrays end type TallyObject - integer(C_INT32_T), bind(C) :: n_tallies = 0 ! # of tallies + integer(C_INT32_T), public, bind(C) :: n_tallies = 0 ! # of tallies - type(TallyObject), allocatable, target :: tallies(:) - type(TallyDerivative), allocatable :: tally_derivs(:) + type(TallyObject), public, allocatable, target :: tallies(:) + type(TallyDerivative), public, allocatable :: tally_derivs(:) !$omp threadprivate(tally_derivs) ! Dictionary that maps user IDs to indices in 'tallies' - type(DictIntInt) :: tally_dict + type(DictIntInt), public :: tally_dict + + ! Global tallies + ! 1) collision estimate of k-eff + ! 2) absorption estimate of k-eff + ! 3) track-length estimate of k-eff + ! 4) leakage fraction + + real(C_DOUBLE), public, allocatable, target :: global_tallies(:,:) + + ! It is possible to protect accumulate operations on global tallies by using + ! an atomic update. However, when multiple threads accumulate to the same + ! global tally, it can cause a higher cache miss rate due to + ! invalidation. Thus, we use threadprivate variables to accumulate global + ! tallies and then reduce at the end of a generation. + real(C_DOUBLE), public :: global_tally_collision = ZERO + real(C_DOUBLE), public :: global_tally_absorption = ZERO + real(C_DOUBLE), public :: global_tally_tracklength = ZERO + real(C_DOUBLE), public :: global_tally_leakage = ZERO +!$omp threadprivate(global_tally_collision, global_tally_absorption, & +!$omp& global_tally_tracklength, global_tally_leakage) contains - subroutine write_results_hdf5(this, group_id) + subroutine tally_write_results_hdf5(this, group_id) class(TallyObject), intent(in) :: this integer(HID_T), intent(in) :: group_id @@ -140,9 +169,9 @@ contains call h5dclose_f(dset, hdf5_err) call h5sclose_f(memspace, hdf5_err) call h5sclose_f(dspace, hdf5_err) - end subroutine write_results_hdf5 + end subroutine tally_write_results_hdf5 - subroutine read_results_hdf5(this, group_id) + subroutine tally_read_results_hdf5(this, group_id) class(TallyObject), intent(inout) :: this integer(HID_T), intent(in) :: group_id @@ -173,7 +202,69 @@ contains call h5dclose_f(dset, hdf5_err) call h5sclose_f(memspace, hdf5_err) call h5sclose_f(dspace, hdf5_err) - end subroutine read_results_hdf5 + end subroutine tally_read_results_hdf5 + +!=============================================================================== +! SETUP_ARRAYS allocates and populates several member arrays of the TallyObject +! derived type, including stride, filter_matches, and results. +!=============================================================================== + + subroutine tally_setup_arrays(this) + class(TallyObject), intent(inout) :: this + + integer :: i ! loop index for tallies + integer :: j ! loop index for filters + integer :: n ! temporary stride + integer :: i_filt ! filter index + + ! Allocate stride + if (allocated(this % filter)) then + if (allocated(this % stride)) deallocate(this % stride) + allocate(this % stride(size(this % filter))) + + ! The filters are traversed in opposite order so that the last filter has + ! the shortest stride in memory and the first filter has the largest + ! stride + n = 1 + STRIDE: do j = size(this % filter), 1, -1 + i_filt = this % filter(j) + this % stride(j) = n + n = n * filters(i_filt) % obj % n_bins + end do STRIDE + this % n_filter_bins = n + else + this % n_filter_bins = 1 + end if + + ! Set total number of filter and scoring bins + this % total_score_bins = this % n_score_bins * this % n_nuclide_bins + + ! Allocate results array + if (allocated(this % results)) deallocate(this % results) + allocate(this % results(3, this % total_score_bins, this % n_filter_bins)) + this % results(:,:,:) = ZERO + + end subroutine tally_setup_arrays + +!=============================================================================== +! CONFIGURE_TALLIES initializes several data structures related to tallies. This +! is called after the basic tally data has already been read from the +! tallies.xml file. +!=============================================================================== + + subroutine configure_tallies() + + integer :: i + + ! Allocate global tallies + allocate(global_tallies(3, N_GLOBAL_TALLIES)) + global_tallies(:,:) = ZERO + + do i = 1, n_tallies + call tallies(i) % setup_arrays() + end do + + end subroutine configure_tallies !=============================================================================== ! C API FUNCTIONS @@ -324,13 +415,7 @@ contains end select end do - ! Recalculate total number of scoring bins - t % total_score_bins = t % n_score_bins * t % n_nuclide_bins - - ! (Re)allocate results array - if (allocated(t % results)) deallocate(t % results) - allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) - t % results(:,:,:) = ZERO + call t % setup_arrays() err = 0 end associate diff --git a/src/tallies/tally_initialize.F90 b/src/tallies/tally_initialize.F90 deleted file mode 100644 index 637476b0c..000000000 --- a/src/tallies/tally_initialize.F90 +++ /dev/null @@ -1,71 +0,0 @@ -module tally_initialize - - use constants - use global - use tally_header, only: TallyObject - - implicit none - private - public :: configure_tallies - -contains - -!=============================================================================== -! CONFIGURE_TALLIES initializes several data structures related to tallies. This -! is called after the basic tally data has already been read from the -! tallies.xml file. -!=============================================================================== - - subroutine configure_tallies() - - ! Allocate global tallies - allocate(global_tallies(3, N_GLOBAL_TALLIES)) - global_tallies(:,:) = ZERO - - call setup_tally_arrays() - - end subroutine configure_tallies - -!=============================================================================== -! SETUP_TALLY_ARRAYS allocates and populates several member arrays of the -! TallyObject derived type, including stride, filter_matches, and results. -!=============================================================================== - - subroutine setup_tally_arrays() - - integer :: i ! loop index for tallies - integer :: j ! loop index for filters - integer :: n ! temporary stride - integer :: i_filt ! filter index - type(TallyObject), pointer :: t - - TALLY_LOOP: do i = 1, n_tallies - ! Get pointer to tally - t => tallies(i) - - ! Allocate stride - allocate(t % stride(size(t % filter))) - - ! The filters are traversed in opposite order so that the last filter has - ! the shortest stride in memory and the first filter has the largest - ! stride - n = 1 - STRIDE: do j = size(t % filter), 1, -1 - i_filt = t % filter(j) - t % stride(j) = n - n = n * filters(i_filt) % obj % n_bins - end do STRIDE - - ! Set total number of filter and scoring bins - t % total_filter_bins = n - t % total_score_bins = t % n_score_bins * t % n_nuclide_bins - - ! Allocate results array - allocate(t % results(3, t % total_score_bins, t % total_filter_bins)) - t % results(:,:,:) = ZERO - - end do TALLY_LOOP - - end subroutine setup_tally_arrays - -end module tally_initialize diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index d8a0f078c..c9310a55a 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -178,7 +178,7 @@ contains call filter_matches(t % filter(j)) % bins % push_back(0) end do - FILTER_LOOP: do filter_index = 1, t % total_filter_bins + FILTER_LOOP: do filter_index = 1, t % n_filter_bins ! Initialize score index score_index = trigger % score_index From 87323d42b541df24eab9c4de622eb3748f00e596 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 15:52:01 -0500 Subject: [PATCH 126/229] Get rid of active_batches and tallies_on global variables --- src/api.F90 | 4 ---- src/cmfd_input.F90 | 1 - src/geometry.F90 | 4 +--- src/global.F90 | 4 ---- src/simulation.F90 | 6 +----- src/state_point.F90 | 4 ++-- src/tallies/tally.F90 | 2 +- 7 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 04b6cd391..25b16eb93 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -678,10 +678,6 @@ contains k_abs_tra = ZERO k_sum(:) = ZERO - ! Turn off tally flags - tallies_on = .false. - active_batches = .false. - ! Clear active tally lists call active_analog_tallies % clear() call active_tracklength_tallies % clear() diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 8327ac32a..297d413cf 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -609,7 +609,6 @@ contains ! Put cmfd tallies into active tally array and turn tallies on call setup_active_cmfdtallies() - tallies_on = .true. end subroutine create_cmfd_tally diff --git a/src/geometry.F90 b/src/geometry.F90 index 7f75a817f..e27ceeedb 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -424,9 +424,7 @@ contains end if ! Score to global leakage tally - if (tallies_on) then - global_tally_leakage = global_tally_leakage + p % wgt - end if + global_tally_leakage = global_tally_leakage + p % wgt ! Display message if (verbosity >= 10 .or. trace) then diff --git a/src/global.F90 b/src/global.F90 index b6c92b13a..98f174166 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -95,10 +95,6 @@ module global integer :: n_realizations = 0 ! # of independent realizations real(8) :: total_weight ! total starting particle weight in realization - ! Flag for turning tallies on - logical :: tallies_on = .false. - logical :: active_batches = .false. - ! Assume all tallies are spatially distinct logical :: assume_separate = .false. diff --git a/src/simulation.F90 b/src/simulation.F90 index 64632a343..5d8d95493 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -171,10 +171,6 @@ contains call time_inactive % stop() call time_active % start() - ! Enable active batches (and tallies_on if it hasn't been enabled) - active_batches = .true. - tallies_on = .true. - ! Add user tallies to active tallies list call setup_active_usertallies() end if @@ -295,7 +291,7 @@ contains call time_tallies % stop() ! Reset global tally results - if (.not. active_batches) then + if (current_batch <= n_inactive) then global_tallies(:,:) = ZERO n_realizations = 0 end if diff --git a/src/state_point.F90 b/src/state_point.F90 index 3705f90e3..ea6104bce 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -364,7 +364,7 @@ contains call write_dataset(file_id, "global_tallies", global_tallies) ! Write tallies - if (tallies_on) then + if (active_tallies % size() > 0) then ! Indicate that tallies are on call write_attribute(file_id, "tallies_present", 1) @@ -544,7 +544,7 @@ contains call write_dataset(file_id, "global_tallies", global_temp) end if - if (tallies_on) then + if (active_tallies % size() > 0) then ! Indicate that tallies are on if (master) then call write_attribute(file_id, "tallies_present", 1) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 247214365..bf85cbb6a 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4272,7 +4272,7 @@ contains end do if (run_mode == MODE_EIGENVALUE) then - if (active_batches) then + if (current_batch > n_inactive) then ! Accumulate products of different estimators of k k_col = global_tallies(RESULT_VALUE, K_COLLISION) / total_weight k_abs = global_tallies(RESULT_VALUE, K_ABSORPTION) / total_weight From 6de7b8b1304141abd7e932f2eb32e4f8ed360d88 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 21:21:50 -0500 Subject: [PATCH 127/229] Simplify setting active tallies --- src/api.F90 | 3 +- src/cmfd_input.F90 | 9 ++-- src/global.F90 | 4 -- src/input_xml.F90 | 1 - src/simulation.F90 | 12 +++-- src/tallies/tally.F90 | 102 ++++++++++------------------------- src/tallies/tally_header.F90 | 1 + 7 files changed, 41 insertions(+), 91 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 25b16eb93..203347250 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -186,8 +186,6 @@ contains energy_min_neutron = ZERO entropy_on = .false. gen_per_batch = 1 - i_user_tallies = -1 - i_cmfd_tallies = -1 keff = ONE legendre_to_tabular = .true. legendre_to_tabular_points = 33 @@ -661,6 +659,7 @@ contains if (allocated(tallies)) then do i = 1, size(tallies) + tallies(i) % active = .false. tallies(i) % n_realizations = 0 if (allocated(tallies(i) % results)) then tallies(i) % results(:, :, :) = ZERO diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 297d413cf..52226e8b4 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -252,7 +252,6 @@ contains use error, only: fatal_error, warning use mesh_header, only: RegularMesh use string - use tally, only: setup_active_cmfdtallies use tally_header, only: TallyObject, openmc_extend_tallies use tally_filter_header use tally_filter @@ -465,7 +464,6 @@ contains end select ! Allocate tallies - i_cmfd_tallies = n_tallies err = openmc_extend_tallies(n_cmfd_tallies, i_start, i_end) cmfd_tallies => tallies(i_start:i_end) @@ -497,7 +495,7 @@ contains t % n_nuclide_bins = 1 ! Record tally id which is equivalent to loop number - t % id = i_cmfd_tallies + i + t % id = i_start + i - 1 if (i == 1) then @@ -605,11 +603,10 @@ contains t % type = TALLY_MESH_CURRENT end if + ! Make CMFD tallies active from the start + t % active = .true. end do - ! Put cmfd tallies into active tally array and turn tallies on - call setup_active_cmfdtallies() - end subroutine create_cmfd_tally end module cmfd_input diff --git a/src/global.F90 b/src/global.F90 index 98f174166..08d024c9f 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -75,10 +75,6 @@ module global type(TallyObject), pointer :: user_tallies(:) => null() type(TallyObject), pointer :: cmfd_tallies(:) => null() - ! Starting index (minus 1) in tallies for each tally group - integer :: i_user_tallies = -1 - integer :: i_cmfd_tallies = -1 - ! Active tally lists type(VectorInt) :: active_analog_tallies type(VectorInt) :: active_tracklength_tallies diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6a2d6ded3..271bd9fc1 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2748,7 +2748,6 @@ contains ! Allocate user tallies if (n_user_tallies > 0 .and. run_mode /= MODE_PLOTTING) then - i_user_tallies = n_tallies err = openmc_extend_tallies(n_user_tallies, i_start, i_end) user_tallies => tallies(i_start:i_end) end if diff --git a/src/simulation.F90 b/src/simulation.F90 index 5d8d95493..2a063ddeb 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -20,7 +20,7 @@ module simulation use source, only: initialize_source, sample_external_source use state_point, only: write_state_point, write_source_point use string, only: to_str - use tally, only: accumulate_tallies, setup_active_usertallies + use tally, only: accumulate_tallies, setup_active_tallies use trigger, only: check_triggers use tracking, only: transport @@ -158,6 +158,8 @@ contains subroutine initialize_batch() + integer :: i + if (run_mode == MODE_FIXEDSOURCE) then call write_message("Simulating batch " // trim(to_str(current_batch)) & // "...", 6) @@ -171,8 +173,9 @@ contains call time_inactive % stop() call time_active % start() - ! Add user tallies to active tallies list - call setup_active_usertallies() + do i = 1, n_tallies + tallies(i) % active = .true. + end do end if ! check CMFD initialize batch @@ -180,6 +183,9 @@ contains if (cmfd_run) call cmfd_init_batch() end if + ! Add user tallies to active tallies list + call setup_active_tallies() + end subroutine initialize_batch !=============================================================================== diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index bf85cbb6a..b62f5547b 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4391,90 +4391,42 @@ contains end subroutine accumulate_tally !=============================================================================== -! SETUP_ACTIVE_USERTALLIES +! SETUP_ACTIVE_TALLIES !=============================================================================== - subroutine setup_active_usertallies() + subroutine setup_active_tallies() integer :: i ! loop counter - do i = 1, n_user_tallies - ! Add tally to active tallies - call active_tallies % push_back(i_user_tallies + i) + call active_tallies % clear() + call active_analog_tallies % clear() + call active_collision_tallies % clear() + call active_tracklength_tallies % clear() + call active_surface_tallies % clear() + call active_current_tallies % clear() - ! Check what type of tally this is and add it to the appropriate list - if (user_tallies(i) % type == TALLY_VOLUME) then - if (user_tallies(i) % estimator == ESTIMATOR_ANALOG) then - call active_analog_tallies % push_back(i_user_tallies + i) - elseif (user_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then - call active_tracklength_tallies % push_back(i_user_tallies + i) - elseif (user_tallies(i) % estimator == ESTIMATOR_COLLISION) then - call active_collision_tallies % push_back(i_user_tallies + i) + do i = 1, n_tallies + if (tallies(i) % active) then + ! Add tally to active tallies + call active_tallies % push_back(i) + + ! Check what type of tally this is and add it to the appropriate list + if (tallies(i) % type == TALLY_VOLUME) then + if (tallies(i) % estimator == ESTIMATOR_ANALOG) then + call active_analog_tallies % push_back(i) + elseif (tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then + call active_tracklength_tallies % push_back(i) + elseif (tallies(i) % estimator == ESTIMATOR_COLLISION) then + call active_collision_tallies % push_back(i) + end if + elseif (tallies(i) % type == TALLY_MESH_CURRENT) then + call active_current_tallies % push_back(i) + elseif (tallies(i) % type == TALLY_SURFACE) then + call active_surface_tallies % push_back(i) end if - elseif (user_tallies(i) % type == TALLY_MESH_CURRENT) then - call active_current_tallies % push_back(i_user_tallies + i) - elseif (user_tallies(i) % type == TALLY_SURFACE) then - call active_surface_tallies % push_back(i_user_tallies + i) - end if - - end do - - call active_tallies % shrink_to_fit() - call active_analog_tallies % shrink_to_fit() - call active_tracklength_tallies % shrink_to_fit() - call active_collision_tallies % shrink_to_fit() - call active_current_tallies % shrink_to_fit() - call active_surface_tallies % shrink_to_fit() - - end subroutine setup_active_usertallies - -!=============================================================================== -! SETUP_ACTIVE_CMFDTALLIES -!=============================================================================== - - subroutine setup_active_cmfdtallies() - - integer :: i ! loop counter - - ! check to see if any of the active tally lists has been allocated - if (active_tallies % size() > 0) then - call fatal_error("Active tallies should not exist before CMFD tallies!") - else if (active_analog_tallies % size() > 0) then - call fatal_error('Active analog tallies should not exist before CMFD & - &tallies!') - else if (active_tracklength_tallies % size() > 0) then - call fatal_error("Active tracklength tallies should not exist before & - &CMFD tallies!") - else if (active_current_tallies % size() > 0) then - call fatal_error("Active current tallies should not exist before CMFD & - &tallies!") - else if (active_surface_tallies % size() > 0) then - call fatal_error("Active cell to cell tallies should not exist before & - &CMFD tallies!") - end if - - do i = 1, n_cmfd_tallies - ! Add CMFD tally to active tallies - call active_tallies % push_back(i_cmfd_tallies + i) - - ! Check what type of tally this is and add it to the appropriate list - if (cmfd_tallies(i) % type == TALLY_VOLUME) then - if (cmfd_tallies(i) % estimator == ESTIMATOR_ANALOG) then - call active_analog_tallies % push_back(i_cmfd_tallies + i) - elseif (cmfd_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then - call active_tracklength_tallies % push_back(i_cmfd_tallies + i) - end if - elseif (cmfd_tallies(i) % type == TALLY_MESH_CURRENT) then - call active_current_tallies % push_back(i_cmfd_tallies + i) end if end do - call active_tallies % shrink_to_fit() - call active_analog_tallies % shrink_to_fit() - call active_tracklength_tallies % shrink_to_fit() - call active_collision_tallies % shrink_to_fit() - call active_current_tallies % shrink_to_fit() - - end subroutine setup_active_cmfdtallies + end subroutine setup_active_tallies end module tally diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index ffad1700b..5c1f71ab3 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -49,6 +49,7 @@ module tally_header integer :: type ! volume, surface current integer :: estimator ! collision, track-length real(8) :: volume ! volume of region + logical :: active = .false. integer, allocatable :: filter(:) ! index in filters array ! The stride attribute is used for determining the index in the results From c7985aa269e5d961b2b7327dda98cd32758905a3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Aug 2017 21:53:24 -0500 Subject: [PATCH 128/229] add_filters -> openmc_extend_filters --- src/api.F90 | 3 ++ src/cmfd_input.F90 | 4 +-- src/input_xml.F90 | 14 ++++---- src/tallies/tally_filter.F90 | 30 ----------------- src/tallies/tally_filter_header.F90 | 52 +++++++++++++++++++++++++---- 5 files changed, 58 insertions(+), 45 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 203347250..8be51e1e7 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -18,6 +18,7 @@ module openmc_api use plot, only: openmc_plot_geometry use random_lcg, only: seed, initialize_prng use tally_header + use tally_filter_header use simulation, only: openmc_run use string, only: to_f_string use volume_calc, only: openmc_calculate_volumes @@ -28,6 +29,8 @@ module openmc_api public :: openmc_calculate_volumes public :: openmc_cell_get_id public :: openmc_cell_set_temperature + public :: openmc_extend_filters + public :: openmc_extend_tallies public :: openmc_finalize public :: openmc_find public :: openmc_get_cell diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 52226e8b4..ff6b65a97 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -383,10 +383,10 @@ contains n_cmfd_filters = merge(5, 3, energy_filters) ! Extend filters array so we can add CMFD filters - call add_filters(n_cmfd_filters) + err = openmc_extend_filters(n_cmfd_filters, i_start, i_end) ! Set up mesh filter - i_filt = n_user_filters + 1 + i_filt = i_start allocate(MeshFilter :: filters(i_filt) % obj) select type (filt => filters(i_filt) % obj) type is (MeshFilter) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 271bd9fc1..5d90407ff 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2738,7 +2738,9 @@ contains n_user_filters = size(node_filt_list) ! Allocate filters array - if (n_user_filters > 0) call add_filters(n_user_filters) + if (n_user_filters > 0) then + err = openmc_extend_filters(n_user_filters) + end if ! Check for user tallies n_user_tallies = size(node_tal_list) @@ -3877,13 +3879,13 @@ contains ! Extend the filters array so we can add a surface filter and ! mesh filter - call add_filters(2) + err = openmc_extend_filters(2, i_start, i_end) ! Increment number of user filters n_user_filters = n_user_filters + 2 ! Get index of the new mesh filter - i_filt = n_user_filters - 1 + i_filt = i_start ! Duplicate the mesh filter since other tallies might use this ! filter and we need to change the dimension @@ -3897,13 +3899,13 @@ contains ! currents coming into and out of the boundary mesh cells. filt % n_bins = product(m % dimension + 1) - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + ! Add filter to dictionary + call filter_dict % add_key(filt % id, i_filt) end select t % filter(t % find_filter(FILTER_MESH)) = i_filt ! Get index of the new surface filter - i_filt = n_user_filters + i_filt = i_end ! Add surface filter allocate(SurfaceFilter :: filters(i_filt) % obj) diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 4a6f35b01..15718e746 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -1144,34 +1144,4 @@ contains end do end subroutine find_offset -!=============================================================================== -! ADD_FILTERS creates or extends the filters array -!=============================================================================== - - subroutine add_filters(n) - - integer, intent(in) :: n ! number of filters to add - - integer :: i ! loop counter - type(TallyFilterContainer), allocatable :: temp(:) ! temporary filters - - if (n_filters == 0) then - ! Allocate filters array - allocate(filters(n)) - else - ! Move filters to temporary array - allocate(temp(n_filters + n)) - do i = 1, n_filters - call move_alloc(filters(i) % obj, temp(i) % obj) - end do - - ! Move filters back from temporary array to filters array - call move_alloc(temp, filters) - end if - - ! Set n_filters - n_filters = size(filters) - - end subroutine add_filters - end module tally_filter diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index 155357695..b499a74ab 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -10,12 +10,14 @@ module tally_filter_header use hdf5 implicit none + private + public :: openmc_extend_filters !=============================================================================== ! TALLYFILTERMATCH stores every valid bin and weight for a filter !=============================================================================== - type TallyFilterMatch + type, public :: TallyFilterMatch ! Index of the bin and weight being used in the current filter combination integer :: i_bin type(VectorInt) :: bins @@ -31,7 +33,7 @@ module tally_filter_header ! should score to the tally. !=============================================================================== - type, abstract :: TallyFilter + type, public, abstract :: TallyFilter integer :: id integer :: n_bins = 0 contains @@ -93,18 +95,18 @@ module tally_filter_header ! TallyFilters !=============================================================================== - type TallyFilterContainer + type, public :: TallyFilterContainer class(TallyFilter), allocatable :: obj end type TallyFilterContainer - integer :: n_filters = 0 ! # of filters + integer(C_INT32_T), public, bind(C) :: n_filters = 0 ! # of filters - type(TallyFilterContainer), allocatable, target :: filters(:) - type(TallyFilterMatch), allocatable :: filter_matches(:) + type(TallyFilterContainer), public, allocatable, target :: filters(:) + type(TallyFilterMatch), public, allocatable :: filter_matches(:) !$omp threadprivate(filter_matches) ! Dictionary that maps user IDs to indices in 'filters' - type(DictIntInt) :: filter_dict + type(DictIntInt), public :: filter_dict contains @@ -116,4 +118,40 @@ contains class(TallyFilter), intent(inout) :: this end subroutine filter_initialize +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_extend_filters(n, index_start, index_end) result(err) bind(C) + ! Creates or extends the filters array + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), optional, intent(out) :: index_start + integer(C_INT32_T), optional, intent(out) :: index_end + integer(C_INT) :: err + + integer :: i ! loop counter + type(TallyFilterContainer), allocatable :: temp(:) ! temporary filters + + if (n_filters == 0) then + ! Allocate filters array + allocate(filters(n)) + else + ! Move filters to temporary array + allocate(temp(n_filters + n)) + do i = 1, n_filters + call move_alloc(filters(i) % obj, temp(i) % obj) + end do + + ! Move filters back from temporary array to filters array + call move_alloc(temp, filters) + end if + + ! Return indices in filters array + if (present(index_start)) index_start = n_filters + 1 + if (present(index_end)) index_end = n_filters + n + n_filters = n_filters + n + + err = 0 + end function openmc_extend_filters + end module tally_filter_header From 01165aedad7a41f98d66a12a15dbabf67e2fb274 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 11 Aug 2017 07:37:34 -0500 Subject: [PATCH 129/229] Get rid of a bunch of globals, add openmc_extend_meshes, revert to storing int in mesh filter --- src/api.F90 | 3 -- src/cmfd_data.F90 | 11 ++-- src/cmfd_execute.F90 | 15 +++--- src/cmfd_header.F90 | 7 +++ src/cmfd_input.F90 | 46 ++++++++-------- src/global.F90 | 13 ----- src/input_xml.F90 | 90 ++++++++++++++----------------- src/mesh_header.F90 | 47 +++++++++++++--- src/output.F90 | 2 +- src/tallies/tally.F90 | 8 +-- src/tallies/tally_filter.F90 | 2 +- src/tallies/tally_filter_mesh.F90 | 10 ++-- src/tallies/tally_header.F90 | 11 ++-- src/tallies/trigger.F90 | 2 +- 14 files changed, 135 insertions(+), 132 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 8be51e1e7..f083c7a46 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -199,9 +199,6 @@ contains n_source_points = 0 n_state_points = 0 n_tallies = 0 - n_user_filters = 0 - n_user_meshes = 0 - n_user_tallies = 0 output_summary = .true. output_tallies = .true. particle_restart_run = .false. diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index 779c350d7..e66c89457 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -50,14 +50,14 @@ contains subroutine compute_xs() + use cmfd_header, only: cmfd_tallies use constants, only: FILTER_MESH, FILTER_ENERGYIN, FILTER_ENERGYOUT, & FILTER_SURFACE, OUT_LEFT, OUT_RIGHT, OUT_BACK, & OUT_FRONT, OUT_BOTTOM, OUT_TOP, IN_LEFT, IN_RIGHT, & IN_BACK, IN_FRONT, IN_BOTTOM, IN_TOP, CMFD_NOACCEL, & ZERO, ONE, TINY_BIT use error, only: fatal_error - use global, only: cmfd, n_cmfd_tallies, cmfd_tallies, meshes, & - filters, filter_matches + use global, only: cmfd, meshes, filters, filter_matches use mesh_header, only: RegularMesh use string, only: to_str use tally_header, only: TallyObject @@ -75,7 +75,6 @@ contains integer :: ital ! tally object index integer :: ijk(3) ! indices for mesh cell integer :: score_index ! index to pull from tally object - integer :: i_mesh ! index in meshes array integer :: i_filt ! index in filters array integer :: i_filter_mesh ! index for mesh filter integer :: i_filter_ein ! index for incoming energy filter @@ -102,7 +101,7 @@ contains i_filt = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filt) % obj) type is (MeshFilter) - m => filt % mesh + m => meshes(filt % mesh) end select ! Set mesh widths @@ -113,14 +112,14 @@ contains cmfd % keff_bal = ZERO ! Begin loop around tallies - TAL: do ital = 1, n_cmfd_tallies + TAL: do ital = 1, size(cmfd_tallies) ! Associate tallies and mesh t => cmfd_tallies(ital) i_filt = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filt) % obj) type is (MeshFilter) - m => filt % mesh + m => meshes(filt % mesh) end select ! Check for energy filters diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index b9aae0da5..89e763187 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -214,9 +214,10 @@ contains subroutine cmfd_reweight(new_weights) use algorithm, only: binary_search + use cmfd_header, only: cmfd_mesh use constants, only: ZERO, ONE use error, only: warning, fatal_error - use global, only: meshes, source_bank, work, n_user_meshes, cmfd + use global, only: source_bank, work, cmfd use mesh_header, only: RegularMesh use mesh, only: count_bank_sites use message_passing @@ -234,14 +235,10 @@ contains integer :: n_groups ! number of energy groups logical :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh - type(RegularMesh), pointer :: m ! point to mesh #ifdef MPI integer :: mpi_err #endif - ! Associate pointer - m => meshes(n_user_meshes + 1) - ! Get maximum of spatial and group indices nx = cmfd % indices(1) ny = cmfd % indices(2) @@ -265,8 +262,8 @@ contains cmfd%weightfactors = ONE ! Count bank sites in mesh and reverse due to egrid structure - call count_bank_sites(m, source_bank, cmfd%sourcecounts, cmfd % egrid, & - sites_outside=outside, size_bank=work) + call count_bank_sites(cmfd_mesh, source_bank, cmfd%sourcecounts, & + cmfd % egrid, sites_outside=outside, size_bank=work) cmfd % sourcecounts = cmfd%sourcecounts(ng:1:-1,:,:,:) ! Check for sites outside of the mesh @@ -295,7 +292,7 @@ contains do i = 1, int(work,4) ! Determine spatial bin - call m % get_indices(source_bank(i) % xyz, ijk, in_mesh) + call cmfd_mesh % get_indices(source_bank(i) % xyz, ijk, in_mesh) ! Determine energy bin n_groups = size(cmfd % egrid) - 1 @@ -363,7 +360,7 @@ contains subroutine cmfd_tally_reset() - use global, only: cmfd_tallies + use cmfd_header, only: cmfd_tallies use output, only: write_message integer :: i ! loop counter diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index e743cc928..0a8e5ae9f 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -1,6 +1,8 @@ module cmfd_header use constants, only: CMFD_NOACCEL, ZERO, ONE + use mesh_header, only: RegularMesh + use tally_header, only: TallyObject implicit none private @@ -88,6 +90,11 @@ module cmfd_header end type cmfd_type + type(RegularMesh), public, pointer :: cmfd_mesh => null() + + ! Pointers for different tallies + type(TallyObject), public, pointer :: cmfd_tallies(:) => null() + contains !============================================================================== diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index ff6b65a97..020885528 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -248,9 +248,10 @@ contains subroutine create_cmfd_tally(root) + use cmfd_header, only: cmfd_mesh, cmfd_tallies use constants, only: MAX_LINE_LEN use error, only: fatal_error, warning - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, openmc_extend_meshes use string use tally_header, only: TallyObject, openmc_extend_tallies use tally_filter_header @@ -265,6 +266,7 @@ contains integer :: ng ! number of energy groups (default 1) integer :: n_filter ! number of filters integer :: i_start, i_end + integer :: i_filt_start, i_filt_end integer(C_INT) :: err integer :: i_filt ! index in filters array integer :: iarray3(3) ! temp integer array @@ -273,16 +275,14 @@ contains type(RegularMesh), pointer :: m type(XMLNode) :: node_mesh - ! Set global variables if they are 0 (this can happen if there is no tally - ! file) - if (n_meshes == 0) n_meshes = n_user_meshes + n_cmfd_meshes + err = openmc_extend_meshes(1, i_start) ! Allocate mesh - if (.not. allocated(meshes)) allocate(meshes(n_meshes)) - m => meshes(n_user_meshes+1) + cmfd_mesh => meshes(i_start) + m => meshes(i_start) ! Set mesh id - m % id = n_user_meshes + 1 + m % id = i_start ! Set mesh type to rectangular m % type = LATTICE_RECT @@ -376,23 +376,23 @@ contains m % volume_frac = ONE/real(product(m % dimension),8) ! Add mesh to dictionary - call mesh_dict % add_key(m % id, n_user_meshes + 1) + call mesh_dict % add_key(m % id, i_start) ! Determine number of filters energy_filters = check_for_node(node_mesh, "energy") - n_cmfd_filters = merge(5, 3, energy_filters) + n = merge(5, 3, energy_filters) ! Extend filters array so we can add CMFD filters - err = openmc_extend_filters(n_cmfd_filters, i_start, i_end) + err = openmc_extend_filters(n, i_filt_start, i_filt_end) ! Set up mesh filter - i_filt = i_start + i_filt = i_filt_start allocate(MeshFilter :: filters(i_filt) % obj) select type (filt => filters(i_filt) % obj) type is (MeshFilter) filt % id = i_filt filt % n_bins = product(m % dimension) - filt % mesh => meshes(n_user_meshes + 1) + filt % mesh = i_start ! Add filter to dictionary call filter_dict % add_key(filt % id, i_filt) end select @@ -437,7 +437,7 @@ contains ! We need to increase the dimension by one since we also need ! currents coming into and out of the boundary mesh cells. filt % n_bins = product(m % dimension + 1) - filt % mesh => meshes(n_user_meshes + 1) + filt % mesh = i_start ! Add filter to dictionary call filter_dict % add_key(filt % id, i_filt) end select @@ -464,11 +464,11 @@ contains end select ! Allocate tallies - err = openmc_extend_tallies(n_cmfd_tallies, i_start, i_end) + err = openmc_extend_tallies(3, i_start, i_end) cmfd_tallies => tallies(i_start:i_end) ! Begin loop around tallies - do i = 1, n_cmfd_tallies + do i = 1, size(cmfd_tallies) ! Point t to tally variable t => cmfd_tallies(i) @@ -510,9 +510,9 @@ contains ! Allocate and set filters allocate(t % filter(n_filter)) - t % filter(1) = n_user_filters + 1 + t % filter(1) = i_filt_start if (energy_filters) then - t % filter(2) = n_user_filters + 2 + t % filter(2) = i_filt_start + 1 end if ! Allocate scoring bins @@ -550,10 +550,10 @@ contains ! Allocate and set indices in filters array allocate(t % filter(n_filter)) - t % filter(1) = n_user_filters + 1 + t % filter(1) = i_filt_start if (energy_filters) then - t % filter(2) = n_user_filters + 2 - t % filter(3) = n_user_filters + 3 + t % filter(2) = i_filt_start + 1 + t % filter(3) = i_filt_start + 2 end if ! Allocate macro reactions @@ -583,10 +583,10 @@ contains ! Allocate and set filters allocate(t % filter(n_filter)) - t % filter(1) = n_user_filters + n_cmfd_filters - 1 - t % filter(n_filter) = n_user_filters + n_cmfd_filters + t % filter(1) = i_filt_end - 1 + t % filter(n_filter) = i_filt_end if (energy_filters) then - t % filter(2) = n_user_filters + 2 + t % filter(2) = i_filt_start + 1 end if ! Allocate macro reactions diff --git a/src/global.F90 b/src/global.F90 index 08d024c9f..baac4638a 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -71,10 +71,6 @@ module global ! ============================================================================ ! TALLY-RELATED VARIABLES - ! Pointers for different tallies - type(TallyObject), pointer :: user_tallies(:) => null() - type(TallyObject), pointer :: cmfd_tallies(:) => null() - ! Active tally lists type(VectorInt) :: active_analog_tallies type(VectorInt) :: active_tracklength_tallies @@ -83,10 +79,6 @@ module global type(VectorInt) :: active_tallies type(VectorInt) :: active_surface_tallies - integer :: n_user_meshes = 0 ! # of structured user meshes - integer :: n_user_filters = 0 ! # of user filters - integer :: n_user_tallies = 0 ! # of user tallies - ! Normalization for statistics integer :: n_realizations = 0 ! # of independent realizations real(8) :: total_weight ! total starting particle weight in realization @@ -264,11 +256,6 @@ module global ! Flag to activate neutronic feedback via source weights logical :: cmfd_feedback = .false. - ! User-defined tally information - integer :: n_cmfd_meshes = 1 ! # of structured meshes - integer :: n_cmfd_filters = 0 ! # of filters - integer :: n_cmfd_tallies = 3 ! # of user-defined tallies - ! Adjoint method type character(len=10) :: cmfd_adjoint_type = 'physical' diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 5d90407ff..3225c51b7 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4,6 +4,7 @@ module input_xml use algorithm, only: find use cmfd_input, only: configure_cmfd + use cmfd_header, only: cmfd_mesh use constants use dict_header, only: DictIntInt, DictCharInt, ElemKeyValueCI use distribution_multivariate @@ -2652,6 +2653,7 @@ contains integer :: trig_ind ! index of triggers array for each tally integer :: user_trig_ind ! index of user-specified triggers for each tally integer :: i_start, i_end + integer :: i_filt_start, i_filt_end integer(C_INT) :: err real(8) :: threshold ! trigger convergence threshold integer :: n_order ! moment order requested @@ -2723,37 +2725,6 @@ contains ! Get pointer list to XML call get_node_list(root, "tally", node_tal_list) - ! Check for user meshes - n_user_meshes = size(node_mesh_list) - if (cmfd_run) then - n_meshes = n_user_meshes + n_cmfd_meshes - else - n_meshes = n_user_meshes - end if - - ! Allocate mesh array - if (n_meshes > 0) allocate(meshes(n_meshes)) - - ! Check for user filters - n_user_filters = size(node_filt_list) - - ! Allocate filters array - if (n_user_filters > 0) then - err = openmc_extend_filters(n_user_filters) - end if - - ! Check for user tallies - n_user_tallies = size(node_tal_list) - if (n_user_tallies == 0) then - if (master) call warning("No tallies present in tallies.xml file!") - end if - - ! Allocate user tallies - if (n_user_tallies > 0 .and. run_mode /= MODE_PLOTTING) then - err = openmc_extend_tallies(n_user_tallies, i_start, i_end) - user_tallies => tallies(i_start:i_end) - end if - ! Check for setting if (check_for_node(root, "assume_separate")) then call get_node_value(root, "assume_separate", assume_separate) @@ -2762,8 +2733,14 @@ contains ! ========================================================================== ! READ MESH DATA - do i = 1, n_user_meshes - m => meshes(i) + ! Check for user meshes and allocate + n = size(node_mesh_list) + if (n > 0) then + err = openmc_extend_meshes(n, i_start, i_end) + end if + + do i = 1, n + m => meshes(i_start + i - 1) ! Get pointer to mesh node node_mesh = node_mesh_list(i) @@ -2979,8 +2956,14 @@ contains ! ========================================================================== ! READ FILTER DATA - READ_FILTERS: do i = 1, n_user_filters - f => filters(i) + ! Check for user filters and allocate + n = size(node_filt_list) + if (n > 0) then + err = openmc_extend_filters(n, i_start, i_end) + end if + + READ_FILTERS: do i = 1, n + f => filters(i_start + i - 1) ! Get pointer to filter xml node node_filt = node_filt_list(i) @@ -3123,7 +3106,7 @@ contains filt % n_bins = product(m % dimension) ! Store the index of the mesh - filt % mesh => meshes(i_mesh) + filt % mesh = i_mesh end select case ('energy') @@ -3342,9 +3325,20 @@ contains ! ========================================================================== ! READ TALLY DATA - READ_TALLIES: do i = 1, n_user_tallies + ! Check for user tallies + n = size(node_tal_list) + if (n == 0) then + if (master) call warning("No tallies present in tallies.xml file!") + end if + + ! Allocate user tallies + if (n > 0 .and. run_mode /= MODE_PLOTTING) then + err = openmc_extend_tallies(n, i_start, i_end) + end if + + READ_TALLIES: do i = 1, n ! Get pointer to tally - t => tallies(i) + t => tallies(i_start + i - 1) ! Get pointer to tally xml node node_tal = node_tal_list(i) @@ -3865,7 +3859,8 @@ contains ! Get pointer to mesh select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => filt % mesh + i_mesh = filt % mesh + m => meshes(filt % mesh) end select ! Copy filter indices to temporary array @@ -3879,13 +3874,10 @@ contains ! Extend the filters array so we can add a surface filter and ! mesh filter - err = openmc_extend_filters(2, i_start, i_end) - - ! Increment number of user filters - n_user_filters = n_user_filters + 2 + err = openmc_extend_filters(2, i_filt_start, i_filt_end) ! Get index of the new mesh filter - i_filt = i_start + i_filt = i_filt_start ! Duplicate the mesh filter since other tallies might use this ! filter and we need to change the dimension @@ -3893,7 +3885,7 @@ contains select type(filt => filters(i_filt) % obj) type is (MeshFilter) filt % id = i_filt - filt % mesh => m + filt % mesh = i_mesh ! We need to increase the dimension by one since we also need ! currents coming into and out of the boundary mesh cells. @@ -3905,7 +3897,7 @@ contains t % filter(t % find_filter(FILTER_MESH)) = i_filt ! Get index of the new surface filter - i_filt = i_end + i_filt = i_filt_end ! Add surface filter allocate(SurfaceFilter :: filters(i_filt) % obj) @@ -4683,11 +4675,7 @@ contains &meshlines on plot " // trim(to_str(pl % id))) end if - select type(filt => filters(cmfd_tallies(1) % & - filter(cmfd_tallies(1) % find_filter(FILTER_MESH))) % obj) - type is (MeshFilter) - pl % meshlines_mesh => filt % mesh - end select + pl % meshlines_mesh => cmfd_mesh case ('entropy') diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index d94189161..4ab3bab32 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -11,7 +11,7 @@ module mesh_header implicit none private - public :: RegularMesh, meshes, n_meshes, mesh_dict + public :: openmc_extend_meshes !=============================================================================== ! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by @@ -36,12 +36,12 @@ module mesh_header procedure :: to_hdf5 => regular_to_hdf5 end type RegularMesh - integer(C_INT32_T), bind(C) :: n_meshes = 0 ! # of structured meshes + integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes - type(RegularMesh), allocatable, target :: meshes(:) + type(RegularMesh), public, allocatable, target :: meshes(:) ! Dictionary that maps user IDs to indices in 'meshes' - type(DictIntInt) :: mesh_dict + type(DictIntInt), public :: mesh_dict contains @@ -164,8 +164,8 @@ contains pure function regular_intersects(this, xyz0, xyz1) result(intersects) class(RegularMesh), intent(in) :: this - real(8), intent(in) :: xyz0(1) - real(8), intent(in) :: xyz1(1) + real(8), intent(in) :: xyz0(:) + real(8), intent(in) :: xyz1(:) logical :: intersects select case(this % n_dimension) @@ -415,4 +415,39 @@ contains call close_group(mesh_group) end subroutine regular_to_hdf5 +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C) + ! Extend the meshes array by n elements + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), optional, intent(out) :: index_start + integer(C_INT32_T), optional, intent(out) :: index_end + integer(C_INT) :: err + + type(RegularMesh), allocatable :: temp(:) ! temporary meshes array + + if (n_meshes == 0) then + ! Allocate meshes array + allocate(meshes(n)) + else + ! Allocate meshes array with increased size + allocate(temp(n_meshes + n)) + + ! Copy original meshes to temporary array + temp(1:n_meshes) = meshes + + ! Move allocation from temporary array + call move_alloc(FROM=temp, TO=meshes) + end if + + ! Return indices in meshes array + if (present(index_start)) index_start = n_meshes + 1 + if (present(index_end)) index_end = n_meshes + n + n_meshes = n_meshes + n + + err = 0 + end function openmc_extend_meshes + end module mesh_header diff --git a/src/output.F90 b/src/output.F90 index 2b69906b2..ec47070ef 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -1023,7 +1023,7 @@ contains i_filter_mesh = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => filt % mesh + m => meshes(filt % mesh) end select ! Get surface filter index and stride diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index b62f5547b..fd8ae6d3c 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -2223,7 +2223,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array - integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations type(TallyObject), pointer :: t @@ -2368,7 +2367,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array - integer :: matching_bin ! next valid filter bin real(8) :: filter_weight ! combined weight of all filters real(8) :: atom_density logical :: finished ! found all valid bin combinations @@ -2744,7 +2742,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) - integer :: matching_bin ! next valid filter bin real(8) :: flux ! tracklength estimate of flux real(8) :: atom_density ! atom density of single nuclide in atom/b-cm real(8) :: filter_weight ! combined weight of all filters @@ -2905,7 +2902,6 @@ contains integer :: k ! loop index for nuclide bins integer :: filter_index ! single index for single bin integer :: i_nuclide ! index in nuclides array (from bins) - integer :: matching_bin ! next valid filter bin real(8) :: flux ! collision estimate of flux real(8) :: atom_density ! atom density of single nuclide ! in atom/b-cm @@ -3192,7 +3188,6 @@ contains integer :: i integer :: i_tally - integer :: i_filt integer :: j, k ! loop indices integer :: n_dim ! num dimensions of the mesh integer :: d1 ! dimension index @@ -3211,7 +3206,6 @@ contains real(8) :: xyz_cross(3) ! coordinates of bounding surfaces real(8) :: d(3) ! distance to each bounding surface real(8) :: distance ! actual distance traveled - real(8) :: filt_score ! score applied by filters integer :: matching_bin ! next valid filter bin logical :: start_in_mesh ! particle's starting xyz in mesh? logical :: end_in_mesh ! particle's ending xyz in mesh? @@ -3249,7 +3243,7 @@ contains ! Get pointer to mesh select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => filt % mesh + m => meshes(filt % mesh) end select n_dim = m % n_dimension diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 15718e746..7c3706dc6 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -188,7 +188,7 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - integer :: i, start + integer :: i ! Iterate over coordinate levels to see which universes match do i = 1, p % n_coord diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index f1c8615f5..c56902bab 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -4,7 +4,7 @@ module tally_filter_mesh use constants use error, only: warning - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use hdf5_interface use particle_header, only: Particle use string, only: to_str @@ -20,7 +20,7 @@ module tally_filter_mesh !=============================================================================== type, public, extends(TallyFilter) :: MeshFilter - type(RegularMesh), pointer :: mesh => null() + integer :: mesh contains procedure :: get_all_bins => get_all_bins_mesh procedure :: to_statepoint => to_statepoint_mesh @@ -60,7 +60,7 @@ contains weight = ERROR_REAL ! Get a pointer to the mesh. - m => this % mesh + m => meshes(this % mesh) n = m % n_dimension if (estimator /= ESTIMATOR_TRACKLENGTH) then @@ -215,7 +215,7 @@ contains call write_dataset(filter_group, "type", "mesh") call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % mesh % id) + call write_dataset(filter_group, "bins", meshes(this % mesh) % id) end subroutine to_statepoint_mesh function text_label_mesh(this, bin) result(label) @@ -225,7 +225,7 @@ contains integer, allocatable :: ijk(:) - associate (m => this % mesh) + associate (m => meshes(this % mesh)) allocate(ijk(m % n_dimension)) call m % get_indices_from_bin(bin, ijk) if (m % n_dimension == 1) then diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 5c1f71ab3..27a6ce674 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -213,7 +213,6 @@ contains subroutine tally_setup_arrays(this) class(TallyObject), intent(inout) :: this - integer :: i ! loop index for tallies integer :: j ! loop index for filters integer :: n ! temporary stride integer :: i_filt ! filter index @@ -274,8 +273,8 @@ contains function openmc_extend_tallies(n, index_start, index_end) result(err) bind(C) ! Extend the tallies array by n elements integer(C_INT32_T), value, intent(in) :: n - integer(C_INT32_T), intent(out) :: index_start - integer(C_INT32_T), intent(out) :: index_end + integer(C_INT32_T), optional, intent(out) :: index_start + integer(C_INT32_T), optional, intent(out) :: index_end integer(C_INT) :: err type(TallyObject), allocatable :: temp(:) ! temporary tallies array @@ -295,9 +294,9 @@ contains end if ! Return indices in tallies array - index_start = n_tallies + 1 - index_end = n_tallies + n - n_tallies = index_end + if (present(index_start)) index_start = n_tallies + 1 + if (present(index_end)) index_end = n_tallies + n + n_tallies = n_tallies + n err = 0 end function openmc_extend_tallies diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index c9310a55a..29c2ecedd 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -315,7 +315,7 @@ contains i_filter_surf = t % filter(t % find_filter(FILTER_SURFACE)) select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => filt % mesh + m => meshes(filt % mesh) end select ! initialize bins array From 8a94f1b8c7994873df40376e8f5e99516874fc1e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 11 Aug 2017 09:32:39 -0500 Subject: [PATCH 130/229] Move CMFD-related variables to cmfd_header --- src/cmfd_data.F90 | 16 ++++------- src/cmfd_execute.F90 | 14 ++++----- src/cmfd_header.F90 | 58 ++++++++++++++++++++++++++++++++++++++ src/cmfd_input.F90 | 4 +-- src/cmfd_loss_operator.F90 | 2 +- src/cmfd_prod_operator.F90 | 2 +- src/cmfd_solver.F90 | 23 +++++++-------- src/global.F90 | 56 ------------------------------------ 8 files changed, 83 insertions(+), 92 deletions(-) diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index e66c89457..d1db7c509 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -5,6 +5,8 @@ module cmfd_data ! parameters for CMFD calculation. !============================================================================== + use cmfd_header, only: allocate_cmfd, cmfd, cmfd_coremap, & + cmfd_downscatter, cmfd_tallies, dhat_reset use constants use tally_filter_mesh, only: MeshFilter @@ -20,9 +22,7 @@ contains subroutine set_up_cmfd() - use cmfd_header, only: allocate_cmfd use constants, only: CMFD_NOACCEL - use global, only: cmfd, cmfd_coremap, cmfd_downscatter ! Check for core map and set it up if ((cmfd_coremap) .and. (cmfd%mat_dim == CMFD_NOACCEL)) call set_coremap() @@ -50,17 +50,16 @@ contains subroutine compute_xs() - use cmfd_header, only: cmfd_tallies use constants, only: FILTER_MESH, FILTER_ENERGYIN, FILTER_ENERGYOUT, & FILTER_SURFACE, OUT_LEFT, OUT_RIGHT, OUT_BACK, & OUT_FRONT, OUT_BOTTOM, OUT_TOP, IN_LEFT, IN_RIGHT, & IN_BACK, IN_FRONT, IN_BOTTOM, IN_TOP, CMFD_NOACCEL, & ZERO, ONE, TINY_BIT use error, only: fatal_error - use global, only: cmfd, meshes, filters, filter_matches - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use string, only: to_str use tally_header, only: TallyObject + use tally_filter_header, only: filters, filter_matches integer :: nx ! number of mesh cells in x direction integer :: ny ! number of mesh cells in y direction @@ -335,7 +334,6 @@ contains subroutine set_coremap() use constants, only: CMFD_NOACCEL - use global, only: cmfd integer :: counter=1 ! counter for unique fuel assemblies integer :: nx ! number of mesh cells in x direction @@ -396,7 +394,7 @@ contains subroutine neutron_balance() use constants, only: ONE, ZERO, CMFD_NOACCEL, CMFD_NORES - use global, only: cmfd, keff, current_batch + use global, only: keff, current_batch integer :: nx ! number of mesh cells in x direction integer :: ny ! number of mesh cells in y direction @@ -505,7 +503,6 @@ contains subroutine compute_dtilde() use constants, only: CMFD_NOACCEL, ZERO_FLUX, TINY_BIT - use global, only: cmfd, cmfd_coremap integer :: nx ! maximum number of cells in x direction integer :: ny ! maximum number of cells in y direction @@ -647,7 +644,6 @@ contains subroutine compute_dhat() use constants, only: CMFD_NOACCEL, ZERO - use global, only: cmfd, cmfd_coremap, dhat_reset use output, only: write_message use string, only: to_str @@ -797,7 +793,6 @@ contains function get_reflector_albedo(l, g, i, j, k) use constants, only: ONE - use global, only: cmfd real(8) :: get_reflector_albedo ! reflector albedo integer, intent(in) :: i ! iteration counter for x @@ -836,7 +831,6 @@ contains subroutine compute_effective_downscatter() use constants, only: ZERO, CMFD_NOACCEL - use global, only: cmfd integer :: nx ! number of mesh cells in x direction integer :: ny ! number of mesh cells in y direction diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 89e763187..2edc8b08f 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -5,6 +5,8 @@ module cmfd_execute ! cross section generation, diffusion calculation, and source re-weighting !============================================================================== + use cmfd_header, only: cmfd_begin, cmfd_on, cmfd_reset, cmfd, cmfd_coremap, & + cmfd_mesh use global implicit none @@ -63,9 +65,7 @@ contains subroutine cmfd_init_batch() - use global, only: cmfd_begin, cmfd_on, & - cmfd_reset, cmfd_run, & - current_batch + use global, only: cmfd_run, current_batch ! Check to activate CMFD diffusion and possible feedback ! this guarantees that when cmfd begins at least one batch of tallies are @@ -91,7 +91,7 @@ contains subroutine calc_fission_source() use constants, only: CMFD_NOACCEL, ZERO, TWO - use global, only: cmfd, cmfd_coremap, entropy_on, current_batch + use global, only: entropy_on, current_batch use message_passing use string, only: to_str @@ -214,10 +214,9 @@ contains subroutine cmfd_reweight(new_weights) use algorithm, only: binary_search - use cmfd_header, only: cmfd_mesh use constants, only: ZERO, ONE use error, only: warning, fatal_error - use global, only: source_bank, work, cmfd + use global, only: source_bank, work use mesh_header, only: RegularMesh use mesh, only: count_bank_sites use message_passing @@ -328,8 +327,6 @@ contains function get_matrix_idx(g, i, j, k, ng, nx, ny) result (matidx) - use global, only: cmfd, cmfd_coremap - integer :: matidx ! the index location in matrix integer, intent(in) :: i ! current x index integer, intent(in) :: j ! current y index @@ -360,7 +357,6 @@ contains subroutine cmfd_tally_reset() - use cmfd_header, only: cmfd_tallies use output, only: write_message integer :: i ! loop counter diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index 0a8e5ae9f..1d1056f4d 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -2,7 +2,9 @@ module cmfd_header use constants, only: CMFD_NOACCEL, ZERO, ONE use mesh_header, only: RegularMesh + use set_header, only: SetInt use tally_header, only: TallyObject + use timer_header, only: Timer implicit none private @@ -90,11 +92,67 @@ module cmfd_header end type cmfd_type + ! Main object + type(cmfd_type), public :: cmfd + type(RegularMesh), public, pointer :: cmfd_mesh => null() ! Pointers for different tallies type(TallyObject), public, pointer :: cmfd_tallies(:) => null() + ! Timing objects + type(Timer), public :: time_cmfd ! timer for whole cmfd calculation + type(Timer), public :: time_cmfdbuild ! timer for matrix build + type(Timer), public :: time_cmfdsolve ! timer for solver + + ! Flag for active core map + logical, public :: cmfd_coremap = .false. + + ! Flag to reset dhats to zero + logical, public :: dhat_reset = .false. + + ! Flag to activate neutronic feedback via source weights + logical, public :: cmfd_feedback = .false. + + ! Adjoint method type + character(len=10), public :: cmfd_adjoint_type = 'physical' + + ! Number of incomplete ilu factorization levels + integer, public :: cmfd_ilu_levels = 1 + + ! Batch to begin cmfd + integer, public :: cmfd_begin = 1 + + ! Tally reset list + integer, public :: n_cmfd_resets + type(SetInt), public :: cmfd_reset + + ! Compute effective downscatter cross section + logical, public :: cmfd_downscatter = .false. + + ! Convergence monitoring + logical, public :: cmfd_power_monitor = .false. + + ! Cmfd output + logical, public :: cmfd_write_matrices = .false. + + ! Run an adjoint calculation (last batch only) + logical, public :: cmfd_run_adjoint = .false. + + ! CMFD run logicals + logical, public :: cmfd_on = .false. + + ! CMFD display info + character(len=25), public :: cmfd_display = 'balance' + + ! Estimate of spectral radius of CMFD matrices and tolerances + real(8), public :: cmfd_spectral = ZERO + real(8), public :: cmfd_shift = 1.e6 + real(8), public :: cmfd_ktol = 1.e-8_8 + real(8), public :: cmfd_stol = 1.e-8_8 + real(8), public :: cmfd_atoli = 1.e-10_8 + real(8), public :: cmfd_rtoli = 1.e-5_8 + contains !============================================================================== diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 020885528..67341ae95 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -2,6 +2,7 @@ module cmfd_input use, intrinsic :: ISO_C_BINDING + use cmfd_header use global implicit none @@ -16,7 +17,6 @@ contains subroutine configure_cmfd() - use cmfd_header, only: allocate_cmfd use message_passing, only: master integer :: color ! color group of processor @@ -49,7 +49,6 @@ contains use constants, only: ZERO, ONE use error, only: fatal_error, warning - use global use output, only: write_message use string, only: to_lower use xml_interface @@ -248,7 +247,6 @@ contains subroutine create_cmfd_tally(root) - use cmfd_header, only: cmfd_mesh, cmfd_tallies use constants, only: MAX_LINE_LEN use error, only: fatal_error, warning use mesh_header, only: RegularMesh, openmc_extend_meshes diff --git a/src/cmfd_loss_operator.F90 b/src/cmfd_loss_operator.F90 index 7dfeed1db..50a75e52d 100644 --- a/src/cmfd_loss_operator.F90 +++ b/src/cmfd_loss_operator.F90 @@ -1,7 +1,7 @@ module cmfd_loss_operator use constants, only: CMFD_NOACCEL, ZERO - use global, only: cmfd, cmfd_coremap + use cmfd_header, only: cmfd, cmfd_coremap use matrix_header, only: Matrix implicit none diff --git a/src/cmfd_prod_operator.F90 b/src/cmfd_prod_operator.F90 index 7779c2455..91ce43b35 100644 --- a/src/cmfd_prod_operator.F90 +++ b/src/cmfd_prod_operator.F90 @@ -1,7 +1,7 @@ module cmfd_prod_operator use constants, only: CMFD_NOACCEL - use global, only: cmfd, cmfd_coremap + use cmfd_header, only: cmfd, cmfd_coremap use matrix_header, only: Matrix implicit none diff --git a/src/cmfd_solver.F90 b/src/cmfd_solver.F90 index fb687d10b..42d93f02f 100644 --- a/src/cmfd_solver.F90 +++ b/src/cmfd_solver.F90 @@ -53,7 +53,7 @@ contains subroutine cmfd_solver_execute(adjoint) - use global, only: cmfd_adjoint_type, time_cmfdbuild, time_cmfdsolve + use cmfd_header, only: cmfd_adjoint_type, time_cmfdbuild, time_cmfdsolve logical, optional, intent(in) :: adjoint ! adjoint calc @@ -100,8 +100,8 @@ contains subroutine init_data(adjoint) use constants, only: ONE, ZERO - use global, only: cmfd_shift, keff, cmfd_ktol, cmfd_stol, & - cmfd_write_matrices + use cmfd_header, only: cmfd_shift, cmfd_ktol, cmfd_stol, cmfd_write_matrices + use global, only: keff logical, intent(in) :: adjoint @@ -167,7 +167,7 @@ contains subroutine compute_adjoint() use error, only: fatal_error - use global, only: cmfd_write_matrices + use cmfd_header, only: cmfd_write_matrices ! Transpose matrices loss = loss % transpose() @@ -190,7 +190,7 @@ contains use constants, only: ONE use error, only: fatal_error - use global, only: cmfd, cmfd_atoli, cmfd_rtoli + use cmfd_header, only: cmfd, cmfd_atoli, cmfd_rtoli integer :: i ! iteration counter integer :: innerits ! # of inner iterations @@ -304,7 +304,7 @@ contains use, intrinsic :: ISO_FORTRAN_ENV use constants, only: ONE, ZERO - use global, only: cmfd_power_monitor + use cmfd_header, only: cmfd_power_monitor use message_passing, only: master integer, intent(in) :: iter ! outer iteration number @@ -346,7 +346,7 @@ contains use constants, only: ONE, ZERO use error, only: fatal_error - use global, only: cmfd, cmfd_spectral + use cmfd_header, only: cmfd, cmfd_spectral type(Matrix), intent(inout) :: A ! coefficient matrix type(Vector), intent(inout) :: b ! right hand side vector @@ -452,7 +452,7 @@ contains use constants, only: ONE, ZERO use error, only: fatal_error - use global, only: cmfd, cmfd_spectral + use cmfd_header, only: cmfd, cmfd_spectral type(Matrix), intent(inout) :: A ! coefficient matrix type(Vector), intent(inout) :: b ! right hand side vector @@ -597,7 +597,7 @@ contains use constants, only: ONE, ZERO use error, only: fatal_error - use global, only: cmfd, cmfd_spectral + use cmfd_header, only: cmfd, cmfd_spectral type(Matrix), intent(inout) :: A ! coefficient matrix type(Vector), intent(inout) :: b ! right hand side vector @@ -693,7 +693,8 @@ contains subroutine extract_results() - use global, only: cmfd, cmfd_write_matrices, current_batch + use cmfd_header, only: cmfd, cmfd_write_matrices + use global, only: current_batch character(len=25) :: filename ! name of file to write data integer :: n ! problem size @@ -750,7 +751,7 @@ contains subroutine matrix_to_indices(irow, g, i, j, k, ng, nx, ny, nz) - use global, only: cmfd, cmfd_coremap + use cmfd_header, only: cmfd, cmfd_coremap integer, intent(out) :: i ! iteration counter for x integer, intent(out) :: j ! iteration counter for y diff --git a/src/global.F90 b/src/global.F90 index baac4638a..e080e9515 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -236,65 +236,9 @@ module global ! ============================================================================ ! CMFD VARIABLES - ! Main object - type(cmfd_type) :: cmfd - ! Is CMFD active logical :: cmfd_run = .false. - ! Timing objects - type(Timer) :: time_cmfd ! timer for whole cmfd calculation - type(Timer) :: time_cmfdbuild ! timer for matrix build - type(Timer) :: time_cmfdsolve ! timer for solver - - ! Flag for active core map - logical :: cmfd_coremap = .false. - - ! Flag to reset dhats to zero - logical :: dhat_reset = .false. - - ! Flag to activate neutronic feedback via source weights - logical :: cmfd_feedback = .false. - - ! Adjoint method type - character(len=10) :: cmfd_adjoint_type = 'physical' - - ! Number of incomplete ilu factorization levels - integer :: cmfd_ilu_levels = 1 - - ! Batch to begin cmfd - integer :: cmfd_begin = 1 - - ! Tally reset list - integer :: n_cmfd_resets - type(SetInt) :: cmfd_reset - - ! Compute effective downscatter cross section - logical :: cmfd_downscatter = .false. - - ! Convergence monitoring - logical :: cmfd_power_monitor = .false. - - ! Cmfd output - logical :: cmfd_write_matrices = .false. - - ! Run an adjoint calculation (last batch only) - logical :: cmfd_run_adjoint = .false. - - ! CMFD run logicals - logical :: cmfd_on = .false. - - ! CMFD display info - character(len=25) :: cmfd_display = 'balance' - - ! Estimate of spectral radius of CMFD matrices and tolerances - real(8) :: cmfd_spectral = ZERO - real(8) :: cmfd_shift = 1.e6 - real(8) :: cmfd_ktol = 1.e-8_8 - real(8) :: cmfd_stol = 1.e-8_8 - real(8) :: cmfd_atoli = 1.e-10_8 - real(8) :: cmfd_rtoli = 1.e-5_8 - ! Information about state points to be written integer :: n_state_points = 0 type(SetInt) :: statepoint_batch From 22f3e0d30e0c8726107d27da92d6a3164b18c292 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 11 Aug 2017 09:35:11 -0500 Subject: [PATCH 131/229] Move threadprivate declaration for micro_xs and material_xs --- src/global.F90 | 3 +-- src/nuclide_header.F90 | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index e080e9515..2ebf1b346 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -260,8 +260,7 @@ module global real(8) :: res_scat_energy_max = 1000.0_8 character(10), allocatable :: res_scat_nuclides(:) -!$omp threadprivate(micro_xs, material_xs, fission_bank, n_bank, & -!$omp& trace, thread_id, current_work) +!$omp threadprivate(fission_bank, n_bank, trace, thread_id, current_work) contains diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 784888172..1ed2fee9e 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -169,6 +169,7 @@ module nuclide_header ! Cross section caches type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide type(MaterialMacroXS) :: material_xs ! Cache for current material +!$omp threadprivate(micro_xs, material_xs) ! Minimum/maximum energies real(8) :: energy_min_neutron = ZERO From 0b112820c8d1205528d8210b226b2f3f7e739def Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 11 Aug 2017 11:08:13 -0500 Subject: [PATCH 132/229] Add openmc_filter_set_type --- openmc/capi/__init__.py | 1 + openmc/capi/filter.py | 15 +++++++++ src/api.F90 | 2 ++ src/error.F90 | 1 + src/tallies/tally_filter.F90 | 62 +++++++++++++++++++++++++++++++++++- 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 openmc/capi/filter.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 355304a31..4cea121f7 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -35,4 +35,5 @@ from .core import * from .nuclide import * from .material import * from .cell import * +from .filter import * from .tally import * diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py new file mode 100644 index 000000000..f671ce401 --- /dev/null +++ b/openmc/capi/filter.py @@ -0,0 +1,15 @@ +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER + +from . import _dll +from .error import _error_handler + + +__all__ = [] + +# Tally functions +_dll.openmc_extend_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] +_dll.openmc_extend_filters.restype = c_int +_dll.openmc_extend_filters.errcheck = _error_handler +_dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p] +_dll.openmc_filter_set_type.restype = c_int +_dll.openmc_filter_set_type.errcheck = _error_handler diff --git a/src/api.F90 b/src/api.F90 index f083c7a46..975fb36a9 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -19,6 +19,7 @@ module openmc_api use random_lcg, only: seed, initialize_prng use tally_header use tally_filter_header + use tally_filter, only: openmc_filter_set_type use simulation, only: openmc_run use string, only: to_f_string use volume_calc, only: openmc_calculate_volumes @@ -31,6 +32,7 @@ module openmc_api public :: openmc_cell_set_temperature public :: openmc_extend_filters public :: openmc_extend_tallies + public :: openmc_filter_set_type public :: openmc_finalize public :: openmc_find public :: openmc_get_cell diff --git a/src/error.F90 b/src/error.F90 index 9dec93147..b7736d0a7 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -27,6 +27,7 @@ module error integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 + integer(C_INT), public, bind(C) :: E_ALREADY_ALLOCATED = -15 ! Warning codes integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 7c3706dc6..e5026f95c 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -5,11 +5,12 @@ module tally_filter use algorithm, only: binary_search use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION, ERROR_REAL use dict_header, only: DictIntInt + use error use geometry_header use hdf5_interface use particle_header, only: Particle use surface_header - use string, only: to_str + use string, only: to_str, to_f_string use tally_filter_header ! Inherit other filters @@ -1144,4 +1145,63 @@ contains end do end subroutine find_offset +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_filter_set_type(index, type) result(err) bind(C) + ! Set the type of a filter + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(in) :: type(*) + integer(C_INT) :: err + + character(:), allocatable :: type_ + + type_ = to_f_string(type) + + err = 0 + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + err = E_ALREADY_ALLOCATED + else + select case (type_) + case ('azimuthal') + allocate(AzimuthalFilter :: filters(index) % obj) + case ('cell') + allocate(CellFilter :: filters(index) % obj) + case ('cellborn') + allocate(CellbornFilter :: filters(index) % obj) + case ('cellfrom') + allocate(CellfromFilter :: filters(index) % obj) + case ('delayedgroup') + allocate(DelayedGroupFilter :: filters(index) % obj) + case ('distribcell') + allocate(DistribcellFilter :: filters(index) % obj) + case ('energy') + allocate(EnergyFilter :: filters(index) % obj) + case ('energyout') + allocate(EnergyoutFilter :: filters(index) % obj) + case ('energyfunction') + allocate(EnergyFunctionFilter :: filters(index) % obj) + case ('material') + allocate(MaterialFilter :: filters(index) % obj) + case ('mesh') + allocate(MeshFilter :: filters(index) % obj) + case ('mu') + allocate(MuFilter :: filters(index) % obj) + case ('polar') + allocate(PolarFilter :: filters(index) % obj) + case ('surface') + allocate(SurfaceFilter :: filters(index) % obj) + case ('universe') + allocate(UniverseFilter :: filters(index) % obj) + case default + err = E_UNASSIGNED + end select + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_filter_set_type + end module tally_filter From 463b19156bf7527cc446050c43150223192b3fab Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 11 Aug 2017 15:20:37 -0500 Subject: [PATCH 133/229] Start writing openmc_tally_set_scores --- src/api.F90 | 1 + src/error.F90 | 1 + src/tallies/tally_header.F90 | 170 ++++++++++++++++++++++++++++++++++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 975fb36a9..dec1c332e 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -56,6 +56,7 @@ module openmc_api public :: openmc_tally_get_nuclides public :: openmc_tally_results public :: openmc_tally_set_nuclides + public :: openmc_tally_set_scores contains diff --git a/src/error.F90 b/src/error.F90 index b7736d0a7..f72e3ad8b 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -28,6 +28,7 @@ module error integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 integer(C_INT), public, bind(C) :: E_ALREADY_ALLOCATED = -15 + integer(C_INT), public, bind(C) :: E_ARGUMENT_INVALID = -16 ! Warning codes integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 27a6ce674..bcd156ae8 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -4,11 +4,11 @@ module tally_header use hdf5 - use constants, only: NONE, N_FILTER_TYPES, ZERO, N_GLOBAL_TALLIES + use constants use error use dict_header, only: DictIntInt use nuclide_header, only: nuclide_dict - use string, only: to_lower, to_f_string + use string, only: to_lower, to_f_string, str_to_int use tally_filter_header, only: TallyFilterContainer, filters use trigger_header, only: TriggerObject @@ -21,6 +21,7 @@ module tally_header public :: openmc_tally_get_nuclides public :: openmc_tally_results public :: openmc_tally_set_nuclides + public :: openmc_tally_set_scores !=============================================================================== ! TALLYDERIVATIVE describes a first-order derivative that can be applied to @@ -424,4 +425,169 @@ contains end if end function openmc_tally_set_nuclides + function openmc_tally_set_scores(index, n, scores) result(err) bind(C) + ! Sets the scores in the tally + integer(C_INT32_T), value :: index + integer(C_INT), value :: n + type(C_PTR), intent(in) :: scores(n) + integer(C_INT) :: err + + integer :: i + integer :: MT + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: score_ + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % score_bins)) deallocate(t % score_bins) + allocate(t % score_bins(n)) + t % n_user_score_bins = n + t % n_score_bins = n + + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(scores(i), string, [20]) + score_ = to_lower(to_f_string(string)) + + select case (score_) + case ('flux') + t % score_bins(i) = SCORE_FLUX + case ('total', '(n,total)') + t % score_bins(i) = SCORE_TOTAL + case ('scatter') + t % score_bins(i) = SCORE_SCATTER + case ('nu-scatter') + t % score_bins(i) = SCORE_NU_SCATTER + case ('(n,2n)') + t % score_bins(i) = N_2N + case ('(n,3n)') + t % score_bins(i) = N_3N + case ('(n,4n)') + t % score_bins(i) = N_4N + case ('absorption') + t % score_bins(i) = SCORE_ABSORPTION + case ('fission', '18') + t % score_bins(i) = SCORE_FISSION + case ('nu-fission') + t % score_bins(i) = SCORE_NU_FISSION + case ('decay-rate') + t % score_bins(i) = SCORE_DECAY_RATE + case ('delayed-nu-fission') + t % score_bins(i) = SCORE_DELAYED_NU_FISSION + case ('prompt-nu-fission') + t % score_bins(i) = SCORE_PROMPT_NU_FISSION + case ('kappa-fission') + t % score_bins(i) = SCORE_KAPPA_FISSION + case ('inverse-velocity') + t % score_bins(i) = SCORE_INVERSE_VELOCITY + case ('fission-q-prompt') + t % score_bins(i) = SCORE_FISS_Q_PROMPT + case ('fission-q-recoverable') + t % score_bins(i) = SCORE_FISS_Q_RECOV + case ('current') + t % score_bins(i) = SCORE_CURRENT + case ('events') + t % score_bins(i) = SCORE_EVENTS + case ('elastic', '(n,elastic)') + t % score_bins(i) = ELASTIC + case ('(n,2nd)') + t % score_bins(i) = N_2ND + case ('(n,na)') + t % score_bins(i) = N_2NA + case ('(n,n3a)') + t % score_bins(i) = N_N3A + case ('(n,2na)') + t % score_bins(i) = N_2NA + case ('(n,3na)') + t % score_bins(i) = N_3NA + case ('(n,np)') + t % score_bins(i) = N_NP + case ('(n,n2a)') + t % score_bins(i) = N_N2A + case ('(n,2n2a)') + t % score_bins(i) = N_2N2A + case ('(n,nd)') + t % score_bins(i) = N_ND + case ('(n,nt)') + t % score_bins(i) = N_NT + case ('(n,nHe-3)') + t % score_bins(i) = N_N3HE + case ('(n,nd2a)') + t % score_bins(i) = N_ND2A + case ('(n,nt2a)') + t % score_bins(i) = N_NT2A + case ('(n,3nf)') + t % score_bins(i) = N_3NF + case ('(n,2np)') + t % score_bins(i) = N_2NP + case ('(n,3np)') + t % score_bins(i) = N_3NP + case ('(n,n2p)') + t % score_bins(i) = N_N2P + case ('(n,npa)') + t % score_bins(i) = N_NPA + case ('(n,n1)') + t % score_bins(i) = N_N1 + case ('(n,nc)') + t % score_bins(i) = N_NC + case ('(n,gamma)') + t % score_bins(i) = N_GAMMA + case ('(n,p)') + t % score_bins(i) = N_P + case ('(n,d)') + t % score_bins(i) = N_D + case ('(n,t)') + t % score_bins(i) = N_T + case ('(n,3He)') + t % score_bins(i) = N_3HE + case ('(n,a)') + t % score_bins(i) = N_A + case ('(n,2a)') + t % score_bins(i) = N_2A + case ('(n,3a)') + t % score_bins(i) = N_3A + case ('(n,2p)') + t % score_bins(i) = N_2P + case ('(n,pa)') + t % score_bins(i) = N_PA + case ('(n,t2a)') + t % score_bins(i) = N_T2A + case ('(n,d2a)') + t % score_bins(i) = N_D2A + case ('(n,pd)') + t % score_bins(i) = N_PD + case ('(n,pt)') + t % score_bins(i) = N_PT + case ('(n,da)') + t % score_bins(i) = N_DA + case default + ! Assume that user has specified an MT number + MT = int(str_to_int(score_)) + + if (MT /= ERROR_INT) then + ! Specified score was an integer + if (MT > 1) then + t % score_bins(i) = MT + else + err = E_ARGUMENT_INVALID + end if + + else + err = E_ARGUMENT_INVALID + end if + + end select + end do + + call t % setup_arrays() + + err = 0 + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_scores + + end module tally_header From 45993ab2d91d069c3d1cc19b05697ee19d48a439 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 14 Aug 2017 13:19:00 -0500 Subject: [PATCH 134/229] Add various filter-related C API functions --- openmc/capi/filter.py | 6 ++++ openmc/capi/tally.py | 9 +++++ src/api.F90 | 6 +++- src/error.F90 | 2 ++ src/tallies/tally_filter_energy.F90 | 37 ++++++++++++++++++- src/tallies/tally_filter_mesh.F90 | 41 +++++++++++++++++++-- src/tallies/tally_header.F90 | 55 ++++++++++++++++++++++++++++- 7 files changed, 150 insertions(+), 6 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index f671ce401..aea968dad 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -7,9 +7,15 @@ from .error import _error_handler __all__ = [] # Tally functions +_dll.openmc_energy_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_double)] +_dll.openmc_energy_filter_set_bins.restype = c_int +_dll.openmc_energy_filter_set_bins.errcheck = _error_handler _dll.openmc_extend_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_extend_filters.restype = c_int _dll.openmc_extend_filters.errcheck = _error_handler _dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_set_type.restype = c_int _dll.openmc_filter_set_type.errcheck = _error_handler +_dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32] +_dll.openmc_mesh_filter_set_mesh.restype = c_int +_dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index f2498ed90..3b76aa400 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -20,6 +20,9 @@ _dll.openmc_extend_tallies.errcheck = _error_handler _dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_id.restype = c_int _dll.openmc_tally_get_id.errcheck = _error_handler +_dll.openmc_tally_get_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int)] +_dll.openmc_tally_get_filters.restype = c_int +_dll.openmc_tally_get_filters.errcheck = _error_handler _dll.openmc_tally_get_nuclides.argtypes = [ c_int32, POINTER(POINTER(c_int)), POINTER(c_int)] _dll.openmc_tally_get_nuclides.restype = c_int @@ -28,9 +31,15 @@ _dll.openmc_tally_results.argtypes = [ c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] _dll.openmc_tally_results.restype = c_int _dll.openmc_tally_results.errcheck = _error_handler +_dll.openmc_tally_set_filters.argtypes = [c_int32, c_int, POINTER(c_int32)] +_dll.openmc_tally_set_filters.restype = c_int +_dll.openmc_tally_set_filters.errcheck = _error_handler _dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_nuclides.restype = c_int _dll.openmc_tally_set_nuclides.errcheck = _error_handler +_dll.openmc_tally_set_scores.argtypes = [c_int32, c_int, POINTER(c_char_p)] +_dll.openmc_tally_set_scores.restype = c_int +_dll.openmc_tally_set_scores.errcheck = _error_handler class TallyView(object): diff --git a/src/api.F90 b/src/api.F90 index dec1c332e..a6dc6aba8 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -19,7 +19,7 @@ module openmc_api use random_lcg, only: seed, initialize_prng use tally_header use tally_filter_header - use tally_filter, only: openmc_filter_set_type + use tally_filter use simulation, only: openmc_run use string, only: to_f_string use volume_calc, only: openmc_calculate_volumes @@ -30,6 +30,7 @@ module openmc_api public :: openmc_calculate_volumes public :: openmc_cell_get_id public :: openmc_cell_set_temperature + public :: openmc_energy_filter_set_bins public :: openmc_extend_filters public :: openmc_extend_tallies public :: openmc_filter_set_type @@ -48,13 +49,16 @@ module openmc_api public :: openmc_material_get_densities public :: openmc_material_set_density public :: openmc_material_set_densities + public :: openmc_mesh_filter_set_mesh public :: openmc_nuclide_name public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run public :: openmc_tally_get_id + public :: openmc_tally_get_filters public :: openmc_tally_get_nuclides public :: openmc_tally_results + public :: openmc_tally_set_filters public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores diff --git a/src/error.F90 b/src/error.F90 index f72e3ad8b..70f5c0a21 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -29,6 +29,8 @@ module error integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 integer(C_INT), public, bind(C) :: E_ALREADY_ALLOCATED = -15 integer(C_INT), public, bind(C) :: E_ARGUMENT_INVALID = -16 + integer(C_INT), public, bind(C) :: E_WRONG_TYPE = -17 + integer(C_INT), public, bind(C) :: E_FILTER_NOT_ALLOCATED = -18 ! Warning codes integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index 29a203d17..064359663 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -1,17 +1,21 @@ module tally_filter_energy + use, intrinsic :: ISO_C_BINDING + use hdf5, only: HID_T use algorithm, only: binary_search use constants + use error use hdf5_interface use mgxs_header, only: num_energy_groups use particle_header, only: Particle use string, only: to_str - use tally_filter_header, only: TallyFilter, TallyFilterMatch + use tally_filter_header implicit none private + public :: openmc_energy_filter_set_bins !=============================================================================== ! ENERGYFILTER bins the incident neutron energy. @@ -157,4 +161,35 @@ contains // trim(to_str(E1)) // ")" end function text_label_energyout +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_energy_filter_set_bins(index, n, energies) result(err) bind(C) + ! Set the bounding energies for an energy filter + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: n + real(C_DOUBLE), intent(in) :: energies(n) + integer(C_INT) :: err + + err = 0 + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + select type (f => filters(index) % obj) + type is (EnergyFilter) + f % n_bins = n - 1 + if (allocated(f % bins)) deallocate(f % bins) + allocate(f % bins(n)) + f % bins(:) = energies + class default + err = E_WRONG_TYPE + end select + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_energy_filter_set_bins + end module tally_filter_energy diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index c56902bab..bef1cd5fd 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -1,17 +1,20 @@ module tally_filter_mesh + use, intrinsic :: ISO_C_BINDING + use hdf5 use constants - use error, only: warning - use mesh_header, only: RegularMesh, meshes + use error + use mesh_header, only: RegularMesh, meshes, n_meshes use hdf5_interface use particle_header, only: Particle use string, only: to_str - use tally_filter_header, only: TallyFilter, TallyFilterMatch + use tally_filter_header implicit none private + public :: openmc_mesh_filter_set_mesh !=============================================================================== ! MESHFILTER indexes the location of particle events to a regular mesh. For @@ -240,4 +243,36 @@ contains end associate end function text_label_mesh +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_mesh_filter_set_mesh(index, index_mesh) result(err) bind(C) + ! Set the mesh for a mesh filter + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: index_mesh + integer(C_INT) :: err + + err = 0 + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + select type (f => filters(index) % obj) + type is (MeshFilter) + if (index_mesh >= 1 .and. index_mesh <= n_meshes) then + f % mesh = index_mesh + f % n_bins = product(meshes(index_mesh) % dimension) + else + err = E_OUT_OF_BOUNDS + end if + class default + err = E_WRONG_TYPE + end select + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_mesh_filter_set_mesh + end module tally_filter_mesh diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index bcd156ae8..66e00a65c 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -9,7 +9,7 @@ module tally_header use dict_header, only: DictIntInt use nuclide_header, only: nuclide_dict use string, only: to_lower, to_f_string, str_to_int - use tally_filter_header, only: TallyFilterContainer, filters + use tally_filter_header, only: TallyFilterContainer, filters, n_filters use trigger_header, only: TriggerObject implicit none @@ -18,8 +18,10 @@ module tally_header public :: openmc_extend_tallies public :: openmc_get_tally public :: openmc_tally_get_id + public :: openmc_tally_get_filters public :: openmc_tally_get_nuclides public :: openmc_tally_results + public :: openmc_tally_set_filters public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores @@ -337,6 +339,28 @@ contains end function openmc_tally_get_id + function openmc_tally_get_filters(index, filter_indices, n) result(err) bind(C) + ! Return the list of nuclides assigned to a tally + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: filter_indices + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(tallies)) then + associate (t => tallies(index)) + if (allocated(t % filter)) then + filter_indices = C_LOC(t % filter(1)) + n = size(t % filter) + err = 0 + end if + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_get_filters + + function openmc_tally_get_nuclides(index, nuclides, n) result(err) bind(C) ! Return the list of nuclides assigned to a tally integer(C_INT32_T), value :: index @@ -380,6 +404,34 @@ contains end function openmc_tally_results + function openmc_tally_set_filters(index, n, filter_indices) result(err) bind(C) + ! Set the list of filters for a tally + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), value, intent(in) :: n + integer(C_INT32_T), intent(in) :: filter_indices(n) + integer(C_INT) :: err + + integer :: i + + err = 0 + if (index >= 1 .and. index <= n_tallies) then + associate (t => tallies(index)) + if (allocated(t % filter)) deallocate(t % filter) + allocate(t % filter(n)) + do i = 1, n + if (filter_indices(n) < 1 .or. filter_indices(i) > n_filters) then + err = E_OUT_OF_BOUNDS + exit + end if + end do + if (err == 0) t % filter(:) = filter_indices + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_filters + + function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) ! Sets the nuclides in the tally which results should be scored for integer(C_INT32_T), value :: index @@ -425,6 +477,7 @@ contains end if end function openmc_tally_set_nuclides + function openmc_tally_set_scores(index, n, scores) result(err) bind(C) ! Sets the scores in the tally integer(C_INT32_T), value :: index From 9d737ea69e1973b5bf1469235ff815847aafef13 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 14 Aug 2017 14:53:57 -0500 Subject: [PATCH 135/229] Add filter get/set id C API functions --- openmc/capi/filter.py | 6 +++++ src/api.F90 | 2 ++ src/tallies/tally_filter_header.F90 | 37 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index aea968dad..0525378f9 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -13,6 +13,12 @@ _dll.openmc_energy_filter_set_bins.errcheck = _error_handler _dll.openmc_extend_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_extend_filters.restype = c_int _dll.openmc_extend_filters.errcheck = _error_handler +_dll.openmc_filter_get_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_filter_get_id.restype = c_int +_dll.openmc_filter_get_id.errcheck = _error_handler +_dll.openmc_filter_set_id.argtypes = [c_int32, c_int32] +_dll.openmc_filter_set_id.restype = c_int +_dll.openmc_filter_set_id.errcheck = _error_handler _dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_set_type.restype = c_int _dll.openmc_filter_set_type.errcheck = _error_handler diff --git a/src/api.F90 b/src/api.F90 index a6dc6aba8..200d3704c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -33,6 +33,8 @@ module openmc_api public :: openmc_energy_filter_set_bins public :: openmc_extend_filters public :: openmc_extend_tallies + public :: openmc_filter_get_id + public :: openmc_filter_set_id public :: openmc_filter_set_type public :: openmc_finalize public :: openmc_find diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index b499a74ab..f87101dfc 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -4,6 +4,7 @@ module tally_filter_header use constants, only: MAX_LINE_LEN use dict_header, only: DictIntInt + use error use particle_header, only: Particle use stl_vector, only: VectorInt, VectorReal @@ -12,6 +13,8 @@ module tally_filter_header implicit none private public :: openmc_extend_filters + public :: openmc_filter_get_id + public :: openmc_filter_set_id !=============================================================================== ! TALLYFILTERMATCH stores every valid bin and weight for a filter @@ -154,4 +157,38 @@ contains err = 0 end function openmc_extend_filters + + function openmc_filter_get_id(index, id) result(err) bind(C) + ! Return the ID of a filter + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_filters) then + id = filters(index) % obj % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_filter_get_id + + + function openmc_filter_set_id(index, id) result(err) bind(C) + ! Set the ID of a filter + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + filters(index) % obj % id = id + err = 0 + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_filter_set_id + end module tally_filter_header From 208cc0a614b93cf4000c25d0a42fbaa0f71494c3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 14 Aug 2017 15:08:00 -0500 Subject: [PATCH 136/229] Set find_filter from openmc_tally_set_filters --- src/tallies/tally_header.F90 | 43 +++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 66e00a65c..edfa66f3b 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -10,6 +10,7 @@ module tally_header use nuclide_header, only: nuclide_dict use string, only: to_lower, to_f_string, str_to_int use tally_filter_header, only: TallyFilterContainer, filters, n_filters + use tally_filter use trigger_header, only: TriggerObject implicit none @@ -412,17 +413,57 @@ contains integer(C_INT) :: err integer :: i + integer :: j err = 0 if (index >= 1 .and. index <= n_tallies) then associate (t => tallies(index)) if (allocated(t % filter)) deallocate(t % filter) allocate(t % filter(n)) + + t % find_filter(:) = 0 do i = 1, n - if (filter_indices(n) < 1 .or. filter_indices(i) > n_filters) then + if (filter_indices(i) < 1 .or. filter_indices(i) > n_filters) then err = E_OUT_OF_BOUNDS exit end if + + ! Set the filter index in the tally find_filter array + select type (filt => filters(i) % obj) + type is (DistribcellFilter) + j = FILTER_DISTRIBCELL + type is (CellFilter) + j = FILTER_CELL + type is (CellFromFilter) + j = FILTER_CELLFROM + type is (CellbornFilter) + j = FILTER_CELLBORN + type is (MaterialFilter) + j = FILTER_MATERIAL + type is (UniverseFilter) + j = FILTER_UNIVERSE + type is (SurfaceFilter) + j = FILTER_SURFACE + type is (MeshFilter) + j = FILTER_MESH + type is (EnergyFilter) + j = FILTER_ENERGYIN + type is (EnergyoutFilter) + j = FILTER_ENERGYOUT + t % estimator = ESTIMATOR_ANALOG + type is (DelayedGroupFilter) + j = FILTER_DELAYEDGROUP + type is (MuFilter) + j = FILTER_MU + t % estimator = ESTIMATOR_ANALOG + type is (PolarFilter) + j = FILTER_POLAR + type is (AzimuthalFilter) + j = FILTER_AZIMUTHAL + type is (EnergyFunctionFilter) + j = FILTER_ENERGYFUNCTION + end select + t % find_filter(j) = i end do if (err == 0) t % filter(:) = filter_indices end associate From 35a69a4434441c4daf1e362dc8d8a4d278b17745 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 15 Aug 2017 14:20:04 -0500 Subject: [PATCH 137/229] Add several filter-related functions to C API and bindings --- openmc/capi/filter.py | 164 +++++++++++++++++++++++++++- openmc/capi/tally.py | 15 ++- src/api.F90 | 2 + src/error.F90 | 1 + src/tallies/tally_filter.F90 | 62 +++++++++++ src/tallies/tally_filter_energy.F90 | 27 +++++ src/tallies/tally_filter_header.F90 | 19 ++++ 7 files changed, 286 insertions(+), 4 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 0525378f9..6dab6d10c 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -1,12 +1,27 @@ -from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, \ + create_string_buffer +from weakref import WeakValueDictionary + +import numpy as np +from numpy.ctypeslib import as_array from . import _dll from .error import _error_handler -__all__ = [] +__all__ = ['FilterView', 'AzimuthalFilterView', 'CellFilterView', + 'CellbornFilterView', 'CellfromFilterView', 'DistribcellFilterView', + 'DelayedGroupFilterView', 'EnergyFilterView', 'EnergyoutFilterView', + 'EnergyFunctionFilterView', 'MaterialFilterView', 'MeshFilterView', + 'MuFilterView', 'PolarFilterView', 'SurfaceFilterView', + 'UniverseFilterView', 'filters'] # Tally functions +_dll.openmc_energy_filter_get_bins.argtypes = [ + c_int32, POINTER(POINTER(c_double)), POINTER(c_int32)] +_dll.openmc_energy_filter_get_bins.restype = c_int +_dll.openmc_energy_filter_get_bins.errcheck = _error_handler _dll.openmc_energy_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_double)] _dll.openmc_energy_filter_set_bins.restype = c_int _dll.openmc_energy_filter_set_bins.errcheck = _error_handler @@ -16,12 +31,157 @@ _dll.openmc_extend_filters.errcheck = _error_handler _dll.openmc_filter_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_filter_get_id.restype = c_int _dll.openmc_filter_get_id.errcheck = _error_handler +_dll.openmc_filter_get_type.argtypes = [c_int32, c_char_p] +_dll.openmc_filter_get_type.restype = c_int +_dll.openmc_filter_get_type.errcheck = _error_handler _dll.openmc_filter_set_id.argtypes = [c_int32, c_int32] _dll.openmc_filter_set_id.restype = c_int _dll.openmc_filter_set_id.errcheck = _error_handler _dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_set_type.restype = c_int _dll.openmc_filter_set_type.errcheck = _error_handler +_dll.openmc_get_filter.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_filter.restype = c_int +_dll.openmc_get_filter.errcheck = _error_handler _dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32] _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler + + +class FilterView(object): + __instances = WeakValueDictionary() + + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + filter_id = c_int32() + _dll.openmc_filter_get_id(self._index, filter_id) + return filter_id.value + + @id.setter + def id(self, filter_id): + _dll.openmc_filter_set_id(self._index, filter_id) + + +class EnergyFilterView(FilterView): + @property + def bins(self): + energies = POINTER(c_double)() + n = c_int32() + _dll.openmc_energy_filter_get_bins(self._index, energies, n) + return as_array(energies, (n.value,)) + + @bins.setter + def bins(self, bins): + # Get numpy array as a double* + energies = np.asarray(bins) + energies_p = energies.ctypes.data_as(POINTER(c_double)) + + _dll.openmc_energy_filter_set_bins( + self._index, len(energies), energies_p) + + +class EnergyoutFilterView(FilterView): + pass + + +class AzimuthalFilterView(FilterView): + pass + + +class CellFilterView(FilterView): + pass + + +class CellbornFilterView(FilterView): + pass + + +class CellfromFilterView(FilterView): + pass + + +class DelayedGroupFilterView(FilterView): + pass + + +class DistribcellFilterView(FilterView): + pass + + +class EnergyFunctionFilterView(FilterView): + pass + + +class MaterialFilterView(FilterView): + pass + + +class MeshFilterView(FilterView): + pass + + +class MuFilterView(FilterView): + pass + + +class PolarFilterView(FilterView): + pass + + +class SurfaceFilterView(FilterView): + pass + + +class UniverseFilterView(FilterView): + pass + + +_filter_type_map = { + 'azimuthal': AzimuthalFilterView, + 'cell': CellFilterView, + 'cellborn': CellbornFilterView, + 'cellfrom': CellfromFilterView, + 'delayedgroup': DelayedGroupFilterView, + 'distribcell': DistribcellFilterView, + 'energy': EnergyFilterView, + 'energyout': EnergyoutFilterView, + 'energyfunction': EnergyFunctionFilterView, + 'material': MaterialFilterView, + 'mesh': MeshFilterView, + 'mu': MuFilterView, + 'polar': PolarFilterView, + 'surface': SurfaceFilterView, + 'universe': UniverseFilterView, +} + + +def _get_filter(index): + filter_type = create_string_buffer(20) + _dll.openmc_filter_get_type(index, filter_type) + filter_type = filter_type.value.decode() + return _filter_type_map[filter_type](index) + + +class _FilterMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_filter(key, index) + return _get_filter(index.value) + + def __iter__(self): + for i in range(len(self)): + yield TallyView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_filters').value + +filters = _FilterMapping() diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 3b76aa400..cd52068fa 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -6,6 +6,7 @@ from numpy.ctypeslib import as_array from . import _dll, NuclideView from .error import _error_handler +from .filter import _get_filter __all__ = ['TallyView', 'tallies'] @@ -20,7 +21,8 @@ _dll.openmc_extend_tallies.errcheck = _error_handler _dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_id.restype = c_int _dll.openmc_tally_get_id.errcheck = _error_handler -_dll.openmc_tally_get_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int)] +_dll.openmc_tally_get_filters.argtypes = [ + c_int32, POINTER(POINTER(c_int32)), POINTER(c_int)] _dll.openmc_tally_get_filters.restype = c_int _dll.openmc_tally_get_filters.errcheck = _error_handler _dll.openmc_tally_get_nuclides.argtypes = [ @@ -52,12 +54,14 @@ class TallyView(object): Parameters ---------- index : int - Index in the `tallys` array. + Index in the `tallies` array. Attributes ---------- id : int ID of the tally + filters : list + List of views to tally filters nuclides : list of str List of nuclides to score results for results : numpy.ndarray @@ -81,6 +85,13 @@ class TallyView(object): _dll.openmc_tally_get_id(self._index, tally_id) return tally_id.value + @property + def filters(self): + filt_idx = POINTER(c_int32)() + n = c_int() + _dll.openmc_tally_get_filters(self._index, filt_idx, n) + return [_get_filter(filt_idx[i]) for i in range(n.value)] + @property def nuclides(self): nucs = POINTER(c_int)() diff --git a/src/api.F90 b/src/api.F90 index 200d3704c..b2097783a 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -30,10 +30,12 @@ module openmc_api public :: openmc_calculate_volumes public :: openmc_cell_get_id public :: openmc_cell_set_temperature + public :: openmc_energy_filter_get_bins public :: openmc_energy_filter_set_bins public :: openmc_extend_filters public :: openmc_extend_tallies public :: openmc_filter_get_id + public :: openmc_filter_get_type public :: openmc_filter_set_id public :: openmc_filter_set_type public :: openmc_finalize diff --git a/src/error.F90 b/src/error.F90 index 70f5c0a21..4e707c567 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -31,6 +31,7 @@ module error integer(C_INT), public, bind(C) :: E_ARGUMENT_INVALID = -16 integer(C_INT), public, bind(C) :: E_WRONG_TYPE = -17 integer(C_INT), public, bind(C) :: E_FILTER_NOT_ALLOCATED = -18 + integer(C_INT), public, bind(C) :: E_FILTER_INVALID_ID = -19 ! Warning codes integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index e5026f95c..17c43025e 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -1149,6 +1149,68 @@ contains ! C API FUNCTIONS !=============================================================================== + function openmc_filter_get_type(index, type) result(err) bind(C) + ! Get the type of a filter + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(out) :: type(*) + integer(C_INT) :: err + + integer :: i + character(20) :: type_ + + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + ! Get type as a Fortran string + select type (f => filters(index) % obj) + type is (AzimuthalFilter) + type_ = 'azimuthal' + type is (CellFilter) + type_ = 'cell' + type is (CellbornFilter) + type_ = 'cellborn' + type is (CellfromFilter) + type_ = 'cellfrom' + type is (DelayedGroupFilter) + type_ = 'delayedgroup' + type is (DistribcellFilter) + type_ = 'distribcell' + type is (EnergyFilter) + type_ = 'energy' + type is (EnergyoutFilter) + type_ = 'energyout' + type is (EnergyFunctionFilter) + type_ = 'energyfunction' + type is (MaterialFilter) + type_ = 'material' + type is (MeshFilter) + type_ = 'mesh' + type is (MuFilter) + type_ = 'mu' + type is (PolarFilter) + type_ = 'polar' + type is (SurfaceFilter) + type_ = 'surface' + type is (UniverseFilter) + type_ = 'universe' + end select + + ! Convert Fortran string to null-terminated C string. We assume the + ! caller has allocated a char array buffer + do i = 1, len_trim(type_) + type(i) = type_(i:i) + end do + type(len_trim(type_) + 1) = C_NULL_CHAR + + err = 0 + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_filter_get_type + + function openmc_filter_set_type(index, type) result(err) bind(C) ! Set the type of a filter integer(C_INT32_T), value, intent(in) :: index diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index 064359663..400525468 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -15,6 +15,7 @@ module tally_filter_energy implicit none private + public :: openmc_energy_filter_get_bins public :: openmc_energy_filter_set_bins !=============================================================================== @@ -165,6 +166,32 @@ contains ! C API FUNCTIONS !=============================================================================== + function openmc_energy_filter_get_bins(index, energies, n) result(err) bind(C) + ! Return the bounding energies for an energy filter + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: energies + integer(C_INT32_T), intent(out) :: n + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + select type (f => filters(index) % obj) + type is (EnergyFilter) + energies = C_LOC(f % bins) + n = size(f % bins) + err = 0 + class default + err = E_WRONG_TYPE + end select + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_energy_filter_get_bins + + function openmc_energy_filter_set_bins(index, n, energies) result(err) bind(C) ! Set the bounding energies for an energy filter integer(C_INT32_T), value, intent(in) :: index diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index f87101dfc..a76d08bf4 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -191,4 +191,23 @@ contains end if end function openmc_filter_set_id + + function openmc_get_filter(id, index) result(err) bind(C) + ! Returns the index in the filters array of a filter with a given ID + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(filters)) then + if (filter_dict % has_key(id)) then + index = filter_dict % get_key(id) + err = 0 + else + err = E_FILTER_INVALID_ID + end if + else + err = E_FILTER_NOT_ALLOCATED + end if + end function openmc_get_filter + end module tally_filter_header From 2a1492666146f27dbf7507bc8923a6ab5a2b0992 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 16 Aug 2017 10:39:14 -0500 Subject: [PATCH 138/229] Separate material filter into its own module --- CMakeLists.txt | 1 + openmc/capi/filter.py | 23 +++- src/api.F90 | 2 + src/tallies/tally_filter.F90 | 77 +----------- src/tallies/tally_filter_energy.F90 | 2 +- src/tallies/tally_filter_material.F90 | 163 ++++++++++++++++++++++++++ 6 files changed, 190 insertions(+), 78 deletions(-) create mode 100644 src/tallies/tally_filter_material.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a47cfa1b..669494e05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,6 +379,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 src/tallies/tally_filter_energy.F90 + src/tallies/tally_filter_material.F90 src/tallies/tally_filter_mesh.F90 src/tallies/tally_header.F90 src/tallies/trigger.F90 diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 6dab6d10c..2d3766dbf 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -8,6 +8,7 @@ from numpy.ctypeslib import as_array from . import _dll from .error import _error_handler +from .material import MaterialView __all__ = ['FilterView', 'AzimuthalFilterView', 'CellFilterView', @@ -43,6 +44,13 @@ _dll.openmc_filter_set_type.errcheck = _error_handler _dll.openmc_get_filter.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_filter.restype = c_int _dll.openmc_get_filter.errcheck = _error_handler +_dll.openmc_material_filter_get_bins.argtypes = [ + c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] +_dll.openmc_material_filter_get_bins.restype = c_int +_dll.openmc_material_filter_get_bins.errcheck = _error_handler +_dll.openmc_material_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_int32)] +_dll.openmc_material_filter_set_bins.restype = c_int +_dll.openmc_material_filter_set_bins.errcheck = _error_handler _dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32] _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler @@ -122,7 +130,20 @@ class EnergyFunctionFilterView(FilterView): class MaterialFilterView(FilterView): - pass + @property + def bins(self): + materials = POINTER(c_int32)() + n = c_int32() + _dll.openmc_material_filter_get_bins(self._index, materials, n) + return [MaterialView(materials[i]) for i in range(n.value)] + + @bins.setter + def bins(self, materials): + # Get material indices as int32_t[] + n = len(materials) + bins = (c_int32*n)(*(m._index for m in materials)) + + _dll.openmc_material_filter_set_bins(self._index, n, bins) class MeshFilterView(FilterView): diff --git a/src/api.F90 b/src/api.F90 index b2097783a..359e67e54 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -53,6 +53,8 @@ module openmc_api public :: openmc_material_get_densities public :: openmc_material_set_density public :: openmc_material_set_densities + public :: openmc_material_filter_get_bins + public :: openmc_material_filter_set_bins public :: openmc_mesh_filter_set_mesh public :: openmc_nuclide_name public :: openmc_plot_geometry diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 17c43025e..2642874a2 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -15,6 +15,7 @@ module tally_filter ! Inherit other filters use tally_filter_energy + use tally_filter_material use tally_filter_mesh implicit none @@ -32,19 +33,6 @@ module tally_filter procedure :: initialize => initialize_universe end type UniverseFilter -!=============================================================================== -! MATERIAL specifies which material tally events reside in. -!=============================================================================== - type, extends(TallyFilter) :: MaterialFilter - integer, allocatable :: materials(:) - type(DictIntInt) :: map - contains - procedure :: get_all_bins => get_all_bins_material - procedure :: to_statepoint => to_statepoint_material - procedure :: text_label => text_label_material - procedure :: initialize => initialize_material - end type MaterialFilter - !=============================================================================== ! CELLFILTER specifies which geometric cells tally events reside in. !=============================================================================== @@ -249,69 +237,6 @@ contains label = "Universe " // to_str(universes(this % universes(bin)) % id) end function text_label_universe -!=============================================================================== -! MaterialFilter methods -!=============================================================================== - subroutine get_all_bins_material(this, p, estimator, match) - class(MaterialFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - if (this % map % has_key(p % material)) then - call match % bins % push_back(this % map % get_key(p % material)) - call match % weights % push_back(ONE) - end if - - end subroutine get_all_bins_material - - subroutine to_statepoint_material(this, filter_group) - class(MaterialFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: material_ids(:) - - call write_dataset(filter_group, "type", "material") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(material_ids(size(this % materials))) - do i = 1, size(this % materials) - material_ids(i) = materials(this % materials(i)) % id - end do - call write_dataset(filter_group, "bins", material_ids) - end subroutine to_statepoint_material - - subroutine initialize_material(this) - class(MaterialFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % materials(i) - if (material_dict % has_key(id)) then - this % materials(i) = material_dict % get_key(id) - else - call fatal_error("Could not find material " // trim(to_str(id)) & - &// " specified on a tally filter.") - end if - end do - - ! Generate mapping from material indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % materials(i), i) - end do - end subroutine initialize_material - - function text_label_material(this, bin) result(label) - class(MaterialFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Material " // to_str(materials(this % materials(bin)) % id) - end function text_label_material - !=============================================================================== ! CellFilter methods !=============================================================================== diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index 400525468..f5a635e6e 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -208,7 +208,7 @@ contains if (allocated(f % bins)) deallocate(f % bins) allocate(f % bins(n)) f % bins(:) = energies - class default + class default err = E_WRONG_TYPE end select else diff --git a/src/tallies/tally_filter_material.F90 b/src/tallies/tally_filter_material.F90 new file mode 100644 index 000000000..fbeb3a4ec --- /dev/null +++ b/src/tallies/tally_filter_material.F90 @@ -0,0 +1,163 @@ +module tally_filter_material + + use, intrinsic :: ISO_C_BINDING + + use hdf5, only: HID_T + + use constants + use dict_header, only: DictIntInt + use error + use hdf5_interface + use material_header, only: materials, material_dict + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + public :: openmc_material_filter_get_bins + public :: openmc_material_filter_set_bins + +!=============================================================================== +! MATERIAL specifies which material tally events reside in. +!=============================================================================== + + type, public, extends(TallyFilter) :: MaterialFilter + integer, allocatable :: materials(:) + type(DictIntInt) :: map + contains + procedure :: get_all_bins => get_all_bins_material + procedure :: to_statepoint => to_statepoint_material + procedure :: text_label => text_label_material + procedure :: initialize => initialize_material + end type MaterialFilter + +contains + + subroutine get_all_bins_material(this, p, estimator, match) + class(MaterialFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + if (this % map % has_key(p % material)) then + call match % bins % push_back(this % map % get_key(p % material)) + call match % weights % push_back(ONE) + end if + + end subroutine get_all_bins_material + + subroutine to_statepoint_material(this, filter_group) + class(MaterialFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: material_ids(:) + + call write_dataset(filter_group, "type", "material") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(material_ids(size(this % materials))) + do i = 1, size(this % materials) + material_ids(i) = materials(this % materials(i)) % id + end do + call write_dataset(filter_group, "bins", material_ids) + end subroutine to_statepoint_material + + subroutine initialize_material(this) + class(MaterialFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % materials(i) + if (material_dict % has_key(id)) then + this % materials(i) = material_dict % get_key(id) + else + call fatal_error("Could not find material " // trim(to_str(id)) & + &// " specified on a tally filter.") + end if + end do + + ! Generate mapping from material indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % materials(i), i) + end do + end subroutine initialize_material + + function text_label_material(this, bin) result(label) + class(MaterialFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Material " // to_str(materials(this % materials(bin)) % id) + end function text_label_material + +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_material_filter_get_bins(index, bins, n) result(err) bind(C) + ! Return the bins for a material filter + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: bins + integer(C_INT32_T), intent(out) :: n + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + select type (f => filters(index) % obj) + type is (MaterialFilter) + bins = C_LOC(f % materials) + n = size(f % materials) + err = 0 + class default + err = E_WRONG_TYPE + end select + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_filter_get_bins + + + function openmc_material_filter_set_bins(index, n, bins) result(err) bind(C) + ! Set the materials for the filter + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), intent(in) :: bins(n) + integer(C_INT) :: err + + integer :: i + + err = 0 + if (index >= 1 .and. index <= n_filters) then + if (allocated(filters(index) % obj)) then + select type (f => filters(index) % obj) + type is (MaterialFilter) + f % n_bins = n + if (allocated(f % materials)) deallocate(f % materials) + allocate(f % materials(n)) + f % materials(:) = bins + + ! Generate mapping from material indices to filter bins. + call f % map % clear() + do i = 1, n + call f % map % add_key(f % materials(i), i) + end do + + class default + err = E_WRONG_TYPE + end select + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_filter_set_bins + +end module tally_filter_material From 4998e1f83224cb3bc6bfb79a05f353b7f3f88087 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 16 Aug 2017 14:06:11 -0500 Subject: [PATCH 139/229] Make better use of C API functions in cmfd_input and input_xml modules --- openmc/capi/tally.py | 8 +++ src/cmfd_input.F90 | 103 ++++++++++++---------------- src/initialize.F90 | 5 +- src/input_xml.F90 | 82 ++++++---------------- src/simulation.F90 | 5 ++ src/tallies/tally_filter_header.F90 | 2 + src/tallies/tally_header.F90 | 97 ++++++++++++++------------ 7 files changed, 131 insertions(+), 171 deletions(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index cd52068fa..155b0eaf5 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -107,6 +107,14 @@ class TallyView(object): _dll.openmc_tally_results(self._index, data, shape) return as_array(data, tuple(shape[::-1])) + @filters.setter + def filters(self, filters): + # Get filter indices as int32_t[] + n = len(filters) + indices = (c_int32*n)(*(f._index for f in filters)) + + _dll.openmc_tally_set_filters(self._index, n, indices) + @nuclides.setter def nuclides(self, nuclides): nucs = (c_char_p * len(nuclides))() diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 67341ae95..769abf123 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -261,14 +261,16 @@ contains logical :: energy_filters integer :: i ! loop counter integer :: n ! size of arrays in mesh specification - integer :: ng ! number of energy groups (default 1) + integer(C_INT32_T) :: ng ! number of energy groups (default 1) integer :: n_filter ! number of filters integer :: i_start, i_end integer :: i_filt_start, i_filt_end + integer(C_INT32_T), allocatable :: filter_indices(:) integer(C_INT) :: err integer :: i_filt ! index in filters array integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array + real(C_DOUBLE), allocatable :: energies(:) type(TallyObject), pointer :: t type(RegularMesh), pointer :: m type(XMLNode) :: node_mesh @@ -385,60 +387,39 @@ contains ! Set up mesh filter i_filt = i_filt_start - allocate(MeshFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) - type is (MeshFilter) - filt % id = i_filt - filt % n_bins = product(m % dimension) - filt % mesh = i_start - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select + err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) + err = openmc_filter_set_id(i_filt, i_filt) + err = openmc_mesh_filter_set_mesh(i_filt, i_start) if (energy_filters) then ! Read and set incoming energy mesh filter i_filt = i_filt + 1 - allocate(EnergyFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) - type is (EnergyFilter) - filt % id = i_filt - ng = node_word_count(node_mesh, "energy") - filt % n_bins = ng - 1 - allocate(filt % bins(ng)) - call get_node_array(node_mesh, "energy", filt % bins) - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select + err = openmc_filter_set_type(i_filt, C_CHAR_'energy' // C_NULL_CHAR) + err = openmc_filter_set_id(i_filt, i_filt) + + ! Get energies and set bins + ng = node_word_count(node_mesh, "energy") + allocate(energies(ng)) + call get_node_array(node_mesh, "energy", energies) + err = openmc_energy_filter_set_bins(i_filt, ng, energies) ! Read and set outgoing energy mesh filter i_filt = i_filt + 1 - allocate(EnergyoutFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) - type is (EnergyoutFilter) - filt % id = i_filt - ng = node_word_count(node_mesh, "energy") - filt % n_bins = ng - 1 - allocate(filt % bins(ng)) - call get_node_array(node_mesh, "energy", filt % bins) - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select + err = openmc_filter_set_type(i_filt, C_CHAR_'energyout' // C_NULL_CHAR) + err = openmc_filter_set_id(i_filt, i_filt) + err = openmc_energy_filter_set_bins(i_filt, ng, energies) end if ! Duplicate the mesh filter for the mesh current tally since other ! tallies use this filter and we need to change the dimension i_filt = i_filt + 1 - allocate(MeshFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) - type is (MeshFilter) - filt % id = i_filt - ! We need to increase the dimension by one since we also need - ! currents coming into and out of the boundary mesh cells. - filt % n_bins = product(m % dimension + 1) - filt % mesh = i_start - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select + err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) + err = openmc_filter_set_id(i_filt, i_filt) + err = openmc_mesh_filter_set_mesh(i_filt, i_start) + + ! We need to increase the dimension by one since we also need + ! currents coming into and out of the boundary mesh cells. + filters(i_filt) % obj % n_bins = product(m % dimension + 1) ! Set up surface filter i_filt = i_filt + 1 @@ -476,15 +457,11 @@ contains call get_node_value(root, "reset", t % reset) end if - ! Set the mesh filter index in the tally find_filter array - n_filter = 1 - t % find_filter(FILTER_MESH) = n_filter - ! Set the incoming energy mesh filter index in the tally find_filter ! array + n_filter = 1 if (energy_filters) then n_filter = n_filter + 1 - t % find_filter(FILTER_ENERGYIN) = n_filter end if ! Set number of nucilde bins @@ -507,11 +484,13 @@ contains t % type = TALLY_VOLUME ! Allocate and set filters - allocate(t % filter(n_filter)) - t % filter(1) = i_filt_start + allocate(filter_indices(n_filter)) + filter_indices(1) = i_filt_start if (energy_filters) then - t % filter(2) = i_filt_start + 1 + filter_indices(2) = i_filt_start + 1 end if + err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices) + deallocate(filter_indices) ! Allocate scoring bins allocate(t % score_bins(3)) @@ -543,16 +522,17 @@ contains ! array if (energy_filters) then n_filter = n_filter + 1 - t % find_filter(FILTER_ENERGYOUT) = n_filter end if ! Allocate and set indices in filters array - allocate(t % filter(n_filter)) - t % filter(1) = i_filt_start + allocate(filter_indices(n_filter)) + filter_indices(1) = i_filt_start if (energy_filters) then - t % filter(2) = i_filt_start + 1 - t % filter(3) = i_filt_start + 2 + filter_indices(2) = i_filt_start + 1 + filter_indices(3) = i_filt_start + 2 end if + err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices) + deallocate(filter_indices) ! Allocate macro reactions allocate(t % score_bins(2)) @@ -577,15 +557,16 @@ contains ! Set the surface filter index in the tally find_filter array n_filter = n_filter + 1 - t % find_filter(FILTER_SURFACE) = n_filter ! Allocate and set filters - allocate(t % filter(n_filter)) - t % filter(1) = i_filt_end - 1 - t % filter(n_filter) = i_filt_end + allocate(filter_indices(n_filter)) + filter_indices(1) = i_filt_end - 1 + filter_indices(n_filter) = i_filt_end if (energy_filters) then - t % filter(2) = i_filt_start + 1 + filter_indices(2) = i_filt_start + 1 end if + err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices) + deallocate(filter_indices) ! Allocate macro reactions allocate(t % score_bins(1)) diff --git a/src/initialize.F90 b/src/initialize.F90 index 92273a6ca..42db8c777 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -29,7 +29,7 @@ module initialize use state_point, only: load_state_point use string, only: to_str, starts_with, ends_with, str_to_int use summary, only: write_summary - use tally_header, only: TallyObject, configure_tallies + use tally_header, only: TallyObject use tally_filter use tally, only: init_tally_routines @@ -116,9 +116,6 @@ contains end if if (run_mode /= MODE_PLOTTING) then - ! Allocate and setup tally stride, filter_matches, and tally maps - call configure_tallies() - ! Set up tally procedure pointers call init_tally_routines() diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 3225c51b7..15ee43f1b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3315,11 +3315,7 @@ contains end select ! Set filter id - f % obj % id = filter_id - - ! Add filter to dictionary - call filter_dict % add_key(filter_id, i) - + err = openmc_filter_set_id(i_start + i - 1, filter_id) end do READ_FILTERS ! ========================================================================== @@ -3394,64 +3390,28 @@ contains allocate(temp_filter(n_filter)) if (n_filter > 0) then call get_node_array(node_tal, "filters", temp_filter) + + do j = 1, n_filter + ! Get pointer to filter + if (filter_dict % has_key(temp_filter(j))) then + i_filt = filter_dict % get_key(temp_filter(j)) + f => filters(i_filt) + else + call fatal_error("Could not find filter " & + // trim(to_str(temp_filter(j))) // " specified on tally " & + // trim(to_str(t % id))) + end if + + ! Store the index of the filter + temp_filter(j) = i_filt + end do + + ! Set the filters + err = openmc_tally_set_filters(i_start + i - 1, n_filter, temp_filter) + else + allocate(t % filter(n_filter)) end if - do j = 1, n_filter - ! Get pointer to filter - if (filter_dict % has_key(temp_filter(j))) then - i_filt = filter_dict % get_key(temp_filter(j)) - f => filters(i_filt) - else - call fatal_error("Could not find filter " & - // trim(to_str(temp_filter(j))) // " specified on tally " & - // trim(to_str(t % id))) - end if - - ! Set the filter index in the tally find_filter array - select type (filt => f % obj) - type is (DistribcellFilter) - t % find_filter(FILTER_DISTRIBCELL) = j - type is (CellFilter) - t % find_filter(FILTER_CELL) = j - type is (CellFromFilter) - t % find_filter(FILTER_CELLFROM) = j - type is (CellbornFilter) - t % find_filter(FILTER_CELLBORN) = j - type is (MaterialFilter) - t % find_filter(FILTER_MATERIAL) = j - type is (UniverseFilter) - t % find_filter(FILTER_UNIVERSE) = j - type is (SurfaceFilter) - t % find_filter(FILTER_SURFACE) = j - type is (MeshFilter) - t % find_filter(FILTER_MESH) = j - type is (EnergyFilter) - t % find_filter(FILTER_ENERGYIN) = j - type is (EnergyoutFilter) - t % find_filter(FILTER_ENERGYOUT) = j - ! Set to analog estimator - t % estimator = ESTIMATOR_ANALOG - type is (DelayedGroupFilter) - t % find_filter(FILTER_DELAYEDGROUP) = j - type is (MuFilter) - t % find_filter(FILTER_MU) = j - ! Set to analog estimator - t % estimator = ESTIMATOR_ANALOG - type is (PolarFilter) - t % find_filter(FILTER_POLAR) = j - type is (AzimuthalFilter) - t % find_filter(FILTER_AZIMUTHAL) = j - type is (EnergyFunctionFilter) - t % find_filter(FILTER_ENERGYFUNCTION) = j - end select - - ! Store the index of the filter - temp_filter(j) = i_filt - end do - - ! Store the filter indices - call move_alloc(FROM=temp_filter, TO=t % filter) - ! ======================================================================= ! READ DATA FOR NUCLIDES diff --git a/src/simulation.F90 b/src/simulation.F90 index 2a063ddeb..8e977bbdc 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -21,6 +21,7 @@ module simulation use state_point, only: write_state_point, write_source_point use string, only: to_str use tally, only: accumulate_tallies, setup_active_tallies + use tally_header, only: configure_tallies use trigger, only: check_triggers use tracking, only: transport @@ -371,7 +372,11 @@ contains subroutine initialize_simulation() + ! Allocate tally results arrays if they're not allocated yet + call configure_tallies() + !$omp parallel + ! Allocate array for microscopic cross section cache allocate(micro_xs(n_nuclides)) ! Allocate array for matching filter bins diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index a76d08bf4..32baad3e9 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -182,6 +182,8 @@ contains if (index >= 1 .and. index <= n_filters) then if (allocated(filters(index) % obj)) then filters(index) % obj % id = id + call filter_dict % add_key(id, index) + err = 0 else err = E_FILTER_NOT_ALLOCATED diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index edfa66f3b..e9654f609 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -108,7 +108,7 @@ module tally_header contains procedure :: read_results_hdf5 => tally_read_results_hdf5 procedure :: write_results_hdf5 => tally_write_results_hdf5 - procedure :: setup_arrays => tally_setup_arrays + procedure :: allocate_results => tally_allocate_results end type TallyObject integer(C_INT32_T), public, bind(C) :: n_tallies = 0 ! # of tallies @@ -210,45 +210,32 @@ contains end subroutine tally_read_results_hdf5 !=============================================================================== -! SETUP_ARRAYS allocates and populates several member arrays of the TallyObject -! derived type, including stride, filter_matches, and results. +! ALLOCATE_RESULTS allocates and initializes the results component of the +! TallyObject derived type !=============================================================================== - subroutine tally_setup_arrays(this) + subroutine tally_allocate_results(this) class(TallyObject), intent(inout) :: this - integer :: j ! loop index for filters - integer :: n ! temporary stride - integer :: i_filt ! filter index - - ! Allocate stride - if (allocated(this % filter)) then - if (allocated(this % stride)) deallocate(this % stride) - allocate(this % stride(size(this % filter))) - - ! The filters are traversed in opposite order so that the last filter has - ! the shortest stride in memory and the first filter has the largest - ! stride - n = 1 - STRIDE: do j = size(this % filter), 1, -1 - i_filt = this % filter(j) - this % stride(j) = n - n = n * filters(i_filt) % obj % n_bins - end do STRIDE - this % n_filter_bins = n - else - this % n_filter_bins = 1 - end if - ! Set total number of filter and scoring bins this % total_score_bins = this % n_score_bins * this % n_nuclide_bins - ! Allocate results array - if (allocated(this % results)) deallocate(this % results) - allocate(this % results(3, this % total_score_bins, this % n_filter_bins)) + if (allocated(this % results)) then + ! If results was already allocated but shape is wrong, then reallocate it + ! to the correct shape + if (this % total_score_bins /= size(this % results, 2) .or. & + this % n_filter_bins /= size(this % results, 3)) then + deallocate(this % results) + allocate(this % results(3, this % total_score_bins, this % n_filter_bins)) + end if + else + allocate(this % results(3, this % total_score_bins, this % n_filter_bins)) + end if + + ! Initialize results array to zero this % results(:,:,:) = ZERO - end subroutine tally_setup_arrays + end subroutine tally_allocate_results !=============================================================================== ! CONFIGURE_TALLIES initializes several data structures related to tallies. This @@ -260,12 +247,14 @@ contains integer :: i - ! Allocate global tallies - allocate(global_tallies(3, N_GLOBAL_TALLIES)) + ! Allocate and initialize global tallies + if (.not. allocated(global_tallies)) then + allocate(global_tallies(3, N_GLOBAL_TALLIES)) + end if global_tallies(:,:) = ZERO do i = 1, n_tallies - call tallies(i) % setup_arrays() + call tallies(i) % allocate_results() end do end subroutine configure_tallies @@ -412,24 +401,25 @@ contains integer(C_INT32_T), intent(in) :: filter_indices(n) integer(C_INT) :: err - integer :: i - integer :: j + integer :: i ! index in t % filter/stride + integer :: j ! index in t % find_filter + integer :: k ! index in global filters array + integer :: stride ! filter stride err = 0 if (index >= 1 .and. index <= n_tallies) then associate (t => tallies(index)) - if (allocated(t % filter)) deallocate(t % filter) - allocate(t % filter(n)) t % find_filter(:) = 0 do i = 1, n - if (filter_indices(i) < 1 .or. filter_indices(i) > n_filters) then + k = filter_indices(i) + if (k < 1 .or. k > n_filters) then err = E_OUT_OF_BOUNDS exit end if ! Set the filter index in the tally find_filter array - select type (filt => filters(i) % obj) + select type (filt => filters(k) % obj) type is (DistribcellFilter) j = FILTER_DISTRIBCELL type is (CellFilter) @@ -465,7 +455,28 @@ contains end select t % find_filter(j) = i end do - if (err == 0) t % filter(:) = filter_indices + + if (err == 0) then + if (allocated(t % filter)) deallocate(t % filter) + if (allocated(t % stride)) deallocate(t % stride) + allocate(t % filter(n), t % stride(n)) + + ! Filters are traversed in reverse so that the last filter has the + ! shortest stride in memory and the first filter has the largest stride + stride = 1 + do i = n, 1, -1 + ! Set filter and stride + k = filter_indices(i) + t % filter(i) = k + t % stride(i) = stride + + ! Multiply stride by number of bins in this filter + stride = stride * filters(k) % obj % n_bins + end do + + ! Set total number of filter bins + t % n_filter_bins = stride + end if end associate else err = E_OUT_OF_BOUNDS @@ -509,8 +520,6 @@ contains end select end do - call t % setup_arrays() - err = 0 end associate else @@ -674,8 +683,6 @@ contains end select end do - call t % setup_arrays() - err = 0 end associate else From edb537d1fab12a13ddf04e7ac9d724d14d2f9d85 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 11:48:58 -0500 Subject: [PATCH 140/229] Make tallies (possibly) polymorphic --- src/api.F90 | 13 ++++--- src/cmfd_data.F90 | 12 +++--- src/cmfd_execute.F90 | 4 +- src/cmfd_header.F90 | 4 +- src/cmfd_input.F90 | 9 +++-- src/initialize.F90 | 12 +++--- src/input_xml.F90 | 10 +++-- src/output.F90 | 6 +-- src/simulation.F90 | 6 +-- src/state_point.F90 | 26 ++++++------- src/tallies/tally.F90 | 72 +++++++++++++++++------------------- src/tallies/tally_filter.F90 | 1 + src/tallies/tally_header.F90 | 70 +++++++++++++++++++++++++++-------- src/tallies/trigger.F90 | 12 +++--- 14 files changed, 150 insertions(+), 107 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 359e67e54..77b259fa4 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -67,6 +67,7 @@ module openmc_api public :: openmc_tally_set_filters public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores + public :: openmc_tally_set_type contains @@ -672,11 +673,13 @@ contains if (allocated(tallies)) then do i = 1, size(tallies) - tallies(i) % active = .false. - tallies(i) % n_realizations = 0 - if (allocated(tallies(i) % results)) then - tallies(i) % results(:, :, :) = ZERO - end if + associate (t => tallies(i) % obj) + t % active = .false. + t % n_realizations = 0 + if (allocated(t % results)) then + t % results(:, :, :) = ZERO + end if + end associate end do end if diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index d1db7c509..3a6e965ac 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -58,7 +58,6 @@ contains use error, only: fatal_error use mesh_header, only: RegularMesh, meshes use string, only: to_str - use tally_header, only: TallyObject use tally_filter_header, only: filters, filter_matches integer :: nx ! number of mesh cells in x direction @@ -82,7 +81,6 @@ contains integer :: stride_surf ! stride for surface filter logical :: energy_filters! energy filters present real(8) :: flux ! temp variable for flux - type(TallyObject), pointer :: t ! pointer for tally object type(RegularMesh), pointer :: m ! pointer for mesh object ! Extract spatial and energy indices from object @@ -96,8 +94,10 @@ contains cmfd % openmc_src = ZERO ! Associate tallies and mesh - t => cmfd_tallies(1) - i_filt = t % filter(t % find_filter(FILTER_MESH)) + associate (t => cmfd_tallies(1) % obj) + i_filt = t % filter(t % find_filter(FILTER_MESH)) + end associate + select type(filt => filters(i_filt) % obj) type is (MeshFilter) m => meshes(filt % mesh) @@ -114,7 +114,7 @@ contains TAL: do ital = 1, size(cmfd_tallies) ! Associate tallies and mesh - t => cmfd_tallies(ital) + associate (t => cmfd_tallies(ital) % obj) i_filt = t % filter(t % find_filter(FILTER_MESH)) select type(filt => filters(i_filt) % obj) type is (MeshFilter) @@ -316,13 +316,13 @@ contains end do ZLOOP + end associate end do TAL ! Normalize openmc source distribution cmfd % openmc_src = cmfd % openmc_src/sum(cmfd % openmc_src)*cmfd%norm ! Nullify all pointers - if (associated(t)) nullify(t) if (associated(m)) nullify(m) end subroutine compute_xs diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 2edc8b08f..803ae8247 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -366,8 +366,8 @@ contains ! Reset CMFD tallies do i = 1, size(cmfd_tallies) - cmfd_tallies(i) % n_realizations = 0 - cmfd_tallies(i) % results(:,:,:) = ZERO + cmfd_tallies(i) % obj % n_realizations = 0 + cmfd_tallies(i) % obj % results(:,:,:) = ZERO end do end subroutine cmfd_tally_reset diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index 1d1056f4d..887edc559 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -3,7 +3,7 @@ module cmfd_header use constants, only: CMFD_NOACCEL, ZERO, ONE use mesh_header, only: RegularMesh use set_header, only: SetInt - use tally_header, only: TallyObject + use tally_header, only: TallyContainer use timer_header, only: Timer implicit none @@ -98,7 +98,7 @@ module cmfd_header type(RegularMesh), public, pointer :: cmfd_mesh => null() ! Pointers for different tallies - type(TallyObject), public, pointer :: cmfd_tallies(:) => null() + type(TallyContainer), public, pointer :: cmfd_tallies(:) => null() ! Timing objects type(Timer), public :: time_cmfd ! timer for whole cmfd calculation diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 769abf123..e8701fe6d 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -251,7 +251,7 @@ contains use error, only: fatal_error, warning use mesh_header, only: RegularMesh, openmc_extend_meshes use string - use tally_header, only: TallyObject, openmc_extend_tallies + use tally_header, only: openmc_extend_tallies, openmc_tally_set_type use tally_filter_header use tally_filter use xml_interface @@ -271,7 +271,6 @@ contains integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array real(C_DOUBLE), allocatable :: energies(:) - type(TallyObject), pointer :: t type(RegularMesh), pointer :: m type(XMLNode) :: node_mesh @@ -448,9 +447,11 @@ contains ! Begin loop around tallies do i = 1, size(cmfd_tallies) + ! Allocate tally + err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'generic' // C_NULL_CHAR) ! Point t to tally variable - t => cmfd_tallies(i) + associate (t => cmfd_tallies(i) % obj) ! Set reset property if (check_for_node(root, "reset")) then @@ -584,6 +585,8 @@ contains ! Make CMFD tallies active from the start t % active = .true. + + end associate end do end subroutine create_cmfd_tally diff --git a/src/initialize.F90 b/src/initialize.F90 index 42db8c777..387343577 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -695,8 +695,8 @@ contains ! We need distribcell if any tallies have distribcell filters. do i = 1, n_tallies - do j = 1, size(tallies(i) % filter) - select type(filt => filters(tallies(i) % filter(j)) % obj) + do j = 1, size(tallies(i) % obj % filter) + select type(filt => filters(tallies(i) % obj % filter(j)) % obj) type is (DistribcellFilter) distribcell_active = .true. end select @@ -722,8 +722,8 @@ contains ! Set the number of bins in all distribcell filters. do i = 1, n_tallies - do j = 1, size(tallies(i) % filter) - select type(filt => filters(tallies(i) % filter(j)) % obj) + do j = 1, size(tallies(i) % obj % filter) + select type(filt => filters(tallies(i) % obj % filter(j)) % obj) type is (DistribcellFilter) ! Set the number of bins to the number of instances of the cell. filt % n_bins = cells(filt % cell) % instances @@ -787,8 +787,8 @@ contains ! List all cells referenced in distribcell filters. do i = 1, n_tallies - do j = 1, size(tallies(i) % filter) - select type(filt => filters(tallies(i) % filter(j)) % obj) + do j = 1, size(tallies(i) % obj % filter) + select type(filt => filters(tallies(i) % obj % filter(j)) % obj) type is (DistribcellFilter) call cell_list % add(filt % cell) end select diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 15ee43f1b..84e05aa7f 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -30,7 +30,7 @@ module input_xml use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & zero_padded - use tally_header, only: TallyObject, openmc_extend_tallies + use tally_header, only: openmc_extend_tallies, openmc_tally_set_type use tally_filter_header, only: TallyFilterContainer use tally_filter use xml_interface @@ -2674,7 +2674,6 @@ contains character(MAX_WORD_LEN), allocatable :: sarray(:) type(DictCharInt) :: trigger_scores type(ElemKeyValueCI), pointer :: pair_list - type(TallyObject), pointer :: t type(TallyFilterContainer), pointer :: f type(RegularMesh), pointer :: m type(XMLDocument) :: doc @@ -3333,8 +3332,12 @@ contains end if READ_TALLIES: do i = 1, n + ! Allocate tally + err = openmc_tally_set_type(i_start + i - 1, & + C_CHAR_'generic' // C_NULL_CHAR) + ! Get pointer to tally - t => tallies(i_start + i - 1) + associate (t => tallies(i_start + i - 1) % obj) ! Get pointer to tally xml node node_tal = node_tal_list(i) @@ -4288,6 +4291,7 @@ contains ! Add tally to dictionary call tally_dict % add_key(t % id, i) + end associate end do READ_TALLIES ! Close XML document diff --git a/src/output.F90 b/src/output.F90 index ec47070ef..215942bfe 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -730,8 +730,7 @@ contains character(36) :: score_names(N_SCORE_TYPES) ! names of scoring function character(36) :: score_name ! names of scoring function ! to be applied at write-time - type(TallyObject), pointer :: t - type(TallyfilterMatch), allocatable :: matches(:) + type(TallyFilterMatch), allocatable :: matches(:) ! Skip if there are no tallies if (n_tallies == 0) return @@ -779,7 +778,7 @@ contains end if TALLY_LOOP: do i = 1, n_tallies - t => tallies(i) + associate (t => tallies(i) % obj) nr = t % n_realizations if (confidence_intervals) then @@ -980,6 +979,7 @@ contains end do print_bin + end associate end do TALLY_LOOP close(UNIT=unit_tally) diff --git a/src/simulation.F90 b/src/simulation.F90 index 8e977bbdc..9c8fb67bb 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -175,7 +175,7 @@ contains call time_active % start() do i = 1, n_tallies - tallies(i) % active = .true. + tallies(i) % obj % active = .true. end do end if @@ -426,8 +426,8 @@ contains ! Broadcast tally results so that each process has access to results if (allocated(tallies)) then do i = 1, size(tallies) - n = size(tallies(i) % results) - call MPI_BCAST(tallies(i) % results, n, MPI_DOUBLE, 0, & + n = size(tallies(i) % obj % results) + call MPI_BCAST(tallies(i) % obj % results, n, MPI_DOUBLE, 0, & mpi_intracomm, mpi_err) end do end if diff --git a/src/state_point.F90 b/src/state_point.F90 index ea6104bce..29356beef 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -26,7 +26,6 @@ module state_point use output, only: write_message, time_stamp use random_lcg, only: seed use string, only: to_str, count_digits, zero_padded - use tally_header, only: TallyObject implicit none @@ -51,7 +50,6 @@ contains real(C_DOUBLE) :: k_combined(2) character(MAX_WORD_LEN), allocatable :: str_array(:) character(MAX_FILE_LEN) :: filename - type(TallyObject), pointer :: tally ! Set filename for state point filename = trim(path_output) // 'statepoint.' // & @@ -227,7 +225,7 @@ contains ! Write array of tally IDs allocate(id_array(n_tallies)) do i = 1, n_tallies - id_array(i) = tallies(i) % id + id_array(i) = tallies(i) % obj % id end do call write_attribute(tallies_group, "ids", id_array) deallocate(id_array) @@ -236,7 +234,7 @@ contains TALLY_METADATA: do i = 1, n_tallies ! Get pointer to tally - tally => tallies(i) + associate (tally => tallies(i) % obj) tally_group = create_group(tallies_group, "tally " // & trim(to_str(tally % id))) @@ -341,6 +339,7 @@ contains deallocate(str_array) call close_group(tally_group) + end associate end do TALLY_METADATA end if @@ -372,14 +371,13 @@ contains ! Write all tally results TALLY_RESULTS: do i = 1, n_tallies - ! Set point to current tally - tally => tallies(i) - - ! Write sum and sum_sq for each bin - tally_group = open_group(tallies_group, "tally " & - // to_str(tally % id)) - call tally % write_results_hdf5(tally_group) - call close_group(tally_group) + associate (tally => tallies(i) % obj) + ! Write sum and sum_sq for each bin + tally_group = open_group(tallies_group, "tally " & + // to_str(tally % id)) + call tally % write_results_hdf5(tally_group) + call close_group(tally_group) + end associate end do TALLY_RESULTS call close_group(tallies_group) @@ -552,7 +550,7 @@ contains ! Write all tally results TALLY_RESULTS: do i = 1, n_tallies - associate (t => tallies(i)) + associate (t => tallies(i) % obj) ! Determine size of tally results array m = size(t % results, 2) n = size(t % results, 3) @@ -761,7 +759,7 @@ contains tallies_group = open_group(file_id, "tallies") TALLY_RESULTS: do i = 1, n_tallies - associate (t => tallies(i)) + associate (t => tallies(i) % obj) ! Read sum, sum_sq, and N for each bin tally_group = open_group(tallies_group, "tally " // & trim(to_str(t % id))) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index fd8ae6d3c..c97ff01e1 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -2158,22 +2158,18 @@ contains ! the user requests all. !=============================================================================== - subroutine score_all_nuclides(p, i_tally, flux, filter_index) + subroutine score_all_nuclides(p, t, flux, filter_index) type(Particle), intent(in) :: p - integer, intent(in) :: i_tally + type(TallyObject), intent(inout) :: t real(8), intent(in) :: flux integer, intent(in) :: filter_index integer :: i ! loop index for nuclides in material integer :: i_nuclide ! index in nuclides array real(8) :: atom_density ! atom density of single nuclide in atom/b-cm - type(TallyObject), pointer :: t type(Material), pointer :: mat - ! Get pointer to tally - t => tallies(i_tally) - ! Get pointer to current material. We need this in order to determine what ! nuclides are in the material mat => materials(p % material) @@ -2225,7 +2221,6 @@ contains integer :: i_nuclide ! index in nuclides array real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations - type(TallyObject), pointer :: t ! A loop over all tallies is necessary because we need to simultaneously ! determine different filter bins for the same tally in order to score to it @@ -2233,7 +2228,7 @@ contains TALLY_LOOP: do i = 1, active_analog_tallies % size() ! Get index of tally and pointer to tally i_tally = active_analog_tallies % data(i) - t => tallies(i_tally) + associate (t => tallies(i_tally) % obj) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. @@ -2349,6 +2344,7 @@ contains if (assume_separate) exit TALLY_LOOP + end associate end do TALLY_LOOP ! Reset filter matches flag @@ -2370,7 +2366,6 @@ contains real(8) :: filter_weight ! combined weight of all filters real(8) :: atom_density logical :: finished ! found all valid bin combinations - type(TallyObject), pointer :: t type(Material), pointer :: mat ! A loop over all tallies is necessary because we need to simultaneously @@ -2379,7 +2374,7 @@ contains TALLY_LOOP: do i = 1, active_analog_tallies % size() ! Get index of tally and pointer to tally i_tally = active_analog_tallies % data(i) - t => tallies(i_tally) + associate (t => tallies(i_tally) % obj) ! Get pointer to current material. We need this in order to determine what ! nuclides are in the material @@ -2487,6 +2482,7 @@ contains if (assume_separate) exit TALLY_LOOP + end associate end do TALLY_LOOP ! Reset filter matches flag @@ -2746,7 +2742,6 @@ contains real(8) :: atom_density ! atom density of single nuclide in atom/b-cm real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations - type(TallyObject), pointer :: t type(Material), pointer :: mat ! Determine track-length estimate of flux @@ -2758,7 +2753,7 @@ contains TALLY_LOOP: do i = 1, active_tracklength_tallies % size() ! Get index of tally and pointer to tally i_tally = active_tracklength_tallies % data(i) - t => tallies(i_tally) + associate (t => tallies(i_tally) % obj) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. @@ -2803,8 +2798,7 @@ contains if (t % all_nuclides) then if (p % material /= MATERIAL_VOID) then - call score_all_nuclides(p, i_tally, flux * filter_weight, & - filter_index) + call score_all_nuclides(p, t, flux * filter_weight, filter_index) end if else @@ -2875,6 +2869,7 @@ contains if (assume_separate) exit TALLY_LOOP + end associate end do TALLY_LOOP ! Reset filter matches flag @@ -2907,7 +2902,6 @@ contains ! in atom/b-cm real(8) :: filter_weight ! combined weight of all filters logical :: finished ! found all valid bin combinations - type(TallyObject), pointer :: t type(Material), pointer :: mat ! Determine collision estimate of flux @@ -2924,7 +2918,7 @@ contains TALLY_LOOP: do i = 1, active_collision_tallies % size() ! Get index of tally and pointer to tally i_tally = active_collision_tallies % data(i) - t => tallies(i_tally) + associate (t => tallies(i_tally) % obj) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. @@ -2969,8 +2963,7 @@ contains if (t % all_nuclides) then if (p % material /= MATERIAL_VOID) then - call score_all_nuclides(p, i_tally, flux * filter_weight, & - filter_index) + call score_all_nuclides(p, t, flux * filter_weight, filter_index) end if else @@ -3041,6 +3034,7 @@ contains if (assume_separate) exit TALLY_LOOP + end associate end do TALLY_LOOP ! Reset filter matches flag @@ -3078,7 +3072,7 @@ contains TALLY_LOOP: do i = 1, active_surface_tallies % size() ! Get index of tally and pointer to tally i_tally = active_surface_tallies % data(i) - associate (t => tallies(i_tally)) + associate (t => tallies(i_tally) % obj) ! Find all valid bins in each filter if they have not already been found ! for a previous tally. @@ -3211,7 +3205,6 @@ contains logical :: end_in_mesh ! particle's ending xyz in mesh? logical :: cross_surface ! whether the particle crosses a surface logical :: energy_filter ! energy filter present - type(TallyObject), pointer :: t type(RegularMesh), pointer :: m TALLY_LOOP: do i = 1, active_current_tallies % size() @@ -3221,7 +3214,7 @@ contains ! Get pointer to tally i_tally = active_current_tallies % data(i) - t => tallies(i_tally) + associate (t => tallies(i_tally) % obj) ! Check for energy filter energy_filter = (t % find_filter(FILTER_ENERGYIN) > 0) @@ -3457,6 +3450,7 @@ contains xyz0 = xyz0 + distance * uvw end do + end associate end do TALLY_LOOP end subroutine score_surface_current @@ -4262,7 +4256,7 @@ contains if (master .or. (.not. reduce_tallies)) then ! Accumulate results for each tally do i = 1, active_tallies % size() - call accumulate_tally(tallies(active_tallies % data(i))) + call accumulate_tally(tallies(active_tallies % data(i)) % obj) end do if (run_mode == MODE_EIGENVALUE) then @@ -4400,25 +4394,27 @@ contains call active_current_tallies % clear() do i = 1, n_tallies - if (tallies(i) % active) then - ! Add tally to active tallies - call active_tallies % push_back(i) + associate (t => tallies(i) % obj) + if (t % active) then + ! Add tally to active tallies + call active_tallies % push_back(i) - ! Check what type of tally this is and add it to the appropriate list - if (tallies(i) % type == TALLY_VOLUME) then - if (tallies(i) % estimator == ESTIMATOR_ANALOG) then - call active_analog_tallies % push_back(i) - elseif (tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then - call active_tracklength_tallies % push_back(i) - elseif (tallies(i) % estimator == ESTIMATOR_COLLISION) then - call active_collision_tallies % push_back(i) + ! Check what type of tally this is and add it to the appropriate list + if (t % type == TALLY_VOLUME) then + if (t % estimator == ESTIMATOR_ANALOG) then + call active_analog_tallies % push_back(i) + elseif (t % estimator == ESTIMATOR_TRACKLENGTH) then + call active_tracklength_tallies % push_back(i) + elseif (t % estimator == ESTIMATOR_COLLISION) then + call active_collision_tallies % push_back(i) + end if + elseif (t % type == TALLY_MESH_CURRENT) then + call active_current_tallies % push_back(i) + elseif (t % type == TALLY_SURFACE) then + call active_surface_tallies % push_back(i) end if - elseif (tallies(i) % type == TALLY_MESH_CURRENT) then - call active_current_tallies % push_back(i) - elseif (tallies(i) % type == TALLY_SURFACE) then - call active_surface_tallies % push_back(i) end if - end if + end associate end do end subroutine setup_active_tallies diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 2642874a2..d48939f8a 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -1144,6 +1144,7 @@ contains character(:), allocatable :: type_ + ! Convert C string to Fortran string type_ = to_f_string(type) err = 0 diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index e9654f609..fcb1660d6 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -25,6 +25,7 @@ module tally_header public :: openmc_tally_set_filters public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores + public :: openmc_tally_set_type !=============================================================================== ! TALLYDERIVATIVE describes a first-order derivative that can be applied to @@ -111,9 +112,13 @@ module tally_header procedure :: allocate_results => tally_allocate_results end type TallyObject + type, public :: TallyContainer + class(TallyObject), allocatable :: obj + end type TallyContainer + integer(C_INT32_T), public, bind(C) :: n_tallies = 0 ! # of tallies - type(TallyObject), public, allocatable, target :: tallies(:) + type(TallyContainer), public, allocatable, target :: tallies(:) type(TallyDerivative), public, allocatable :: tally_derivs(:) !$omp threadprivate(tally_derivs) @@ -254,7 +259,7 @@ contains global_tallies(:,:) = ZERO do i = 1, n_tallies - call tallies(i) % allocate_results() + call tallies(i) % obj % allocate_results() end do end subroutine configure_tallies @@ -270,7 +275,8 @@ contains integer(C_INT32_T), optional, intent(out) :: index_end integer(C_INT) :: err - type(TallyObject), allocatable :: temp(:) ! temporary tallies array + integer :: i + type(TallyContainer), allocatable :: temp(:) ! temporary tallies array if (n_tallies == 0) then ! Allocate tallies array @@ -279,8 +285,10 @@ contains ! Allocate tallies array with increased size allocate(temp(n_tallies + n)) - ! Copy original tallies to temporary array - temp(1:n_tallies) = tallies + ! Move original tallies to temporary array + do i = 1, n_tallies + call move_alloc(tallies(i) % obj, temp(i) % obj) + end do ! Move allocation from temporary array call move_alloc(FROM=temp, TO=tallies) @@ -321,7 +329,7 @@ contains integer(C_INT) :: err if (index >= 1 .and. index <= size(tallies)) then - id = tallies(index) % id + id = tallies(index) % obj % id err = 0 else err = E_OUT_OF_BOUNDS @@ -338,7 +346,7 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) + associate (t => tallies(index) % obj) if (allocated(t % filter)) then filter_indices = C_LOC(t % filter(1)) n = size(t % filter) @@ -360,7 +368,7 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) + associate (t => tallies(index) % obj) if (allocated(t % nuclide_bins)) then nuclides = C_LOC(t % nuclide_bins(1)) n = size(t % nuclide_bins) @@ -383,11 +391,13 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then - if (allocated(tallies(index) % results)) then - ptr = C_LOC(tallies(index) % results(1,1,1)) - shape_(:) = shape(tallies(index) % results) - err = 0 - end if + associate (t => tallies(index) % obj) + if (allocated(t % results)) then + ptr = C_LOC(t % results(1,1,1)) + shape_(:) = shape(t % results) + err = 0 + end if + end associate else err = E_OUT_OF_BOUNDS end if @@ -408,7 +418,7 @@ contains err = 0 if (index >= 1 .and. index <= n_tallies) then - associate (t => tallies(index)) + associate (t => tallies(index) % obj) t % find_filter(:) = 0 do i = 1, n @@ -497,7 +507,7 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) + associate (t => tallies(index) % obj) if (allocated(t % nuclide_bins)) deallocate(t % nuclide_bins) allocate(t % nuclide_bins(n)) t % n_nuclide_bins = n @@ -542,7 +552,7 @@ contains err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then - associate (t => tallies(index)) + associate (t => tallies(index) % obj) if (allocated(t % score_bins)) deallocate(t % score_bins) allocate(t % score_bins(n)) t % n_user_score_bins = n @@ -691,4 +701,32 @@ contains end function openmc_tally_set_scores + function openmc_tally_set_type(index, type) result(err) bind(C) + ! Set the type of the tally + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(in) :: type(*) + integer(C_INT) :: err + + character(:), allocatable :: type_ + + ! Convert C string to Fortran string + type_ = to_f_string(type) + + err = 0 + if (index >= 1 .and. index <= n_tallies) then + if (allocated(tallies(index) % obj)) then + err = E_ALREADY_ALLOCATED + else + select case (type_) + case ('generic') + allocate(TallyObject :: tallies(index) % obj) + case default + err = E_UNASSIGNED + end select + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_type + end module tally_header diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 29c2ecedd..643e6fae4 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -109,8 +109,6 @@ contains real(8) :: rel_err = ZERO ! trigger relative error real(8) :: ratio ! ratio of the uncertainty/trigger threshold real(C_DOUBLE) :: k_combined(2) - type(TallyObject), pointer :: t ! tally pointer - type(TriggerObject), pointer :: trigger ! tally trigger ! Initialize tally trigger maximum uncertainty ratio to zero max_ratio = 0 @@ -151,7 +149,7 @@ contains ! Compute uncertainties for all tallies, scores with triggers TALLY_LOOP: do i = 1, n_tallies - t => tallies(i) + associate (t => tallies(i) % obj) ! Cycle through if only one batch has been simumlate if (t % n_realizations == 1) then @@ -159,7 +157,7 @@ contains end if TRIGGER_LOOP: do s = 1, t % n_triggers - trigger => t % triggers(s) + associate (trigger => t % triggers(s)) ! Initialize trigger uncertainties to zero trigger % std_dev = ZERO @@ -279,7 +277,9 @@ contains if (size(t % filter) == 0) exit FILTER_LOOP end do FILTER_LOOP end if + end associate end do TRIGGER_LOOP + end associate end do TALLY_LOOP end if end subroutine check_tally_triggers @@ -291,6 +291,8 @@ contains !=============================================================================== subroutine compute_tally_current(t, trigger) + type(TallyObject), intent(in) :: t ! mesh current tally + type(TriggerObject), intent(inout) :: trigger ! mesh current tally trigger integer :: i ! mesh index integer :: j ! loop index for tally filters @@ -306,8 +308,6 @@ contains logical :: print_ebin ! should incoming energy bin be displayed? real(8) :: rel_err = ZERO ! temporary relative error of result real(8) :: std_dev = ZERO ! temporary standard deviration of result - type(TallyObject), pointer :: t ! mesh current tally - type(TriggerObject) :: trigger ! mesh current tally trigger type(RegularMesh), pointer :: m ! surface current mesh ! Get pointer to mesh From 96d35a1acbe0c0900c5f6504c0a3ddd83c152aee Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 11:58:57 -0500 Subject: [PATCH 141/229] Move distribcell filter into its own module --- CMakeLists.txt | 1 + src/summary.F90 | 2 +- src/tallies/tally_filter.F90 | 373 +-------------------- src/tallies/tally_filter_distribcell.F90 | 391 +++++++++++++++++++++++ 4 files changed, 394 insertions(+), 373 deletions(-) create mode 100644 src/tallies/tally_filter_distribcell.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 669494e05..b0bcd1b1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally.F90 src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 + src/tallies/tally_filter_distribcell.F90 src/tallies/tally_filter_energy.F90 src/tallies/tally_filter_material.F90 src/tallies/tally_filter_mesh.F90 diff --git a/src/summary.F90 b/src/summary.F90 index e4263d8d0..6ee8b2e78 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -16,7 +16,7 @@ module summary use surface_header use string, only: to_str use tally_header, only: TallyObject - use tally_filter, only: find_offset + use tally_filter_distribcell, only: find_offset implicit none private diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index d48939f8a..dc3aa36b1 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -14,6 +14,7 @@ module tally_filter use tally_filter_header ! Inherit other filters + use tally_filter_distribcell use tally_filter_energy use tally_filter_material use tally_filter_mesh @@ -57,19 +58,6 @@ module tally_filter procedure :: text_label => text_label_cell_from end type CellFromFilter -!=============================================================================== -! DISTRIBCELLFILTER specifies which distributed geometric cells tally events -! reside in. -!=============================================================================== - type, extends(TallyFilter) :: DistribcellFilter - integer :: cell - contains - procedure :: get_all_bins => get_all_bins_distribcell - procedure :: to_statepoint => to_statepoint_distribcell - procedure :: text_label => text_label_distribcell - procedure :: initialize => initialize_distribcell - end type DistribcellFilter - !=============================================================================== ! CELLBORNFILTER specifies which cell the particle was born in. !=============================================================================== @@ -352,83 +340,6 @@ contains label = "Cell from " // to_str(cells(this % cells(bin)) % id) end function text_label_cell_from -!=============================================================================== -! DistribcellFilter methods -!=============================================================================== - subroutine get_all_bins_distribcell(this, p, estimator, match) - class(DistribcellFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: distribcell_index, offset, i - - distribcell_index = cells(this % cell) % distribcell_index - offset = 0 - do i = 1, p % n_coord - if (cells(p % coord(i) % cell) % type == FILL_UNIVERSE) then - offset = offset + cells(p % coord(i) % cell) % & - offset(distribcell_index) - elseif (cells(p % coord(i) % cell) % type == FILL_LATTICE) then - if (lattices(p % coord(i + 1) % lattice) % obj & - % are_valid_indices([& - p % coord(i + 1) % lattice_x, & - p % coord(i + 1) % lattice_y, & - p % coord(i + 1) % lattice_z])) then - offset = offset + lattices(p % coord(i + 1) % lattice) % obj % & - offset(distribcell_index, & - p % coord(i + 1) % lattice_x, & - p % coord(i + 1) % lattice_y, & - p % coord(i + 1) % lattice_z) - end if - end if - if (this % cell == p % coord(i) % cell) then - call match % bins % push_back(offset + 1) - call match % weights % push_back(ONE) - return - end if - end do - end subroutine get_all_bins_distribcell - - subroutine to_statepoint_distribcell(this, filter_group) - class(DistribcellFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "distribcell") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", cells(this % cell) % id) - end subroutine to_statepoint_distribcell - - subroutine initialize_distribcell(this) - class(DistribcellFilter), intent(inout) :: this - - integer :: id - - ! Convert id to index. - id = this % cell - if (cell_dict % has_key(id)) then - this % cell = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end subroutine initialize_distribcell - - function text_label_distribcell(this, bin) result(label) - class(DistribcellFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - integer :: offset - type(Universe), pointer :: univ - - univ => universes(root_universe) - offset = 0 - label = '' - call find_offset(this % cell, univ, bin-1, offset, label) - label = "Distributed Cell " // label - end function text_label_distribcell - !=============================================================================== ! CellbornFilter methods !=============================================================================== @@ -788,288 +699,6 @@ contains end select end function text_label_energyfunction -!=============================================================================== -! FIND_OFFSET (for distribcell) uses a given map number, a target cell ID, and -! a target offset to build a string which is the path from the base universe to -! the target cell with the given offset -!=============================================================================== - - recursive subroutine find_offset(i_cell, univ, target_offset, offset, path) - - integer, intent(in) :: i_cell ! The target cell index - type(Universe), intent(in) :: univ ! Universe to begin search - integer, intent(in) :: target_offset ! Target offset - integer, intent(inout) :: offset ! Current offset - character(*), intent(inout) :: path ! Path to offset - - integer :: map ! Index in maps vector - integer :: i, j ! Index over cells - integer :: k, l, m ! Indices in lattice - integer :: old_k, old_l, old_m ! Previous indices in lattice - integer :: n_x, n_y, n_z ! Lattice cell array dimensions - integer :: n ! Number of cells to search - integer :: cell_index ! Index in cells array - integer :: lat_offset ! Offset from lattice - integer :: temp_offset ! Looped sum of offsets - integer :: i_univ ! index in universes array - logical :: this_cell = .false. ! Advance in this cell? - logical :: later_cell = .false. ! Fill cells after this one? - type(Cell), pointer :: c ! Pointer to current cell - type(Universe), pointer :: next_univ ! Next universe to loop through - class(Lattice), pointer :: lat ! Pointer to current lattice - - ! Get the distribcell index for this cell - map = cells(i_cell) % distribcell_index - - n = size(univ % cells) - - ! Write to the geometry stack - i_univ = universe_dict % get_key(univ % id) - if (i_univ == root_universe) then - path = trim(path) // "u" // to_str(univ%id) - else - path = trim(path) // "->u" // to_str(univ%id) - end if - - ! Look through all cells in this universe - do i = 1, n - ! If the cell matches the goal and the offset matches final, write to the - ! geometry stack - if (univ % cells(i) == i_cell .and. offset == target_offset) then - c => cells(univ % cells(i)) - path = trim(path) // "->c" // to_str(c % id) - return - end if - end do - - ! Find the fill cell or lattice cell that we need to enter - do i = 1, n - - later_cell = .false. - - c => cells(univ % cells(i)) - - this_cell = .false. - - ! If we got here, we still think the target is in this universe - ! or further down, but it's not this exact cell. - ! Compare offset to next cell to see if we should enter this cell - if (i /= n) then - - do j = i+1, n - - c => cells(univ % cells(j)) - - ! Skip normal cells which do not have offsets - if (c % type == FILL_MATERIAL) cycle - - ! Break loop once we've found the next cell with an offset - exit - end do - - ! Ensure we didn't just end the loop by iteration - if (c % type /= FILL_MATERIAL) then - - ! There are more cells in this universe that it could be in - later_cell = .true. - - ! Two cases, lattice or fill cell - if (c % type == FILL_UNIVERSE) then - temp_offset = c % offset(map) - - ! Get the offset of the first lattice location - else - lat => lattices(c % fill) % obj - temp_offset = lat % offset(map, 1, 1, 1) - end if - - ! If the final offset is in the range of offset - temp_offset+offset - ! then the goal is in this cell - if (target_offset < temp_offset + offset) then - this_cell = .true. - end if - end if - end if - - if (n == 1 .and. c % type /= FILL_MATERIAL) then - this_cell = .true. - end if - - if (.not. later_cell) then - this_cell = .true. - end if - - ! Get pointer to THIS cell because target must be in this cell - if (this_cell) then - - cell_index = univ % cells(i) - c => cells(cell_index) - - path = trim(path) // "->c" // to_str(c%id) - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type == FILL_UNIVERSE) then - - ! Enter this cell to update the current offset - offset = c % offset(map) + offset - - next_univ => universes(c % fill) - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then - - ! Set current lattice - lat => lattices(c % fill) % obj - - select type (lat) - - ! ================================================================== - ! RECTANGULAR LATTICES - type is (RectLattice) - - ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id) - - n_x = lat % n_cells(1) - n_y = lat % n_cells(2) - n_z = lat % n_cells(3) - old_m = 1 - old_l = 1 - old_k = 1 - - ! Loop over lattice coordinates - do k = 1, n_x - do l = 1, n_y - do m = 1, n_z - - if (target_offset >= lat % offset(map, k, l, m) + offset) then - if (k == n_x .and. l == n_y .and. m == n_z) then - ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map, k, l, m) - offset = offset + lat_offset - next_univ => universes(lat % universes(k, l, m)) - if (lat % is_3d) then - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // "," // & - trim(to_str(m-1)) // ")" - else - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - else - old_m = m - old_l = l - old_k = k - cycle - end if - else - ! Target is at this lattice position - lat_offset = lat % offset(map, old_k, old_l, old_m) - offset = offset + lat_offset - next_univ => universes(lat % universes(old_k, old_l, old_m)) - if (lat % is_3d) then - path = trim(path) // "(" // trim(to_str(old_k-1)) // & - "," // trim(to_str(old_l-1)) // "," // & - trim(to_str(old_m-1)) // ")" - else - path = trim(path) // "(" // trim(to_str(old_k-1)) // & - "," // trim(to_str(old_l-1)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - - end do - end do - end do - - ! ================================================================== - ! HEXAGONAL LATTICES - type is (HexLattice) - - ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id) - - n_z = lat % n_axial - n_y = 2 * lat % n_rings - 1 - n_x = 2 * lat % n_rings - 1 - old_m = 1 - old_l = 1 - old_k = 1 - - ! Loop over lattice coordinates - do m = 1, n_z - do l = 1, n_y - do k = 1, n_x - - ! This array position is never used - if (k + l < lat % n_rings + 1) then - cycle - ! This array position is never used - else if (k + l > 3*lat % n_rings - 1) then - cycle - end if - - if (target_offset >= lat % offset(map, k, l, m) + offset) then - if (k == lat % n_rings .and. l == n_y .and. m == n_z) then - ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map, k, l, m) - offset = offset + lat_offset - next_univ => universes(lat % universes(k, l, m)) - if (lat % is_3d) then - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // "," // & - trim(to_str(m - 1)) // ")" - else - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - else - old_m = m - old_l = l - old_k = k - cycle - end if - else - ! Target is at this lattice position - lat_offset = lat % offset(map, old_k, old_l, old_m) - offset = offset + lat_offset - next_univ => universes(lat % universes(old_k, old_l, old_m)) - if (lat % is_3d) then - path = trim(path) // "(" // & - trim(to_str(old_k - lat % n_rings)) // "," // & - trim(to_str(old_l - lat % n_rings)) // "," // & - trim(to_str(old_m - 1)) // ")" - else - path = trim(path) // "(" // & - trim(to_str(old_k - lat % n_rings)) // "," // & - trim(to_str(old_l - lat % n_rings)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - - end do - end do - end do - - end select - - end if - end if - end do - end subroutine find_offset - !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 new file mode 100644 index 000000000..d0f8adf07 --- /dev/null +++ b/src/tallies/tally_filter_distribcell.F90 @@ -0,0 +1,391 @@ +module tally_filter_distribcell + + use, intrinsic :: ISO_C_BINDING + + use hdf5, only: HID_T + + use constants + use error + use geometry_header + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + public :: find_offset + +!=============================================================================== +! DISTRIBCELLFILTER specifies which distributed geometric cells tally events +! reside in. +!=============================================================================== + + type, public, extends(TallyFilter) :: DistribcellFilter + integer :: cell + contains + procedure :: get_all_bins => get_all_bins_distribcell + procedure :: to_statepoint => to_statepoint_distribcell + procedure :: text_label => text_label_distribcell + procedure :: initialize => initialize_distribcell + end type DistribcellFilter + +contains + + subroutine get_all_bins_distribcell(this, p, estimator, match) + class(DistribcellFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: distribcell_index, offset, i + + distribcell_index = cells(this % cell) % distribcell_index + offset = 0 + do i = 1, p % n_coord + if (cells(p % coord(i) % cell) % type == FILL_UNIVERSE) then + offset = offset + cells(p % coord(i) % cell) % & + offset(distribcell_index) + elseif (cells(p % coord(i) % cell) % type == FILL_LATTICE) then + if (lattices(p % coord(i + 1) % lattice) % obj & + % are_valid_indices([& + p % coord(i + 1) % lattice_x, & + p % coord(i + 1) % lattice_y, & + p % coord(i + 1) % lattice_z])) then + offset = offset + lattices(p % coord(i + 1) % lattice) % obj % & + offset(distribcell_index, & + p % coord(i + 1) % lattice_x, & + p % coord(i + 1) % lattice_y, & + p % coord(i + 1) % lattice_z) + end if + end if + if (this % cell == p % coord(i) % cell) then + call match % bins % push_back(offset + 1) + call match % weights % push_back(ONE) + return + end if + end do + end subroutine get_all_bins_distribcell + + subroutine to_statepoint_distribcell(this, filter_group) + class(DistribcellFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "distribcell") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", cells(this % cell) % id) + end subroutine to_statepoint_distribcell + + subroutine initialize_distribcell(this) + class(DistribcellFilter), intent(inout) :: this + + integer :: id + + ! Convert id to index. + id = this % cell + if (cell_dict % has_key(id)) then + this % cell = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end subroutine initialize_distribcell + + function text_label_distribcell(this, bin) result(label) + class(DistribcellFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + integer :: offset + type(Universe), pointer :: univ + + univ => universes(root_universe) + offset = 0 + label = '' + call find_offset(this % cell, univ, bin-1, offset, label) + label = "Distributed Cell " // label + end function text_label_distribcell + +!=============================================================================== +! FIND_OFFSET (for distribcell) uses a given map number, a target cell ID, and +! a target offset to build a string which is the path from the base universe to +! the target cell with the given offset +!=============================================================================== + + recursive subroutine find_offset(i_cell, univ, target_offset, offset, path) + + integer, intent(in) :: i_cell ! The target cell index + type(Universe), intent(in) :: univ ! Universe to begin search + integer, intent(in) :: target_offset ! Target offset + integer, intent(inout) :: offset ! Current offset + character(*), intent(inout) :: path ! Path to offset + + integer :: map ! Index in maps vector + integer :: i, j ! Index over cells + integer :: k, l, m ! Indices in lattice + integer :: old_k, old_l, old_m ! Previous indices in lattice + integer :: n_x, n_y, n_z ! Lattice cell array dimensions + integer :: n ! Number of cells to search + integer :: cell_index ! Index in cells array + integer :: lat_offset ! Offset from lattice + integer :: temp_offset ! Looped sum of offsets + integer :: i_univ ! index in universes array + logical :: this_cell = .false. ! Advance in this cell? + logical :: later_cell = .false. ! Fill cells after this one? + type(Cell), pointer :: c ! Pointer to current cell + type(Universe), pointer :: next_univ ! Next universe to loop through + class(Lattice), pointer :: lat ! Pointer to current lattice + + ! Get the distribcell index for this cell + map = cells(i_cell) % distribcell_index + + n = size(univ % cells) + + ! Write to the geometry stack + i_univ = universe_dict % get_key(univ % id) + if (i_univ == root_universe) then + path = trim(path) // "u" // to_str(univ%id) + else + path = trim(path) // "->u" // to_str(univ%id) + end if + + ! Look through all cells in this universe + do i = 1, n + ! If the cell matches the goal and the offset matches final, write to the + ! geometry stack + if (univ % cells(i) == i_cell .and. offset == target_offset) then + c => cells(univ % cells(i)) + path = trim(path) // "->c" // to_str(c % id) + return + end if + end do + + ! Find the fill cell or lattice cell that we need to enter + do i = 1, n + + later_cell = .false. + + c => cells(univ % cells(i)) + + this_cell = .false. + + ! If we got here, we still think the target is in this universe + ! or further down, but it's not this exact cell. + ! Compare offset to next cell to see if we should enter this cell + if (i /= n) then + + do j = i+1, n + + c => cells(univ % cells(j)) + + ! Skip normal cells which do not have offsets + if (c % type == FILL_MATERIAL) cycle + + ! Break loop once we've found the next cell with an offset + exit + end do + + ! Ensure we didn't just end the loop by iteration + if (c % type /= FILL_MATERIAL) then + + ! There are more cells in this universe that it could be in + later_cell = .true. + + ! Two cases, lattice or fill cell + if (c % type == FILL_UNIVERSE) then + temp_offset = c % offset(map) + + ! Get the offset of the first lattice location + else + lat => lattices(c % fill) % obj + temp_offset = lat % offset(map, 1, 1, 1) + end if + + ! If the final offset is in the range of offset - temp_offset+offset + ! then the goal is in this cell + if (target_offset < temp_offset + offset) then + this_cell = .true. + end if + end if + end if + + if (n == 1 .and. c % type /= FILL_MATERIAL) then + this_cell = .true. + end if + + if (.not. later_cell) then + this_cell = .true. + end if + + ! Get pointer to THIS cell because target must be in this cell + if (this_cell) then + + cell_index = univ % cells(i) + c => cells(cell_index) + + path = trim(path) // "->c" // to_str(c%id) + + ! ==================================================================== + ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL + if (c % type == FILL_UNIVERSE) then + + ! Enter this cell to update the current offset + offset = c % offset(map) + offset + + next_univ => universes(c % fill) + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + + ! ==================================================================== + ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL + elseif (c % type == FILL_LATTICE) then + + ! Set current lattice + lat => lattices(c % fill) % obj + + select type (lat) + + ! ================================================================== + ! RECTANGULAR LATTICES + type is (RectLattice) + + ! Write to the geometry stack + path = trim(path) // "->l" // to_str(lat%id) + + n_x = lat % n_cells(1) + n_y = lat % n_cells(2) + n_z = lat % n_cells(3) + old_m = 1 + old_l = 1 + old_k = 1 + + ! Loop over lattice coordinates + do k = 1, n_x + do l = 1, n_y + do m = 1, n_z + + if (target_offset >= lat % offset(map, k, l, m) + offset) then + if (k == n_x .and. l == n_y .and. m == n_z) then + ! This is last lattice cell, so target must be here + lat_offset = lat % offset(map, k, l, m) + offset = offset + lat_offset + next_univ => universes(lat % universes(k, l, m)) + if (lat % is_3d) then + path = trim(path) // "(" // trim(to_str(k-1)) // & + "," // trim(to_str(l-1)) // "," // & + trim(to_str(m-1)) // ")" + else + path = trim(path) // "(" // trim(to_str(k-1)) // & + "," // trim(to_str(l-1)) // ")" + end if + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + else + old_m = m + old_l = l + old_k = k + cycle + end if + else + ! Target is at this lattice position + lat_offset = lat % offset(map, old_k, old_l, old_m) + offset = offset + lat_offset + next_univ => universes(lat % universes(old_k, old_l, old_m)) + if (lat % is_3d) then + path = trim(path) // "(" // trim(to_str(old_k-1)) // & + "," // trim(to_str(old_l-1)) // "," // & + trim(to_str(old_m-1)) // ")" + else + path = trim(path) // "(" // trim(to_str(old_k-1)) // & + "," // trim(to_str(old_l-1)) // ")" + end if + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + end if + + end do + end do + end do + + ! ================================================================== + ! HEXAGONAL LATTICES + type is (HexLattice) + + ! Write to the geometry stack + path = trim(path) // "->l" // to_str(lat%id) + + n_z = lat % n_axial + n_y = 2 * lat % n_rings - 1 + n_x = 2 * lat % n_rings - 1 + old_m = 1 + old_l = 1 + old_k = 1 + + ! Loop over lattice coordinates + do m = 1, n_z + do l = 1, n_y + do k = 1, n_x + + ! This array position is never used + if (k + l < lat % n_rings + 1) then + cycle + ! This array position is never used + else if (k + l > 3*lat % n_rings - 1) then + cycle + end if + + if (target_offset >= lat % offset(map, k, l, m) + offset) then + if (k == lat % n_rings .and. l == n_y .and. m == n_z) then + ! This is last lattice cell, so target must be here + lat_offset = lat % offset(map, k, l, m) + offset = offset + lat_offset + next_univ => universes(lat % universes(k, l, m)) + if (lat % is_3d) then + path = trim(path) // "(" // & + trim(to_str(k - lat % n_rings)) // "," // & + trim(to_str(l - lat % n_rings)) // "," // & + trim(to_str(m - 1)) // ")" + else + path = trim(path) // "(" // & + trim(to_str(k - lat % n_rings)) // "," // & + trim(to_str(l - lat % n_rings)) // ")" + end if + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + else + old_m = m + old_l = l + old_k = k + cycle + end if + else + ! Target is at this lattice position + lat_offset = lat % offset(map, old_k, old_l, old_m) + offset = offset + lat_offset + next_univ => universes(lat % universes(old_k, old_l, old_m)) + if (lat % is_3d) then + path = trim(path) // "(" // & + trim(to_str(old_k - lat % n_rings)) // "," // & + trim(to_str(old_l - lat % n_rings)) // "," // & + trim(to_str(old_m - 1)) // ")" + else + path = trim(path) // "(" // & + trim(to_str(old_k - lat % n_rings)) // "," // & + trim(to_str(old_l - lat % n_rings)) // ")" + end if + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + end if + + end do + end do + end do + + end select + + end if + end if + end do + end subroutine find_offset + +end module tally_filter_distribcell From 9cc06eafae82bd50633ede3822b42545b68036f1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 13:19:01 -0500 Subject: [PATCH 142/229] Fix distribcells and refactor initialization quite a bit --- src/cmfd_input.F90 | 10 + src/geometry_header.F90 | 5 +- src/initialize.F90 | 197 +----- src/input_xml.F90 | 789 ++++++++++++++--------- src/mgxs_data.F90 | 4 +- src/simulation.F90 | 10 +- src/tallies/tally_filter_distribcell.F90 | 1 + src/tallies/tally_header.F90 | 2 +- 8 files changed, 494 insertions(+), 524 deletions(-) diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index e8701fe6d..b80991474 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -441,6 +441,16 @@ contains call filter_dict % add_key(filt % id, i_filt) end select + ! Initialize filters + do i = i_filt_start, i_filt_end + select type (filt => filters(i) % obj) + type is (SurfaceFilter) + ! Don't do anything + class default + call filt % initialize() + end select + end do + ! Allocate tallies err = openmc_extend_tallies(3, i_start, i_end) cmfd_tallies => tallies(i_start:i_end) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index ba6992d47..c277d8582 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -347,8 +347,7 @@ contains ! temperatures to read (which may be different if interpolation is used) !=============================================================================== - subroutine get_temperatures(cells, nuc_temps, sab_temps) - type(Cell), allocatable, intent(in) :: cells(:) + subroutine get_temperatures(nuc_temps, sab_temps) type(VectorReal), allocatable, intent(out) :: nuc_temps(:) type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:) @@ -374,7 +373,7 @@ contains temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN end if - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = cells(i) % material(j) associate (mat => materials(i_material)) NUC_NAMES_LOOP: do k = 1, size(mat % names) ! Get index in nuc_temps array diff --git a/src/initialize.F90 b/src/initialize.F90 index 387343577..ced55d575 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -12,7 +12,7 @@ module initialize use dict_header, only: DictIntInt, ElemKeyValueII use set_header, only: SetInt use error, only: fatal_error, warning - use geometry, only: neighbor_lists, count_instance, calc_offsets, & + use geometry, only: calc_offsets, & maximum_levels use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,& root_universe @@ -26,7 +26,6 @@ module initialize use output, only: print_version, write_message, print_usage, & print_plot use random_lcg, only: initialize_prng - use state_point, only: load_state_point use string, only: to_str, starts_with, ends_with, str_to_int use summary, only: write_summary use tally_header, only: TallyObject @@ -96,16 +95,9 @@ contains ! XML files because we need the PRNG to be initialized first if (run_mode == MODE_PLOTTING) call read_plots_xml() - ! Use dictionaries to redefine index pointers - call adjust_indices() - ! Initialize distribcell_filters call prepare_distribcell() - ! After reading input and basic geometry setup is complete, build lists of - ! neighboring cells for efficient tracking - call neighbor_lists() - ! Check to make sure there are not too many nested coordinate levels in the ! geometry since the coordinate list is statically allocated for performance ! reasons @@ -126,9 +118,6 @@ contains ! fission bank call allocate_banks() - ! If this is a restart run, load the state point data and binary source - ! file - if (restart_run) call load_state_point() end if if (master) then @@ -420,176 +409,6 @@ contains end subroutine read_command_line -!=============================================================================== -! ADJUST_INDICES changes the values for 'surfaces' for each cell and the -! material index assigned to each to the indices in the surfaces and material -! array rather than the unique IDs assigned to each surface and material. Also -! assigns boundary conditions to surfaces based on those read into the bc_dict -! dictionary -!=============================================================================== - - subroutine adjust_indices() - - integer :: i ! index for various purposes - integer :: j ! index for various purposes - integer :: k ! loop index for lattices - integer :: m ! loop index for lattices - integer :: lid ! lattice IDs - integer :: i_array ! index in surfaces/materials array - integer :: id ! user-specified id - type(Cell), pointer :: c => null() - class(Lattice), pointer :: lat => null() - - do i = 1, n_cells - ! ======================================================================= - ! ADJUST REGION SPECIFICATION FOR EACH CELL - - c => cells(i) - do j = 1, size(c%region) - id = c%region(j) - ! Make sure that only regions are checked. Since OP_UNION is the - ! operator with the lowest integer value, anything below it must denote - ! a half-space - if (id < OP_UNION) then - if (surface_dict%has_key(abs(id))) then - i_array = surface_dict%get_key(abs(id)) - c%region(j) = sign(i_array, id) - else - call fatal_error("Could not find surface " // trim(to_str(abs(id)))& - &// " specified on cell " // trim(to_str(c%id))) - end if - end if - end do - - ! Also adjust the indices in the reverse Polish notation - do j = 1, size(c%rpn) - id = c%rpn(j) - ! Again, make sure that only regions are checked - if (id < OP_UNION) then - i_array = surface_dict%get_key(abs(id)) - c%rpn(j) = sign(i_array, id) - end if - end do - - ! ======================================================================= - ! ADJUST UNIVERSE INDEX FOR EACH CELL - - id = c%universe - if (universe_dict%has_key(id)) then - c%universe = universe_dict%get_key(id) - else - call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c%id))) - end if - - ! ======================================================================= - ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL - - if (c % material(1) == NONE) then - id = c % fill - if (universe_dict % has_key(id)) then - c % type = FILL_UNIVERSE - c % fill = universe_dict % get_key(id) - elseif (lattice_dict % has_key(id)) then - lid = lattice_dict % get_key(id) - c % type = FILL_LATTICE - c % fill = lid - else - call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& - // trim(to_str(c % id)) // " is neither a universe nor a & - &lattice.") - end if - else - do j = 1, size(c % material) - id = c % material(j) - if (id == MATERIAL_VOID) then - c % type = FILL_MATERIAL - else if (material_dict % has_key(id)) then - c % type = FILL_MATERIAL - c % material(j) = material_dict % get_key(id) - else - call fatal_error("Could not find material " // trim(to_str(id)) & - // " specified on cell " // trim(to_str(c % id))) - end if - end do - end if - end do - - ! ========================================================================== - ! ADJUST UNIVERSE INDICES FOR EACH LATTICE - - do i = 1, n_lattices - lat => lattices(i)%obj - select type (lat) - - type is (RectLattice) - do m = 1, lat%n_cells(3) - do k = 1, lat%n_cells(2) - do j = 1, lat%n_cells(1) - id = lat%universes(j,k,m) - if (universe_dict%has_key(id)) then - lat%universes(j,k,m) = universe_dict%get_key(id) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat%id))) - end if - end do - end do - end do - - type is (HexLattice) - do m = 1, lat%n_axial - do k = 1, 2*lat%n_rings - 1 - do j = 1, 2*lat%n_rings - 1 - if (j + k < lat%n_rings + 1) then - cycle - else if (j + k > 3*lat%n_rings - 1) then - cycle - end if - id = lat%universes(j, k, m) - if (universe_dict%has_key(id)) then - lat%universes(j, k, m) = universe_dict%get_key(id) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat%id))) - end if - end do - end do - end do - - end select - - if (lat%outer /= NO_OUTER_UNIVERSE) then - if (universe_dict%has_key(lat%outer)) then - lat%outer = universe_dict%get_key(lat%outer) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(lat%outer)) & - &// " specified on lattice " // trim(to_str(lat%id))) - end if - end if - - end do - - ! ======================================================================= - ! ADJUST INDICES FOR EACH TALLY FILTER - - FILTER_LOOP: do i = 1, n_filters - - select type(filt => filters(i) % obj) - type is (SurfaceFilter) - ! Check if this is a surface filter only for surface currents - if (.not. filt % current) call filt % initialize() - class default - call filt % initialize() - end select - - end do FILTER_LOOP - - end subroutine adjust_indices - !=============================================================================== ! CALCULATE_WORK determines how many particles each processor should simulate !=============================================================================== @@ -717,20 +536,6 @@ contains ! If distribcell isn't used in this simulation then no more work left to do. if (.not. distribcell_active) return - ! Count the number of instances of each cell. - call count_instance(universes(root_universe)) - - ! Set the number of bins in all distribcell filters. - do i = 1, n_tallies - do j = 1, size(tallies(i) % obj % filter) - select type(filt => filters(tallies(i) % obj % filter(j)) % obj) - type is (DistribcellFilter) - ! Set the number of bins to the number of instances of the cell. - filt % n_bins = cells(filt % cell) % instances - end select - end do - end do - ! Make sure the number of materials and temperatures matches the number of ! cell instances. do i = 1, n_cells diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 84e05aa7f..0c3cc08c3 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,6 +11,7 @@ module input_xml use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning + use geometry, only: count_instance, neighbor_lists use geometry_header, only: Cell, Lattice, RectLattice, HexLattice, & get_temperatures, root_universe use global @@ -47,9 +48,25 @@ contains subroutine read_input_xml() + type(VectorReal), allocatable :: nuc_temps(:) ! List of T to read for each nuclide + type(VectorReal), allocatable :: sab_temps(:) ! List of T to read for each S(a,b) + real(8), allocatable :: material_temps(:) + call read_settings_xml() + call read_cross_sections_xml() + call read_materials_xml(material_temps) call read_geometry_xml() - call read_materials() + + ! Set up neighbor lists, convert user IDs -> indices, assign temperatures + call finalize_geometry(material_temps, nuc_temps, sab_temps) + + ! Read continuous-energy cross sections + if (run_CE .and. run_mode /= MODE_PLOTTING) then + call time_read_xs % start() + call read_ce_cross_sections(nuc_temps, sab_temps) + call time_read_xs % stop() + end if + call read_tallies_xml() if (cmfd_run) call configure_cmfd() @@ -66,6 +83,27 @@ contains end subroutine read_input_xml + subroutine finalize_geometry(material_temps, nuc_temps, sab_temps) + real(8), intent(in) :: material_temps(:) + type(VectorReal), allocatable, intent(out) :: nuc_temps(:) + type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:) + + ! Perform some final operations to set up the geometry + call adjust_indices() + call count_instance(universes(root_universe)) + + ! After reading input and basic geometry setup is complete, build lists of + ! neighboring cells for efficient tracking + call neighbor_lists() + + ! Assign temperatures to cells that don't have temperatures already assigned + call assign_temperatures(material_temps) + + ! Determine desired txemperatures for each nuclide and S(a,b) table + call get_temperatures(nuc_temps, sab_temps) + + end subroutine finalize_geometry + !=============================================================================== ! READ_SETTINGS_XML reads data from a settings.xml file and parses it, checking ! for errors and placing properly-formatted data in the right data structures @@ -1078,6 +1116,7 @@ contains integer :: i, j, k, m, i_x, i_a, input_index integer :: n, n_mats, n_x, n_y, n_z, n_rings, n_rlats, n_hlats + integer :: id integer :: univ_id integer :: n_cells_in_univ integer :: coeffs_reqd @@ -1111,13 +1150,9 @@ contains type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains - ! Display output message call write_message("Reading geometry XML file...", 5) - ! ========================================================================== - ! READ CELLS FROM GEOMETRY.XML - ! Check if geometry.xml exists filename = trim(path_input) // "geometry.xml" inquire(FILE=filename, EXIST=file_exists) @@ -1130,265 +1165,6 @@ contains call doc % load_file(filename) root = doc % document_element() - ! Get pointer to list of XML - call get_node_list(root, "cell", node_cell_list) - - ! Get number of tags - n_cells = size(node_cell_list) - - ! Check for no cells - if (n_cells == 0) then - call fatal_error("No cells found in geometry.xml!") - end if - - ! Allocate cells array - allocate(cells(n_cells)) - - if (check_overlaps) then - allocate(overlap_check_cnt(n_cells)) - overlap_check_cnt = 0 - end if - - n_universes = 0 - do i = 1, n_cells - c => cells(i) - - ! Initialize distribcell instances and distribcell index - c % instances = 0 - c % distribcell_index = NONE - - ! Get pointer to i-th cell node - node_cell = node_cell_list(i) - - ! Copy data into cells - if (check_for_node(node_cell, "id")) then - call get_node_value(node_cell, "id", c % id) - else - call fatal_error("Must specify id of cell in geometry XML file.") - end if - - ! Copy cell name - if (check_for_node(node_cell, "name")) then - call get_node_value(node_cell, "name", c % name) - end if - - if (check_for_node(node_cell, "universe")) then - call get_node_value(node_cell, "universe", c % universe) - else - c % universe = 0 - end if - if (check_for_node(node_cell, "fill")) then - call get_node_value(node_cell, "fill", c % fill) - if (find(fill_univ_ids, c % fill) == -1) & - call fill_univ_ids % push_back(c % fill) - else - c % fill = NONE - end if - - ! Check to make sure 'id' hasn't been used - if (cell_dict % has_key(c % id)) then - call fatal_error("Two or more cells use the same unique ID: " & - // to_str(c % id)) - end if - - ! Read material - if (check_for_node(node_cell, "material")) then - n_mats = node_word_count(node_cell, "material") - - if (n_mats > 0) then - allocate(sarray(n_mats)) - call get_node_array(node_cell, "material", sarray) - - allocate(c % material(n_mats)) - do j = 1, n_mats - select case(trim(to_lower(sarray(j)))) - case ('void') - c % material(j) = MATERIAL_VOID - case default - c % material(j) = int(str_to_int(sarray(j)), 4) - - ! Check for error - if (c % material(j) == ERROR_INT) then - call fatal_error("Invalid material specified on cell " & - // to_str(c % id)) - end if - end select - end do - - deallocate(sarray) - - else - allocate(c % material(1)) - c % material(1) = NONE - end if - - else - allocate(c % material(1)) - c % material(1) = NONE - end if - - ! Check to make sure that either material or fill was specified - if (c % material(1) == NONE .and. c % fill == NONE) then - call fatal_error("Neither material nor fill was specified for cell " & - // trim(to_str(c % id))) - end if - - ! Check to make sure that both material and fill haven't been - ! specified simultaneously - if (c % material(1) /= NONE .and. c % fill /= NONE) then - call fatal_error("Cannot specify material and fill simultaneously") - end if - - ! Check for region specification (also under deprecated name surfaces) - if (check_for_node(node_cell, "surfaces")) then - call warning("The use of 'surfaces' is deprecated and will be & - &disallowed in a future release. Use 'region' instead. The & - &openmc-update-inputs utility can be used to automatically & - &update geometry.xml files.") - region_spec = node_value_string(node_cell, "surfaces") - call get_node_value(node_cell, "surfaces", region_spec) - elseif (check_for_node(node_cell, "region")) then - region_spec = node_value_string(node_cell, "region") - else - region_spec = '' - end if - - if (len_trim(region_spec) > 0) then - ! Create surfaces array from string - call tokenize(region_spec, tokens) - - ! Use shunting-yard algorithm to determine RPN for surface algorithm - call generate_rpn(c%id, tokens, rpn) - - ! Copy region spec and RPN form to cell arrays - allocate(c % region(tokens%size())) - allocate(c % rpn(rpn%size())) - c % region(:) = tokens%data(1:tokens%size()) - c % rpn(:) = rpn%data(1:rpn%size()) - - call tokens%clear() - call rpn%clear() - end if - if (.not. allocated(c%region)) allocate(c%region(0)) - if (.not. allocated(c%rpn)) allocate(c%rpn(0)) - - ! Check if this is a simple cell - if (any(c%rpn == OP_COMPLEMENT) .or. any(c%rpn == OP_UNION)) then - c%simple = .false. - else - c%simple = .true. - end if - - ! Rotation matrix - if (check_for_node(node_cell, "rotation")) then - ! Rotations can only be applied to cells that are being filled with - ! another universe - if (c % fill == NONE) then - call fatal_error("Cannot apply a rotation to cell " // trim(to_str(& - &c % id)) // " because it is not filled with another universe") - end if - - ! Read number of rotation parameters - n = node_word_count(node_cell, "rotation") - if (n /= 3) then - call fatal_error("Incorrect number of rotation parameters on cell " & - // to_str(c % id)) - end if - - ! Copy rotation angles in x,y,z directions - allocate(c % rotation(3)) - call get_node_array(node_cell, "rotation", c % rotation) - phi = -c % rotation(1) * PI/180.0_8 - theta = -c % rotation(2) * PI/180.0_8 - psi = -c % rotation(3) * PI/180.0_8 - - ! Calculate rotation matrix based on angles given - allocate(c % rotation_matrix(3,3)) - c % rotation_matrix = reshape((/ & - cos(theta)*cos(psi), cos(theta)*sin(psi), -sin(theta), & - -cos(phi)*sin(psi) + sin(phi)*sin(theta)*cos(psi), & - cos(phi)*cos(psi) + sin(phi)*sin(theta)*sin(psi), & - sin(phi)*cos(theta), & - sin(phi)*sin(psi) + cos(phi)*sin(theta)*cos(psi), & - -sin(phi)*cos(psi) + cos(phi)*sin(theta)*sin(psi), & - cos(phi)*cos(theta) /), (/ 3,3 /)) - end if - - ! Translation vector - if (check_for_node(node_cell, "translation")) then - ! Translations can only be applied to cells that are being filled with - ! another universe - if (c % fill == NONE) then - call fatal_error("Cannot apply a translation to cell " & - // trim(to_str(c % id)) // " because it is not filled with & - &another universe") - end if - - ! Read number of translation parameters - n = node_word_count(node_cell, "translation") - if (n /= 3) then - call fatal_error("Incorrect number of translation parameters on & - &cell " // to_str(c % id)) - end if - - ! Copy translation vector - allocate(c % translation(3)) - call get_node_array(node_cell, "translation", c % translation) - end if - - ! Read cell temperatures. If the temperature is not specified, set it to - ! ERROR_REAL for now. During initialization we'll replace ERROR_REAL with - ! the temperature from the material data. - if (check_for_node(node_cell, "temperature")) then - n = node_word_count(node_cell, "temperature") - if (n > 0) then - ! Make sure this is a "normal" cell. - if (c % material(1) == NONE) call fatal_error("Cell " & - // trim(to_str(c % id)) // " was specified with a temperature & - &but no material. Temperature specification is only valid for & - &cells filled with a material.") - - ! Copy in temperatures - allocate(c % sqrtkT(n)) - call get_node_array(node_cell, "temperature", c % sqrtkT) - - ! Make sure all temperatues are positive - do j = 1, size(c % sqrtkT) - if (c % sqrtkT(j) < ZERO) call fatal_error("Cell " & - // trim(to_str(c % id)) // " was specified with a negative & - &temperature. All cell temperatures must be non-negative.") - end do - - ! Convert to sqrt(kT) - c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) - else - allocate(c % sqrtkT(1)) - c % sqrtkT(1) = ERROR_REAL - end if - else - allocate(c % sqrtkT(1)) - c % sqrtkT = ERROR_REAL - end if - - ! Add cell to dictionary - call cell_dict % add_key(c % id, i) - - ! For cells, we also need to check if there's a new universe -- - ! also for every cell add 1 to the count of cells for the - ! specified universe - univ_id = c % universe - if (.not. cells_in_univ_dict % has_key(univ_id)) then - n_universes = n_universes + 1 - n_cells_in_univ = 1 - call universe_dict % add_key(univ_id, n_universes) - call univ_ids % push_back(univ_id) - else - n_cells_in_univ = 1 + cells_in_univ_dict % get_key(univ_id) - end if - call cells_in_univ_dict % add_key(univ_id, n_cells_in_univ) - - end do - ! ========================================================================== ! READ SURFACES FROM GEOMETRY.XML @@ -1688,6 +1464,279 @@ contains end if end do + ! ========================================================================== + ! READ CELLS FROM GEOMETRY.XML + + ! Get pointer to list of XML + call get_node_list(root, "cell", node_cell_list) + + ! Get number of tags + n_cells = size(node_cell_list) + + ! Check for no cells + if (n_cells == 0) then + call fatal_error("No cells found in geometry.xml!") + end if + + ! Allocate cells array + allocate(cells(n_cells)) + + if (check_overlaps) then + allocate(overlap_check_cnt(n_cells)) + overlap_check_cnt = 0 + end if + + n_universes = 0 + do i = 1, n_cells + c => cells(i) + + ! Initialize distribcell instances and distribcell index + c % instances = 0 + c % distribcell_index = NONE + + ! Get pointer to i-th cell node + node_cell = node_cell_list(i) + + ! Copy data into cells + if (check_for_node(node_cell, "id")) then + call get_node_value(node_cell, "id", c % id) + else + call fatal_error("Must specify id of cell in geometry XML file.") + end if + + ! Copy cell name + if (check_for_node(node_cell, "name")) then + call get_node_value(node_cell, "name", c % name) + end if + + if (check_for_node(node_cell, "universe")) then + call get_node_value(node_cell, "universe", c % universe) + else + c % universe = 0 + end if + if (check_for_node(node_cell, "fill")) then + call get_node_value(node_cell, "fill", c % fill) + if (find(fill_univ_ids, c % fill) == -1) & + call fill_univ_ids % push_back(c % fill) + else + c % fill = NONE + end if + + ! Check to make sure 'id' hasn't been used + if (cell_dict % has_key(c % id)) then + call fatal_error("Two or more cells use the same unique ID: " & + // to_str(c % id)) + end if + + ! Read material + if (check_for_node(node_cell, "material")) then + n_mats = node_word_count(node_cell, "material") + + if (n_mats > 0) then + allocate(sarray(n_mats)) + call get_node_array(node_cell, "material", sarray) + + allocate(c % material(n_mats)) + do j = 1, n_mats + select case(trim(to_lower(sarray(j)))) + case ('void') + c % material(j) = MATERIAL_VOID + case default + c % material(j) = int(str_to_int(sarray(j)), 4) + + ! Check for error + if (c % material(j) == ERROR_INT) then + call fatal_error("Invalid material specified on cell " & + // to_str(c % id)) + end if + end select + end do + + deallocate(sarray) + + else + allocate(c % material(1)) + c % material(1) = NONE + end if + + else + allocate(c % material(1)) + c % material(1) = NONE + end if + + ! Check to make sure that either material or fill was specified + if (c % material(1) == NONE .and. c % fill == NONE) then + call fatal_error("Neither material nor fill was specified for cell " & + // trim(to_str(c % id))) + end if + + ! Check to make sure that both material and fill haven't been + ! specified simultaneously + if (c % material(1) /= NONE .and. c % fill /= NONE) then + call fatal_error("Cannot specify material and fill simultaneously") + end if + + ! Check for region specification (also under deprecated name surfaces) + if (check_for_node(node_cell, "surfaces")) then + call warning("The use of 'surfaces' is deprecated and will be & + &disallowed in a future release. Use 'region' instead. The & + &openmc-update-inputs utility can be used to automatically & + &update geometry.xml files.") + region_spec = node_value_string(node_cell, "surfaces") + call get_node_value(node_cell, "surfaces", region_spec) + elseif (check_for_node(node_cell, "region")) then + region_spec = node_value_string(node_cell, "region") + else + region_spec = '' + end if + + if (len_trim(region_spec) > 0) then + ! Create surfaces array from string + call tokenize(region_spec, tokens) + + ! Convert user IDs to surface indices + do j = 1, tokens % size() + id = tokens % data(j) + if (id < OP_UNION) then + if (surface_dict % has_key(abs(id))) then + k = surface_dict % get_key(abs(id)) + tokens % data(j) = sign(k, id) + end if + end if + end do + + ! Use shunting-yard algorithm to determine RPN for surface algorithm + call generate_rpn(c%id, tokens, rpn) + + ! Copy region spec and RPN form to cell arrays + allocate(c % region(tokens%size())) + allocate(c % rpn(rpn%size())) + c % region(:) = tokens%data(1:tokens%size()) + c % rpn(:) = rpn%data(1:rpn%size()) + + call tokens%clear() + call rpn%clear() + end if + if (.not. allocated(c%region)) allocate(c%region(0)) + if (.not. allocated(c%rpn)) allocate(c%rpn(0)) + + ! Check if this is a simple cell + if (any(c%rpn == OP_COMPLEMENT) .or. any(c%rpn == OP_UNION)) then + c%simple = .false. + else + c%simple = .true. + end if + + ! Rotation matrix + if (check_for_node(node_cell, "rotation")) then + ! Rotations can only be applied to cells that are being filled with + ! another universe + if (c % fill == NONE) then + call fatal_error("Cannot apply a rotation to cell " // trim(to_str(& + &c % id)) // " because it is not filled with another universe") + end if + + ! Read number of rotation parameters + n = node_word_count(node_cell, "rotation") + if (n /= 3) then + call fatal_error("Incorrect number of rotation parameters on cell " & + // to_str(c % id)) + end if + + ! Copy rotation angles in x,y,z directions + allocate(c % rotation(3)) + call get_node_array(node_cell, "rotation", c % rotation) + phi = -c % rotation(1) * PI/180.0_8 + theta = -c % rotation(2) * PI/180.0_8 + psi = -c % rotation(3) * PI/180.0_8 + + ! Calculate rotation matrix based on angles given + allocate(c % rotation_matrix(3,3)) + c % rotation_matrix = reshape((/ & + cos(theta)*cos(psi), cos(theta)*sin(psi), -sin(theta), & + -cos(phi)*sin(psi) + sin(phi)*sin(theta)*cos(psi), & + cos(phi)*cos(psi) + sin(phi)*sin(theta)*sin(psi), & + sin(phi)*cos(theta), & + sin(phi)*sin(psi) + cos(phi)*sin(theta)*cos(psi), & + -sin(phi)*cos(psi) + cos(phi)*sin(theta)*sin(psi), & + cos(phi)*cos(theta) /), (/ 3,3 /)) + end if + + ! Translation vector + if (check_for_node(node_cell, "translation")) then + ! Translations can only be applied to cells that are being filled with + ! another universe + if (c % fill == NONE) then + call fatal_error("Cannot apply a translation to cell " & + // trim(to_str(c % id)) // " because it is not filled with & + &another universe") + end if + + ! Read number of translation parameters + n = node_word_count(node_cell, "translation") + if (n /= 3) then + call fatal_error("Incorrect number of translation parameters on & + &cell " // to_str(c % id)) + end if + + ! Copy translation vector + allocate(c % translation(3)) + call get_node_array(node_cell, "translation", c % translation) + end if + + ! Read cell temperatures. If the temperature is not specified, set it to + ! ERROR_REAL for now. During initialization we'll replace ERROR_REAL with + ! the temperature from the material data. + if (check_for_node(node_cell, "temperature")) then + n = node_word_count(node_cell, "temperature") + if (n > 0) then + ! Make sure this is a "normal" cell. + if (c % material(1) == NONE) call fatal_error("Cell " & + // trim(to_str(c % id)) // " was specified with a temperature & + &but no material. Temperature specification is only valid for & + &cells filled with a material.") + + ! Copy in temperatures + allocate(c % sqrtkT(n)) + call get_node_array(node_cell, "temperature", c % sqrtkT) + + ! Make sure all temperatues are positive + do j = 1, size(c % sqrtkT) + if (c % sqrtkT(j) < ZERO) call fatal_error("Cell " & + // trim(to_str(c % id)) // " was specified with a negative & + &temperature. All cell temperatures must be non-negative.") + end do + + ! Convert to sqrt(kT) + c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) + else + allocate(c % sqrtkT(1)) + c % sqrtkT(1) = ERROR_REAL + end if + else + allocate(c % sqrtkT(1)) + c % sqrtkT = ERROR_REAL + end if + + ! Add cell to dictionary + call cell_dict % add_key(c % id, i) + + ! For cells, we also need to check if there's a new universe -- + ! also for every cell add 1 to the count of cells for the + ! specified universe + univ_id = c % universe + if (.not. cells_in_univ_dict % has_key(univ_id)) then + n_universes = n_universes + 1 + n_cells_in_univ = 1 + call universe_dict % add_key(univ_id, n_universes) + call univ_ids % push_back(univ_id) + else + n_cells_in_univ = 1 + cells_in_univ_dict % get_key(univ_id) + end if + call cells_in_univ_dict % add_key(univ_id, n_cells_in_univ) + + end do + ! ========================================================================== ! READ LATTICES FROM GEOMETRY.XML @@ -2071,11 +2120,8 @@ contains ! for errors and placing properly-formatted data in the right data structures !=============================================================================== - subroutine read_materials() + subroutine read_cross_sections_xml() integer :: i, j - type(VectorReal), allocatable :: nuc_temps(:) ! List of T to read for each nuclide - type(VectorReal), allocatable :: sab_temps(:) ! List of T to read for each S(a,b) - real(8), allocatable :: material_temps(:) logical :: file_exists character(MAX_FILE_LEN) :: env_variable character(MAX_LINE_LEN) :: filename @@ -2183,22 +2229,7 @@ contains end do end if - ! Parse data from materials.xml - call read_materials_xml(material_temps) - - ! Assign temperatures to cells that don't have temperatures already assigned - call assign_temperatures(material_temps) - - ! Determine desired temperatures for each nuclide and S(a,b) table - call get_temperatures(cells, nuc_temps, sab_temps) - - ! Read continuous-energy cross sections - if (run_CE .and. run_mode /= MODE_PLOTTING) then - call time_read_xs % start() - call read_ce_cross_sections(nuc_temps, sab_temps) - call time_read_xs % stop() - end if - end subroutine read_materials + end subroutine read_cross_sections_xml subroutine read_materials_xml(material_temps) real(8), allocatable, intent(out) :: material_temps(:) @@ -3315,6 +3346,9 @@ contains ! Set filter id err = openmc_filter_set_id(i_start + i - 1, filter_id) + + ! Initialize filter + call f % obj % initialize() end do READ_FILTERS ! ========================================================================== @@ -3414,6 +3448,7 @@ contains else allocate(t % filter(n_filter)) end if + deallocate(temp_filter) ! ======================================================================= ! READ DATA FOR NUCLIDES @@ -3822,51 +3857,28 @@ contains ! Get pointer to mesh select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - i_mesh = filt % mesh m => meshes(filt % mesh) end select - ! Copy filter indices to temporary array - allocate(temp_filter(size(t % filter) + 1)) - temp_filter(1:size(t % filter)) = t % filter - - ! Move allocation back -- temp_filter becomes deallocated during - ! this call - call move_alloc(FROM=temp_filter, TO=t % filter) - n_filter = size(t % filter) - ! Extend the filters array so we can add a surface filter and ! mesh filter err = openmc_extend_filters(2, i_filt_start, i_filt_end) - ! Get index of the new mesh filter - i_filt = i_filt_start - ! Duplicate the mesh filter since other tallies might use this ! filter and we need to change the dimension - allocate(MeshFilter :: filters(i_filt) % obj) - select type(filt => filters(i_filt) % obj) - type is (MeshFilter) - filt % id = i_filt - filt % mesh = i_mesh + filters(i_filt_start) = filters(i_filter_mesh) - ! We need to increase the dimension by one since we also need - ! currents coming into and out of the boundary mesh cells. - filt % n_bins = product(m % dimension + 1) + ! We need to increase the dimension by one since we also need + ! currents coming into and out of the boundary mesh cells. + filters(i_filt_start) % obj % n_bins = product(m % dimension + 1) - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) - end select - t % filter(t % find_filter(FILTER_MESH)) = i_filt - - ! Get index of the new surface filter - i_filt = i_filt_end + ! Set ID + err = openmc_filter_set_id(i_filt_start, i_filt_start) ! Add surface filter - allocate(SurfaceFilter :: filters(i_filt) % obj) - select type (filt => filters(i_filt) % obj) + allocate(SurfaceFilter :: filters(i_filt_end) % obj) + select type (filt => filters(i_filt_end) % obj) type is (SurfaceFilter) - filt % id = i_filt filt % n_bins = 4 * m % n_dimension allocate(filt % surfaces(4 * m % n_dimension)) if (m % n_dimension == 1) then @@ -3881,11 +3893,23 @@ contains end if filt % current = .true. - ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + ! Set ID + err = openmc_filter_set_id(i_filt_end, i_filt_end) end select - t % find_filter(FILTER_SURFACE) = n_filter - t % filter(n_filter) = i_filt + + ! Copy filter indices to resized array + n_filter = size(t % filter) + allocate(temp_filter(n_filter + 1)) + temp_filter(1:size(t % filter)) = t % filter + n_filter = n_filter + 1 + + ! Set mesh and surface filters + temp_filter(t % find_filter(FILTER_MESH)) = i_filt_start + temp_filter(n_filter) = i_filt_end + + ! Set filters + err = openmc_tally_set_filters(i_start + i - 1, n_filter, temp_filter) + deallocate(temp_filter) end if case ('events') @@ -5289,7 +5313,7 @@ contains end if ! Use material default or global default temperature - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = cells(i) % material(j) if (material_temps(i_material) /= ERROR_REAL) then cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * & material_temps(i_material)) @@ -5428,4 +5452,129 @@ contains end if end subroutine check_data_version +!=============================================================================== +! ADJUST_INDICES changes the values for 'surfaces' for each cell and the +! material index assigned to each to the indices in the surfaces and material +! array rather than the unique IDs assigned to each surface and material. Also +! assigns boundary conditions to surfaces based on those read into the bc_dict +! dictionary +!=============================================================================== + + subroutine adjust_indices() + + integer :: i ! index for various purposes + integer :: j ! index for various purposes + integer :: k ! loop index for lattices + integer :: m ! loop index for lattices + integer :: lid ! lattice IDs + integer :: id ! user-specified id + class(Lattice), pointer :: lat => null() + + do i = 1, n_cells + ! ======================================================================= + ! ADJUST UNIVERSE INDEX FOR EACH CELL + associate (c => cells(i)) + + id = c%universe + if (universe_dict%has_key(id)) then + c%universe = universe_dict%get_key(id) + else + call fatal_error("Could not find universe " // trim(to_str(id)) & + &// " specified on cell " // trim(to_str(c%id))) + end if + + ! ======================================================================= + ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL + + if (c % material(1) == NONE) then + id = c % fill + if (universe_dict % has_key(id)) then + c % type = FILL_UNIVERSE + c % fill = universe_dict % get_key(id) + elseif (lattice_dict % has_key(id)) then + lid = lattice_dict % get_key(id) + c % type = FILL_LATTICE + c % fill = lid + else + call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& + // trim(to_str(c % id)) // " is neither a universe nor a & + &lattice.") + end if + else + do j = 1, size(c % material) + id = c % material(j) + if (id == MATERIAL_VOID) then + c % type = FILL_MATERIAL + else if (material_dict % has_key(id)) then + c % type = FILL_MATERIAL + c % material(j) = material_dict % get_key(id) + else + call fatal_error("Could not find material " // trim(to_str(id)) & + // " specified on cell " // trim(to_str(c % id))) + end if + end do + end if + end associate + end do + + ! ========================================================================== + ! ADJUST UNIVERSE INDICES FOR EACH LATTICE + + do i = 1, n_lattices + lat => lattices(i)%obj + select type (lat) + + type is (RectLattice) + do m = 1, lat%n_cells(3) + do k = 1, lat%n_cells(2) + do j = 1, lat%n_cells(1) + id = lat%universes(j,k,m) + if (universe_dict%has_key(id)) then + lat%universes(j,k,m) = universe_dict%get_key(id) + else + call fatal_error("Invalid universe number " & + &// trim(to_str(id)) // " specified on lattice " & + &// trim(to_str(lat%id))) + end if + end do + end do + end do + + type is (HexLattice) + do m = 1, lat%n_axial + do k = 1, 2*lat%n_rings - 1 + do j = 1, 2*lat%n_rings - 1 + if (j + k < lat%n_rings + 1) then + cycle + else if (j + k > 3*lat%n_rings - 1) then + cycle + end if + id = lat%universes(j, k, m) + if (universe_dict%has_key(id)) then + lat%universes(j, k, m) = universe_dict%get_key(id) + else + call fatal_error("Invalid universe number " & + &// trim(to_str(id)) // " specified on lattice " & + &// trim(to_str(lat%id))) + end if + end do + end do + end do + + end select + + if (lat%outer /= NO_OUTER_UNIVERSE) then + if (universe_dict%has_key(lat%outer)) then + lat%outer = universe_dict%get_key(lat%outer) + else + call fatal_error("Invalid universe number " & + &// trim(to_str(lat%outer)) & + &// " specified on lattice " // trim(to_str(lat%id))) + end if + end if + + end do + + end subroutine adjust_indices + end module input_xml diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 623ad2ee8..a111bc1c4 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -51,7 +51,7 @@ contains call write_message("Loading cross section data...", 5) ! Get temperatures - call get_temperatures(cells, temps) + call get_temperatures(temps) ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) @@ -233,7 +233,7 @@ contains kT = cells(i) % sqrtkT(1)**2 end if - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = cells(i) % material(j) ! Add temperature if it hasn't already been added if (find(kTs(i_material), kT) == -1) then diff --git a/src/simulation.F90 b/src/simulation.F90 index 9c8fb67bb..5ce9d4c36 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -18,7 +18,7 @@ module simulation use particle_header, only: Particle use random_lcg, only: set_particle_seed use source, only: initialize_source, sample_external_source - use state_point, only: write_state_point, write_source_point + use state_point, only: write_state_point, write_source_point, load_state_point use string, only: to_str use tally, only: accumulate_tallies, setup_active_tallies use tally_header, only: configure_tallies @@ -383,7 +383,13 @@ contains allocate(filter_matches(n_filters)) !$omp end parallel - if (.not. restart_run) call initialize_source() + ! If this is a restart run, load the state point data and binary source + ! file + if (restart_run) then + call load_state_point() + else + call initialize_source() + end if ! Display header if (master) then diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index d0f8adf07..b36d0035c 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -85,6 +85,7 @@ contains id = this % cell if (cell_dict % has_key(id)) then this % cell = cell_dict % get_key(id) + this % n_bins = cells(this % cell) % instances else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index fcb1660d6..cca6f4a58 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -89,7 +89,7 @@ module tally_header ! second dimension of the array is for the combination of filters ! (e.g. specific cell, specific energy group, etc.) - integer :: n_filter_bins + integer :: n_filter_bins = 1 integer :: total_score_bins real(C_DOUBLE), allocatable :: results(:,:,:) From a7e1c912df554f49a172967dba9721cbe9c6ac0b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 14:10:49 -0500 Subject: [PATCH 143/229] Read plots.xml with all the other XML files --- src/initialize.F90 | 16 +++++----------- src/input_xml.F90 | 10 ++++++++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index ced55d575..c2d5e3186 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -19,7 +19,7 @@ module initialize use global use hdf5_interface, only: file_open, read_attribute, file_close, & hdf5_bank_t, hdf5_integer8_t - use input_xml, only: read_input_xml, read_plots_xml + use input_xml, only: read_input_xml use material_header, only: Material use message_passing use mgxs_data, only: read_mgxs, create_macro_xs @@ -82,18 +82,12 @@ contains ! Read command line arguments call read_command_line() - ! Read XML input files - call read_input_xml() - - ! Initialize random number generator -- this has to be done after the input - ! files have been read in case the user specified a seed for the random - ! number generator - + ! Initialize random number generator -- if the user specifies a seed, it + ! will be re-initialized later call initialize_prng() - ! Read plots.xml if it exists -- this has to be done separate from the other - ! XML files because we need the PRNG to be initialized first - if (run_mode == MODE_PLOTTING) call read_plots_xml() + ! Read XML input files + call read_input_xml() ! Initialize distribcell_filters call prepare_distribcell() diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 0c3cc08c3..e7ccc1f7c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -24,7 +24,7 @@ module input_xml use multipole, only: multipole_read use output, only: write_message, title, header use plot_header - use random_lcg, only: prn, seed + use random_lcg, only: prn, seed, initialize_prng use surface_header use set_header, only: SetChar use stl_vector, only: VectorInt, VectorReal, VectorChar @@ -81,6 +81,9 @@ contains ! Normalize atom/weight percents if (run_mode /= MODE_PLOTTING) call normalize_ao() + ! Read plots.xml if it exists + if (run_mode == MODE_PLOTTING) call read_plots_xml() + end subroutine read_input_xml subroutine finalize_geometry(material_temps, nuc_temps, sab_temps) @@ -306,7 +309,10 @@ contains end if ! Copy random number seed if specified - if (check_for_node(root, "seed")) call get_node_value(root, "seed", seed) + if (check_for_node(root, "seed")) then + call get_node_value(root, "seed", seed) + call initialize_prng() + end if ! Number of bins for logarithmic grid if (check_for_node(root, "log_grid_bins")) then From ab2417575eeeebb978e46a6185762e1047d96a8b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 14:30:58 -0500 Subject: [PATCH 144/229] Move prepare_distribcells into read_input_xml --- src/initialize.F90 | 189 -------------------------------------------- src/input_xml.F90 | 191 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 190 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index c2d5e3186..7752b8643 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -12,8 +12,6 @@ module initialize use dict_header, only: DictIntInt, ElemKeyValueII use set_header, only: SetInt use error, only: fatal_error, warning - use geometry, only: calc_offsets, & - maximum_levels use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,& root_universe use global @@ -89,18 +87,6 @@ contains ! Read XML input files call read_input_xml() - ! Initialize distribcell_filters - call prepare_distribcell() - - ! Check to make sure there are not too many nested coordinate levels in the - ! geometry since the coordinate list is statically allocated for performance - ! reasons - if (maximum_levels(universes(root_universe)) > MAX_COORD) then - call fatal_error("Too many nested coordinate levels in the geometry. & - &Try increasing the maximum number of coordinate levels by & - &providing the CMake -Dmaxcoord= option.") - end if - if (run_mode /= MODE_PLOTTING) then ! Set up tally procedure pointers call init_tally_routines() @@ -490,179 +476,4 @@ contains end subroutine allocate_banks -!=============================================================================== -! PREPARE_DISTRIBCELL initializes any distribcell filters present and sets the -! offsets for distribcells -!=============================================================================== - - subroutine prepare_distribcell() - - integer :: i, j ! Tally, filter loop counters - logical :: distribcell_active ! Does simulation use distribcell? - integer, allocatable :: univ_list(:) ! Target offsets - integer, allocatable :: counts(:,:) ! Target count - logical, allocatable :: found(:,:) ! Target found - - ! Assume distribcell is not needed until proven otherwise. - distribcell_active = .false. - - ! We need distribcell if any tallies have distribcell filters. - do i = 1, n_tallies - do j = 1, size(tallies(i) % obj % filter) - select type(filt => filters(tallies(i) % obj % filter(j)) % obj) - type is (DistribcellFilter) - distribcell_active = .true. - end select - end do - end do - - ! We also need distribcell if any distributed materials or distributed - ! temperatues are present. - if (.not. distribcell_active) then - do i = 1, n_cells - if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then - distribcell_active = .true. - exit - end if - end do - end if - - ! If distribcell isn't used in this simulation then no more work left to do. - if (.not. distribcell_active) return - - ! Make sure the number of materials and temperatures matches the number of - ! cell instances. - do i = 1, n_cells - associate (c => cells(i)) - if (size(c % material) > 1) then - if (size(c % material) /= c % instances) then - call fatal_error("Cell " // trim(to_str(c % id)) // " was & - &specified with " // trim(to_str(size(c % material))) & - // " materials but has " // trim(to_str(c % instances)) & - // " distributed instances. The number of materials must & - &equal one or the number of instances.") - end if - end if - if (size(c % sqrtkT) > 1) then - if (size(c % sqrtkT) /= c % instances) then - call fatal_error("Cell " // trim(to_str(c % id)) // " was & - &specified with " // trim(to_str(size(c % sqrtkT))) & - // " temperatures but has " // trim(to_str(c % instances)) & - // " distributed instances. The number of temperatures must & - &equal one or the number of instances.") - end if - end if - end associate - end do - - ! Allocate offset maps at each level in the geometry - call allocate_offsets(univ_list, counts, found) - - ! Calculate offsets for each target distribcell - do i = 1, n_maps - do j = 1, n_universes - call calc_offsets(univ_list(i), i, universes(j), counts, found) - end do - end do - - end subroutine prepare_distribcell - -!=============================================================================== -! ALLOCATE_OFFSETS determines the number of maps needed and allocates required -! memory for distribcell offset tables -!=============================================================================== - - recursive subroutine allocate_offsets(univ_list, counts, found) - - integer, intent(out), allocatable :: univ_list(:) ! Target offsets - integer, intent(out), allocatable :: counts(:,:) ! Target count - logical, intent(out), allocatable :: found(:,:) ! Target found - - integer :: i, j, k ! Loop counters - type(SetInt) :: cell_list ! distribells to track - - ! Begin gathering list of cells in distribcell tallies - n_maps = 0 - - ! List all cells referenced in distribcell filters. - do i = 1, n_tallies - do j = 1, size(tallies(i) % obj % filter) - select type(filt => filters(tallies(i) % obj % filter(j)) % obj) - type is (DistribcellFilter) - call cell_list % add(filt % cell) - end select - end do - end do - - ! List all cells with multiple (distributed) materials or temperatures. - do i = 1, n_cells - if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then - call cell_list % add(i) - end if - end do - - ! Compute the number of unique universes containing these distribcells - ! to determine the number of offset tables to allocate - do i = 1, n_universes - do j = 1, size(universes(i) % cells) - if (cell_list % contains(universes(i) % cells(j))) then - n_maps = n_maps + 1 - end if - end do - end do - - ! Allocate the list of offset tables for each unique universe - allocate(univ_list(n_maps)) - - ! Allocate list to accumulate target distribcell counts in each universe - allocate(counts(n_universes, n_maps)) - counts(:,:) = 0 - - ! Allocate list to track if target distribcells are found in each universe - allocate(found(n_universes, n_maps)) - found(:,:) = .false. - - - ! Search through universes for distributed cells and assign each one a - ! unique distribcell array index. - k = 1 - do i = 1, n_universes - do j = 1, size(universes(i) % cells) - if (cell_list % contains(universes(i) % cells(j))) then - cells(universes(i) % cells(j)) % distribcell_index = k - univ_list(k) = universes(i) % id - k = k + 1 - end if - end do - end do - - ! Allocate the offset tables for lattices - do i = 1, n_lattices - associate(lat => lattices(i) % obj) - select type(lat) - - type is (RectLattice) - allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & - lat % n_cells(3))) - type is (HexLattice) - allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & - 2 * lat % n_rings - 1, lat % n_axial)) - end select - - lat % offset(:, :, :, :) = 0 - end associate - end do - - ! Allocate offset table for fill cells - do i = 1, n_cells - if (cells(i) % type /= FILL_MATERIAL) then - allocate(cells(i) % offset(n_maps)) - end if - end do - - ! Free up memory - call cell_list % clear() - - end subroutine allocate_offsets - end module initialize diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e7ccc1f7c..9f0b77b33 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,7 +11,8 @@ module input_xml use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning - use geometry, only: count_instance, neighbor_lists + use geometry, only: calc_offsets, maximum_levels, count_instance, & + neighbor_lists use geometry_header, only: Cell, Lattice, RectLattice, HexLattice, & get_temperatures, root_universe use global @@ -68,6 +69,10 @@ contains end if call read_tallies_xml() + + ! Initialize distribcell_filters + call prepare_distribcell() + if (cmfd_run) call configure_cmfd() if (.not. run_CE) then @@ -105,6 +110,15 @@ contains ! Determine desired txemperatures for each nuclide and S(a,b) table call get_temperatures(nuc_temps, sab_temps) + ! Check to make sure there are not too many nested coordinate levels in the + ! geometry since the coordinate list is statically allocated for performance + ! reasons + if (maximum_levels(universes(root_universe)) > MAX_COORD) then + call fatal_error("Too many nested coordinate levels in the geometry. & + &Try increasing the maximum number of coordinate levels by & + &providing the CMake -Dmaxcoord= option.") + end if + end subroutine finalize_geometry !=============================================================================== @@ -5583,4 +5597,179 @@ contains end subroutine adjust_indices +!=============================================================================== +! PREPARE_DISTRIBCELL initializes any distribcell filters present and sets the +! offsets for distribcells +!=============================================================================== + + subroutine prepare_distribcell() + + integer :: i, j ! Tally, filter loop counters + logical :: distribcell_active ! Does simulation use distribcell? + integer, allocatable :: univ_list(:) ! Target offsets + integer, allocatable :: counts(:,:) ! Target count + logical, allocatable :: found(:,:) ! Target found + + ! Assume distribcell is not needed until proven otherwise. + distribcell_active = .false. + + ! We need distribcell if any tallies have distribcell filters. + do i = 1, n_tallies + do j = 1, size(tallies(i) % obj % filter) + select type(filt => filters(tallies(i) % obj % filter(j)) % obj) + type is (DistribcellFilter) + distribcell_active = .true. + end select + end do + end do + + ! We also need distribcell if any distributed materials or distributed + ! temperatues are present. + if (.not. distribcell_active) then + do i = 1, n_cells + if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then + distribcell_active = .true. + exit + end if + end do + end if + + ! If distribcell isn't used in this simulation then no more work left to do. + if (.not. distribcell_active) return + + ! Make sure the number of materials and temperatures matches the number of + ! cell instances. + do i = 1, n_cells + associate (c => cells(i)) + if (size(c % material) > 1) then + if (size(c % material) /= c % instances) then + call fatal_error("Cell " // trim(to_str(c % id)) // " was & + &specified with " // trim(to_str(size(c % material))) & + // " materials but has " // trim(to_str(c % instances)) & + // " distributed instances. The number of materials must & + &equal one or the number of instances.") + end if + end if + if (size(c % sqrtkT) > 1) then + if (size(c % sqrtkT) /= c % instances) then + call fatal_error("Cell " // trim(to_str(c % id)) // " was & + &specified with " // trim(to_str(size(c % sqrtkT))) & + // " temperatures but has " // trim(to_str(c % instances)) & + // " distributed instances. The number of temperatures must & + &equal one or the number of instances.") + end if + end if + end associate + end do + + ! Allocate offset maps at each level in the geometry + call allocate_offsets(univ_list, counts, found) + + ! Calculate offsets for each target distribcell + do i = 1, n_maps + do j = 1, n_universes + call calc_offsets(univ_list(i), i, universes(j), counts, found) + end do + end do + + end subroutine prepare_distribcell + +!=============================================================================== +! ALLOCATE_OFFSETS determines the number of maps needed and allocates required +! memory for distribcell offset tables +!=============================================================================== + + recursive subroutine allocate_offsets(univ_list, counts, found) + + integer, intent(out), allocatable :: univ_list(:) ! Target offsets + integer, intent(out), allocatable :: counts(:,:) ! Target count + logical, intent(out), allocatable :: found(:,:) ! Target found + + integer :: i, j, k ! Loop counters + type(SetInt) :: cell_list ! distribells to track + + ! Begin gathering list of cells in distribcell tallies + n_maps = 0 + + ! List all cells referenced in distribcell filters. + do i = 1, n_tallies + do j = 1, size(tallies(i) % obj % filter) + select type(filt => filters(tallies(i) % obj % filter(j)) % obj) + type is (DistribcellFilter) + call cell_list % add(filt % cell) + end select + end do + end do + + ! List all cells with multiple (distributed) materials or temperatures. + do i = 1, n_cells + if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then + call cell_list % add(i) + end if + end do + + ! Compute the number of unique universes containing these distribcells + ! to determine the number of offset tables to allocate + do i = 1, n_universes + do j = 1, size(universes(i) % cells) + if (cell_list % contains(universes(i) % cells(j))) then + n_maps = n_maps + 1 + end if + end do + end do + + ! Allocate the list of offset tables for each unique universe + allocate(univ_list(n_maps)) + + ! Allocate list to accumulate target distribcell counts in each universe + allocate(counts(n_universes, n_maps)) + counts(:,:) = 0 + + ! Allocate list to track if target distribcells are found in each universe + allocate(found(n_universes, n_maps)) + found(:,:) = .false. + + + ! Search through universes for distributed cells and assign each one a + ! unique distribcell array index. + k = 1 + do i = 1, n_universes + do j = 1, size(universes(i) % cells) + if (cell_list % contains(universes(i) % cells(j))) then + cells(universes(i) % cells(j)) % distribcell_index = k + univ_list(k) = universes(i) % id + k = k + 1 + end if + end do + end do + + ! Allocate the offset tables for lattices + do i = 1, n_lattices + associate(lat => lattices(i) % obj) + select type(lat) + + type is (RectLattice) + allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & + lat % n_cells(3))) + type is (HexLattice) + allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & + 2 * lat % n_rings - 1, lat % n_axial)) + end select + + lat % offset(:, :, :, :) = 0 + end associate + end do + + ! Allocate offset table for fill cells + do i = 1, n_cells + if (cells(i) % type /= FILL_MATERIAL) then + allocate(cells(i) % offset(n_maps)) + end if + end do + + ! Free up memory + call cell_list % clear() + + end subroutine allocate_offsets + end module input_xml From 9caf6d6611e8c38ea2d4b0335c9282b160edfcf7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 14:53:12 -0500 Subject: [PATCH 145/229] Continue withering away openmc_init --- src/initialize.F90 | 120 +-------------------------------------------- src/input_xml.F90 | 22 +++++++-- src/simulation.F90 | 100 ++++++++++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 125 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index 7752b8643..258ac3b30 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -21,14 +21,11 @@ module initialize use material_header, only: Material use message_passing use mgxs_data, only: read_mgxs, create_macro_xs - use output, only: print_version, write_message, print_usage, & - print_plot + use output, only: print_version, write_message, print_usage use random_lcg, only: initialize_prng use string, only: to_str, starts_with, ends_with, str_to_int - use summary, only: write_summary use tally_header, only: TallyObject use tally_filter - use tally, only: init_tally_routines implicit none @@ -87,37 +84,9 @@ contains ! Read XML input files call read_input_xml() - if (run_mode /= MODE_PLOTTING) then - ! Set up tally procedure pointers - call init_tally_routines() - - ! Determine how much work each processor should do - call calculate_work() - - ! Allocate source bank, and for eigenvalue simulations also allocate the - ! fission bank - call allocate_banks() - - end if - - if (master) then - if (run_mode == MODE_PLOTTING) then - ! Display plotting information - if (verbosity >= 5) call print_plot() - else - ! Write summary information - if (output_summary) call write_summary() - end if - end if - ! Check for particle restart run if (particle_restart_run) run_mode = MODE_PARTICLE - ! Warn if overlap checking is on - if (master .and. check_overlaps .and. run_mode /= MODE_PLOTTING) then - call warning("Cell overlap checking is ON.") - end if - ! Stop initialization timer call time_initialize%stop() @@ -389,91 +358,4 @@ contains end subroutine read_command_line -!=============================================================================== -! CALCULATE_WORK determines how many particles each processor should simulate -!=============================================================================== - - subroutine calculate_work() - - integer :: i ! loop index - integer :: remainder ! Number of processors with one extra particle - integer(8) :: i_bank ! Running count of number of particles - integer(8) :: min_work ! Minimum number of particles on each proc - integer(8) :: work_i ! Number of particles on rank i - - allocate(work_index(0:n_procs)) - - ! Determine minimum amount of particles to simulate on each processor - min_work = n_particles/n_procs - - ! Determine number of processors that have one extra particle - remainder = int(mod(n_particles, int(n_procs,8)), 4) - - i_bank = 0 - work_index(0) = 0 - do i = 0, n_procs - 1 - ! Number of particles for rank i - if (i < remainder) then - work_i = min_work + 1 - else - work_i = min_work - end if - - ! Set number of particles - if (rank == i) work = work_i - - ! Set index into source bank for rank i - i_bank = i_bank + work_i - work_index(i+1) = i_bank - end do - - end subroutine calculate_work - -!=============================================================================== -! ALLOCATE_BANKS allocates memory for the fission and source banks -!=============================================================================== - - subroutine allocate_banks() - - integer :: alloc_err ! allocation error code - - ! Allocate source bank - allocate(source_bank(work), STAT=alloc_err) - - ! Check for allocation errors - if (alloc_err /= 0) then - call fatal_error("Failed to allocate source bank.") - end if - - if (run_mode == MODE_EIGENVALUE) then -#ifdef _OPENMP - ! If OpenMP is being used, each thread needs its own private fission - ! bank. Since the private fission banks need to be combined at the end of - ! a generation, there is also a 'master_fission_bank' that is used to - ! collect the sites from each thread. - - n_threads = omp_get_max_threads() - -!$omp parallel - thread_id = omp_get_thread_num() - - if (thread_id == 0) then - allocate(fission_bank(3*work)) - else - allocate(fission_bank(3*work/n_threads)) - end if -!$omp end parallel - allocate(master_fission_bank(3*work), STAT=alloc_err) -#else - allocate(fission_bank(3*work), STAT=alloc_err) -#endif - - ! Check for allocation errors - if (alloc_err /= 0) then - call fatal_error("Failed to allocate fission bank.") - end if - end if - - end subroutine allocate_banks - end module initialize diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 9f0b77b33..08fad7202 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -23,7 +23,7 @@ module input_xml use mgxs_data, only: create_macro_xs, read_mgxs use mgxs_header use multipole, only: multipole_read - use output, only: write_message, title, header + use output, only: write_message, title, header, print_plot use plot_header use random_lcg, only: prn, seed, initialize_prng use surface_header @@ -32,6 +32,7 @@ module input_xml use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & zero_padded + use summary, only: write_summary use tally_header, only: openmc_extend_tallies, openmc_tally_set_type use tally_filter_header, only: TallyFilterContainer use tally_filter @@ -83,11 +84,22 @@ contains call time_read_xs % stop() end if - ! Normalize atom/weight percents - if (run_mode /= MODE_PLOTTING) call normalize_ao() + if (run_mode == MODE_PLOTTING) then + ! Read plots.xml if it exists + call read_plots_xml() + if (master .and. verbosity >= 5) call print_plot() - ! Read plots.xml if it exists - if (run_mode == MODE_PLOTTING) call read_plots_xml() + else + ! Normalize atom/weight percents + call normalize_ao() + + ! Write summary information + if (master .and. output_summary) call write_summary() + + ! Warn if overlap checking is on + if (master .and. check_overlaps) & + call warning("Cell overlap checking is ON.") + end if end subroutine read_input_xml diff --git a/src/simulation.F90 b/src/simulation.F90 index 5ce9d4c36..36804b9a0 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -20,7 +20,8 @@ module simulation use source, only: initialize_source, sample_external_source use state_point, only: write_state_point, write_source_point, load_state_point use string, only: to_str - use tally, only: accumulate_tallies, setup_active_tallies + use tally, only: accumulate_tallies, setup_active_tallies, & + init_tally_routines use tally_header, only: configure_tallies use trigger, only: check_triggers use tracking, only: transport @@ -372,6 +373,16 @@ contains subroutine initialize_simulation() + ! Set up tally procedure pointers + call init_tally_routines() + + ! Determine how much work each processor should do + call calculate_work() + + ! Allocate source bank, and for eigenvalue simulations also allocate the + ! fission bank + call allocate_banks() + ! Allocate tally results arrays if they're not allocated yet call configure_tallies() @@ -473,4 +484,91 @@ contains end subroutine finalize_simulation +!=============================================================================== +! CALCULATE_WORK determines how many particles each processor should simulate +!=============================================================================== + + subroutine calculate_work() + + integer :: i ! loop index + integer :: remainder ! Number of processors with one extra particle + integer(8) :: i_bank ! Running count of number of particles + integer(8) :: min_work ! Minimum number of particles on each proc + integer(8) :: work_i ! Number of particles on rank i + + allocate(work_index(0:n_procs)) + + ! Determine minimum amount of particles to simulate on each processor + min_work = n_particles/n_procs + + ! Determine number of processors that have one extra particle + remainder = int(mod(n_particles, int(n_procs,8)), 4) + + i_bank = 0 + work_index(0) = 0 + do i = 0, n_procs - 1 + ! Number of particles for rank i + if (i < remainder) then + work_i = min_work + 1 + else + work_i = min_work + end if + + ! Set number of particles + if (rank == i) work = work_i + + ! Set index into source bank for rank i + i_bank = i_bank + work_i + work_index(i+1) = i_bank + end do + + end subroutine calculate_work + +!=============================================================================== +! ALLOCATE_BANKS allocates memory for the fission and source banks +!=============================================================================== + + subroutine allocate_banks() + + integer :: alloc_err ! allocation error code + + ! Allocate source bank + allocate(source_bank(work), STAT=alloc_err) + + ! Check for allocation errors + if (alloc_err /= 0) then + call fatal_error("Failed to allocate source bank.") + end if + + if (run_mode == MODE_EIGENVALUE) then +#ifdef _OPENMP + ! If OpenMP is being used, each thread needs its own private fission + ! bank. Since the private fission banks need to be combined at the end of + ! a generation, there is also a 'master_fission_bank' that is used to + ! collect the sites from each thread. + + n_threads = omp_get_max_threads() + +!$omp parallel + thread_id = omp_get_thread_num() + + if (thread_id == 0) then + allocate(fission_bank(3*work)) + else + allocate(fission_bank(3*work/n_threads)) + end if +!$omp end parallel + allocate(master_fission_bank(3*work), STAT=alloc_err) +#else + allocate(fission_bank(3*work), STAT=alloc_err) +#endif + + ! Check for allocation errors + if (alloc_err /= 0) then + call fatal_error("Failed to allocate fission bank.") + end if + end if + + end subroutine allocate_banks + end module simulation From d796ed14561e5e71eb3450ee9cb70e33c80b44f8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 16:18:55 -0500 Subject: [PATCH 146/229] Move simulation settings into a separate module --- CMakeLists.txt | 1 + src/global.F90 | 154 ++------------------------------- src/tallies/trigger_header.F90 | 7 +- src/timer_header.F90 | 16 ++++ 4 files changed, 27 insertions(+), 151 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0bcd1b1b..86bc20f59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,6 +359,7 @@ set(LIBOPENMC_FORTRAN_SRC src/secondary_nbody.F90 src/secondary_uncorrelated.F90 src/set_header.F90 + src/settings.F90 src/simulation.F90 src/source.F90 src/source_header.F90 diff --git a/src/global.F90 b/src/global.F90 index 2ebf1b346..1668bee14 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -9,11 +9,7 @@ module global use bank_header, only: Bank use cmfd_header use constants - use set_header, only: SetInt use stl_vector, only: VectorInt - use source_header, only: SourceDistribution - use trigger_header, only: KTrigger - use timer_header, only: Timer ! Inherit module variables from other modules use geometry_header @@ -26,8 +22,13 @@ module global use surface_header use tally_filter_header use tally_header + use timer_header + use trigger_header use volume_header + ! Inherit settings + use settings + implicit none ! ============================================================================ @@ -36,38 +37,8 @@ module global ! Number of lost particles integer :: n_lost_particles - ! ============================================================================ - ! ENERGY TREATMENT RELATED VARIABLES - logical :: run_CE = .true. ! Run in CE mode? - - ! ============================================================================ - ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES - - ! Unreoslved resonance probablity tables - logical :: urr_ptables_on = .true. - - ! Default temperature and method for choosing temperatures - integer :: temperature_method = TEMPERATURE_NEAREST - logical :: temperature_multipole = .false. - real(8) :: temperature_tolerance = 10.0_8 - real(8) :: temperature_default = 293.6_8 - real(8) :: temperature_range(2) = [ZERO, ZERO] - - integer :: n_log_bins ! number of bins for logarithmic grid real(8) :: log_spacing ! spacing on logarithmic grid - ! ============================================================================ - ! MULTI-GROUP CROSS SECTION RELATED VARIABLES - - ! Maximum Data Order - integer :: max_order - - ! Whether or not to convert Legendres to tabulars - logical :: legendre_to_tabular = .true. - - ! Number of points to use in the Legendre to tabular conversion - integer :: legendre_to_tabular_points = 33 - ! ============================================================================ ! TALLY-RELATED VARIABLES @@ -83,20 +54,9 @@ module global integer :: n_realizations = 0 ! # of independent realizations real(8) :: total_weight ! total starting particle weight in realization - ! Assume all tallies are spatially distinct - logical :: assume_separate = .false. - - ! Use confidence intervals for results instead of standard deviations - logical :: confidence_intervals = .false. - ! ============================================================================ ! EIGENVALUE SIMULATION VARIABLES - integer(8) :: n_particles = 0 ! # of particles per generation - integer :: n_batches ! # of batches - integer :: n_inactive ! # of inactive batches - integer :: n_active ! # of active batches - integer :: gen_per_batch = 1 ! # of generations per batch integer :: current_batch ! current batch integer :: current_gen ! current generation within a batch integer :: total_gen = 0 ! total number of generations simulated @@ -104,16 +64,8 @@ module global ! ============================================================================ ! TALLY PRECISION TRIGGER VARIABLES - integer :: n_max_batches ! max # of batches - integer :: n_batch_interval = 1 ! batch interval for triggers - logical :: pred_batches = .false. ! predict batches for triggers - logical :: trigger_on = .false. ! flag for turning triggers on/off - type(KTrigger) :: keff_trigger ! trigger for k-effective logical :: satisfy_triggers = .false. ! whether triggers are satisfied - ! External source - type(SourceDistribution), allocatable :: external_source(:) - ! Source and fission bank type(Bank), allocatable, target :: source_bank(:) type(Bank), allocatable, target :: fission_bank(:) @@ -134,21 +86,12 @@ module global real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength ! Shannon entropy - logical :: entropy_on = .false. real(8), allocatable :: entropy(:) ! shannon entropy at each generation real(8), allocatable :: entropy_p(:,:,:,:) ! % of source sites in each cell - type(RegularMesh), pointer :: entropy_mesh ! Uniform fission source weighting - logical :: ufs = .false. - type(RegularMesh), pointer :: ufs_mesh => null() real(8), allocatable :: source_frac(:,:,:,:) - ! Write source at end of simulation - logical :: source_separate = .false. - logical :: source_write = .true. - logical :: source_latest = .false. - ! ============================================================================ ! PARALLEL PROCESSING VARIABLES @@ -160,106 +103,19 @@ module global ! No reduction at end of batch logical :: reduce_tallies = .true. - ! ============================================================================ - ! TIMING VARIABLES - - type(Timer) :: time_total ! timer for total run - type(Timer) :: time_initialize ! timer for initialization - type(Timer) :: time_read_xs ! timer for reading cross sections - type(Timer) :: time_unionize ! timer for material xs-energy grid union - type(Timer) :: time_bank ! timer for fission bank synchronization - type(Timer) :: time_bank_sample ! timer for fission bank sampling - type(Timer) :: time_bank_sendrecv ! timer for fission bank SEND/RECV - type(Timer) :: time_tallies ! timer for accumulate tallies - type(Timer) :: time_inactive ! timer for inactive batches - type(Timer) :: time_active ! timer for active batches - type(Timer) :: time_transport ! timer for transport only - type(Timer) :: time_finalize ! timer for finalization - - ! =========================================================================== - ! VARIANCE REDUCTION VARIABLES - - logical :: survival_biasing = .false. - real(8) :: weight_cutoff = 0.25_8 - real(8) :: energy_cutoff = ZERO - real(8) :: weight_survive = ONE - ! ============================================================================ ! MISCELLANEOUS VARIABLES - ! Mode to run in (fixed source, eigenvalue, plotting, etc) - integer :: run_mode = NONE - - ! Restart run - logical :: restart_run = .false. integer :: restart_batch - character(MAX_FILE_LEN) :: path_input ! Path to input file - character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml - character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library - character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source - character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point - character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point - character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart - character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory - - ! The verbosity controls how much information will be printed to the - ! screen and in logs - integer :: verbosity = 7 - ! Flag for enabling cell overlap checking during transport - logical :: check_overlaps = .false. integer(8), allocatable :: overlap_check_cnt(:) - ! Trace for single particle logical :: trace - integer :: trace_batch - integer :: trace_gen - integer(8) :: trace_particle - - ! Particle tracks - logical :: write_all_tracks = .false. - integer, allocatable :: track_identifiers(:,:) - - ! Particle restart run - logical :: particle_restart_run = .false. ! Number of distribcell maps integer :: n_maps - ! Write out initial source - logical :: write_initial_source = .false. - - ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE - logical :: create_fission_neutrons = .true. - - ! ============================================================================ - ! CMFD VARIABLES - - ! Is CMFD active - logical :: cmfd_run = .false. - - ! Information about state points to be written - integer :: n_state_points = 0 - type(SetInt) :: statepoint_batch - - ! Information about source points to be written - integer :: n_source_points = 0 - type(SetInt) :: sourcepoint_batch - - ! Various output options - logical :: output_summary = .true. - logical :: output_tallies = .true. - - ! ============================================================================ - ! RESONANCE SCATTERING VARIABLES - - logical :: res_scat_on = .false. ! is resonance scattering treated? - integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method - real(8) :: res_scat_energy_min = 0.01_8 - real(8) :: res_scat_energy_max = 1000.0_8 - character(10), allocatable :: res_scat_nuclides(:) - !$omp threadprivate(fission_bank, n_bank, trace, thread_id, current_work) contains diff --git a/src/tallies/trigger_header.F90 b/src/tallies/trigger_header.F90 index 96421314c..87507224a 100644 --- a/src/tallies/trigger_header.F90 +++ b/src/tallies/trigger_header.F90 @@ -3,12 +3,13 @@ module trigger_header use constants, only: NONE, N_FILTER_TYPES, ZERO implicit none + private !=============================================================================== ! TRIGGEROBJECT stores the variance, relative error and standard deviation ! for some user-specified trigger. !=============================================================================== - type TriggerObject + type, public :: TriggerObject integer :: type ! "variance", "std_dev" or "rel_err" real(8) :: threshold ! a convergence threshold character(len=52) :: score_name ! the name of the score @@ -21,9 +22,11 @@ module trigger_header !=============================================================================== ! KTRIGGER describes a user-specified precision trigger for k-effective !=============================================================================== - type KTrigger + type, public :: KTrigger integer :: trigger_type = 0 real(8) :: threshold = ZERO end type KTrigger + type(KTrigger), public :: keff_trigger ! trigger for k-effective + end module trigger_header diff --git a/src/timer_header.F90 b/src/timer_header.F90 index 6f9785d56..a147a551d 100644 --- a/src/timer_header.F90 +++ b/src/timer_header.F90 @@ -22,6 +22,22 @@ module timer_header procedure :: reset => timer_reset end type Timer + ! ============================================================================ + ! TIMING VARIABLES + + type(Timer) :: time_total ! timer for total run + type(Timer) :: time_initialize ! timer for initialization + type(Timer) :: time_read_xs ! timer for reading cross sections + type(Timer) :: time_unionize ! timer for material xs-energy grid union + type(Timer) :: time_bank ! timer for fission bank synchronization + type(Timer) :: time_bank_sample ! timer for fission bank sampling + type(Timer) :: time_bank_sendrecv ! timer for fission bank SEND/RECV + type(Timer) :: time_tallies ! timer for accumulate tallies + type(Timer) :: time_inactive ! timer for inactive batches + type(Timer) :: time_active ! timer for active batches + type(Timer) :: time_transport ! timer for transport only + type(Timer) :: time_finalize ! timer for finalization + contains !=============================================================================== From 06afa17c796091928f629a2fd175ac9cf1aabca1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 22:29:36 -0500 Subject: [PATCH 147/229] Move more tally-related variables to tally_header --- src/global.F90 | 19 ------------------- src/tallies/tally_header.F90 | 13 +++++++++++++ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index 1668bee14..5940b6a01 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -9,7 +9,6 @@ module global use bank_header, only: Bank use cmfd_header use constants - use stl_vector, only: VectorInt ! Inherit module variables from other modules use geometry_header @@ -39,21 +38,6 @@ module global real(8) :: log_spacing ! spacing on logarithmic grid - ! ============================================================================ - ! TALLY-RELATED VARIABLES - - ! Active tally lists - type(VectorInt) :: active_analog_tallies - type(VectorInt) :: active_tracklength_tallies - type(VectorInt) :: active_current_tallies - type(VectorInt) :: active_collision_tallies - type(VectorInt) :: active_tallies - type(VectorInt) :: active_surface_tallies - - ! Normalization for statistics - integer :: n_realizations = 0 ! # of independent realizations - real(8) :: total_weight ! total starting particle weight in realization - ! ============================================================================ ! EIGENVALUE SIMULATION VARIABLES @@ -100,9 +84,6 @@ module global integer :: thread_id ! ID of a given thread #endif - ! No reduction at end of batch - logical :: reduce_tallies = .true. - ! ============================================================================ ! MISCELLANEOUS VARIABLES diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index cca6f4a58..f13768b36 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -8,6 +8,7 @@ module tally_header use error use dict_header, only: DictIntInt use nuclide_header, only: nuclide_dict + use stl_vector, only: VectorInt use string, only: to_lower, to_f_string, str_to_int use tally_filter_header, only: TallyFilterContainer, filters, n_filters use tally_filter @@ -145,6 +146,18 @@ module tally_header !$omp threadprivate(global_tally_collision, global_tally_absorption, & !$omp& global_tally_tracklength, global_tally_leakage) + ! Active tally lists + type(VectorInt), public :: active_analog_tallies + type(VectorInt), public :: active_tracklength_tallies + type(VectorInt), public :: active_current_tallies + type(VectorInt), public :: active_collision_tallies + type(VectorInt), public :: active_tallies + type(VectorInt), public :: active_surface_tallies + + ! Normalization for statistics + integer, public :: n_realizations = 0 ! # of independent realizations + real(8), public :: total_weight ! total starting particle weight in realization + contains subroutine tally_write_results_hdf5(this, group_id) From deacc5d5a56c1d31e802658dd97dbe88faf86f80 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 17 Aug 2017 22:40:47 -0500 Subject: [PATCH 148/229] Make sure source/fission bank are deallocated before allocating --- src/simulation.F90 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/simulation.F90 b/src/simulation.F90 index 36804b9a0..914fa9a9c 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -496,7 +496,7 @@ contains integer(8) :: min_work ! Minimum number of particles on each proc integer(8) :: work_i ! Number of particles on rank i - allocate(work_index(0:n_procs)) + if (.not. allocated(work_index)) allocate(work_index(0:n_procs)) ! Determine minimum amount of particles to simulate on each processor min_work = n_particles/n_procs @@ -533,6 +533,7 @@ contains integer :: alloc_err ! allocation error code ! Allocate source bank + if (allocated(source_bank)) deallocate(source_bank) allocate(source_bank(work), STAT=alloc_err) ! Check for allocation errors @@ -541,6 +542,7 @@ contains end if if (run_mode == MODE_EIGENVALUE) then + #ifdef _OPENMP ! If OpenMP is being used, each thread needs its own private fission ! bank. Since the private fission banks need to be combined at the end of @@ -552,14 +554,17 @@ contains !$omp parallel thread_id = omp_get_thread_num() + if (allocated(fission_bank)) deallocate(fission_bank) if (thread_id == 0) then allocate(fission_bank(3*work)) else allocate(fission_bank(3*work/n_threads)) end if !$omp end parallel + if (allocated(master_fission_bank)) deallocate(master_fission_bank) allocate(master_fission_bank(3*work), STAT=alloc_err) #else + if (allocated(fission_bank)) deallocate(fission_bank) allocate(fission_bank(3*work), STAT=alloc_err) #endif From 42c2a8739c74f8545f64c1942f7a06079ebda531 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 18 Aug 2017 06:57:46 -0500 Subject: [PATCH 149/229] Move openmc_tally_set_type to tally module --- src/api.F90 | 1 + src/cmfd_input.F90 | 14 ++------------ src/input_xml.F90 | 23 +++++++++++------------ src/tallies/tally.F90 | 32 ++++++++++++++++++++++++++++++++ src/tallies/tally_header.F90 | 30 ------------------------------ 5 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 77b259fa4..af00cdd83 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -20,6 +20,7 @@ module openmc_api use tally_header use tally_filter_header use tally_filter + use tally, only: openmc_tally_set_type use simulation, only: openmc_run use string, only: to_f_string use volume_calc, only: openmc_calculate_volumes diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index b80991474..f44048665 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -17,20 +17,9 @@ contains subroutine configure_cmfd() - use message_passing, only: master - - integer :: color ! color group of processor - ! Read in cmfd input file call read_cmfd_xml() - ! Assign color - if (master) then - color = 1 - else - color = 2 - end if - ! Initialize timers call time_cmfd % reset() call time_cmfdbuild % reset() @@ -251,7 +240,8 @@ contains use error, only: fatal_error, warning use mesh_header, only: RegularMesh, openmc_extend_meshes use string - use tally_header, only: openmc_extend_tallies, openmc_tally_set_type + use tally, only: openmc_tally_set_type + use tally_header, only: openmc_extend_tallies use tally_filter_header use tally_filter use xml_interface diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 08fad7202..5f24c9c40 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -33,7 +33,8 @@ module input_xml starts_with, ends_with, tokenize, split_string, & zero_padded use summary, only: write_summary - use tally_header, only: openmc_extend_tallies, openmc_tally_set_type + use tally, only: openmc_tally_set_type + use tally_header, only: openmc_extend_tallies use tally_filter_header, only: TallyFilterContainer use tally_filter use xml_interface @@ -62,10 +63,16 @@ contains ! Set up neighbor lists, convert user IDs -> indices, assign temperatures call finalize_geometry(material_temps, nuc_temps, sab_temps) - ! Read continuous-energy cross sections - if (run_CE .and. run_mode /= MODE_PLOTTING) then + if (run_mode /= MODE_PLOTTING) then call time_read_xs % start() - call read_ce_cross_sections(nuc_temps, sab_temps) + if (run_CE) then + ! Read continuous-energy cross sections + call read_ce_cross_sections(nuc_temps, sab_temps) + else + ! Create material macroscopic data for MGXS + call read_mgxs() + call create_macro_xs() + end if call time_read_xs % stop() end if @@ -76,14 +83,6 @@ contains if (cmfd_run) call configure_cmfd() - if (.not. run_CE) then - ! Create material macroscopic data for MGXS - call time_read_xs % start() - call read_mgxs() - call create_macro_xs() - call time_read_xs % stop() - end if - if (run_mode == MODE_PLOTTING) then ! Read plots.xml if it exists call read_plots_xml() diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index c97ff01e1..0ed9b47e7 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4419,4 +4419,36 @@ contains end subroutine setup_active_tallies +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_tally_set_type(index, type) result(err) bind(C) + ! Set the type of the tally + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(in) :: type(*) + integer(C_INT) :: err + + character(:), allocatable :: type_ + + ! Convert C string to Fortran string + type_ = to_f_string(type) + + err = 0 + if (index >= 1 .and. index <= n_tallies) then + if (allocated(tallies(index) % obj)) then + err = E_ALREADY_ALLOCATED + else + select case (type_) + case ('generic') + allocate(TallyObject :: tallies(index) % obj) + case default + err = E_UNASSIGNED + end select + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_type + end module tally diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index f13768b36..596cf42c5 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -26,7 +26,6 @@ module tally_header public :: openmc_tally_set_filters public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores - public :: openmc_tally_set_type !=============================================================================== ! TALLYDERIVATIVE describes a first-order derivative that can be applied to @@ -713,33 +712,4 @@ contains end if end function openmc_tally_set_scores - - function openmc_tally_set_type(index, type) result(err) bind(C) - ! Set the type of the tally - integer(C_INT32_T), value, intent(in) :: index - character(kind=C_CHAR), intent(in) :: type(*) - integer(C_INT) :: err - - character(:), allocatable :: type_ - - ! Convert C string to Fortran string - type_ = to_f_string(type) - - err = 0 - if (index >= 1 .and. index <= n_tallies) then - if (allocated(tallies(index) % obj)) then - err = E_ALREADY_ALLOCATED - else - select case (type_) - case ('generic') - allocate(TallyObject :: tallies(index) % obj) - case default - err = E_UNASSIGNED - end select - end if - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_tally_set_type - end module tally_header From 3ebe4abe9ac718224d18828160dc66bd5713d19e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 18 Aug 2017 09:50:29 -0500 Subject: [PATCH 150/229] Make set_filters a type-bound procedure on TallyObject --- src/tallies/tally_header.F90 | 164 +++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 75 deletions(-) diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 596cf42c5..f97df50b8 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -110,6 +110,7 @@ module tally_header procedure :: read_results_hdf5 => tally_read_results_hdf5 procedure :: write_results_hdf5 => tally_write_results_hdf5 procedure :: allocate_results => tally_allocate_results + procedure :: set_filters => tally_set_filters end type TallyObject type, public :: TallyContainer @@ -254,6 +255,89 @@ contains end subroutine tally_allocate_results + function tally_set_filters(this, filter_indices) result(err) + class(TallyObject), intent(inout) :: this + integer(C_INT32_T), intent(in) :: filter_indices(:) + integer(C_INT) :: err + + integer :: i ! index in t % filter/stride + integer :: j ! index in t % find_filter + integer :: k ! index in global filters array + integer :: n ! number of filters + integer :: stride ! filter stride + + err = 0 + this % find_filter(:) = 0 + n = size(filter_indices) + do i = 1, n + k = filter_indices(i) + if (k < 1 .or. k > n_filters) then + err = E_OUT_OF_BOUNDS + exit + end if + + ! Set the filter index in the tally find_filter array + select type (filt => filters(k) % obj) + type is (DistribcellFilter) + j = FILTER_DISTRIBCELL + type is (CellFilter) + j = FILTER_CELL + type is (CellFromFilter) + j = FILTER_CELLFROM + type is (CellbornFilter) + j = FILTER_CELLBORN + type is (MaterialFilter) + j = FILTER_MATERIAL + type is (UniverseFilter) + j = FILTER_UNIVERSE + type is (SurfaceFilter) + j = FILTER_SURFACE + type is (MeshFilter) + j = FILTER_MESH + type is (EnergyFilter) + j = FILTER_ENERGYIN + type is (EnergyoutFilter) + j = FILTER_ENERGYOUT + this % estimator = ESTIMATOR_ANALOG + type is (DelayedGroupFilter) + j = FILTER_DELAYEDGROUP + type is (MuFilter) + j = FILTER_MU + this % estimator = ESTIMATOR_ANALOG + type is (PolarFilter) + j = FILTER_POLAR + type is (AzimuthalFilter) + j = FILTER_AZIMUTHAL + type is (EnergyFunctionFilter) + j = FILTER_ENERGYFUNCTION + end select + this % find_filter(j) = i + end do + + if (err == 0) then + if (allocated(this % filter)) deallocate(this % filter) + if (allocated(this % stride)) deallocate(this % stride) + allocate(this % filter(n), this % stride(n)) + + ! Filters are traversed in reverse so that the last filter has the + ! shortest stride in memory and the first filter has the largest stride + stride = 1 + do i = n, 1, -1 + ! Set filter and stride + k = filter_indices(i) + this % filter(i) = k + this % stride(i) = stride + + ! Multiply stride by number of bins in this filter + stride = stride * filters(k) % obj % n_bins + end do + + ! Set total number of filter bins + this % n_filter_bins = stride + end if + + end function tally_set_filters + !=============================================================================== ! CONFIGURE_TALLIES initializes several data structures related to tallies. This ! is called after the basic tally data has already been read from the @@ -423,83 +507,13 @@ contains integer(C_INT32_T), intent(in) :: filter_indices(n) integer(C_INT) :: err - integer :: i ! index in t % filter/stride - integer :: j ! index in t % find_filter - integer :: k ! index in global filters array - integer :: stride ! filter stride - err = 0 if (index >= 1 .and. index <= n_tallies) then - associate (t => tallies(index) % obj) - - t % find_filter(:) = 0 - do i = 1, n - k = filter_indices(i) - if (k < 1 .or. k > n_filters) then - err = E_OUT_OF_BOUNDS - exit - end if - - ! Set the filter index in the tally find_filter array - select type (filt => filters(k) % obj) - type is (DistribcellFilter) - j = FILTER_DISTRIBCELL - type is (CellFilter) - j = FILTER_CELL - type is (CellFromFilter) - j = FILTER_CELLFROM - type is (CellbornFilter) - j = FILTER_CELLBORN - type is (MaterialFilter) - j = FILTER_MATERIAL - type is (UniverseFilter) - j = FILTER_UNIVERSE - type is (SurfaceFilter) - j = FILTER_SURFACE - type is (MeshFilter) - j = FILTER_MESH - type is (EnergyFilter) - j = FILTER_ENERGYIN - type is (EnergyoutFilter) - j = FILTER_ENERGYOUT - t % estimator = ESTIMATOR_ANALOG - type is (DelayedGroupFilter) - j = FILTER_DELAYEDGROUP - type is (MuFilter) - j = FILTER_MU - t % estimator = ESTIMATOR_ANALOG - type is (PolarFilter) - j = FILTER_POLAR - type is (AzimuthalFilter) - j = FILTER_AZIMUTHAL - type is (EnergyFunctionFilter) - j = FILTER_ENERGYFUNCTION - end select - t % find_filter(j) = i - end do - - if (err == 0) then - if (allocated(t % filter)) deallocate(t % filter) - if (allocated(t % stride)) deallocate(t % stride) - allocate(t % filter(n), t % stride(n)) - - ! Filters are traversed in reverse so that the last filter has the - ! shortest stride in memory and the first filter has the largest stride - stride = 1 - do i = n, 1, -1 - ! Set filter and stride - k = filter_indices(i) - t % filter(i) = k - t % stride(i) = stride - - ! Multiply stride by number of bins in this filter - stride = stride * filters(k) % obj % n_bins - end do - - ! Set total number of filter bins - t % n_filter_bins = stride - end if - end associate + if (allocated(tallies(index) % obj)) then + err = tallies(index) % obj % set_filters(filter_indices) + else + err = E_TALLY_NOT_ALLOCATED + end if else err = E_OUT_OF_BOUNDS end if From 348f6d63a722f7e961b09263dd373bb703f483b3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 19 Aug 2017 16:59:42 -0500 Subject: [PATCH 151/229] Use _update_filter_strides when reading statepoints --- openmc/statepoint.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 474b03033..16d5b5d84 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -402,14 +402,6 @@ class StatePoint(object): scores = group['score_bins'].value n_score_bins = group['n_score_bins'].value - # Compute and set the filter strides - for i in range(n_filters): - tally_filter = tally.filters[i] - tally_filter.stride = n_score_bins * len(nuclide_names) - - for j in range(i+1, n_filters): - tally_filter.stride *= tally.filters[j].num_bins - # Read scattering moment order strings (e.g., P3, Y1,2, etc.) moments = group['moment_orders'].value @@ -423,6 +415,9 @@ class StatePoint(object): tally.scores.append(score) + # Compute and set the filter strides + tally._update_filter_strides() + # Add Tally to the global dictionary of all Tallies tally.sparse = self.sparse self._tallies[tally_id] = tally From 26e894eb6ba8c16a2c6226e60d532f37a7810d80 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 20 Aug 2017 15:03:59 -0500 Subject: [PATCH 152/229] Fix MPI-related bug --- src/tallies/tally.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 0ed9b47e7..77747b85a 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4301,7 +4301,7 @@ contains real(C_DOUBLE) :: temp(N_GLOBAL_TALLIES), temp2(N_GLOBAL_TALLIES) do i = 1, active_tallies % size() - associate (t => tallies(active_tallies % data(i))) + associate (t => tallies(active_tallies % data(i)) % obj) m = size(t % results, 2) n = size(t % results, 3) From 575e1533035a8de55d30f893ff4ed0ac5700b576 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 21 Aug 2017 07:09:47 -0500 Subject: [PATCH 153/229] Fix compiling with OpenMP --- src/simulation.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/simulation.F90 b/src/simulation.F90 index 914fa9a9c..f6ffcf24b 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -2,6 +2,10 @@ module simulation use, intrinsic :: ISO_C_BINDING +#ifdef _OPENMP + use omp_lib +#endif + use cmfd_execute, only: cmfd_init_batch, execute_cmfd use constants, only: ZERO use eigenvalue, only: count_source_for_ufs, calculate_average_keff, & From ee70dfdecaf47e21c0578798d4ffc64e927ddddb Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 21 Aug 2017 10:13:41 -0500 Subject: [PATCH 154/229] Move reading of into mesh_header --- src/input_xml.F90 | 128 +++----------------------------------------- src/mesh_header.F90 | 124 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 123 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 5f24c9c40..0cf33c024 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2721,10 +2721,8 @@ contains integer :: n_order ! moment order requested integer :: n_order_pos ! oosition of Scattering order in score name string integer :: MT ! user-specified MT for score - integer :: iarray3(3) ! temporary integer array integer :: imomstr ! Index of MOMENT_STRS & MOMENT_N_STRS logical :: file_exists ! does tallies.xml file exist? - real(8) :: rarray3(3) ! temporary double prec. array integer :: Nangle ! Number of angular bins real(8) :: dangle ! Mu spacing if using automatic allocation integer :: iangle ! Loop counter for building mu filter bins @@ -2740,7 +2738,6 @@ contains type(RegularMesh), pointer :: m type(XMLDocument) :: doc type(XMLNode) :: root - type(XMLNode) :: node_mesh type(XMLNode) :: node_tal type(XMLNode) :: node_filt type(XMLNode) :: node_trigger @@ -2803,128 +2800,18 @@ contains do i = 1, n m => meshes(i_start + i - 1) - ! Get pointer to mesh node - node_mesh = node_mesh_list(i) - - ! Copy mesh id - if (check_for_node(node_mesh, "id")) then - call get_node_value(node_mesh, "id", m % id) - else - call fatal_error("Must specify id for mesh in tally XML file.") - end if - - ! Check to make sure 'id' hasn't been used - if (mesh_dict % has_key(m % id)) then - call fatal_error("Two or more meshes use the same unique ID: " & - // to_str(m % id)) - end if - - ! Read mesh type - temp_str = '' - if (check_for_node(node_mesh, "type")) & - call get_node_value(node_mesh, "type", temp_str) - select case (to_lower(temp_str)) - case ('rect', 'rectangle', 'rectangular') - call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & - &Please use 'regular' instead.") - m % type = MESH_REGULAR - case ('regular') - m % type = MESH_REGULAR - case default - call fatal_error("Invalid mesh type: " // trim(temp_str)) - end select - - ! Determine number of dimensions for mesh - n = node_word_count(node_mesh, "dimension") - if (n /= 1 .and. n /= 2 .and. n /= 3) then - call fatal_error("Mesh must be one, two, or three dimensions.") - end if - m % n_dimension = n - - ! Allocate attribute arrays - allocate(m % dimension(n)) - allocate(m % lower_left(n)) - allocate(m % width(n)) - allocate(m % upper_right(n)) - - ! Check that dimensions are all greater than zero - call get_node_array(node_mesh, "dimension", iarray3(1:n)) - if (any(iarray3(1:n) <= 0)) then - call fatal_error("All entries on the element for a tally & - &mesh must be positive.") - end if - - ! Read dimensions in each direction - m % dimension = iarray3(1:n) - - ! Read mesh lower-left corner location - if (m % n_dimension /= node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the same & - &as the number of entries on .") - end if - call get_node_array(node_mesh, "lower_left", m % lower_left) - - ! Make sure both upper-right or width were specified - if (check_for_node(node_mesh, "upper_right") .and. & - check_for_node(node_mesh, "width")) then - call fatal_error("Cannot specify both and on a & - &tally mesh.") - end if - - ! Make sure either upper-right or width was specified - if (.not. check_for_node(node_mesh, "upper_right") .and. & - .not. check_for_node(node_mesh, "width")) then - call fatal_error("Must specify either and on a & - &tally mesh.") - end if - - if (check_for_node(node_mesh, "width")) then - ! Check to ensure width has same dimensions - if (node_word_count(node_mesh, "width") /= & - node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the same as & - &the number of entries on .") - end if - - ! Check for negative widths - call get_node_array(node_mesh, "width", rarray3(1:n)) - if (any(rarray3(1:n) < ZERO)) then - call fatal_error("Cannot have a negative on a tally mesh.") - end if - - ! Set width and upper right coordinate - m % width = rarray3(1:n) - m % upper_right = m % lower_left + m % dimension * m % width - - elseif (check_for_node(node_mesh, "upper_right")) then - ! Check to ensure width has same dimensions - if (node_word_count(node_mesh, "upper_right") /= & - node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the & - &same as the number of entries on .") - end if - - ! Check that upper-right is above lower-left - call get_node_array(node_mesh, "upper_right", rarray3(1:n)) - if (any(rarray3(1:n) < m % lower_left)) then - call fatal_error("The coordinates must be greater than & - &the coordinates on a tally mesh.") - end if - - ! Set width and upper right coordinate - m % upper_right = rarray3(1:n) - m % width = (m % upper_right - m % lower_left) / m % dimension - end if - - ! Set volume fraction - m % volume_frac = ONE/real(product(m % dimension),8) + ! Instantiate mesh from XML node + call m % from_xml(node_mesh_list(i)) ! Add mesh to dictionary call mesh_dict % add_key(m % id, i) end do ! We only need the mesh info for plotting - if (run_mode == MODE_PLOTTING) return + if (run_mode == MODE_PLOTTING) then + call doc % clear() + return + end if ! ========================================================================== ! READ DATA FOR DERIVATIVES @@ -3157,14 +3044,13 @@ contains ! Get pointer to mesh if (mesh_dict % has_key(id)) then i_mesh = mesh_dict % get_key(id) - m => meshes(i_mesh) else call fatal_error("Could not find mesh " // trim(to_str(id)) & // " specified on filter " // trim(to_str(filter_id))) end if ! Determine number of bins - filt % n_bins = product(m % dimension) + filt % n_bins = product(meshes(i_mesh) % dimension) ! Store the index of the mesh filt % mesh = i_mesh diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 4ab3bab32..4b8eae09e 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -4,10 +4,12 @@ module mesh_header use hdf5 - use constants, only: NO_BIN_FOUND + use constants use dict_header, only: DictIntInt + use error, only: warning, fatal_error use hdf5_interface - use string, only: to_str + use string, only: to_str, to_lower + use xml_interface implicit none private @@ -28,6 +30,7 @@ module mesh_header real(8), allocatable :: upper_right(:) ! upper-right corner of mesh real(8), allocatable :: width(:) ! width of each mesh cell contains + procedure :: from_xml => regular_from_xml procedure :: get_bin => regular_get_bin procedure :: get_indices => regular_get_indices procedure :: get_bin_from_indices => regular_get_bin_from_indices @@ -45,6 +48,123 @@ module mesh_header contains + subroutine regular_from_xml(this, node) + class(RegularMesh), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + character(MAX_LINE_LEN) :: temp_str + + ! Copy mesh id + if (check_for_node(node, "id")) then + call get_node_value(node, "id", this % id) + else + call fatal_error("Must specify id for mesh in tally XML file.") + end if + + ! Check to make sure 'id' hasn't been used + if (mesh_dict % has_key(this % id)) then + call fatal_error("Two or more meshes use the same unique ID: " & + // to_str(this % id)) + end if + + ! Read mesh type + temp_str = '' + if (check_for_node(node, "type")) & + call get_node_value(node, "type", temp_str) + select case (to_lower(temp_str)) + case ('rect', 'rectangle', 'rectangular') + call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & + &Please use 'regular' instead.") + this % type = MESH_REGULAR + case ('regular') + this % type = MESH_REGULAR + case default + call fatal_error("Invalid mesh type: " // trim(temp_str)) + end select + + ! Determine number of dimensions for mesh + n = node_word_count(node, "dimension") + if (n /= 1 .and. n /= 2 .and. n /= 3) then + call fatal_error("Mesh must be one, two, or three dimensions.") + end if + this % n_dimension = n + + ! Allocate attribute arrays + allocate(this % dimension(n)) + allocate(this % lower_left(n)) + allocate(this % width(n)) + allocate(this % upper_right(n)) + + ! Check that dimensions are all greater than zero + call get_node_array(node, "dimension", this % dimension) + if (any(this % dimension <= 0)) then + call fatal_error("All entries on the element for a tally & + &mesh must be positive.") + end if + + ! Read mesh lower-left corner location + if (this % n_dimension /= node_word_count(node, "lower_left")) then + call fatal_error("Number of entries on must be the same & + &as the number of entries on .") + end if + call get_node_array(node, "lower_left", this % lower_left) + + ! Make sure both upper-right or width were specified + if (check_for_node(node, "upper_right") .and. & + check_for_node(node, "width")) then + call fatal_error("Cannot specify both and on a & + &tally mesh.") + end if + + ! Make sure either upper-right or width was specified + if (.not. check_for_node(node, "upper_right") .and. & + .not. check_for_node(node, "width")) then + call fatal_error("Must specify either and on a & + &tally mesh.") + end if + + if (check_for_node(node, "width")) then + ! Check to ensure width has same dimensions + if (node_word_count(node, "width") /= & + node_word_count(node, "lower_left")) then + call fatal_error("Number of entries on must be the same as & + &the number of entries on .") + end if + + ! Check for negative widths + call get_node_array(node, "width", this % width) + if (any(this % width < ZERO)) then + call fatal_error("Cannot have a negative on a tally mesh.") + end if + + ! Set width and upper right coordinate + this % upper_right = this % lower_left + this % dimension * this % width + + elseif (check_for_node(node, "upper_right")) then + ! Check to ensure width has same dimensions + if (node_word_count(node, "upper_right") /= & + node_word_count(node, "lower_left")) then + call fatal_error("Number of entries on must be the & + &same as the number of entries on .") + end if + + ! Check that upper-right is above lower-left + call get_node_array(node, "upper_right", this % upper_right) + if (any(this % upper_right < this % lower_left)) then + call fatal_error("The coordinates must be greater than & + &the coordinates on a tally mesh.") + end if + + ! Set width and upper right coordinate + this % width = (this % upper_right - this % lower_left) / this % dimension + end if + + ! Set volume fraction + this % volume_frac = ONE/real(product(this % dimension),8) + + end subroutine regular_from_xml + !=============================================================================== ! GET_MESH_BIN determines the tally bin for a particle in a structured mesh !=============================================================================== From 569a532af61cc0b2b27306d4e9e73ed04a1ba45c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 21 Aug 2017 11:16:56 -0500 Subject: [PATCH 155/229] Store entropy and UFS meshes in global meshes array --- src/eigenvalue.F90 | 43 +++----------- src/global.F90 | 17 ------ src/input_xml.F90 | 137 +++++++++++++++++++++++---------------------- src/mesh.F90 | 2 +- src/physics.F90 | 24 ++++---- src/physics_mg.F90 | 25 +++++---- 6 files changed, 107 insertions(+), 141 deletions(-) diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index accf80b31..a1bb35655 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -300,39 +300,9 @@ contains integer :: ent_idx ! entropy index integer :: i, j, k ! index for bank sites - integer :: n ! # of boxes in each dimension logical :: sites_outside ! were there sites outside entropy box? - type(RegularMesh), pointer :: m - ! Get pointer to entropy mesh - m => entropy_mesh - - ! On the first pass through this subroutine, we need to determine how big - ! the entropy mesh should be in each direction and then allocate a - ! three-dimensional array to store the fraction of source sites in each mesh - ! box - - if (.not. allocated(entropy_p)) then - if (.not. allocated(m % dimension)) then - ! If the user did not specify how many mesh cells are to be used in - ! each direction, we automatically determine an appropriate number of - ! cells - n = ceiling((n_particles/20)**(ONE/THREE)) - - ! copy dimensions - m % n_dimension = 3 - allocate(m % dimension(3)) - m % dimension = n - - ! determine width - m % width = (m % upper_right - m % lower_left) / m % dimension - - end if - - ! allocate p - allocate(entropy_p(1, m % dimension(1), m % dimension(2), & - m % dimension(3))) - end if + associate (m => meshes(index_entropy_mesh)) ! count number of fission sites over mesh call count_bank_sites(m, fission_bank, entropy_p, & @@ -362,6 +332,7 @@ contains end do end if + end associate end subroutine shannon_entropy !=============================================================================== @@ -621,16 +592,18 @@ contains integer :: mpi_err ! MPI error code #endif + associate (m => meshes(index_ufs_mesh)) + if (current_batch == 1 .and. current_gen == 1) then ! On the first generation, just assume that the source is already evenly ! distributed so that effectively the production of fission sites is not ! biased - source_frac = ufs_mesh % volume_frac + source_frac = m % volume_frac else ! count number of source sites in each ufs mesh cell - call count_bank_sites(ufs_mesh, source_bank, source_frac, & + call count_bank_sites(m, source_bank, source_frac, & sites_outside=sites_outside, size_bank=work) ! Check for sites outside of the mesh @@ -640,7 +613,7 @@ contains #ifdef MPI ! Send source fraction to all processors - n = product(ufs_mesh % dimension) + n = product(m % dimension) call MPI_BCAST(source_frac, n, MPI_REAL8, 0, mpi_intracomm, mpi_err) #endif @@ -654,6 +627,8 @@ contains source_bank % wgt = source_bank % wgt * n_particles / total end if + end associate + end subroutine count_source_for_ufs #ifdef _OPENMP diff --git a/src/global.F90 b/src/global.F90 index 5940b6a01..dea17a102 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -202,25 +202,8 @@ contains call statepoint_batch % clear() call sourcepoint_batch % clear() - ! Deallocate entropy mesh - if (associated(entropy_mesh)) then - if (allocated(entropy_mesh % lower_left)) & - deallocate(entropy_mesh % lower_left) - if (allocated(entropy_mesh % upper_right)) & - deallocate(entropy_mesh % upper_right) - if (allocated(entropy_mesh % width)) deallocate(entropy_mesh % width) - deallocate(entropy_mesh) - end if - ! Deallocate ufs if (allocated(source_frac)) deallocate(source_frac) - if (associated(ufs_mesh)) then - if (allocated(ufs_mesh % lower_left)) deallocate(ufs_mesh % lower_left) - if (allocated(ufs_mesh % upper_right)) & - deallocate(ufs_mesh % upper_right) - if (allocated(ufs_mesh % width)) deallocate(ufs_mesh % width) - deallocate(ufs_mesh) - end if end subroutine free_memory diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 0cf33c024..e650f0fdf 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -144,6 +144,7 @@ contains integer :: n integer :: temp_int integer :: temp_int_array3(3) + integer(C_INT) :: err integer, allocatable :: temp_int_array(:) real(8), allocatable :: temp_real(:) integer :: n_tracks @@ -700,47 +701,54 @@ contains &corner of Shannon entropy mesh.") end if - ! Allocate mesh object and coordinates on mesh - allocate(entropy_mesh) - allocate(entropy_mesh % lower_left(3)) - allocate(entropy_mesh % upper_right(3)) - allocate(entropy_mesh % width(3)) + err = openmc_extend_meshes(1, index_entropy_mesh) - ! Copy values - call get_node_array(node_entropy, "lower_left", & - entropy_mesh % lower_left) - call get_node_array(node_entropy, "upper_right", & - entropy_mesh % upper_right) + associate (m => meshes(index_entropy_mesh)) + ! Allocate mesh object and coordinates on mesh + allocate(m % lower_left(3)) + allocate(m % upper_right(3)) + allocate(m % width(3)) - ! Check on values provided - if (.not. all(entropy_mesh % upper_right > entropy_mesh % lower_left)) & - &then - call fatal_error("Upper-right coordinate must be greater than & - &lower-left coordinate for Shannon entropy mesh.") - end if + ! Copy values + call get_node_array(node_entropy, "lower_left", m % lower_left) + call get_node_array(node_entropy, "upper_right", m % upper_right) - ! Check if dimensions were specified -- if not, they will be calculated - ! automatically upon first entry into shannon_entropy - if (check_for_node(node_entropy, "dimension")) then - - ! If so, make sure proper number of values were given - if (node_word_count(node_entropy, "dimension") /= 3) then - call fatal_error("Dimension of entropy mesh must be given as three & - &integers.") + ! Check on values provided + if (.not. all(m % upper_right > m % lower_left)) & + &then + call fatal_error("Upper-right coordinate must be greater than & + &lower-left coordinate for Shannon entropy mesh.") end if ! Allocate dimensions - entropy_mesh % n_dimension = 3 - allocate(entropy_mesh % dimension(3)) + m % n_dimension = 3 + allocate(m % dimension(3)) - ! Copy dimensions - call get_node_array(node_entropy, "dimension", entropy_mesh % dimension) + ! Check if dimensions were specified -- if not, they will be calculated + ! automatically upon first entry into shannon_entropy + if (check_for_node(node_entropy, "dimension")) then + ! If so, make sure proper number of values were given + if (node_word_count(node_entropy, "dimension") /= 3) then + call fatal_error("Dimension of entropy mesh must be given as three & + &integers.") + end if + + ! Copy dimensions + call get_node_array(node_entropy, "dimension", m % dimension) + else + ! If the user did not specify how many mesh cells are to be used in + ! each direction, we automatically determine an appropriate number of + ! cells + m % dimension = ceiling((n_particles/20)**(ONE/THREE)) + end if ! Calculate width - entropy_mesh % width = (entropy_mesh % upper_right - & - entropy_mesh % lower_left) / entropy_mesh % dimension + m % width = (m % upper_right - m % lower_left) / m % dimension - end if + ! Allocate space for storing number of fission sites in each mesh cell + allocate(entropy_p(1, m % dimension(1), m % dimension(2), & + m % dimension(3))) + end associate ! Turn on Shannon entropy calculation entropy_on = .true. @@ -764,42 +772,44 @@ contains &integers.") end if + err = openmc_extend_meshes(1, index_ufs_mesh) + ! Allocate mesh object and coordinates on mesh - allocate(ufs_mesh) - allocate(ufs_mesh % lower_left(3)) - allocate(ufs_mesh % upper_right(3)) - allocate(ufs_mesh % width(3)) + associate (m => meshes(index_ufs_mesh)) + allocate(m % lower_left(3)) + allocate(m % upper_right(3)) + allocate(m % width(3)) - ! Allocate dimensions - ufs_mesh % n_dimension = 3 - allocate(ufs_mesh % dimension(3)) + ! Allocate dimensions + m % n_dimension = 3 + allocate(m % dimension(3)) - ! Copy dimensions - call get_node_array(node_ufs, "dimension", ufs_mesh % dimension) + ! Copy dimensions + call get_node_array(node_ufs, "dimension", m % dimension) - ! Copy values - call get_node_array(node_ufs, "lower_left", ufs_mesh % lower_left) - call get_node_array(node_ufs, "upper_right", ufs_mesh % upper_right) + ! Copy values + call get_node_array(node_ufs, "lower_left", m % lower_left) + call get_node_array(node_ufs, "upper_right", m % upper_right) - ! Check on values provided - if (.not. all(ufs_mesh % upper_right > ufs_mesh % lower_left)) then - call fatal_error("Upper-right coordinate must be greater than & - &lower-left coordinate for UFS mesh.") - end if + ! Check on values provided + if (.not. all(m % upper_right > m % lower_left)) then + call fatal_error("Upper-right coordinate must be greater than & + &lower-left coordinate for UFS mesh.") + end if - ! Calculate width - ufs_mesh % width = (ufs_mesh % upper_right - & - ufs_mesh % lower_left) / ufs_mesh % dimension + ! Calculate width + m % width = (m % upper_right - m % lower_left) / m % dimension - ! Calculate volume fraction of each cell - ufs_mesh % volume_frac = ONE/real(product(ufs_mesh % dimension),8) + ! Calculate volume fraction of each cell + m % volume_frac = ONE/real(product(m % dimension),8) + + ! Allocate source_frac + allocate(source_frac(1, m % dimension(1), m % dimension(2), & + m % dimension(3))) + end associate ! Turn on uniform fission source weighting ufs = .true. - - ! Allocate source_frac - allocate(source_frac(1, ufs_mesh % dimension(1), & - ufs_mesh % dimension(2), ufs_mesh % dimension(3))) end if ! Check if the user has specified to write state points @@ -4566,12 +4576,12 @@ contains select case (trim(meshtype)) case ('ufs') - if (.not. associated(ufs_mesh)) then + if (index_ufs_mesh < 0) then call fatal_error("No UFS mesh for meshlines on plot " & // trim(to_str(pl % id))) end if - pl % meshlines_mesh => ufs_mesh + pl % meshlines_mesh => meshes(index_ufs_mesh) case ('cmfd') @@ -4584,17 +4594,12 @@ contains case ('entropy') - if (.not. associated(entropy_mesh)) then + if (index_entropy_mesh < 0) then call fatal_error("No entropy mesh for meshlines on plot " & // trim(to_str(pl % id))) end if - if (.not. allocated(entropy_mesh % dimension)) then - call fatal_error("No dimension specified on entropy mesh & - &for meshlines on plot " // trim(to_str(pl % id))) - end if - - pl % meshlines_mesh => entropy_mesh + pl % meshlines_mesh => meshes(index_entropy_mesh) case ('tally') diff --git a/src/mesh.F90 b/src/mesh.F90 index 6d94ffba4..9b8943ff2 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -20,7 +20,7 @@ contains subroutine count_bank_sites(m, bank_array, cnt, energies, size_bank, & sites_outside) - type(RegularMesh), pointer :: m ! mesh to count sites + type(RegularMesh), intent(in) :: m ! mesh to count sites type(Bank), intent(in) :: bank_array(:) ! fission or source bank real(8), intent(out) :: cnt(:,:,:,:) ! weight of sites in each ! cell and energy group diff --git a/src/physics.F90 b/src/physics.F90 index 8081aebcb..774106ddf 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -1088,18 +1088,20 @@ contains ! the expected number of fission sites produced if (ufs) then - ! Determine indices on ufs mesh for current location - call ufs_mesh % get_indices(p % coord(1) % xyz, ijk, in_mesh) - if (.not. in_mesh) then - call write_particle_restart(p) - call fatal_error("Source site outside UFS mesh!") - end if + associate (m => meshes(index_ufs_mesh)) + ! Determine indices on ufs mesh for current location + call m % get_indices(p % coord(1) % xyz, ijk, in_mesh) + if (.not. in_mesh) then + call write_particle_restart(p) + call fatal_error("Source site outside UFS mesh!") + end if - if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then - weight = ufs_mesh % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) - else - weight = ONE - end if + if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then + weight = m % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) + else + weight = ONE + end if + end associate else weight = ONE end if diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index c412e9e32..7f1ead66a 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -193,20 +193,21 @@ contains ! the expected number of fission sites produced if (ufs) then + associate (m => meshes(index_ufs_mesh)) + ! Determine indices on ufs mesh for current location + call m % get_indices(p % coord(1) % xyz, ijk, in_mesh) - ! Determine indices on ufs mesh for current location - call ufs_mesh % get_indices(p % coord(1) % xyz, ijk, in_mesh) + if (.not. in_mesh) then + call write_particle_restart(p) + call fatal_error("Source site outside UFS mesh!") + end if - if (.not. in_mesh) then - call write_particle_restart(p) - call fatal_error("Source site outside UFS mesh!") - end if - - if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then - weight = ufs_mesh % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) - else - weight = ONE - end if + if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then + weight = m % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) + else + weight = ONE + end if + end associate else weight = ONE end if From 5acbcc4416ac7490099d89f2c4c0da37bf5588a8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 21 Aug 2017 12:10:35 -0500 Subject: [PATCH 156/229] Change error checking in RegularMesh % from_xml --- src/input_xml.F90 | 6 +++ src/mesh_header.F90 | 103 ++++++++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e650f0fdf..cafc59678 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -704,6 +704,9 @@ contains err = openmc_extend_meshes(1, index_entropy_mesh) associate (m => meshes(index_entropy_mesh)) + ! Assign ID + m % id = 10000 + ! Allocate mesh object and coordinates on mesh allocate(m % lower_left(3)) allocate(m % upper_right(3)) @@ -776,6 +779,9 @@ contains ! Allocate mesh object and coordinates on mesh associate (m => meshes(index_ufs_mesh)) + ! Assign ID + m % id = 10001 + allocate(m % lower_left(3)) allocate(m % upper_right(3)) allocate(m % width(3)) diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 4b8eae09e..6f32bdcbd 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -21,7 +21,7 @@ module mesh_header !=============================================================================== type, public :: RegularMesh - integer :: id ! user-specified id + integer :: id = -1 ! user-specified id integer :: type ! rectangular, hexagonal integer :: n_dimension ! rank of mesh real(8) :: volume_frac ! volume fraction of each cell @@ -58,14 +58,12 @@ contains ! Copy mesh id if (check_for_node(node, "id")) then call get_node_value(node, "id", this % id) - else - call fatal_error("Must specify id for mesh in tally XML file.") - end if - ! Check to make sure 'id' hasn't been used - if (mesh_dict % has_key(this % id)) then - call fatal_error("Two or more meshes use the same unique ID: " & - // to_str(this % id)) + ! Check to make sure 'id' hasn't been used + if (mesh_dict % has_key(this % id)) then + call fatal_error("Two or more meshes use the same unique ID: " & + // to_str(this % id)) + end if end if ! Read mesh type @@ -84,50 +82,48 @@ contains end select ! Determine number of dimensions for mesh - n = node_word_count(node, "dimension") - if (n /= 1 .and. n /= 2 .and. n /= 3) then - call fatal_error("Mesh must be one, two, or three dimensions.") - end if - this % n_dimension = n + if (check_for_node(node, "dimension")) then + n = node_word_count(node, "dimension") + if (n /= 1 .and. n /= 2 .and. n /= 3) then + call fatal_error("Mesh must be one, two, or three dimensions.") + end if + this % n_dimension = n - ! Allocate attribute arrays - allocate(this % dimension(n)) - allocate(this % lower_left(n)) - allocate(this % width(n)) - allocate(this % upper_right(n)) + ! Allocate attribute arrays + allocate(this % dimension(n)) - ! Check that dimensions are all greater than zero - call get_node_array(node, "dimension", this % dimension) - if (any(this % dimension <= 0)) then - call fatal_error("All entries on the element for a tally & - &mesh must be positive.") + ! Check that dimensions are all greater than zero + call get_node_array(node, "dimension", this % dimension) + if (any(this % dimension <= 0)) then + call fatal_error("All entries on the element for a tally & + &mesh must be positive.") + end if end if - ! Read mesh lower-left corner location - if (this % n_dimension /= node_word_count(node, "lower_left")) then - call fatal_error("Number of entries on must be the same & - &as the number of entries on .") - end if - call get_node_array(node, "lower_left", this % lower_left) + ! Check for lower-left coordinates + if (check_for_node(node, "lower_left")) then + n = node_word_count(node, "lower_left") + allocate(this % lower_left(n)) - ! Make sure both upper-right or width were specified - if (check_for_node(node, "upper_right") .and. & - check_for_node(node, "width")) then - call fatal_error("Cannot specify both and on a & - &tally mesh.") - end if - - ! Make sure either upper-right or width was specified - if (.not. check_for_node(node, "upper_right") .and. & - .not. check_for_node(node, "width")) then - call fatal_error("Must specify either and on a & - &tally mesh.") + ! Read mesh lower-left corner location + call get_node_array(node, "lower_left", this % lower_left) + else + call fatal_error("Must specify on a mesh.") end if if (check_for_node(node, "width")) then + ! Make sure both upper-right or width were specified + if (check_for_node(node, "upper_right")) then + call fatal_error("Cannot specify both and on a & + &mesh.") + end if + + n = node_word_count(node, "width") + allocate(this % width(n)) + allocate(this % upper_right(n)) + ! Check to ensure width has same dimensions - if (node_word_count(node, "width") /= & - node_word_count(node, "lower_left")) then + if (n /= size(this % lower_left)) then call fatal_error("Number of entries on must be the same as & &the number of entries on .") end if @@ -142,9 +138,12 @@ contains this % upper_right = this % lower_left + this % dimension * this % width elseif (check_for_node(node, "upper_right")) then + n = node_word_count(node, "upper_right") + allocate(this % upper_right(n)) + allocate(this % width(n)) + ! Check to ensure width has same dimensions - if (node_word_count(node, "upper_right") /= & - node_word_count(node, "lower_left")) then + if (n /= size(this % lower_left)) then call fatal_error("Number of entries on must be the & &same as the number of entries on .") end if @@ -158,10 +157,20 @@ contains ! Set width and upper right coordinate this % width = (this % upper_right - this % lower_left) / this % dimension + else + call fatal_error("Must specify either and on a & + &mesh.") end if - ! Set volume fraction - this % volume_frac = ONE/real(product(this % dimension),8) + if (allocated(this % dimension)) then + if (size(this % dimension) /= size(this % lower_left)) then + call fatal_error("Number of entries on must be the same & + &as the number of entries on .") + end if + + ! Set volume fraction + this % volume_frac = ONE/real(product(this % dimension),8) + end if end subroutine regular_from_xml From e5869597cd43dc4e2d832b8957fb33a9481eb6ff Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 21 Aug 2017 12:31:20 -0500 Subject: [PATCH 157/229] Use RegularMesh % from_xml for entropy/UFS --- src/input_xml.F90 | 84 +++++++-------------------------------------- src/mesh_header.F90 | 26 +++++++------- 2 files changed, 26 insertions(+), 84 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index cafc59678..071677fe4 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -688,44 +688,16 @@ contains ! Shannon Entropy mesh if (check_for_node(root, "entropy")) then - ! Get pointer to entropy node node_entropy = root % child("entropy") - ! Check to make sure enough values were supplied - if (node_word_count(node_entropy, "lower_left") /= 3) then - call fatal_error("Need to specify (x,y,z) coordinates of lower-left & - &corner of Shannon entropy mesh.") - elseif (node_word_count(node_entropy, "upper_right") /= 3) then - call fatal_error("Need to specify (x,y,z) coordinates of upper-right & - &corner of Shannon entropy mesh.") - end if - err = openmc_extend_meshes(1, index_entropy_mesh) associate (m => meshes(index_entropy_mesh)) ! Assign ID m % id = 10000 - ! Allocate mesh object and coordinates on mesh - allocate(m % lower_left(3)) - allocate(m % upper_right(3)) - allocate(m % width(3)) - - ! Copy values - call get_node_array(node_entropy, "lower_left", m % lower_left) - call get_node_array(node_entropy, "upper_right", m % upper_right) - - ! Check on values provided - if (.not. all(m % upper_right > m % lower_left)) & - &then - call fatal_error("Upper-right coordinate must be greater than & - &lower-left coordinate for Shannon entropy mesh.") - end if - - ! Allocate dimensions - m % n_dimension = 3 - allocate(m % dimension(3)) + call m % from_xml(node_entropy) ! Check if dimensions were specified -- if not, they will be calculated ! automatically upon first entry into shannon_entropy @@ -735,18 +707,17 @@ contains call fatal_error("Dimension of entropy mesh must be given as three & &integers.") end if - - ! Copy dimensions - call get_node_array(node_entropy, "dimension", m % dimension) else ! If the user did not specify how many mesh cells are to be used in ! each direction, we automatically determine an appropriate number of ! cells + m % n_dimension = 3 + allocate(m % dimension(3)) m % dimension = ceiling((n_particles/20)**(ONE/THREE)) - end if - ! Calculate width - m % width = (m % upper_right - m % lower_left) / m % dimension + ! Calculate width + m % width = (m % upper_right - m % lower_left) / m % dimension + end if ! Allocate space for storing number of fission sites in each mesh cell allocate(entropy_p(1, m % dimension(1), m % dimension(2), & @@ -759,22 +730,9 @@ contains ! Uniform fission source weighting mesh if (check_for_node(root, "uniform_fs")) then - ! Get pointer to ufs node node_ufs = root % child("uniform_fs") - ! Check to make sure enough values were supplied - if (node_word_count(node_ufs, "lower_left") /= 3) then - call fatal_error("Need to specify (x,y,z) coordinates of lower-left & - &corner of UFS mesh.") - elseif (node_word_count(node_ufs, "upper_right") /= 3) then - call fatal_error("Need to specify (x,y,z) coordinates of upper-right & - &corner of UFS mesh.") - elseif (node_word_count(node_ufs, "dimension") /= 3) then - call fatal_error("Dimension of UFS mesh must be given as three & - &integers.") - end if - err = openmc_extend_meshes(1, index_ufs_mesh) ! Allocate mesh object and coordinates on mesh @@ -782,33 +740,15 @@ contains ! Assign ID m % id = 10001 - allocate(m % lower_left(3)) - allocate(m % upper_right(3)) - allocate(m % width(3)) + call m % from_xml(node_ufs) - ! Allocate dimensions - m % n_dimension = 3 - allocate(m % dimension(3)) - - ! Copy dimensions - call get_node_array(node_ufs, "dimension", m % dimension) - - ! Copy values - call get_node_array(node_ufs, "lower_left", m % lower_left) - call get_node_array(node_ufs, "upper_right", m % upper_right) - - ! Check on values provided - if (.not. all(m % upper_right > m % lower_left)) then - call fatal_error("Upper-right coordinate must be greater than & - &lower-left coordinate for UFS mesh.") + if (check_for_node(node_ufs, "dimension")) then + if (node_word_count(node_ufs, "dimension") /= 3) then + call fatal_error("Dimension of UFS mesh must be given as three & + &integers.") + end if end if - ! Calculate width - m % width = (m % upper_right - m % lower_left) / m % dimension - - ! Calculate volume fraction of each cell - m % volume_frac = ONE/real(product(m % dimension),8) - ! Allocate source_frac allocate(source_frac(1, m % dimension(1), m % dimension(2), & m % dimension(3))) diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 6f32bdcbd..1bef22181 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -67,19 +67,21 @@ contains end if ! Read mesh type - temp_str = '' - if (check_for_node(node, "type")) & - call get_node_value(node, "type", temp_str) - select case (to_lower(temp_str)) - case ('rect', 'rectangle', 'rectangular') - call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & - &Please use 'regular' instead.") + if (check_for_node(node, "type")) then + call get_node_value(node, "type", temp_str) + select case (to_lower(temp_str)) + case ('rect', 'rectangle', 'rectangular') + call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & + &Please use 'regular' instead.") + this % type = MESH_REGULAR + case ('regular') + this % type = MESH_REGULAR + case default + call fatal_error("Invalid mesh type: " // trim(temp_str)) + end select + else this % type = MESH_REGULAR - case ('regular') - this % type = MESH_REGULAR - case default - call fatal_error("Invalid mesh type: " // trim(temp_str)) - end select + end if ! Determine number of dimensions for mesh if (check_for_node(node, "dimension")) then From 23159d0c3b692d02e2d0de193a30e479866d7c7e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Aug 2017 15:44:30 -0500 Subject: [PATCH 158/229] Ability to create tallies from Python bindings to C API --- openmc/capi/filter.py | 10 ++++++++++ openmc/capi/tally.py | 27 +++++++++++++++++++++++++++ src/api.F90 | 1 + src/input_xml.F90 | 13 ------------- src/tallies/tally.F90 | 4 ++++ src/tallies/tally_header.F90 | 33 +++++++++++++++++++++++++++++++-- 6 files changed, 73 insertions(+), 15 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 2d3766dbf..0bcab1110 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -145,6 +145,16 @@ class MaterialFilterView(FilterView): _dll.openmc_material_filter_set_bins(self._index, n, bins) + @classmethod + def new(cls, bins=None): + index = c_int32() + _dll.openmc_extend_filters(1, index, None) + _dll.openmc_filter_set_type(index, b'material') + f = cls(index.value) + if bins is not None: + f.bins = bins + return f + class MeshFilterView(FilterView): pass diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 155b0eaf5..6a62fb8bd 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -36,12 +36,18 @@ _dll.openmc_tally_results.errcheck = _error_handler _dll.openmc_tally_set_filters.argtypes = [c_int32, c_int, POINTER(c_int32)] _dll.openmc_tally_set_filters.restype = c_int _dll.openmc_tally_set_filters.errcheck = _error_handler +_dll.openmc_tally_set_id.argtypes = [c_int32, c_int32] +_dll.openmc_tally_set_id.restype = c_int +_dll.openmc_tally_set_id.errcheck = _error_handler _dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_nuclides.restype = c_int _dll.openmc_tally_set_nuclides.errcheck = _error_handler _dll.openmc_tally_set_scores.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_scores.restype = c_int _dll.openmc_tally_set_scores.errcheck = _error_handler +_dll.openmc_tally_set_type.argtypes = [c_int32, c_char_p] +_dll.openmc_tally_set_type.restype = c_int +_dll.openmc_tally_set_type.errcheck = _error_handler class TallyView(object): @@ -85,6 +91,10 @@ class TallyView(object): _dll.openmc_tally_get_id(self._index, tally_id) return tally_id.value + @id.setter + def id(self, tally_id): + _dll.openmc_tally_set_id(self._index, tally_id) + @property def filters(self): filt_idx = POINTER(c_int32)() @@ -121,6 +131,23 @@ class TallyView(object): nucs[:] = [x.encode() for x in nuclides] _dll.openmc_tally_set_nuclides(self._index, len(nuclides), nucs) + @property + def scores(self): + pass + + @scores.setter + def scores(self, scores): + scores_ = (c_char_p * len(scores))() + scores_[:] = [x.encode() for x in scores] + _dll.openmc_tally_set_scores(self._index, len(scores), scores_) + + @classmethod + def new(cls): + index = c_int32() + _dll.openmc_extend_tallies(1, index, None) + _dll.openmc_tally_set_type(index, b'generic') + return cls(index.value) + class _TallyMapping(Mapping): def __getitem__(self, key): diff --git a/src/api.F90 b/src/api.F90 index af00cdd83..247410d2b 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -66,6 +66,7 @@ module openmc_api public :: openmc_tally_get_nuclides public :: openmc_tally_results public :: openmc_tally_set_filters + public :: openmc_tally_set_id public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores public :: openmc_tally_set_type diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 071677fe4..ee6dd98d4 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3249,17 +3249,6 @@ contains ! Get pointer to tally xml node node_tal = node_tal_list(i) - ! Set tally type to volume by default - t % type = TALLY_VOLUME - - ! It's desirable to use a track-length esimator for tallies since - ! generally more events will score to the tally, reducing the - ! variance. However, for tallies that require information on - ! post-collision parameters (e.g. tally with an energyout filter) the - ! analog esimator must be used. - - t % estimator = ESTIMATOR_TRACKLENGTH - ! Copy tally id if (check_for_node(node_tal, "id")) then call get_node_value(node_tal, "id", t % id) @@ -3318,8 +3307,6 @@ contains ! Set the filters err = openmc_tally_set_filters(i_start + i - 1, n_filter, temp_filter) - else - allocate(t % filter(n_filter)) end if deallocate(temp_filter) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 77747b85a..3c83aa6e9 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4429,6 +4429,7 @@ contains character(kind=C_CHAR), intent(in) :: type(*) integer(C_INT) :: err + integer(C_INT32_T) :: empty(0) character(:), allocatable :: type_ ! Convert C string to Fortran string @@ -4445,6 +4446,9 @@ contains case default err = E_UNASSIGNED end select + + ! When a tally is allocated, set it to have 0 filters + err = tallies(index) % obj % set_filters(empty) end if else err = E_OUT_OF_BOUNDS diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index f97df50b8..6c5c3106b 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -24,6 +24,7 @@ module tally_header public :: openmc_tally_get_nuclides public :: openmc_tally_results public :: openmc_tally_set_filters + public :: openmc_tally_set_id public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores @@ -51,8 +52,8 @@ module tally_header integer :: id ! user-defined identifier character(len=104) :: name = "" ! user-defined name - integer :: type ! volume, surface current - integer :: estimator ! collision, track-length + integer :: type = TALLY_VOLUME ! volume, surface current + integer :: estimator = ESTIMATOR_TRACKLENGTH ! collision, track-length real(8) :: volume ! volume of region logical :: active = .false. integer, allocatable :: filter(:) ! index in filters array @@ -235,6 +236,13 @@ contains subroutine tally_allocate_results(this) class(TallyObject), intent(inout) :: this + ! If no nuclides were specified, add a single bin for total material + if (.not. allocated(this % nuclide_bins)) then + allocate(this % nuclide_bins(1)) + this % nuclide_bins(1) = -1 + this % n_nuclide_bins = 1 + end if + ! Set total number of filter and scoring bins this % total_score_bins = this % n_score_bins * this % n_nuclide_bins @@ -520,6 +528,27 @@ contains end function openmc_tally_set_filters + function openmc_tally_set_id(index, id) result(err) bind(C) + ! Set the ID of a tally + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_tallies) then + if (allocated(tallies(index) % obj)) then + tallies(index) % obj % id = id + call tally_dict % add_key(id, index) + + err = 0 + else + err = E_FILTER_NOT_ALLOCATED + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_set_id + + function openmc_tally_set_nuclides(index, n, nuclides) result(err) bind(C) ! Sets the nuclides in the tally which results should be scored for integer(C_INT32_T), value :: index From 523fb33bab88049e67c2c5985d11bfafb4178abe Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Aug 2017 16:40:55 -0500 Subject: [PATCH 159/229] Allow entropy mesh and UFS mesh to be specified using elements --- openmc/settings.py | 46 +++---- src/input_xml.F90 | 65 ++++++++- src/relaxng/settings.rnc | 36 ++--- src/relaxng/settings.rng | 204 +++++++++++++--------------- tests/test_cmfd_feed/settings.xml | 9 +- tests/test_cmfd_nofeed/settings.xml | 5 +- tests/test_entropy/settings.xml | 6 +- tests/test_plot/settings.xml | 5 +- 8 files changed, 209 insertions(+), 167 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index 3efdf1ab7..054b8b382 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -958,20 +958,15 @@ class Settings(object): subelement = ET.SubElement(element, "energy") subelement.text = str(self._cutoff['energy']) - def _create_entropy_subelement(self, root): - if self._entropy_mesh is not None: - element = ET.SubElement(root, "entropy") + def _create_entropy_mesh_subelement(self, root): + if self.entropy_mesh is not None: + # See if a element already exists -- if not, add it + path = "./mesh[@id='{}']".format(self.entropy_mesh.id) + if root.find(path) is None: + root.append(self.entropy_mesh.to_xml_element) - if self._entropy_mesh.dimension is not None: - subelement = ET.SubElement(element, "dimension") - subelement.text = ' '.join( - str(x) for x in self._entropy_mesh.dimension) - subelement = ET.SubElement(element, "lower_left") - subelement.text = ' '.join( - str(x) for x in self._entropy_mesh.lower_left) - subelement = ET.SubElement(element, "upper_right") - subelement.text = ' '.join( - str(x) for x in self._entropy_mesh.upper_right) + subelement = ET.SubElement(element, "entropy_mesh") + subelement.text = str(self.entropy_mesh.id) def _create_trigger_subelement(self, root): if self._trigger_active is not None: @@ -1028,18 +1023,15 @@ class Settings(object): element = ET.SubElement(root, "track") element.text = ' '.join(map(str, self._track)) - def _create_ufs_subelement(self, root): - if self._ufs_mesh is not None: - element = ET.SubElement(root, "uniform_fs") - subelement = ET.SubElement(element, "dimension") - subelement.text = ' '.join(str(x) for x in - self._ufs_mesh.dimension) - subelement = ET.SubElement(element, "lower_left") - subelement.text = ' '.join(str(x) for x in - self._ufs_mesh.lower_left) - subelement = ET.SubElement(element, "upper_right") - subelement.text = ' '.join(str(x) for x in - self._ufs_mesh.upper_right) + def _create_ufs_mesh_subelement(self, root): + if self.ufs_mesh is not None: + # See if a element already exists -- if not, add it + path = "./mesh[@id='{}']".format(self.ufs_mesh.id) + if root.find(path) is None: + root.append(self.ufs_mesh.to_xml_element) + + subelement = ET.SubElement(element, "ufs_mesh") + subelement.text = str(self.ufs_mesh.id) def _create_dd_subelement(self, root): if self._dd_mesh_lower_left is not None and \ @@ -1126,7 +1118,7 @@ class Settings(object): self._create_seed_subelement(root_element) self._create_survival_biasing_subelement(root_element) self._create_cutoff_subelement(root_element) - self._create_entropy_subelement(root_element) + self._create_entropy_mesh_subelement(root_element) self._create_trigger_subelement(root_element) self._create_no_reduce_subelement(root_element) self._create_threads_subelement(root_element) @@ -1135,7 +1127,7 @@ class Settings(object): self._create_temperature_subelements(root_element) self._create_trace_subelement(root_element) self._create_track_subelement(root_element) - self._create_ufs_subelement(root_element) + self._create_ufs_mesh_subelement(root_element) self._create_dd_subelement(root_element) self._create_resonance_scattering_subelement(root_element) self._create_volume_calcs_subelement(root_element) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index ee6dd98d4..37d230c31 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -144,6 +144,7 @@ contains integer :: n integer :: temp_int integer :: temp_int_array3(3) + integer(C_INT32_T) :: i_start, i_end integer(C_INT) :: err integer, allocatable :: temp_int_array(:) real(8), allocatable :: temp_real(:) @@ -167,6 +168,7 @@ contains type(XMLNode) :: node_trigger type(XMLNode) :: node_vol type(XMLNode) :: node_tab_leg + type(XMLNode), allocatable :: node_mesh_list(:) type(XMLNode), allocatable :: node_source_list(:) type(XMLNode), allocatable :: node_vol_list(:) @@ -686,8 +688,39 @@ contains track_identifiers = reshape(temp_int_array, [3, n_tracks/3]) end if + ! Read meshes + call get_node_list(root, "mesh", node_mesh_list) + + ! Check for user meshes and allocate + n = size(node_mesh_list) + if (n > 0) then + err = openmc_extend_meshes(n, i_start, i_end) + end if + + do i = 1, n + associate (m => meshes(i_start + i - 1)) + ! Instantiate mesh from XML node + call m % from_xml(node_mesh_list(i)) + + ! Add mesh to dictionary + call mesh_dict % add_key(m % id, i) + end associate + end do + ! Shannon Entropy mesh - if (check_for_node(root, "entropy")) then + if (check_for_node(root, "entropy_mesh")) then + call get_node_value(root, "entropy_mesh", temp_int) + if (mesh_dict % has_key(temp_int)) then + index_entropy_mesh = mesh_dict % get_key(temp_int) + else + call fatal_error("Mesh " // to_str(temp_int) // " specified for & + &Shannon entropy does not exist.") + end if + elseif (check_for_node(root, "entropy")) then + call warning("Specifying a Shannon entropy mesh via the element & + &is deprecated. Please create a mesh using and then reference & + &it by specifying its ID in an element.") + ! Get pointer to entropy node node_entropy = root % child("entropy") @@ -698,12 +731,16 @@ contains m % id = 10000 call m % from_xml(node_entropy) + end associate + end if + if (index_entropy_mesh > 0) then + associate(m => meshes(index_entropy_mesh)) ! Check if dimensions were specified -- if not, they will be calculated ! automatically upon first entry into shannon_entropy - if (check_for_node(node_entropy, "dimension")) then + if (allocated(m % dimension)) then ! If so, make sure proper number of values were given - if (node_word_count(node_entropy, "dimension") /= 3) then + if (m % n_dimension /= 3) then call fatal_error("Dimension of entropy mesh must be given as three & &integers.") end if @@ -729,7 +766,19 @@ contains end if ! Uniform fission source weighting mesh - if (check_for_node(root, "uniform_fs")) then + if (check_for_node(root, "ufs_mesh")) then + call get_node_value(root, "ufs_mesh", temp_int) + if (mesh_dict % has_key(temp_int)) then + index_ufs_mesh = mesh_dict % get_key(temp_int) + else + call fatal_error("Mesh " // to_str(temp_int) // " specified for & + &uniform fission site method does not exist.") + end if + elseif (check_for_node(root, "uniform_fs")) then + call warning("Specifying a UFS mesh via the element & + &is deprecated. Please create a mesh using and then reference & + &it by specifying its ID in a element.") + ! Get pointer to ufs node node_ufs = root % child("uniform_fs") @@ -741,9 +790,13 @@ contains m % id = 10001 call m % from_xml(node_ufs) + end associate + end if - if (check_for_node(node_ufs, "dimension")) then - if (node_word_count(node_ufs, "dimension") /= 3) then + if (index_ufs_mesh > 0) then + associate (m => meshes(index_ufs_mesh)) + if (allocated(m % dimension)) then + if (m % n_dimension /= 3) then call fatal_error("Dimension of UFS mesh must be given as three & &integers.") end if diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc index 23a0cfd4b..19a2948c5 100644 --- a/src/relaxng/settings.rnc +++ b/src/relaxng/settings.rnc @@ -12,14 +12,7 @@ element settings { element energy_mode { ( "continuous-energy" | "ce" | "CE" | "multi-group" | "mg" | "MG" ) }? & - element entropy { - (element dimension { list { xsd:int+ } } | - attribute dimension { list { xsd:int+ } })? & - (element lower_left { list { xsd:double+ } } | - attribute lower_left { list { xsd:double+ } }) & - (element upper_right { list { xsd:double+ } } | - attribute upper_right { list { xsd:double+ } }) - }? & + element entropy_mesh { xsd:positiveInteger }? & element generations_per_batch { xsd:positiveInteger }? & @@ -34,6 +27,22 @@ element settings { element max_order { xsd:nonNegativeInteger }? & + element mesh { + (element id { xsd:int } | attribute id { xsd:int }) & + (element type { ( "regular" ) } | + attribute type { ( "regular" ) })? & + (element dimension { list { xsd:positiveInteger+ } } | + attribute dimension { list { xsd:positiveInteger+ } }) & + (element lower_left { list { xsd:double+ } } | + attribute lower_left { list { xsd:double+ } }) & + ( + (element upper_right { list { xsd:double+ } } | + attribute upper_right { list { xsd:double+ } }) | + (element width { list { xsd:double+ } } | + attribute width { list { xsd:double+ } }) + ) + }* & + element no_reduce { xsd:boolean }? & element output { @@ -132,6 +141,8 @@ element settings { (element batch_interval { xsd:positiveInteger } | attribute batch_interval { xsd:positiveInteger })? }? & + element ufs_mesh { xsd:positiveInteger }? & + element verbosity { xsd:positiveInteger }? & element volume_calc { @@ -147,15 +158,6 @@ element settings { attribute upper_right { list { xsd:double+ } }) }* & - element uniform_fs{ - (element dimension { list { xsd:positiveInteger+ } } | - attribute dimension { list { xsd:positiveInteger+ } }) & - (element lower_left { list { xsd:double+ } } | - attribute lower_left { list { xsd:double+ } }) & - (element upper_right { list { xsd:double+ } } | - attribute upper_right { list { xsd:double+ } }) - }? & - element resonance_scattering { (element enable { xsd:boolean } | attribute enable { xsd:boolean })? & (element method { xsd:string } | attribute method { xsd:string })? & diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng index e75dc7c15..606b97829 100644 --- a/src/relaxng/settings.rng +++ b/src/relaxng/settings.rng @@ -62,59 +62,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -159,6 +108,96 @@ + + + + + + + + + + + + + + + regular + + + regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -585,6 +624,11 @@ + + + + + @@ -660,60 +704,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/test_cmfd_feed/settings.xml b/tests/test_cmfd_feed/settings.xml index 3e8b77b39..742aa2233 100644 --- a/tests/test_cmfd_feed/settings.xml +++ b/tests/test_cmfd_feed/settings.xml @@ -16,13 +16,14 @@ - + 10 1 1 -10.0 -1.0 -1.0 10.0 1.0 1.0 - + + 10 - - true + + true diff --git a/tests/test_cmfd_nofeed/settings.xml b/tests/test_cmfd_nofeed/settings.xml index 3e8b77b39..b56acb4b7 100644 --- a/tests/test_cmfd_nofeed/settings.xml +++ b/tests/test_cmfd_nofeed/settings.xml @@ -16,11 +16,12 @@ - + 10 1 1 -10.0 -1.0 -1.0 10.0 1.0 1.0 - + + 10 true diff --git a/tests/test_entropy/settings.xml b/tests/test_entropy/settings.xml index df6a851ef..493da7223 100644 --- a/tests/test_entropy/settings.xml +++ b/tests/test_entropy/settings.xml @@ -12,10 +12,12 @@ - + 10 10 10 -10. -10. -10. 10. 10. 10. - + + + 1 diff --git a/tests/test_plot/settings.xml b/tests/test_plot/settings.xml index 197b9c709..adf256d2d 100644 --- a/tests/test_plot/settings.xml +++ b/tests/test_plot/settings.xml @@ -3,10 +3,11 @@ plot - + 5 4 3 -10 -10 -10 10 10 10 - + + 1 From 16cb9f8195233a245b5a9108482378db437b4ca0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Aug 2017 23:14:29 -0500 Subject: [PATCH 160/229] Fix potential mesh-related bugs --- openmc/settings.py | 8 ++++---- src/input_xml.F90 | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index 054b8b382..c608994fa 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -963,9 +963,9 @@ class Settings(object): # See if a element already exists -- if not, add it path = "./mesh[@id='{}']".format(self.entropy_mesh.id) if root.find(path) is None: - root.append(self.entropy_mesh.to_xml_element) + root.append(self.entropy_mesh.to_xml_element()) - subelement = ET.SubElement(element, "entropy_mesh") + subelement = ET.SubElement(root, "entropy_mesh") subelement.text = str(self.entropy_mesh.id) def _create_trigger_subelement(self, root): @@ -1028,9 +1028,9 @@ class Settings(object): # See if a element already exists -- if not, add it path = "./mesh[@id='{}']".format(self.ufs_mesh.id) if root.find(path) is None: - root.append(self.ufs_mesh.to_xml_element) + root.append(self.ufs_mesh.to_xml_element()) - subelement = ET.SubElement(element, "ufs_mesh") + subelement = ET.SubElement(root, "ufs_mesh") subelement.text = str(self.ufs_mesh.id) def _create_dd_subelement(self, root): diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 37d230c31..a2546c08c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -703,7 +703,7 @@ contains call m % from_xml(node_mesh_list(i)) ! Add mesh to dictionary - call mesh_dict % add_key(m % id, i) + call mesh_dict % add_key(m % id, i_start + i - 1) end associate end do @@ -2813,7 +2813,7 @@ contains call m % from_xml(node_mesh_list(i)) ! Add mesh to dictionary - call mesh_dict % add_key(m % id, i) + call mesh_dict % add_key(m % id, i_start + i - 1) end do ! We only need the mesh info for plotting From ce1a3429760a342ae60ad078399ad45b2589c265 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Aug 2017 10:13:42 -0500 Subject: [PATCH 161/229] Have count_bank_sites work on (energy,mesh_bin) arrays --- src/cmfd_execute.F90 | 28 +++++++++++++++++++-------- src/cmfd_header.F90 | 4 ++-- src/eigenvalue.F90 | 46 +++++++++++++++++++------------------------- src/global.F90 | 6 +++--- src/input_xml.F90 | 27 ++++---------------------- src/mesh.F90 | 18 ++++++++--------- src/physics.F90 | 11 +++++------ src/physics_mg.F90 | 11 +++++------ 8 files changed, 67 insertions(+), 84 deletions(-) diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 803ae8247..307f6ab9a 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -229,9 +229,12 @@ contains integer :: nz ! maximum number of cells in z direction integer :: ng ! maximum number of energy groups integer :: i ! iteration counter + integer :: g ! index for group integer :: ijk(3) ! spatial bin location integer :: e_bin ! energy bin of source particle + integer :: mesh_bin ! mesh bin of soruce particle integer :: n_groups ! number of energy groups + real(8) :: norm ! normalization factor logical :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh #ifdef MPI @@ -246,7 +249,7 @@ contains ! allocate arrays in cmfd object (can take out later extend to multigroup) if (.not.allocated(cmfd%sourcecounts)) then - allocate(cmfd%sourcecounts(ng,nx,ny,nz)) + allocate(cmfd%sourcecounts(ng, nx*ny*nz)) cmfd % sourcecounts = 0 end if if (.not.allocated(cmfd % weightfactors)) then @@ -263,7 +266,6 @@ contains ! Count bank sites in mesh and reverse due to egrid structure call count_bank_sites(cmfd_mesh, source_bank, cmfd%sourcecounts, & cmfd % egrid, sites_outside=outside, size_bank=work) - cmfd % sourcecounts = cmfd%sourcecounts(ng:1:-1,:,:,:) ! Check for sites outside of the mesh if (master .and. outside) then @@ -272,10 +274,21 @@ contains ! Have master compute weight factors (watch for 0s) if (master) then - where(cmfd % cmfd_src > ZERO .and. cmfd % sourcecounts > ZERO) - cmfd % weightfactors = cmfd % cmfd_src/sum(cmfd % cmfd_src)* & - sum(cmfd % sourcecounts) / cmfd % sourcecounts - end where + ! Calculate normalization factor + norm = sum(cmfd % sourcecounts) / sum(cmfd % cmfd_src) + + do mesh_bin = 1, nx*ny*nz + call cmfd_mesh % get_indices_from_bin(mesh_bin, ijk) + do g = 1, ng + if (cmfd % sourcecounts(ng - g + 1, mesh_bin) > ZERO) then + if (cmfd % cmfd_src(g,ijk(1),ijk(2),ijk(3)) > ZERO) then + cmfd % weightfactors(g,ijk(1),ijk(2),ijk(3)) = & + cmfd % cmfd_src(g,ijk(1),ijk(2),ijk(3)) * norm & + / cmfd % sourcecounts(ng - g + 1, mesh_bin) + end if + end if + end do + end do end if if (.not. cmfd_feedback) return @@ -315,8 +328,7 @@ contains ! Reweight particle source_bank(i) % wgt = source_bank(i) % wgt * & - cmfd % weightfactors(e_bin, ijk(1), ijk(2), ijk(3)) - + cmfd % weightfactors(e_bin, ijk(1), ijk(2), ijk(3)) end do end subroutine cmfd_reweight diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index 887edc559..2e6162b49 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -53,7 +53,7 @@ module cmfd_header real(8), allocatable :: openmc_src(:,:,:,:) ! Source sites in each mesh box - real(8), allocatable :: sourcecounts(:,:,:,:) + real(8), allocatable :: sourcecounts(:,:) ! Weight adjustment factors real(8), allocatable :: weightfactors(:,:,:,:) @@ -198,7 +198,7 @@ contains if (.not. allocated(this % openmc_src)) allocate(this % openmc_src(ng,nx,ny,nz)) ! Allocate source weight modification vars - if (.not. allocated(this % sourcecounts)) allocate(this % sourcecounts(ng,nx,ny,nz)) + if (.not. allocated(this % sourcecounts)) allocate(this % sourcecounts(ng,nx*ny*nz)) if (.not. allocated(this % weightfactors)) allocate(this % weightfactors(ng,nx,ny,nz)) ! Allocate batchwise parameters diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index a1bb35655..588cfea38 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -299,39 +299,33 @@ contains subroutine shannon_entropy() integer :: ent_idx ! entropy index - integer :: i, j, k ! index for bank sites + integer :: i ! index for mesh elements logical :: sites_outside ! were there sites outside entropy box? associate (m => meshes(index_entropy_mesh)) + ! count number of fission sites over mesh + call count_bank_sites(m, fission_bank, entropy_p, & + size_bank=n_bank, sites_outside=sites_outside) - ! count number of fission sites over mesh - call count_bank_sites(m, fission_bank, entropy_p, & - size_bank=n_bank, sites_outside=sites_outside) + ! display warning message if there were sites outside entropy box + if (sites_outside) then + if (master) call warning("Fission source site(s) outside of entropy box.") + end if - ! display warning message if there were sites outside entropy box - if (sites_outside) then - if (master) call warning("Fission source site(s) outside of entropy box.") - end if + ! sum values to obtain shannon entropy + if (master) then + ! Normalize to total weight of bank sites + entropy_p = entropy_p / sum(entropy_p) - ! sum values to obtain shannon entropy - if (master) then - ! Normalize to total weight of bank sites - entropy_p = entropy_p / sum(entropy_p) - - ent_idx = current_gen + gen_per_batch*(current_batch - 1) - entropy(ent_idx) = ZERO - do i = 1, m % dimension(1) - do j = 1, m % dimension(2) - do k = 1, m % dimension(3) - if (entropy_p(1,i,j,k) > ZERO) then - entropy(ent_idx) = entropy(ent_idx) - & - entropy_p(1,i,j,k) * log(entropy_p(1,i,j,k))/log(TWO) - end if - end do + ent_idx = current_gen + gen_per_batch*(current_batch - 1) + entropy(ent_idx) = ZERO + do i = 1, size(entropy_p, 2) + if (entropy_p(1,i) > ZERO) then + entropy(ent_idx) = entropy(ent_idx) - & + entropy_p(1,i) * log(entropy_p(1,i))/log(TWO) + end if end do - end do - end if - + end if end associate end subroutine shannon_entropy diff --git a/src/global.F90 b/src/global.F90 index dea17a102..013a519a1 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -70,11 +70,11 @@ module global real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength ! Shannon entropy - real(8), allocatable :: entropy(:) ! shannon entropy at each generation - real(8), allocatable :: entropy_p(:,:,:,:) ! % of source sites in each cell + real(8), allocatable :: entropy(:) ! shannon entropy at each generation + real(8), allocatable :: entropy_p(:,:) ! % of source sites in each cell ! Uniform fission source weighting - real(8), allocatable :: source_frac(:,:,:,:) + real(8), allocatable :: source_frac(:,:) ! ============================================================================ ! PARALLEL PROCESSING VARIABLES diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a2546c08c..45a8b1276 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -736,15 +736,7 @@ contains if (index_entropy_mesh > 0) then associate(m => meshes(index_entropy_mesh)) - ! Check if dimensions were specified -- if not, they will be calculated - ! automatically upon first entry into shannon_entropy - if (allocated(m % dimension)) then - ! If so, make sure proper number of values were given - if (m % n_dimension /= 3) then - call fatal_error("Dimension of entropy mesh must be given as three & - &integers.") - end if - else + if (.not. allocated(m % dimension)) then ! If the user did not specify how many mesh cells are to be used in ! each direction, we automatically determine an appropriate number of ! cells @@ -757,8 +749,7 @@ contains end if ! Allocate space for storing number of fission sites in each mesh cell - allocate(entropy_p(1, m % dimension(1), m % dimension(2), & - m % dimension(3))) + allocate(entropy_p(1, product(m % dimension))) end associate ! Turn on Shannon entropy calculation @@ -794,18 +785,8 @@ contains end if if (index_ufs_mesh > 0) then - associate (m => meshes(index_ufs_mesh)) - if (allocated(m % dimension)) then - if (m % n_dimension /= 3) then - call fatal_error("Dimension of UFS mesh must be given as three & - &integers.") - end if - end if - - ! Allocate source_frac - allocate(source_frac(1, m % dimension(1), m % dimension(2), & - m % dimension(3))) - end associate + ! Allocate array to store source fraction for UFS + allocate(source_frac(1, product(meshes(index_ufs_mesh) % dimension))) ! Turn on uniform fission source weighting ufs = .true. diff --git a/src/mesh.F90 b/src/mesh.F90 index 9b8943ff2..785d7761c 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -22,26 +22,25 @@ contains type(RegularMesh), intent(in) :: m ! mesh to count sites type(Bank), intent(in) :: bank_array(:) ! fission or source bank - real(8), intent(out) :: cnt(:,:,:,:) ! weight of sites in each + real(8), intent(out) :: cnt(:,:) ! weight of sites in each ! cell and energy group real(8), intent(in), optional :: energies(:) ! energy grid to search integer(8), intent(in), optional :: size_bank ! # of bank sites (on each proc) logical, intent(inout), optional :: sites_outside ! were there sites outside mesh? - real(8), allocatable :: cnt_(:,:,:,:) + real(8), allocatable :: cnt_(:,:) integer :: i ! loop index for local fission sites integer :: n_sites ! size of bank array - integer :: ijk(3) ! indices on mesh integer :: n ! number of energy groups / size - integer :: e_bin ! energy_bin + integer :: mesh_bin ! mesh bin + integer :: e_bin ! energy bin #ifdef MPI integer :: mpi_err ! MPI error code #endif - logical :: in_mesh ! was single site outside mesh? logical :: outside ! was any site outside mesh? ! initialize variables - allocate(cnt_(size(cnt,1), size(cnt,2), size(cnt,3), size(cnt,4))) + allocate(cnt_(size(cnt,1), size(cnt,2))) cnt_ = ZERO outside = .false. @@ -62,10 +61,10 @@ contains ! loop over fission sites and count how many are in each mesh box FISSION_SITES: do i = 1, n_sites ! determine scoring bin for entropy mesh - call m % get_indices(bank_array(i) % xyz, ijk, in_mesh) + call m % get_bin(bank_array(i) % xyz, mesh_bin) ! if outside mesh, skip particle - if (.not. in_mesh) then + if (mesh_bin == NO_BIN_FOUND) then outside = .true. cycle end if @@ -84,8 +83,7 @@ contains end if ! add to appropriate mesh box - cnt_(e_bin,ijk(1),ijk(2),ijk(3)) = cnt_(e_bin,ijk(1),ijk(2),ijk(3)) + & - bank_array(i) % wgt + cnt_(e_bin, mesh_bin) = cnt_(e_bin, mesh_bin) + bank_array(i) % wgt end do FISSION_SITES #ifdef MPI diff --git a/src/physics.F90 b/src/physics.F90 index 774106ddf..b57ac292e 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -1073,10 +1073,9 @@ contains integer :: nu_d(MAX_DELAYED_GROUPS) ! number of delayed neutrons born integer :: i ! loop index integer :: nu ! actual number of neutrons produced - integer :: ijk(3) ! indices in ufs mesh + integer :: mesh_bin ! mesh bin for source site real(8) :: nu_t ! total nu real(8) :: weight ! weight adjustment for ufs method - logical :: in_mesh ! source site in ufs mesh? type(Nuclide), pointer :: nuc ! Get pointers @@ -1090,14 +1089,14 @@ contains if (ufs) then associate (m => meshes(index_ufs_mesh)) ! Determine indices on ufs mesh for current location - call m % get_indices(p % coord(1) % xyz, ijk, in_mesh) - if (.not. in_mesh) then + call m % get_bin(p % coord(1) % xyz, mesh_bin) + if (mesh_bin == NO_BIN_FOUND) then call write_particle_restart(p) call fatal_error("Source site outside UFS mesh!") end if - if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then - weight = m % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) + if (source_frac(1, mesh_bin) /= ZERO) then + weight = m % volume_frac / source_frac(1, mesh_bin) else weight = ONE end if diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 7f1ead66a..29cdc447f 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -176,12 +176,11 @@ contains integer :: dg ! delayed group integer :: gout ! group out integer :: nu ! actual number of neutrons produced - integer :: ijk(3) ! indices in ufs mesh + integer :: mesh_bin ! mesh bin for source site real(8) :: nu_t ! total nu real(8) :: mu ! fission neutron angular cosine real(8) :: phi ! fission neutron azimuthal angle real(8) :: weight ! weight adjustment for ufs method - logical :: in_mesh ! source site in ufs mesh? class(Mgxs), pointer :: xs ! Get Pointers @@ -195,15 +194,15 @@ contains if (ufs) then associate (m => meshes(index_ufs_mesh)) ! Determine indices on ufs mesh for current location - call m % get_indices(p % coord(1) % xyz, ijk, in_mesh) + call m % get_bin(p % coord(1) % xyz, mesh_bin) - if (.not. in_mesh) then + if (mesh_bin == NO_BIN_FOUND) then call write_particle_restart(p) call fatal_error("Source site outside UFS mesh!") end if - if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then - weight = m % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3)) + if (source_frac(1, mesh_bin) /= ZERO) then + weight = m % volume_frac / source_frac(1, mesh_bin) else weight = ONE end if From 1740d9fb8da81dd6f3cace57160e19c16c1ba6ca Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 07:05:11 -0500 Subject: [PATCH 162/229] Move accumulate tally into type-bound procedure --- src/tallies/tally.F90 | 35 +------------------------------ src/tallies/tally_header.F90 | 40 +++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 3c83aa6e9..2a948a869 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4256,7 +4256,7 @@ contains if (master .or. (.not. reduce_tallies)) then ! Accumulate results for each tally do i = 1, active_tallies % size() - call accumulate_tally(tallies(active_tallies % data(i)) % obj) + call tallies(active_tallies % data(i)) % obj % accumulate() end do if (run_mode == MODE_EIGENVALUE) then @@ -4345,39 +4345,6 @@ contains end subroutine reduce_tally_results #endif -!=============================================================================== -! ACCUMULATE_TALLY -!=============================================================================== - - subroutine accumulate_tally(t) - - type(TallyObject), intent(inout) :: t - - integer :: i, j - real(C_DOUBLE) :: val - - ! Increment number of realizations - if (reduce_tallies) then - t % n_realizations = t % n_realizations + 1 - else - t % n_realizations = t % n_realizations + n_procs - end if - - ! Accumulate each result - do j = 1, size(t % results, 3) - do i = 1, size(t % results, 2) - val = t % results(RESULT_VALUE, i, j)/total_weight - t % results(RESULT_VALUE, i, j) = ZERO - - t % results(RESULT_SUM, i, j) = & - t % results(RESULT_SUM, i, j) + val - t % results(RESULT_SUM_SQ, i, j) = & - t % results(RESULT_SUM_SQ, i, j) + val*val - end do - end do - - end subroutine accumulate_tally - !=============================================================================== ! SETUP_ACTIVE_TALLIES !=============================================================================== diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 6c5c3106b..9c6e69f84 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -7,7 +7,9 @@ module tally_header use constants use error use dict_header, only: DictIntInt + use message_passing, only: n_procs use nuclide_header, only: nuclide_dict + use settings, only: reduce_tallies use stl_vector, only: VectorInt use string, only: to_lower, to_f_string, str_to_int use tally_filter_header, only: TallyFilterContainer, filters, n_filters @@ -108,9 +110,10 @@ module tally_header integer :: deriv = NONE contains + procedure :: accumulate => tally_accumulate + procedure :: allocate_results => tally_allocate_results procedure :: read_results_hdf5 => tally_read_results_hdf5 procedure :: write_results_hdf5 => tally_write_results_hdf5 - procedure :: allocate_results => tally_allocate_results procedure :: set_filters => tally_set_filters end type TallyObject @@ -161,6 +164,37 @@ module tally_header contains +!=============================================================================== +! ACCUMULATE_TALLY +!=============================================================================== + + subroutine tally_accumulate(this) + class(TallyObject), intent(inout) :: this + + integer :: i, j + real(C_DOUBLE) :: val + + ! Increment number of realizations + if (reduce_tallies) then + this % n_realizations = this % n_realizations + 1 + else + this % n_realizations = this % n_realizations + n_procs + end if + + ! Accumulate each result + do j = 1, size(this % results, 3) + do i = 1, size(this % results, 2) + val = this % results(RESULT_VALUE, i, j)/total_weight + this % results(RESULT_VALUE, i, j) = ZERO + + this % results(RESULT_SUM, i, j) = & + this % results(RESULT_SUM, i, j) + val + this % results(RESULT_SUM_SQ, i, j) = & + this % results(RESULT_SUM_SQ, i, j) + val*val + end do + end do + end subroutine tally_accumulate + subroutine tally_write_results_hdf5(this, group_id) class(TallyObject), intent(in) :: this integer(HID_T), intent(in) :: group_id @@ -268,8 +302,8 @@ contains integer(C_INT32_T), intent(in) :: filter_indices(:) integer(C_INT) :: err - integer :: i ! index in t % filter/stride - integer :: j ! index in t % find_filter + integer :: i ! index in this % filter/stride + integer :: j ! index in this % find_filter integer :: k ! index in global filters array integer :: n ! number of filters integer :: stride ! filter stride From df60ae0dfd014cf441d0f27cb4392b36f060a981 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 10:56:12 -0500 Subject: [PATCH 163/229] Move external source reading to source_header and distribution modules --- src/distribution_multivariate.F90 | 97 +++++++++++- src/input_xml.F90 | 244 +----------------------------- src/source_header.F90 | 189 ++++++++++++++++++++++- 3 files changed, 287 insertions(+), 243 deletions(-) diff --git a/src/distribution_multivariate.F90 b/src/distribution_multivariate.F90 index 68b246df8..650ab26fa 100644 --- a/src/distribution_multivariate.F90 +++ b/src/distribution_multivariate.F90 @@ -1,9 +1,11 @@ module distribution_multivariate use constants, only: ONE, TWO, PI - use distribution_univariate, only: Distribution + use distribution_univariate + use error, only: fatal_error use random_lcg, only: prn use math, only: rotate_angle + use xml_interface implicit none @@ -58,10 +60,17 @@ module distribution_multivariate type, abstract :: SpatialDistribution contains + procedure(spatial_distribution_from_xml_), deferred :: from_xml procedure(spatial_distribution_sample_), deferred :: sample end type SpatialDistribution abstract interface + subroutine spatial_distribution_from_xml_(this, node) + import SpatialDistribution, XMLNode + class(SpatialDistribution), intent(inout) :: this + type(XMLNode), intent(in) :: node + end subroutine spatial_distribution_from_xml_ + function spatial_distribution_sample_(this) result(xyz) import SpatialDistribution class(SpatialDistribution), intent(in) :: this @@ -74,6 +83,7 @@ module distribution_multivariate class(Distribution), allocatable :: y class(Distribution), allocatable :: z contains + procedure :: from_xml => cartesian_independent_from_xml procedure :: sample => cartesian_independent_sample end type CartesianIndependent @@ -82,12 +92,14 @@ module distribution_multivariate real(8) :: upper_right(3) logical :: only_fissionable = .false. contains + procedure :: from_xml => spatial_box_from_xml procedure :: sample => spatial_box_sample end type SpatialBox type, extends(SpatialDistribution) :: SpatialPoint real(8) :: xyz(3) contains + procedure :: from_xml => spatial_point_from_xml procedure :: sample => spatial_point_sample end type SpatialPoint @@ -132,6 +144,55 @@ contains uvw(:) = this % reference_uvw end function monodirectional_sample + subroutine cartesian_independent_from_xml(this, node) + class(CartesianIndependent), intent(inout) :: this + type(XMLNode), intent(in) :: node + + type(XMLNode) :: node_dist + + ! Read distribution for x coordinate + if (check_for_node(node, "x")) then + node_dist = node % child("x") + call distribution_from_xml(this % x, node_dist) + else + allocate(Discrete :: this % x) + select type (dist => this % x) + type is (Discrete) + allocate(dist % x(1), dist % p(1)) + dist % x(1) = ZERO + dist % p(1) = ONE + end select + end if + + ! Read distribution for y coordinate + if (check_for_node(node, "y")) then + node_dist = node % child("y") + call distribution_from_xml(this % y, node_dist) + else + allocate(Discrete :: this % y) + select type (dist => this % y) + type is (Discrete) + allocate(dist % x(1), dist % p(1)) + dist % x(1) = ZERO + dist % p(1) = ONE + end select + end if + + if (check_for_node(node, "z")) then + node_dist = node % child("z") + call distribution_from_xml(this % z, node_dist) + else + allocate(Discrete :: this % z) + select type (dist => this % z) + type is (Discrete) + allocate(dist % x(1), dist % p(1)) + dist % x(1) = ZERO + dist % p(1) = ONE + end select + end if + + end subroutine cartesian_independent_from_xml + function cartesian_independent_sample(this) result(xyz) class(CartesianIndependent), intent(in) :: this real(8) :: xyz(3) @@ -141,6 +202,26 @@ contains xyz(3) = this % z % sample() end function cartesian_independent_sample + subroutine spatial_box_from_xml(this, node) + class(SpatialBox), intent(inout) :: this + type(XMLNode), intent(in) :: node + + real(8), allocatable :: temp_real(:) + + ! Make sure correct number of parameters are given + if (node_word_count(node, "parameters") /= 6) then + call fatal_error('Box/fission spatial source must have & + &six parameters specified.') + end if + + ! Read lower-right/upper-left coordinates + allocate(temp_real(6)) + call get_node_array(node, "parameters", temp_real) + this % lower_left(:) = temp_real(1:3) + this % upper_right(:) = temp_real(4:6) + deallocate(temp_real) + end subroutine spatial_box_from_xml + function spatial_box_sample(this) result(xyz) class(SpatialBox), intent(in) :: this real(8) :: xyz(3) @@ -152,6 +233,20 @@ contains xyz(:) = this % lower_left + r*(this % upper_right - this % lower_left) end function spatial_box_sample + subroutine spatial_point_from_xml(this, node) + class(SpatialPoint), intent(inout) :: this + type(XMLNode), intent(in) :: node + + ! Make sure correct number of parameters are given + if (node_word_count(node, "parameters") /= 3) then + call fatal_error('Point spatial source must have & + &three parameters specified.') + end if + + ! Read location of point source + call get_node_array(node, "parameters", this % xyz) + end subroutine spatial_point_from_xml + function spatial_point_sample(this) result(xyz) class(SpatialPoint), intent(in) :: this real(8) :: xyz(3) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 45a8b1276..f01bda4a2 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -147,7 +147,6 @@ contains integer(C_INT32_T) :: i_start, i_end integer(C_INT) :: err integer, allocatable :: temp_int_array(:) - real(8), allocatable :: temp_real(:) integer :: n_tracks logical :: file_exists character(MAX_WORD_LEN) :: type @@ -155,10 +154,6 @@ contains type(XMLDocument) :: doc type(XMLNode) :: root type(XMLNode) :: node_mode - type(XMLNode) :: node_source - type(XMLNode) :: node_space - type(XMLNode) :: node_angle - type(XMLNode) :: node_dist type(XMLNode) :: node_cutoff type(XMLNode) :: node_entropy type(XMLNode) :: node_ufs @@ -400,241 +395,14 @@ contains allocate(external_source(n)) end if + ! Check if we want to write out source + if (check_for_node(root, "write_initial_source")) then + call get_node_value(root, "write_initial_source", write_initial_source) + end if + ! Read each source do i = 1, n - ! Get pointer to source - node_source = node_source_list(i) - - ! Check if we want to write out source - if (check_for_node(node_source, "write_initial")) then - call get_node_value(node_source, "write_initial", write_initial_source) - end if - - ! Check for source strength - if (check_for_node(node_source, "strength")) then - call get_node_value(node_source, "strength", external_source(i)%strength) - else - external_source(i)%strength = ONE - end if - - ! Check for external source file - if (check_for_node(node_source, "file")) then - ! Copy path of source file - call get_node_value(node_source, "file", path_source) - - ! Check if source file exists - inquire(FILE=path_source, EXIST=file_exists) - if (.not. file_exists) then - call fatal_error("Source file '" // trim(path_source) & - // "' does not exist!") - end if - - else - - ! Spatial distribution for external source - if (check_for_node(node_source, "space")) then - - ! Get pointer to spatial distribution - node_space = node_source % child("space") - - ! Check for type of spatial distribution - type = '' - if (check_for_node(node_space, "type")) & - call get_node_value(node_space, "type", type) - select case (to_lower(type)) - case ('cartesian') - allocate(CartesianIndependent :: external_source(i)%space) - - case ('box') - allocate(SpatialBox :: external_source(i)%space) - - case ('fission') - allocate(SpatialBox :: external_source(i)%space) - select type(space => external_source(i)%space) - type is (SpatialBox) - space%only_fissionable = .true. - end select - - case ('point') - allocate(SpatialPoint :: external_source(i)%space) - - case default - call fatal_error("Invalid spatial distribution for external source: "& - // trim(type)) - end select - - select type (space => external_source(i)%space) - type is (CartesianIndependent) - ! Read distribution for x coordinate - if (check_for_node(node_space, "x")) then - node_dist = node_space % child("x") - call distribution_from_xml(space%x, node_dist) - else - allocate(Discrete :: space%x) - select type (dist => space%x) - type is (Discrete) - allocate(dist%x(1), dist%p(1)) - dist%x(1) = ZERO - dist%p(1) = ONE - end select - end if - - ! Read distribution for y coordinate - if (check_for_node(node_space, "y")) then - node_dist = node_space % child("y") - call distribution_from_xml(space%y, node_dist) - else - allocate(Discrete :: space%y) - select type (dist => space%y) - type is (Discrete) - allocate(dist%x(1), dist%p(1)) - dist%x(1) = ZERO - dist%p(1) = ONE - end select - end if - - if (check_for_node(node_space, "z")) then - node_dist = node_space % child("z") - call distribution_from_xml(space%z, node_dist) - else - allocate(Discrete :: space%z) - select type (dist => space%z) - type is (Discrete) - allocate(dist%x(1), dist%p(1)) - dist%x(1) = ZERO - dist%p(1) = ONE - end select - end if - - type is (SpatialBox) - ! Make sure correct number of parameters are given - if (node_word_count(node_space, "parameters") /= 6) then - call fatal_error('Box/fission spatial source must have & - &six parameters specified.') - end if - - ! Read lower-right/upper-left coordinates - allocate(temp_real(6)) - call get_node_array(node_space, "parameters", temp_real) - space%lower_left(:) = temp_real(1:3) - space%upper_right(:) = temp_real(4:6) - deallocate(temp_real) - - type is (SpatialPoint) - ! Make sure correct number of parameters are given - if (node_word_count(node_space, "parameters") /= 3) then - call fatal_error('Point spatial source must have & - &three parameters specified.') - end if - - ! Read location of point source - allocate(temp_real(3)) - call get_node_array(node_space, "parameters", temp_real) - space%xyz(:) = temp_real - deallocate(temp_real) - - end select - - else - ! If no spatial distribution specified, make it a point source - allocate(SpatialPoint :: external_source(i) % space) - select type (space => external_source(i) % space) - type is (SpatialPoint) - space % xyz(:) = [ZERO, ZERO, ZERO] - end select - end if - - ! Determine external source angular distribution - if (check_for_node(node_source, "angle")) then - - ! Get pointer to angular distribution - node_angle = node_source % child("angle") - - ! Check for type of angular distribution - type = '' - if (check_for_node(node_angle, "type")) & - call get_node_value(node_angle, "type", type) - select case (to_lower(type)) - case ('isotropic') - allocate(Isotropic :: external_source(i)%angle) - - case ('monodirectional') - allocate(Monodirectional :: external_source(i)%angle) - - case ('mu-phi') - allocate(PolarAzimuthal :: external_source(i)%angle) - - case default - call fatal_error("Invalid angular distribution for external source: "& - // trim(type)) - end select - - ! Read reference directional unit vector - if (check_for_node(node_angle, "reference_uvw")) then - n = node_word_count(node_angle, "reference_uvw") - if (n /= 3) then - call fatal_error('Angular distribution reference direction must have & - &three parameters specified.') - end if - call get_node_array(node_angle, "reference_uvw", & - external_source(i)%angle%reference_uvw) - else - ! By default, set reference unit vector to be positive z-direction - external_source(i)%angle%reference_uvw(:) = [ZERO, ZERO, ONE] - end if - - ! Read parameters for angle distribution - select type (angle => external_source(i)%angle) - type is (Monodirectional) - call get_node_array(node_angle, "reference_uvw", & - external_source(i)%angle%reference_uvw) - - type is (PolarAzimuthal) - if (check_for_node(node_angle, "mu")) then - node_dist = node_angle % child("mu") - call distribution_from_xml(angle%mu, node_dist) - else - allocate(Uniform :: angle%mu) - select type (mu => angle%mu) - type is (Uniform) - mu%a = -ONE - mu%b = ONE - end select - end if - - if (check_for_node(node_angle, "phi")) then - node_dist = node_angle % child("phi") - call distribution_from_xml(angle%phi, node_dist) - else - allocate(Uniform :: angle%phi) - select type (phi => angle%phi) - type is (Uniform) - phi%a = ZERO - phi%b = TWO*PI - end select - end if - end select - - else - ! Set default angular distribution isotropic - allocate(Isotropic :: external_source(i)%angle) - external_source(i)%angle%reference_uvw(:) = [ZERO, ZERO, ONE] - end if - - ! Determine external source energy distribution - if (check_for_node(node_source, "energy")) then - node_dist = node_source % child("energy") - call distribution_from_xml(external_source(i)%energy, node_dist) - else - ! Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 - allocate(Watt :: external_source(i)%energy) - select type(energy => external_source(i)%energy) - type is (Watt) - energy%a = 0.988e6_8 - energy%b = 2.249e-6_8 - end select - end if - end if + call external_source(i) % from_xml(node_source_list(i), path_source) end do ! Survival biasing diff --git a/src/source_header.F90 b/src/source_header.F90 index eefc007a4..3ae3aca96 100644 --- a/src/source_header.F90 +++ b/src/source_header.F90 @@ -1,20 +1,201 @@ module source_header - use distribution_univariate, only: Distribution - use distribution_multivariate, only: UnitSphereDistribution, SpatialDistribution + use constants + use distribution_univariate + use distribution_multivariate + use error, only: fatal_error + use string, only: to_lower + use xml_interface implicit none + private !=============================================================================== ! SOURCEDISTRIBUTION describes an external source of particles for a ! fixed-source problem or for the starting source in a k eigenvalue problem !=============================================================================== - type SourceDistribution - real(8) :: strength ! source strength + type, public :: SourceDistribution + real(8) :: strength = ONE ! source strength class(SpatialDistribution), allocatable :: space ! spatial distribution class(UnitSphereDistribution), allocatable :: angle ! angle distribution class(Distribution), allocatable :: energy ! energy distribution + contains + procedure :: from_xml => source_from_xml end type SourceDistribution + ! External source distributions + type(SourceDistribution), public, allocatable :: external_source(:) + +contains + + subroutine source_from_xml(this, node, path_source) + class(SourceDistribution), intent(inout) :: this + type(XMLNode), intent(in) :: node + character(MAX_FILE_LEN), intent(out) :: path_source + + integer :: n + logical :: file_exists + character(MAX_WORD_LEN) :: type + type(XMLNode) :: node_space + type(XMLNode) :: node_angle + type(XMLNode) :: node_dist + + ! Check for source strength + if (check_for_node(node, "strength")) then + call get_node_value(node, "strength", this % strength) + end if + + ! Check for external source file + if (check_for_node(node, "file")) then + ! Copy path of source file + call get_node_value(node, "file", path_source) + + ! Check if source file exists + inquire(FILE=path_source, EXIST=file_exists) + if (.not. file_exists) then + call fatal_error("Source file '" // trim(path_source) & + // "' does not exist!") + end if + + else + + ! Spatial distribution for external source + if (check_for_node(node, "space")) then + + ! Get pointer to spatial distribution + node_space = node % child("space") + + ! Check for type of spatial distribution + type = '' + if (check_for_node(node_space, "type")) & + call get_node_value(node_space, "type", type) + select case (to_lower(type)) + case ('cartesian') + allocate(CartesianIndependent :: this % space) + + case ('box') + allocate(SpatialBox :: this % space) + + case ('fission') + allocate(SpatialBox :: this % space) + select type(space => this % space) + type is (SpatialBox) + space % only_fissionable = .true. + end select + + case ('point') + allocate(SpatialPoint :: this % space) + + case default + call fatal_error("Invalid spatial distribution for external source: "& + // trim(type)) + end select + + ! Read spatial distribution from XML + call this % space % from_xml(node_space) + + else + ! If no spatial distribution specified, make it a point source + allocate(SpatialPoint :: this % space) + select type (space => this % space) + type is (SpatialPoint) + space % xyz(:) = [ZERO, ZERO, ZERO] + end select + end if + + ! Determine external source angular distribution + if (check_for_node(node, "angle")) then + + ! Get pointer to angular distribution + node_angle = node % child("angle") + + ! Check for type of angular distribution + type = '' + if (check_for_node(node_angle, "type")) & + call get_node_value(node_angle, "type", type) + select case (to_lower(type)) + case ('isotropic') + allocate(Isotropic :: this % angle) + + case ('monodirectional') + allocate(Monodirectional :: this % angle) + + case ('mu-phi') + allocate(PolarAzimuthal :: this % angle) + + case default + call fatal_error("Invalid angular distribution for external source: "& + // trim(type)) + end select + + ! Read reference directional unit vector + if (check_for_node(node_angle, "reference_uvw")) then + n = node_word_count(node_angle, "reference_uvw") + if (n /= 3) then + call fatal_error('Angular distribution reference direction must have & + &three parameters specified.') + end if + call get_node_array(node_angle, "reference_uvw", & + this % angle % reference_uvw) + else + ! By default, set reference unit vector to be positive z-direction + this % angle % reference_uvw(:) = [ZERO, ZERO, ONE] + end if + + ! Read parameters for angle distribution + select type (angle => this % angle) + type is (Monodirectional) + call get_node_array(node_angle, "reference_uvw", & + this % angle % reference_uvw) + + type is (PolarAzimuthal) + if (check_for_node(node_angle, "mu")) then + node_dist = node_angle % child("mu") + call distribution_from_xml(angle % mu, node_dist) + else + allocate(Uniform :: angle%mu) + select type (mu => angle%mu) + type is (Uniform) + mu % a = -ONE + mu % b = ONE + end select + end if + + if (check_for_node(node_angle, "phi")) then + node_dist = node_angle % child("phi") + call distribution_from_xml(angle % phi, node_dist) + else + allocate(Uniform :: angle%phi) + select type (phi => angle%phi) + type is (Uniform) + phi % a = ZERO + phi % b = TWO*PI + end select + end if + end select + + else + ! Set default angular distribution isotropic + allocate(Isotropic :: this % angle) + this % angle % reference_uvw(:) = [ZERO, ZERO, ONE] + end if + + ! Determine external source energy distribution + if (check_for_node(node, "energy")) then + node_dist = node % child("energy") + call distribution_from_xml(this % energy, node_dist) + else + ! Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 + allocate(Watt :: this % energy) + select type(energy => this % energy) + type is (Watt) + energy % a = 0.988e6_8 + energy % b = 2.249e-6_8 + end select + end if + end if + + end subroutine source_from_xml + end module source_header From df9528d9b69501bc6d8e218ec4232f5cb06cdc69 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 11:39:50 -0500 Subject: [PATCH 164/229] Separate all tally filters into their own modules --- CMakeLists.txt | 14 +- src/settings.F90 | 141 +++++ src/tallies/tally_filter.F90 | 697 +--------------------- src/tallies/tally_filter_azimuthal.F90 | 83 +++ src/tallies/tally_filter_cell.F90 | 99 +++ src/tallies/tally_filter_cellborn.F90 | 93 +++ src/tallies/tally_filter_cellfrom.F90 | 77 +++ src/tallies/tally_filter_delayedgroup.F90 | 60 ++ src/tallies/tally_filter_energyfunc.F90 | 91 +++ src/tallies/tally_filter_mu.F90 | 74 +++ src/tallies/tally_filter_polar.F90 | 82 +++ src/tallies/tally_filter_surface.F90 | 92 +++ src/tallies/tally_filter_universe.F90 | 100 ++++ 13 files changed, 1017 insertions(+), 686 deletions(-) create mode 100644 src/settings.F90 create mode 100644 src/tallies/tally_filter_azimuthal.F90 create mode 100644 src/tallies/tally_filter_cell.F90 create mode 100644 src/tallies/tally_filter_cellborn.F90 create mode 100644 src/tallies/tally_filter_cellfrom.F90 create mode 100644 src/tallies/tally_filter_delayedgroup.F90 create mode 100644 src/tallies/tally_filter_energyfunc.F90 create mode 100644 src/tallies/tally_filter_mu.F90 create mode 100644 src/tallies/tally_filter_polar.F90 create mode 100644 src/tallies/tally_filter_surface.F90 create mode 100644 src/tallies/tally_filter_universe.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 86bc20f59..168663110 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,8 +119,8 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU) list(APPEND f90flags -cpp -std=f2008ts -fbacktrace -O2) if(debug) list(REMOVE_ITEM f90flags -O2) - list(APPEND f90flags -g -Wall -pedantic -fbounds-check - -ffpe-trap=invalid,overflow,underflow) + list(APPEND f90flags -g -Wall -Wno-unused-dummy-argument -pedantic + -fbounds-check -ffpe-trap=invalid,overflow,underflow) list(APPEND ldflags -g) endif() if(profile) @@ -379,10 +379,20 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally.F90 src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 + src/tallies/tally_filter_azimuthal.F90 + src/tallies/tally_filter_cell.F90 + src/tallies/tally_filter_cellborn.F90 + src/tallies/tally_filter_cellfrom.F90 + src/tallies/tally_filter_delayedgroup.F90 src/tallies/tally_filter_distribcell.F90 src/tallies/tally_filter_energy.F90 + src/tallies/tally_filter_energyfunc.F90 src/tallies/tally_filter_material.F90 src/tallies/tally_filter_mesh.F90 + src/tallies/tally_filter_mu.F90 + src/tallies/tally_filter_polar.F90 + src/tallies/tally_filter_surface.F90 + src/tallies/tally_filter_universe.F90 src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 diff --git a/src/settings.F90 b/src/settings.F90 new file mode 100644 index 000000000..d1d41a75c --- /dev/null +++ b/src/settings.F90 @@ -0,0 +1,141 @@ +module settings + + use constants + use set_header, only: SetInt + use source_header + + implicit none + + ! ============================================================================ + ! ENERGY TREATMENT RELATED VARIABLES + logical :: run_CE = .true. ! Run in CE mode? + + ! ============================================================================ + ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES + + ! Unreoslved resonance probablity tables + logical :: urr_ptables_on = .true. + + ! Default temperature and method for choosing temperatures + integer :: temperature_method = TEMPERATURE_NEAREST + logical :: temperature_multipole = .false. + real(8) :: temperature_tolerance = 10.0_8 + real(8) :: temperature_default = 293.6_8 + real(8) :: temperature_range(2) = [ZERO, ZERO] + + integer :: n_log_bins ! number of bins for logarithmic grid + + ! ============================================================================ + ! MULTI-GROUP CROSS SECTION RELATED VARIABLES + + ! Maximum Data Order + integer :: max_order + + ! Whether or not to convert Legendres to tabulars + logical :: legendre_to_tabular = .true. + + ! Number of points to use in the Legendre to tabular conversion + integer :: legendre_to_tabular_points = 33 + + ! Assume all tallies are spatially distinct + logical :: assume_separate = .false. + + ! Use confidence intervals for results instead of standard deviations + logical :: confidence_intervals = .false. + + ! ============================================================================ + ! SIMULATION VARIABLES + + integer(8) :: n_particles = 0 ! # of particles per generation + integer :: n_batches ! # of batches + integer :: n_inactive ! # of inactive batches + integer :: n_active ! # of active batches + integer :: gen_per_batch = 1 ! # of generations per batch + + integer :: n_max_batches ! max # of batches + integer :: n_batch_interval = 1 ! batch interval for triggers + logical :: pred_batches = .false. ! predict batches for triggers + logical :: trigger_on = .false. ! flag for turning triggers on/off + + logical :: entropy_on = .false. + integer :: index_entropy_mesh = -1 + + logical :: ufs = .false. + integer :: index_ufs_mesh = -1 + + ! Write source at end of simulation + logical :: source_separate = .false. + logical :: source_write = .true. + logical :: source_latest = .false. + + ! Variance reduction settins + logical :: survival_biasing = .false. + real(8) :: weight_cutoff = 0.25_8 + real(8) :: energy_cutoff = ZERO + real(8) :: weight_survive = ONE + + ! Mode to run in (fixed source, eigenvalue, plotting, etc) + integer :: run_mode = NONE + + ! Restart run + logical :: restart_run = .false. + + ! The verbosity controls how much information will be printed to the screen + ! and in logs + integer :: verbosity = 7 + + logical :: check_overlaps = .false. + + ! Trace for single particle + integer :: trace_batch + integer :: trace_gen + integer(8) :: trace_particle + + ! Particle tracks + logical :: write_all_tracks = .false. + integer, allocatable :: track_identifiers(:,:) + + ! Particle restart run + logical :: particle_restart_run = .false. + + ! Write out initial source + logical :: write_initial_source = .false. + + ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE + logical :: create_fission_neutrons = .true. + + ! Information about state points to be written + integer :: n_state_points = 0 + type(SetInt) :: statepoint_batch + + ! Information about source points to be written + integer :: n_source_points = 0 + type(SetInt) :: sourcepoint_batch + + character(MAX_FILE_LEN) :: path_input ! Path to input file + character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml + character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library + character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source + character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point + character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point + character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart + character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory + + ! Various output options + logical :: output_summary = .true. + logical :: output_tallies = .true. + + ! Resonance scattering settings + logical :: res_scat_on = .false. ! is resonance scattering treated? + integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method + real(8) :: res_scat_energy_min = 0.01_8 + real(8) :: res_scat_energy_max = 1000.0_8 + character(10), allocatable :: res_scat_nuclides(:) + + ! Is CMFD active + logical :: cmfd_run = .false. + + ! No reduction at end of batch + logical :: reduce_tallies = .true. + +end module settings diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index dc3aa36b1..3b96cade3 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -1,704 +1,33 @@ module tally_filter + use, intrinsic :: ISO_C_BINDING + use hdf5, only: HID_T - use algorithm, only: binary_search - use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION, ERROR_REAL - use dict_header, only: DictIntInt use error - use geometry_header - use hdf5_interface - use particle_header, only: Particle - use surface_header - use string, only: to_str, to_f_string + use string, only: to_f_string use tally_filter_header ! Inherit other filters + use tally_filter_azimuthal + use tally_filter_cell + use tally_filter_cellborn + use tally_filter_cellfrom + use tally_filter_delayedgroup use tally_filter_distribcell use tally_filter_energy + use tally_filter_energyfunc use tally_filter_material use tally_filter_mesh + use tally_filter_mu + use tally_filter_polar + use tally_filter_surface + use tally_filter_universe implicit none -!=============================================================================== -! UNIVERSEFILTER specifies which geometric universes tally events reside in. -!=============================================================================== - type, extends(TallyFilter) :: UniverseFilter - integer, allocatable :: universes(:) - type(DictIntInt) :: map - contains - procedure :: get_all_bins => get_all_bins_universe - procedure :: to_statepoint => to_statepoint_universe - procedure :: text_label => text_label_universe - procedure :: initialize => initialize_universe - end type UniverseFilter - -!=============================================================================== -! CELLFILTER specifies which geometric cells tally events reside in. -!=============================================================================== - type, extends(TallyFilter) :: CellFilter - integer, allocatable :: cells(:) - type(DictIntInt) :: map - contains - procedure :: get_all_bins => get_all_bins_cell - procedure :: to_statepoint => to_statepoint_cell - procedure :: text_label => text_label_cell - procedure :: initialize => initialize_cell - end type CellFilter - -!=============================================================================== -! CELLFROMFILTER specifies which geometric cells particles exit when crossing a -! surface. -!=============================================================================== - type, extends(CellFilter) :: CellFromFilter - contains - procedure :: get_all_bins => get_all_bins_cell_from - procedure :: to_statepoint => to_statepoint_cell_from - procedure :: text_label => text_label_cell_from - end type CellFromFilter - -!=============================================================================== -! CELLBORNFILTER specifies which cell the particle was born in. -!=============================================================================== - type, extends(TallyFilter) :: CellbornFilter - integer, allocatable :: cells(:) - type(DictIntInt) :: map - contains - procedure :: get_all_bins => get_all_bins_cellborn - procedure :: to_statepoint => to_statepoint_cellborn - procedure :: text_label => text_label_cellborn - procedure :: initialize => initialize_cellborn - end type CellbornFilter - -!=============================================================================== -! SURFACEFILTER specifies which surface particles are crossing -!=============================================================================== - type, extends(TallyFilter) :: SurfaceFilter - integer, allocatable :: surfaces(:) - - ! True if this filter is used for surface currents - logical :: current = .false. - contains - procedure :: get_all_bins => get_all_bins_surface - procedure :: to_statepoint => to_statepoint_surface - procedure :: text_label => text_label_surface - procedure :: initialize => initialize_surface - end type SurfaceFilter - -!=============================================================================== -! DELAYEDGROUPFILTER bins outgoing fission neutrons in their delayed groups. -! The get_all_bins functionality is not actually used. The bins are manually -! iterated over in the scoring subroutines. -!=============================================================================== - type, extends(TallyFilter) :: DelayedGroupFilter - integer, allocatable :: groups(:) - contains - procedure :: get_all_bins => get_all_bins_dg - procedure :: to_statepoint => to_statepoint_dg - procedure :: text_label => text_label_dg - end type DelayedGroupFilter - -!=============================================================================== -! MUFILTER bins the incoming-outgoing direction cosine. This is only used for -! scatter reactions. -!=============================================================================== - type, extends(TallyFilter) :: MuFilter - real(8), allocatable :: bins(:) - contains - procedure :: get_all_bins => get_all_bins_mu - procedure :: to_statepoint => to_statepoint_mu - procedure :: text_label => text_label_mu - end type MuFilter - -!=============================================================================== -! POLARFILTER bins the incident neutron polar angle (relative to the global -! z-axis). -!=============================================================================== - type, extends(TallyFilter) :: PolarFilter - real(8), allocatable :: bins(:) - contains - procedure :: get_all_bins => get_all_bins_polar - procedure :: to_statepoint => to_statepoint_polar - procedure :: text_label => text_label_polar - end type PolarFilter - -!=============================================================================== -! AZIMUTHALFILTER bins the incident neutron azimuthal angle (relative to the -! global xy-plane). -!=============================================================================== - type, extends(TallyFilter) :: AzimuthalFilter - real(8), allocatable :: bins(:) - contains - procedure :: get_all_bins => get_all_bins_azimuthal - procedure :: to_statepoint => to_statepoint_azimuthal - procedure :: text_label => text_label_azimuthal - end type AzimuthalFilter - -!=============================================================================== -! EnergyFunctionFilter multiplies tally scores by an arbitrary function of -! incident energy described by a piecewise linear-linear interpolation. -!=============================================================================== - type, extends(TallyFilter) :: EnergyFunctionFilter - real(8), allocatable :: energy(:) - real(8), allocatable :: y(:) - - contains - procedure :: get_all_bins => get_all_bins_energyfunction - procedure :: to_statepoint => to_statepoint_energyfunction - procedure :: text_label => text_label_energyfunction - end type EnergyFunctionFilter - contains -!=============================================================================== -! METHODS: for a description of these methods, see their counterparts bound to -! the abstract TallyFilter class. -!=============================================================================== - -!=============================================================================== -! UniverseFilter methods -!=============================================================================== - subroutine get_all_bins_universe(this, p, estimator, match) - class(UniverseFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: i - - ! Iterate over coordinate levels to see which universes match - do i = 1, p % n_coord - if (this % map % has_key(p % coord(i) % universe)) then - call match % bins % push_back(this % map % get_key(p % coord(i) & - % universe)) - call match % weights % push_back(ONE) - end if - end do - - end subroutine get_all_bins_universe - - subroutine to_statepoint_universe(this, filter_group) - class(UniverseFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: universe_ids(:) - - call write_dataset(filter_group, "type", "universe") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(universe_ids(size(this % universes))) - do i = 1, size(this % universes) - universe_ids(i) = universes(this % universes(i)) % id - end do - call write_dataset(filter_group, "bins", universe_ids) - end subroutine to_statepoint_universe - - subroutine initialize_universe(this) - class(UniverseFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % universes(i) - if (universe_dict % has_key(id)) then - this % universes(i) = universe_dict % get_key(id) - else - call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on a tally filter.") - end if - end do - - ! Generate mapping from universe indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % universes(i), i) - end do - end subroutine initialize_universe - - function text_label_universe(this, bin) result(label) - class(UniverseFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Universe " // to_str(universes(this % universes(bin)) % id) - end function text_label_universe - -!=============================================================================== -! CellFilter methods -!=============================================================================== - subroutine get_all_bins_cell(this, p, estimator, match) - class(CellFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: i - - ! Iterate over coordinate levels to see with cells match - do i = 1, p % n_coord - if (this % map % has_key(p % coord(i) % cell)) then - call match % bins % push_back(this % map % get_key(p % coord(i) % cell)) - call match % weights % push_back(ONE) - end if - end do - - end subroutine get_all_bins_cell - - subroutine to_statepoint_cell(this, filter_group) - class(CellFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: cell_ids(:) - - call write_dataset(filter_group, "type", "cell") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(cell_ids(size(this % cells))) - do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id - end do - call write_dataset(filter_group, "bins", cell_ids) - end subroutine to_statepoint_cell - - subroutine initialize_cell(this) - class(CellFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % cells(i) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - - ! Generate mapping from cell indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) - end do - end subroutine initialize_cell - - function text_label_cell(this, bin) result(label) - class(CellFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Cell " // to_str(cells(this % cells(bin)) % id) - end function text_label_cell - -!=============================================================================== -! CellFromFilter methods -!=============================================================================== - subroutine get_all_bins_cell_from(this, p, estimator, match) - class(CellFromFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: i - - ! Starting one coordinate level deeper, find the next bin. - do i = 1, p % last_n_coord - if (this % map % has_key(p % last_cell(i))) then - call match % bins % push_back(this % map % get_key(p % last_cell(i))) - call match % weights % push_back(ONE) - exit - end if - end do - - end subroutine get_all_bins_cell_from - - subroutine to_statepoint_cell_from(this, filter_group) - class(CellFromFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: cell_ids(:) - - call write_dataset(filter_group, "type", "cellfrom") - call write_dataset(filter_group, "n_bins", this % n_bins) - - allocate(cell_ids(size(this % cells))) - do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id - end do - call write_dataset(filter_group, "bins", cell_ids) - end subroutine to_statepoint_cell_from - - function text_label_cell_from(this, bin) result(label) - class(CellFromFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Cell from " // to_str(cells(this % cells(bin)) % id) - end function text_label_cell_from - -!=============================================================================== -! CellbornFilter methods -!=============================================================================== - subroutine get_all_bins_cellborn(this, p, estimator, match) - class(CellbornFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - if (this % map % has_key(p % cell_born)) then - call match % bins % push_back(this % map % get_key(p % cell_born)) - call match % weights % push_back(ONE) - end if - - end subroutine get_all_bins_cellborn - - subroutine to_statepoint_cellborn(this, filter_group) - class(CellbornFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - integer :: i - integer, allocatable :: cell_ids(:) - - call write_dataset(filter_group, "type", "cellborn") - call write_dataset(filter_group, "n_bins", this % n_bins) - allocate(cell_ids(size(this % cells))) - do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id - end do - call write_dataset(filter_group, "bins", cell_ids) - end subroutine to_statepoint_cellborn - - subroutine initialize_cellborn(this) - class(CellbornFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % cells(i) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) - else - call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - - ! Generate mapping from cell indices to filter bins. - do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) - end do - end subroutine initialize_cellborn - - function text_label_cellborn(this, bin) result(label) - class(CellbornFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Birth Cell " // to_str(cells(this % cells(bin)) % id) - end function text_label_cellborn - -!=============================================================================== -! SurfaceFilter methods -!=============================================================================== - subroutine get_all_bins_surface(this, p, estimator, match) - class(SurfaceFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: i - - do i = 1, this % n_bins - if (abs(p % surface) == this % surfaces(i)) then - call match % bins % push_back(i) - if (p % surface < 0) then - call match % weights % push_back(-ONE) - else - call match % weights % push_back(ONE) - end if - exit - end if - end do - - end subroutine get_all_bins_surface - - subroutine to_statepoint_surface(this, filter_group) - class(SurfaceFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "surface") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % surfaces) - end subroutine to_statepoint_surface - - subroutine initialize_surface(this) - class(SurfaceFilter), intent(inout) :: this - - integer :: i, id - - ! Convert ids to indices. - do i = 1, this % n_bins - id = this % surfaces(i) - if (surface_dict % has_key(id)) then - this % surfaces(i) = surface_dict % get_key(id) - else - call fatal_error("Could not find surface " // trim(to_str(id)) & - &// " specified on tally filter.") - end if - end do - end subroutine initialize_surface - - function text_label_surface(this, bin) result(label) - class(SurfaceFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Surface " // to_str(surfaces(this % surfaces(bin)) % obj % id) - end function text_label_surface - -!=============================================================================== -! DelayedGroupFilter methods -!=============================================================================== - subroutine get_all_bins_dg(this, p, estimator, match) - class(DelayedGroupFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - call match % bins % push_back(1) - call match % weights % push_back(ONE) - end subroutine get_all_bins_dg - - subroutine to_statepoint_dg(this, filter_group) - class(DelayedGroupFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "delayedgroup") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % groups) - end subroutine to_statepoint_dg - - function text_label_dg(this, bin) result(label) - class(DelayedGroupFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - label = "Delayed Group " // to_str(this % groups(bin)) - end function text_label_dg - -!=============================================================================== -! MuFilter methods -!=============================================================================== - subroutine get_all_bins_mu(this, p, estimator, match) - class(MuFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n - integer :: bin - - n = this % n_bins - - ! Search to find incoming energy bin. - bin = binary_search(this % bins, n + 1, p % mu) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - end subroutine get_all_bins_mu - - subroutine to_statepoint_mu(this, filter_group) - class(MuFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "mu") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % bins) - end subroutine to_statepoint_mu - - function text_label_mu(this, bin) result(label) - class(MuFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - real(8) :: E0, E1 - - E0 = this % bins(bin) - E1 = this % bins(bin + 1) - label = "Change-in-Angle [" // trim(to_str(E0)) // ", " & - // trim(to_str(E1)) // ")" - end function text_label_mu - -!=============================================================================== -! PolarFilter methods -!=============================================================================== - subroutine get_all_bins_polar(this, p, estimator, match) - class(PolarFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n - integer :: bin - real(8) :: theta - - n = this % n_bins - - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - theta = acos(p % coord(1) % uvw(3)) - else - theta = acos(p % last_uvw(3)) - end if - - ! Search to find polar angle bin. - bin = binary_search(this % bins, n + 1, theta) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - end subroutine get_all_bins_polar - - subroutine to_statepoint_polar(this, filter_group) - class(PolarFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "polar") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % bins) - end subroutine to_statepoint_polar - - function text_label_polar(this, bin) result(label) - class(PolarFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - real(8) :: E0, E1 - - E0 = this % bins(bin) - E1 = this % bins(bin + 1) - label = "Polar Angle [" // trim(to_str(E0)) // ", " // trim(to_str(E1)) & - // ")" - end function text_label_polar - -!=============================================================================== -! AzimuthalFilter methods -!=============================================================================== - subroutine get_all_bins_azimuthal(this, p, estimator, match) - class(AzimuthalFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n - integer :: bin - real(8) :: phi - - n = this % n_bins - - ! Make sure the correct direction vector is used. - if (estimator == ESTIMATOR_TRACKLENGTH) then - phi = atan2(p % coord(1) % uvw(2), p % coord(1) % uvw(1)) - else - phi = atan2(p % last_uvw(2), p % last_uvw(1)) - end if - - ! Search to find azimuthal angle bin. - bin = binary_search(this % bins, n + 1, phi) - if (bin /= NO_BIN_FOUND) then - call match % bins % push_back(bin) - call match % weights % push_back(ONE) - end if - - end subroutine get_all_bins_azimuthal - - subroutine to_statepoint_azimuthal(this, filter_group) - class(AzimuthalFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - call write_dataset(filter_group, "type", "azimuthal") - call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", this % bins) - end subroutine to_statepoint_azimuthal - - function text_label_azimuthal(this, bin) result(label) - class(AzimuthalFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - real(8) :: E0, E1 - - E0 = this % bins(bin) - E1 = this % bins(bin + 1) - label = "Azimuthal Angle [" // trim(to_str(E0)) // ", " & - // trim(to_str(E1)) // ")" - end function text_label_azimuthal - -!=============================================================================== -! EnergyFunctionFilter methods -!=============================================================================== - subroutine get_all_bins_energyfunction(this, p, estimator, match) - class(EnergyFunctionFilter), intent(in) :: this - type(Particle), intent(in) :: p - integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match - - integer :: n, indx - real(8) :: E, f, weight - - select type(this) - type is (EnergyFunctionFilter) - n = size(this % energy) - - ! Get pre-collision energy of particle - E = p % last_E - - ! Search to find incoming energy bin. - indx = binary_search(this % energy, n, E) - - ! Compute an interpolation factor between nearest bins. - f = (E - this % energy(indx)) & - / (this % energy(indx+1) - this % energy(indx)) - - ! Interpolate on the lin-lin grid. - call match % bins % push_back(1) - weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) - call match % weights % push_back(weight) - end select - end subroutine get_all_bins_energyfunction - - subroutine to_statepoint_energyfunction(this, filter_group) - class(EnergyFunctionFilter), intent(in) :: this - integer(HID_T), intent(in) :: filter_group - - select type(this) - type is (EnergyFunctionFilter) - call write_dataset(filter_group, "type", "energyfunction") - call write_dataset(filter_group, "energy", this % energy) - call write_dataset(filter_group, "y", this % y) - end select - end subroutine to_statepoint_energyfunction - - function text_label_energyfunction(this, bin) result(label) - class(EnergyFunctionFilter), intent(in) :: this - integer, intent(in) :: bin - character(MAX_LINE_LEN) :: label - - select type(this) - type is (EnergyFunctionFilter) - write(label, FMT="(A, ES8.1, A, ES8.1, A, ES8.1, A, ES8.1, A)") & - "Energy Function f([", this % energy(1), ", ..., ", & - this % energy(size(this % energy)), "]) = [", this % y(1), & - ", ..., ", this % y(size(this % y)), "]" - end select - end function text_label_energyfunction - !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/tallies/tally_filter_azimuthal.F90 b/src/tallies/tally_filter_azimuthal.F90 new file mode 100644 index 000000000..a6c92fb8e --- /dev/null +++ b/src/tallies/tally_filter_azimuthal.F90 @@ -0,0 +1,83 @@ +module tally_filter_azimuthal + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use algorithm, only: binary_search + use constants + use error, only: fatal_error + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! AZIMUTHALFILTER bins the incident neutron azimuthal angle (relative to the +! global xy-plane). +!=============================================================================== + + type, public, extends(TallyFilter) :: AzimuthalFilter + real(8), allocatable :: bins(:) + contains + procedure :: get_all_bins => get_all_bins_azimuthal + procedure :: to_statepoint => to_statepoint_azimuthal + procedure :: text_label => text_label_azimuthal + end type AzimuthalFilter + +contains + + subroutine get_all_bins_azimuthal(this, p, estimator, match) + class(AzimuthalFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n + integer :: bin + real(8) :: phi + + n = this % n_bins + + ! Make sure the correct direction vector is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + phi = atan2(p % coord(1) % uvw(2), p % coord(1) % uvw(1)) + else + phi = atan2(p % last_uvw(2), p % last_uvw(1)) + end if + + ! Search to find azimuthal angle bin. + bin = binary_search(this % bins, n + 1, phi) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + + end subroutine get_all_bins_azimuthal + + subroutine to_statepoint_azimuthal(this, filter_group) + class(AzimuthalFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "azimuthal") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % bins) + end subroutine to_statepoint_azimuthal + + function text_label_azimuthal(this, bin) result(label) + class(AzimuthalFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + real(8) :: E0, E1 + + E0 = this % bins(bin) + E1 = this % bins(bin + 1) + label = "Azimuthal Angle [" // trim(to_str(E0)) // ", " & + // trim(to_str(E1)) // ")" + end function text_label_azimuthal + +end module tally_filter_azimuthal diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 new file mode 100644 index 000000000..2171e05e9 --- /dev/null +++ b/src/tallies/tally_filter_cell.F90 @@ -0,0 +1,99 @@ +module tally_filter_cell + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use geometry_header + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! CELLFILTER specifies which geometric cells tally events reside in. +!=============================================================================== + + type, public, extends(TallyFilter) :: CellFilter + integer, allocatable :: cells(:) + type(DictIntInt) :: map + contains + procedure :: get_all_bins => get_all_bins_cell + procedure :: to_statepoint => to_statepoint_cell + procedure :: text_label => text_label_cell + procedure :: initialize => initialize_cell + end type CellFilter + +contains + + subroutine get_all_bins_cell(this, p, estimator, match) + class(CellFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + + ! Iterate over coordinate levels to see with cells match + do i = 1, p % n_coord + if (this % map % has_key(p % coord(i) % cell)) then + call match % bins % push_back(this % map % get_key(p % coord(i) % cell)) + call match % weights % push_back(ONE) + end if + end do + + end subroutine get_all_bins_cell + + subroutine to_statepoint_cell(this, filter_group) + class(CellFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cell") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cell + + subroutine initialize_cell(this) + class(CellFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % cells(i) + if (cell_dict % has_key(id)) then + this % cells(i) = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + + ! Generate mapping from cell indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % cells(i), i) + end do + end subroutine initialize_cell + + function text_label_cell(this, bin) result(label) + class(CellFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Cell " // to_str(cells(this % cells(bin)) % id) + end function text_label_cell + +end module tally_filter_cell diff --git a/src/tallies/tally_filter_cellborn.F90 b/src/tallies/tally_filter_cellborn.F90 new file mode 100644 index 000000000..35031ab00 --- /dev/null +++ b/src/tallies/tally_filter_cellborn.F90 @@ -0,0 +1,93 @@ +module tally_filter_cellborn + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use geometry_header + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! CELLBORNFILTER specifies which cell the particle was born in. +!=============================================================================== + + type, public, extends(TallyFilter) :: CellbornFilter + integer, allocatable :: cells(:) + type(DictIntInt) :: map + contains + procedure :: get_all_bins => get_all_bins_cellborn + procedure :: to_statepoint => to_statepoint_cellborn + procedure :: text_label => text_label_cellborn + procedure :: initialize => initialize_cellborn + end type CellbornFilter + +contains + + subroutine get_all_bins_cellborn(this, p, estimator, match) + class(CellbornFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + if (this % map % has_key(p % cell_born)) then + call match % bins % push_back(this % map % get_key(p % cell_born)) + call match % weights % push_back(ONE) + end if + + end subroutine get_all_bins_cellborn + + subroutine to_statepoint_cellborn(this, filter_group) + class(CellbornFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cellborn") + call write_dataset(filter_group, "n_bins", this % n_bins) + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cellborn + + subroutine initialize_cellborn(this) + class(CellbornFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % cells(i) + if (cell_dict % has_key(id)) then + this % cells(i) = cell_dict % get_key(id) + else + call fatal_error("Could not find cell " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + + ! Generate mapping from cell indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % cells(i), i) + end do + end subroutine initialize_cellborn + + function text_label_cellborn(this, bin) result(label) + class(CellbornFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Birth Cell " // to_str(cells(this % cells(bin)) % id) + end function text_label_cellborn + +end module tally_filter_cellborn diff --git a/src/tallies/tally_filter_cellfrom.F90 b/src/tallies/tally_filter_cellfrom.F90 new file mode 100644 index 000000000..211743f2f --- /dev/null +++ b/src/tallies/tally_filter_cellfrom.F90 @@ -0,0 +1,77 @@ +module tally_filter_cellfrom + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use geometry_header + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + use tally_filter_cell + + implicit none + private + +!=============================================================================== +! CELLFROMFILTER specifies which geometric cells particles exit when crossing a +! surface. +!=============================================================================== + + type, public, extends(CellFilter) :: CellFromFilter + contains + procedure :: get_all_bins => get_all_bins_cell_from + procedure :: to_statepoint => to_statepoint_cell_from + procedure :: text_label => text_label_cell_from + end type CellFromFilter + +contains + + subroutine get_all_bins_cell_from(this, p, estimator, match) + class(CellFromFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + + ! Starting one coordinate level deeper, find the next bin. + do i = 1, p % last_n_coord + if (this % map % has_key(p % last_cell(i))) then + call match % bins % push_back(this % map % get_key(p % last_cell(i))) + call match % weights % push_back(ONE) + exit + end if + end do + + end subroutine get_all_bins_cell_from + + subroutine to_statepoint_cell_from(this, filter_group) + class(CellFromFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: cell_ids(:) + + call write_dataset(filter_group, "type", "cellfrom") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(cell_ids(size(this % cells))) + do i = 1, size(this % cells) + cell_ids(i) = cells(this % cells(i)) % id + end do + call write_dataset(filter_group, "bins", cell_ids) + end subroutine to_statepoint_cell_from + + function text_label_cell_from(this, bin) result(label) + class(CellFromFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Cell from " // to_str(cells(this % cells(bin)) % id) + end function text_label_cell_from + +end module tally_filter_cellfrom diff --git a/src/tallies/tally_filter_delayedgroup.F90 b/src/tallies/tally_filter_delayedgroup.F90 new file mode 100644 index 000000000..d0ecf823a --- /dev/null +++ b/src/tallies/tally_filter_delayedgroup.F90 @@ -0,0 +1,60 @@ +module tally_filter_delayedgroup + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! DELAYEDGROUPFILTER bins outgoing fission neutrons in their delayed groups. +! The get_all_bins functionality is not actually used. The bins are manually +! iterated over in the scoring subroutines. +!=============================================================================== + + type, public, extends(TallyFilter) :: DelayedGroupFilter + integer, allocatable :: groups(:) + contains + procedure :: get_all_bins => get_all_bins_dg + procedure :: to_statepoint => to_statepoint_dg + procedure :: text_label => text_label_dg + end type DelayedGroupFilter + +contains + + subroutine get_all_bins_dg(this, p, estimator, match) + class(DelayedGroupFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + call match % bins % push_back(1) + call match % weights % push_back(ONE) + end subroutine get_all_bins_dg + + subroutine to_statepoint_dg(this, filter_group) + class(DelayedGroupFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "delayedgroup") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % groups) + end subroutine to_statepoint_dg + + function text_label_dg(this, bin) result(label) + class(DelayedGroupFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Delayed Group " // to_str(this % groups(bin)) + end function text_label_dg + +end module tally_filter_delayedgroup diff --git a/src/tallies/tally_filter_energyfunc.F90 b/src/tallies/tally_filter_energyfunc.F90 new file mode 100644 index 000000000..6e7245f20 --- /dev/null +++ b/src/tallies/tally_filter_energyfunc.F90 @@ -0,0 +1,91 @@ +module tally_filter_energyfunc + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use algorithm, only: binary_search + use constants + use error, only: fatal_error + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! EnergyFunctionFilter multiplies tally scores by an arbitrary function of +! incident energy described by a piecewise linear-linear interpolation. +!=============================================================================== + + type, public, extends(TallyFilter) :: EnergyFunctionFilter + real(8), allocatable :: energy(:) + real(8), allocatable :: y(:) + + contains + procedure :: get_all_bins => get_all_bins_energyfunction + procedure :: to_statepoint => to_statepoint_energyfunction + procedure :: text_label => text_label_energyfunction + end type EnergyFunctionFilter + +contains + + subroutine get_all_bins_energyfunction(this, p, estimator, match) + class(EnergyFunctionFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n, indx + real(8) :: E, f, weight + + select type(this) + type is (EnergyFunctionFilter) + n = size(this % energy) + + ! Get pre-collision energy of particle + E = p % last_E + + ! Search to find incoming energy bin. + indx = binary_search(this % energy, n, E) + + ! Compute an interpolation factor between nearest bins. + f = (E - this % energy(indx)) & + / (this % energy(indx+1) - this % energy(indx)) + + ! Interpolate on the lin-lin grid. + call match % bins % push_back(1) + weight = (ONE - f) * this % y(indx) + f * this % y(indx+1) + call match % weights % push_back(weight) + end select + end subroutine get_all_bins_energyfunction + + subroutine to_statepoint_energyfunction(this, filter_group) + class(EnergyFunctionFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + select type(this) + type is (EnergyFunctionFilter) + call write_dataset(filter_group, "type", "energyfunction") + call write_dataset(filter_group, "energy", this % energy) + call write_dataset(filter_group, "y", this % y) + end select + end subroutine to_statepoint_energyfunction + + function text_label_energyfunction(this, bin) result(label) + class(EnergyFunctionFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + select type(this) + type is (EnergyFunctionFilter) + write(label, FMT="(A, ES8.1, A, ES8.1, A, ES8.1, A, ES8.1, A)") & + "Energy Function f([", this % energy(1), ", ..., ", & + this % energy(size(this % energy)), "]) = [", this % y(1), & + ", ..., ", this % y(size(this % y)), "]" + end select + end function text_label_energyfunction + +end module tally_filter_energyfunc diff --git a/src/tallies/tally_filter_mu.F90 b/src/tallies/tally_filter_mu.F90 new file mode 100644 index 000000000..624dbb940 --- /dev/null +++ b/src/tallies/tally_filter_mu.F90 @@ -0,0 +1,74 @@ +module tally_filter_mu + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use algorithm, only: binary_search + use constants, only: ONE, MAX_LINE_LEN, NO_BIN_FOUND + use error, only: fatal_error + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! MUFILTER bins the incoming-outgoing direction cosine. This is only used for +! scatter reactions. +!=============================================================================== + + type, public, extends(TallyFilter) :: MuFilter + real(8), allocatable :: bins(:) + contains + procedure :: get_all_bins => get_all_bins_mu + procedure :: to_statepoint => to_statepoint_mu + procedure :: text_label => text_label_mu + end type MuFilter + +contains + + subroutine get_all_bins_mu(this, p, estimator, match) + class(MuFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n + integer :: bin + + n = this % n_bins + + ! Search to find incoming energy bin. + bin = binary_search(this % bins, n + 1, p % mu) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + end subroutine get_all_bins_mu + + subroutine to_statepoint_mu(this, filter_group) + class(MuFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "mu") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % bins) + end subroutine to_statepoint_mu + + function text_label_mu(this, bin) result(label) + class(MuFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + real(8) :: E0, E1 + + E0 = this % bins(bin) + E1 = this % bins(bin + 1) + label = "Change-in-Angle [" // trim(to_str(E0)) // ", " & + // trim(to_str(E1)) // ")" + end function text_label_mu + +end module tally_filter_mu diff --git a/src/tallies/tally_filter_polar.F90 b/src/tallies/tally_filter_polar.F90 new file mode 100644 index 000000000..9e3d9946b --- /dev/null +++ b/src/tallies/tally_filter_polar.F90 @@ -0,0 +1,82 @@ +module tally_filter_polar + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use algorithm, only: binary_search + use constants + use error, only: fatal_error + use hdf5_interface + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! POLARFILTER bins the incident neutron polar angle (relative to the global +! z-axis). +!=============================================================================== + + type, public, extends(TallyFilter) :: PolarFilter + real(8), allocatable :: bins(:) + contains + procedure :: get_all_bins => get_all_bins_polar + procedure :: to_statepoint => to_statepoint_polar + procedure :: text_label => text_label_polar + end type PolarFilter + +contains + + subroutine get_all_bins_polar(this, p, estimator, match) + class(PolarFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: n + integer :: bin + real(8) :: theta + + n = this % n_bins + + ! Make sure the correct direction vector is used. + if (estimator == ESTIMATOR_TRACKLENGTH) then + theta = acos(p % coord(1) % uvw(3)) + else + theta = acos(p % last_uvw(3)) + end if + + ! Search to find polar angle bin. + bin = binary_search(this % bins, n + 1, theta) + if (bin /= NO_BIN_FOUND) then + call match % bins % push_back(bin) + call match % weights % push_back(ONE) + end if + end subroutine get_all_bins_polar + + subroutine to_statepoint_polar(this, filter_group) + class(PolarFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "polar") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % bins) + end subroutine to_statepoint_polar + + function text_label_polar(this, bin) result(label) + class(PolarFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + real(8) :: E0, E1 + + E0 = this % bins(bin) + E1 = this % bins(bin + 1) + label = "Polar Angle [" // trim(to_str(E0)) // ", " // trim(to_str(E1)) & + // ")" + end function text_label_polar + +end module tally_filter_polar diff --git a/src/tallies/tally_filter_surface.F90 b/src/tallies/tally_filter_surface.F90 new file mode 100644 index 000000000..aa8e390bf --- /dev/null +++ b/src/tallies/tally_filter_surface.F90 @@ -0,0 +1,92 @@ +module tally_filter_surface + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use surface_header + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! SURFACEFILTER specifies which surface particles are crossing +!=============================================================================== + + type, public, extends(TallyFilter) :: SurfaceFilter + integer, allocatable :: surfaces(:) + + ! True if this filter is used for surface currents + logical :: current = .false. + contains + procedure :: get_all_bins => get_all_bins_surface + procedure :: to_statepoint => to_statepoint_surface + procedure :: text_label => text_label_surface + procedure :: initialize => initialize_surface + end type SurfaceFilter + +contains + + subroutine get_all_bins_surface(this, p, estimator, match) + class(SurfaceFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + + do i = 1, this % n_bins + if (abs(p % surface) == this % surfaces(i)) then + call match % bins % push_back(i) + if (p % surface < 0) then + call match % weights % push_back(-ONE) + else + call match % weights % push_back(ONE) + end if + exit + end if + end do + + end subroutine get_all_bins_surface + + subroutine to_statepoint_surface(this, filter_group) + class(SurfaceFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + call write_dataset(filter_group, "type", "surface") + call write_dataset(filter_group, "n_bins", this % n_bins) + call write_dataset(filter_group, "bins", this % surfaces) + end subroutine to_statepoint_surface + + subroutine initialize_surface(this) + class(SurfaceFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % surfaces(i) + if (surface_dict % has_key(id)) then + this % surfaces(i) = surface_dict % get_key(id) + else + call fatal_error("Could not find surface " // trim(to_str(id)) & + &// " specified on tally filter.") + end if + end do + end subroutine initialize_surface + + function text_label_surface(this, bin) result(label) + class(SurfaceFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Surface " // to_str(surfaces(this % surfaces(bin)) % obj % id) + end function text_label_surface + +end module tally_filter_surface diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 new file mode 100644 index 000000000..c48e4e917 --- /dev/null +++ b/src/tallies/tally_filter_universe.F90 @@ -0,0 +1,100 @@ +module tally_filter_universe + + use, intrinsic :: ISO_C_BINDING + + use hdf5 + + use constants, only: ONE, MAX_LINE_LEN + use error, only: fatal_error + use hdf5_interface + use geometry_header + use particle_header, only: Particle + use string, only: to_str + use tally_filter_header + + implicit none + private + +!=============================================================================== +! UNIVERSEFILTER specifies which geometric universes tally events reside in. +!=============================================================================== + + type, public, extends(TallyFilter) :: UniverseFilter + integer, allocatable :: universes(:) + type(DictIntInt) :: map + contains + procedure :: get_all_bins => get_all_bins_universe + procedure :: to_statepoint => to_statepoint_universe + procedure :: text_label => text_label_universe + procedure :: initialize => initialize_universe + end type UniverseFilter + +contains + + subroutine get_all_bins_universe(this, p, estimator, match) + class(UniverseFilter), intent(in) :: this + type(Particle), intent(in) :: p + integer, intent(in) :: estimator + type(TallyFilterMatch), intent(inout) :: match + + integer :: i + + ! Iterate over coordinate levels to see which universes match + do i = 1, p % n_coord + if (this % map % has_key(p % coord(i) % universe)) then + call match % bins % push_back(this % map % get_key(p % coord(i) & + % universe)) + call match % weights % push_back(ONE) + end if + end do + + end subroutine get_all_bins_universe + + subroutine to_statepoint_universe(this, filter_group) + class(UniverseFilter), intent(in) :: this + integer(HID_T), intent(in) :: filter_group + + integer :: i + integer, allocatable :: universe_ids(:) + + call write_dataset(filter_group, "type", "universe") + call write_dataset(filter_group, "n_bins", this % n_bins) + + allocate(universe_ids(size(this % universes))) + do i = 1, size(this % universes) + universe_ids(i) = universes(this % universes(i)) % id + end do + call write_dataset(filter_group, "bins", universe_ids) + end subroutine to_statepoint_universe + + subroutine initialize_universe(this) + class(UniverseFilter), intent(inout) :: this + + integer :: i, id + + ! Convert ids to indices. + do i = 1, this % n_bins + id = this % universes(i) + if (universe_dict % has_key(id)) then + this % universes(i) = universe_dict % get_key(id) + else + call fatal_error("Could not find universe " // trim(to_str(id)) & + &// " specified on a tally filter.") + end if + end do + + ! Generate mapping from universe indices to filter bins. + do i = 1, this % n_bins + call this % map % add_key(this % universes(i), i) + end do + end subroutine initialize_universe + + function text_label_universe(this, bin) result(label) + class(UniverseFilter), intent(in) :: this + integer, intent(in) :: bin + character(MAX_LINE_LEN) :: label + + label = "Universe " // to_str(universes(this % universes(bin)) % id) + end function text_label_universe + +end module tally_filter_universe From 3c94f7ca83f24f5070d0083dcf14ea76f6ce70c8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 12:20:59 -0500 Subject: [PATCH 165/229] Move remaining global variables into simulation_header and bank_header --- CMakeLists.txt | 1 + src/bank_header.F90 | 11 ++++++ src/global.F90 | 83 ++------------------------------------- src/simulation_header.F90 | 70 +++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 src/simulation_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 168663110..7fbaf3c2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,6 +360,7 @@ set(LIBOPENMC_FORTRAN_SRC src/secondary_uncorrelated.F90 src/set_header.F90 src/settings.F90 + src/simulation_header.F90 src/simulation.F90 src/source.F90 src/source_header.F90 diff --git a/src/bank_header.F90 b/src/bank_header.F90 index 97fb1f11f..f20c67385 100644 --- a/src/bank_header.F90 +++ b/src/bank_header.F90 @@ -18,4 +18,15 @@ module bank_header integer(C_INT) :: delayed_group ! delayed group end type Bank + ! Source and fission bank + type(Bank), allocatable, target :: source_bank(:) + type(Bank), allocatable, target :: fission_bank(:) +#ifdef _OPENMP + type(Bank), allocatable, target :: master_fission_bank(:) +#endif + + integer(8) :: n_bank ! # of sites in fission bank + +!$omp threadprivate(fission_bank, n_bank) + end module bank_header diff --git a/src/global.F90 b/src/global.F90 index 013a519a1..28b035e4b 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -2,15 +2,8 @@ module global use, intrinsic :: ISO_C_BINDING -#ifdef MPIF08 - use mpi_f08 -#endif - - use bank_header, only: Bank - use cmfd_header - use constants - ! Inherit module variables from other modules + use cmfd_header use geometry_header use material_header use mesh_header @@ -18,6 +11,8 @@ module global use nuclide_header use plot_header use sab_header + use settings + use simulation_header use surface_header use tally_filter_header use tally_header @@ -25,80 +20,8 @@ module global use trigger_header use volume_header - ! Inherit settings - use settings - implicit none - ! ============================================================================ - ! GEOMETRY-RELATED VARIABLES - - ! Number of lost particles - integer :: n_lost_particles - - real(8) :: log_spacing ! spacing on logarithmic grid - - ! ============================================================================ - ! EIGENVALUE SIMULATION VARIABLES - - integer :: current_batch ! current batch - integer :: current_gen ! current generation within a batch - integer :: total_gen = 0 ! total number of generations simulated - - ! ============================================================================ - ! TALLY PRECISION TRIGGER VARIABLES - - logical :: satisfy_triggers = .false. ! whether triggers are satisfied - - ! Source and fission bank - type(Bank), allocatable, target :: source_bank(:) - type(Bank), allocatable, target :: fission_bank(:) -#ifdef _OPENMP - type(Bank), allocatable, target :: master_fission_bank(:) -#endif - integer(8) :: n_bank ! # of sites in fission bank - integer(8) :: work ! number of particles per processor - integer(8), allocatable :: work_index(:) ! starting index in source bank for each process - integer(8) :: current_work ! index in source bank of current history simulated - - ! Temporary k-effective values - real(8), allocatable :: k_generation(:) ! single-generation estimates of k - real(8) :: keff = ONE ! average k over active batches - real(8) :: keff_std ! standard deviation of average k - real(8) :: k_col_abs = ZERO ! sum over batches of k_collision * k_absorption - real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength - real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength - - ! Shannon entropy - real(8), allocatable :: entropy(:) ! shannon entropy at each generation - real(8), allocatable :: entropy_p(:,:) ! % of source sites in each cell - - ! Uniform fission source weighting - real(8), allocatable :: source_frac(:,:) - - ! ============================================================================ - ! PARALLEL PROCESSING VARIABLES - -#ifdef _OPENMP - integer :: n_threads = NONE ! number of OpenMP threads - integer :: thread_id ! ID of a given thread -#endif - - ! ============================================================================ - ! MISCELLANEOUS VARIABLES - - integer :: restart_batch - - ! Flag for enabling cell overlap checking during transport - integer(8), allocatable :: overlap_check_cnt(:) - - logical :: trace - - ! Number of distribcell maps - integer :: n_maps - -!$omp threadprivate(fission_bank, n_bank, trace, thread_id, current_work) - contains !=============================================================================== diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 new file mode 100644 index 000000000..e47c2dd04 --- /dev/null +++ b/src/simulation_header.F90 @@ -0,0 +1,70 @@ +module simulation_header + + use bank_header + use constants + + implicit none + + ! ============================================================================ + ! GEOMETRY-RELATED VARIABLES + + ! Number of lost particles + integer :: n_lost_particles + + real(8) :: log_spacing ! spacing on logarithmic grid + + ! ============================================================================ + ! EIGENVALUE SIMULATION VARIABLES + + integer :: current_batch ! current batch + integer :: current_gen ! current generation within a batch + integer :: total_gen = 0 ! total number of generations simulated + + ! ============================================================================ + ! TALLY PRECISION TRIGGER VARIABLES + + logical :: satisfy_triggers = .false. ! whether triggers are satisfied + + integer(8) :: work ! number of particles per processor + integer(8), allocatable :: work_index(:) ! starting index in source bank for each process + integer(8) :: current_work ! index in source bank of current history simulated + + ! Temporary k-effective values + real(8), allocatable :: k_generation(:) ! single-generation estimates of k + real(8) :: keff = ONE ! average k over active batches + real(8) :: keff_std ! standard deviation of average k + real(8) :: k_col_abs = ZERO ! sum over batches of k_collision * k_absorption + real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength + real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength + + ! Shannon entropy + real(8), allocatable :: entropy(:) ! shannon entropy at each generation + real(8), allocatable :: entropy_p(:,:) ! % of source sites in each cell + + ! Uniform fission source weighting + real(8), allocatable :: source_frac(:,:) + + ! ============================================================================ + ! PARALLEL PROCESSING VARIABLES + +#ifdef _OPENMP + integer :: n_threads = NONE ! number of OpenMP threads + integer :: thread_id ! ID of a given thread +#endif + + ! ============================================================================ + ! MISCELLANEOUS VARIABLES + + integer :: restart_batch + + ! Flag for enabling cell overlap checking during transport + integer(8), allocatable :: overlap_check_cnt(:) + + logical :: trace + + ! Number of distribcell maps + integer :: n_maps + +!$omp threadprivate(trace, thread_id, current_work) + +end module simulation_header From d9691c5e41477a852ba33e75f8a76f044a85c079 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 12:37:18 -0500 Subject: [PATCH 166/229] Move reading filters to from_xml type-bound procedures --- src/input_xml.F90 | 280 +--------------------- src/tallies/tally_filter_azimuthal.F90 | 39 +++ src/tallies/tally_filter_cell.F90 | 17 ++ src/tallies/tally_filter_cellborn.F90 | 17 ++ src/tallies/tally_filter_cellfrom.F90 | 2 + src/tallies/tally_filter_delayedgroup.F90 | 30 ++- src/tallies/tally_filter_distribcell.F90 | 16 ++ src/tallies/tally_filter_energy.F90 | 33 ++- src/tallies/tally_filter_energyfunc.F90 | 35 +++ src/tallies/tally_filter_header.F90 | 8 + src/tallies/tally_filter_material.F90 | 16 ++ src/tallies/tally_filter_mesh.F90 | 35 ++- src/tallies/tally_filter_mu.F90 | 40 +++- src/tallies/tally_filter_polar.F90 | 38 +++ src/tallies/tally_filter_surface.F90 | 16 ++ src/tallies/tally_filter_universe.F90 | 16 ++ 16 files changed, 355 insertions(+), 283 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index f01bda4a2..75ee6168b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2453,14 +2453,11 @@ contains subroutine read_tallies_xml() - integer :: d ! delayed group index integer :: i ! loop over user-specified tallies integer :: j ! loop over words integer :: k ! another loop index integer :: l ! another loop index - integer :: id ! user-specified identifier integer :: filter_id ! user-specified identifier for filter - integer :: i_mesh ! index in meshes array integer :: i_filt ! index in filters array integer :: i_filter_mesh ! index of mesh filter integer :: n ! size of arrays in mesh specification @@ -2481,9 +2478,6 @@ contains integer :: MT ! user-specified MT for score integer :: imomstr ! Index of MOMENT_STRS & MOMENT_N_STRS logical :: file_exists ! does tallies.xml file exist? - integer :: Nangle ! Number of angular bins - real(8) :: dangle ! Mu spacing if using automatic allocation - integer :: iangle ! Loop counter for building mu filter bins integer, allocatable :: temp_filter(:) ! temporary filter indices character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word @@ -2708,315 +2702,43 @@ contains n_words = node_word_count(node_filt, "bins") end select - ! Determine type of filter + ! Allocate according to the filter type select case (temp_str) - case ('distribcell') - ! Allocate and declare the filter type allocate(DistribcellFilter :: f % obj) - select type (filt => f % obj) - type is (DistribcellFilter) - if (n_words /= 1) call fatal_error("Only one cell can be & - &specified per distribcell filter.") - ! Store bins - call get_node_value(node_filt, "bins", filt % cell) - end select - case ('cell') - ! Allocate and declare the filter type allocate(CellFilter :: f % obj) - select type (filt => f % obj) - type is (CellFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % cells(n_words)) - call get_node_array(node_filt, "bins", filt % cells) - end select - case ('cellfrom') - ! Allocate and declare the filter type allocate(CellFromFilter :: f % obj) - select type (filt => f % obj) - type is (CellFromFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % cells(n_words)) - call get_node_array(node_filt, "bins", filt % cells) - end select - case ('cellborn') - ! Allocate and declare the filter type allocate(CellbornFilter :: f % obj) - select type (filt => f % obj) - type is (CellbornFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % cells(n_words)) - call get_node_array(node_filt, "bins", filt % cells) - end select - case ('material') - ! Allocate and declare the filter type allocate(MaterialFilter :: f % obj) - select type (filt => f % obj) - type is (MaterialFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % materials(n_words)) - call get_node_array(node_filt, "bins", filt % materials) - end select - case ('universe') - ! Allocate and declare the filter type allocate(UniverseFilter :: f % obj) - select type (filt => f % obj) - type is (UniverseFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % universes(n_words)) - call get_node_array(node_filt, "bins", filt % universes) - end select - case ('surface') - ! Allocate and declare the filter type allocate(SurfaceFilter :: f % obj) - select type (filt => f % obj) - type is (SurfaceFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % surfaces(n_words)) - call get_node_array(node_filt, "bins", filt % surfaces) - end select - case ('mesh') - ! Allocate and declare the filter type allocate(MeshFilter :: f % obj) - select type (filt => f % obj) - type is (MeshFilter) - if (n_words /= 1) call fatal_error("Only one mesh can be & - &specified per mesh filter.") - - ! Determine id of mesh - call get_node_value(node_filt, "bins", id) - - ! Get pointer to mesh - if (mesh_dict % has_key(id)) then - i_mesh = mesh_dict % get_key(id) - else - call fatal_error("Could not find mesh " // trim(to_str(id)) & - // " specified on filter " // trim(to_str(filter_id))) - end if - - ! Determine number of bins - filt % n_bins = product(meshes(i_mesh) % dimension) - - ! Store the index of the mesh - filt % mesh = i_mesh - end select - case ('energy') - - ! Allocate and declare the filter type allocate(EnergyFilter :: f % obj) - select type (filt => f % obj) - type is (EnergyFilter) - ! Allocate and store bins - filt % n_bins = n_words - 1 - allocate(filt % bins(n_words)) - call get_node_array(node_filt, "bins", filt % bins) - - ! We can save tallying time if we know that the tally bins match - ! the energy group structure. In that case, the matching bin - ! index is simply the group (after flipping for the different - ! ordering of the library and tallying systems). - if (.not. run_CE) then - if (n_words == num_energy_groups + 1) then - if (all(filt % bins == energy_bins(num_energy_groups + 1:1:-1))) & - then - filt % matches_transport_groups = .true. - end if - end if - end if - end select - case ('energyout') - ! Allocate and declare the filter type allocate(EnergyoutFilter :: f % obj) - select type (filt => f % obj) - type is (EnergyoutFilter) - ! Allocate and store bins - filt % n_bins = n_words - 1 - allocate(filt % bins(n_words)) - call get_node_array(node_filt, "bins", filt % bins) - - ! We can save tallying time if we know that the tally bins match - ! the energy group structure. In that case, the matching bin - ! index is simply the group (after flipping for the different - ! ordering of the library and tallying systems). - if (.not. run_CE) then - if (n_words == num_energy_groups + 1) then - if (all(filt % bins == energy_bins(num_energy_groups + 1:1:-1))) & - then - filt % matches_transport_groups = .true. - end if - end if - end if - end select - case ('delayedgroup') - - ! Allocate and declare the filter type allocate(DelayedGroupFilter :: f % obj) - select type (filt => f % obj) - type is (DelayedGroupFilter) - ! Allocate and store bins - filt % n_bins = n_words - allocate(filt % groups(n_words)) - call get_node_array(node_filt, "bins", filt % groups) - - ! Check that bins are all are between 1 and MAX_DELAYED_GROUPS - do d = 1, n_words - if (filt % groups(d) < 1 .or. & - filt % groups(d) > MAX_DELAYED_GROUPS) then - call fatal_error("Encountered delayedgroup bin with index " & - // trim(to_str(filt % groups(d))) // " that is outside & - &the range of 1 to MAX_DELAYED_GROUPS ( " & - // trim(to_str(MAX_DELAYED_GROUPS)) // ")") - end if - end do - end select - case ('mu') - ! Allocate and declare the filter type allocate(MuFilter :: f % obj) - select type (filt => f % obj) - type is (MuFilter) - ! Allocate and store bins - filt % n_bins = n_words - 1 - allocate(filt % bins(n_words)) - call get_node_array(node_filt, "bins", filt % bins) - - ! Allow a user to input a lone number which will mean that you - ! subdivide [-1,1] evenly with the input being the number of bins - if (n_words == 1) then - Nangle = int(filt % bins(1)) - if (Nangle > 1) then - filt % n_bins = Nangle - dangle = TWO / real(Nangle,8) - deallocate(filt % bins) - allocate(filt % bins(Nangle + 1)) - do iangle = 1, Nangle - filt % bins(iangle) = -ONE + (iangle - 1) * dangle - end do - filt % bins(Nangle + 1) = ONE - else - call fatal_error("Number of bins for mu filter must be& - & greater than 1 on filter " & - // trim(to_str(filter_id)) // ".") - end if - end if - end select - case ('polar') - ! Allocate and declare the filter type allocate(PolarFilter :: f % obj) - select type (filt => f % obj) - type is (PolarFilter) - ! Allocate and store bins - filt % n_bins = n_words - 1 - allocate(filt % bins(n_words)) - call get_node_array(node_filt, "bins", filt % bins) - - ! Allow a user to input a lone number which will mean that you - ! subdivide [0,pi] evenly with the input being the number of bins - if (n_words == 1) then - Nangle = int(filt % bins(1)) - if (Nangle > 1) then - filt % n_bins = Nangle - dangle = PI / real(Nangle,8) - deallocate(filt % bins) - allocate(filt % bins(Nangle + 1)) - do iangle = 1, Nangle - filt % bins(iangle) = (iangle - 1) * dangle - end do - filt % bins(Nangle + 1) = PI - else - call fatal_error("Number of bins for polar filter must be& - & greater than 1 on filter " & - // trim(to_str(filter_id)) // ".") - end if - end if - end select - case ('azimuthal') - ! Allocate and declare the filter type allocate(AzimuthalFilter :: f % obj) - select type (filt => f % obj) - type is (AzimuthalFilter) - ! Allocate and store bins - filt % n_bins = n_words - 1 - allocate(filt % bins(n_words)) - call get_node_array(node_filt, "bins", filt % bins) - - ! Allow a user to input a lone number which will mean that you - ! subdivide [-pi,pi) evenly with the input being the number of - ! bins - if (n_words == 1) then - Nangle = int(filt % bins(1)) - if (Nangle > 1) then - filt % n_bins = Nangle - dangle = TWO * PI / real(Nangle,8) - deallocate(filt % bins) - allocate(filt % bins(Nangle + 1)) - do iangle = 1, Nangle - filt % bins(iangle) = -PI + (iangle - 1) * dangle - end do - filt % bins(Nangle + 1) = PI - else - call fatal_error("Number of bins for azimuthal filter must be& - & greater than 1 on filter " & - // trim(to_str(filter_id)) // ".") - end if - end if - end select - case ('energyfunction') - ! Allocate and declare the filter type. allocate(EnergyFunctionFilter :: f % obj) - select type (filt => f % obj) - type is (EnergyFunctionFilter) - filt % n_bins = 1 - ! Make sure this is continuous-energy mode. - if (.not. run_CE) then - call fatal_error("EnergyFunction filters are only supported for & - &continuous-energy transport calculations") - end if - - ! Allocate and store energy grid. - if (.not. check_for_node(node_filt, "energy")) then - call fatal_error("Energy grid not specified for EnergyFunction & - &filter on filter " // trim(to_str(filter_id))) - end if - n_words = node_word_count(node_filt, "energy") - allocate(filt % energy(n_words)) - call get_node_array(node_filt, "energy", filt % energy) - - ! Allocate and store interpolant values. - if (.not. check_for_node(node_filt, "y")) then - call fatal_error("y values not specified for EnergyFunction & - &filter on filter " // trim(to_str(filter_id))) - end if - n_words = node_word_count(node_filt, "y") - allocate(filt % y(n_words)) - call get_node_array(node_filt, "y", filt % y) - end select - case default ! Specified filter is invalid, raise error call fatal_error("Unknown filter type '" & // trim(temp_str) // "' on filter " & // trim(to_str(filter_id)) // ".") - end select ! Set filter id diff --git a/src/tallies/tally_filter_azimuthal.F90 b/src/tallies/tally_filter_azimuthal.F90 index a6c92fb8e..272d111d1 100644 --- a/src/tallies/tally_filter_azimuthal.F90 +++ b/src/tallies/tally_filter_azimuthal.F90 @@ -11,6 +11,7 @@ module tally_filter_azimuthal use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_azimuthal type, public, extends(TallyFilter) :: AzimuthalFilter real(8), allocatable :: bins(:) contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_azimuthal procedure :: to_statepoint => to_statepoint_azimuthal procedure :: text_label => text_label_azimuthal @@ -30,6 +32,43 @@ module tally_filter_azimuthal contains + subroutine from_xml(this, node) + class(AzimuthalFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: i + integer :: n + integer :: n_angle + real(8) :: d_angle + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n - 1 + allocate(this % bins(n)) + call get_node_array(node, "bins", this % bins) + + ! Allow a user to input a lone number which will mean that you + ! subdivide [-pi,pi) evenly with the input being the number of + ! bins + if (n == 1) then + n_angle = int(this % bins(1)) + if (n_angle > 1) then + this % n_bins = n_angle + d_angle = TWO * PI / n_angle + deallocate(this % bins) + allocate(this % bins(n_angle + 1)) + do i = 1, n_angle + this % bins(i) = -PI + (i - 1) * d_angle + end do + this % bins(n_angle + 1) = PI + else + call fatal_error("Number of bins for azimuthal filter must be& + & greater than 1.") + end if + end if + end subroutine from_xml + subroutine get_all_bins_azimuthal(this, p, estimator, match) class(AzimuthalFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 index 2171e05e9..22f3c0c57 100644 --- a/src/tallies/tally_filter_cell.F90 +++ b/src/tallies/tally_filter_cell.F90 @@ -11,6 +11,7 @@ module tally_filter_cell use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_cell integer, allocatable :: cells(:) type(DictIntInt) :: map contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_cell procedure :: to_statepoint => to_statepoint_cell procedure :: text_label => text_label_cell @@ -31,6 +33,21 @@ module tally_filter_cell contains + subroutine from_xml(this, node) + class(CellFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + ! Determine how many bins were given + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % cells(n)) + call get_node_array(node, "bins", this % cells) + end subroutine from_xml + subroutine get_all_bins_cell(this, p, estimator, match) class(CellFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_cellborn.F90 b/src/tallies/tally_filter_cellborn.F90 index 35031ab00..b23b5b344 100644 --- a/src/tallies/tally_filter_cellborn.F90 +++ b/src/tallies/tally_filter_cellborn.F90 @@ -11,6 +11,7 @@ module tally_filter_cellborn use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_cellborn integer, allocatable :: cells(:) type(DictIntInt) :: map contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_cellborn procedure :: to_statepoint => to_statepoint_cellborn procedure :: text_label => text_label_cellborn @@ -31,6 +33,21 @@ module tally_filter_cellborn contains + subroutine from_xml(this, node) + class(CellbornFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + ! Determine number of bins + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % cells(n)) + call get_node_array(node, "bins", this % cells) + end subroutine from_xml + subroutine get_all_bins_cellborn(this, p, estimator, match) class(CellbornFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_cellfrom.F90 b/src/tallies/tally_filter_cellfrom.F90 index 211743f2f..fa1f87e0e 100644 --- a/src/tallies/tally_filter_cellfrom.F90 +++ b/src/tallies/tally_filter_cellfrom.F90 @@ -12,6 +12,7 @@ module tally_filter_cellfrom use string, only: to_str use tally_filter_header use tally_filter_cell + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_cellfrom type, public, extends(CellFilter) :: CellFromFilter contains + ! Inherit from_xml from CellFilter procedure :: get_all_bins => get_all_bins_cell_from procedure :: to_statepoint => to_statepoint_cell_from procedure :: text_label => text_label_cell_from diff --git a/src/tallies/tally_filter_delayedgroup.F90 b/src/tallies/tally_filter_delayedgroup.F90 index d0ecf823a..32010e815 100644 --- a/src/tallies/tally_filter_delayedgroup.F90 +++ b/src/tallies/tally_filter_delayedgroup.F90 @@ -4,12 +4,13 @@ module tally_filter_delayedgroup use hdf5 - use constants, only: ONE, MAX_LINE_LEN + use constants, only: ONE, MAX_LINE_LEN, MAX_DELAYED_GROUPS use error, only: fatal_error use hdf5_interface use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_delayedgroup type, public, extends(TallyFilter) :: DelayedGroupFilter integer, allocatable :: groups(:) contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_dg procedure :: to_statepoint => to_statepoint_dg procedure :: text_label => text_label_dg @@ -30,6 +32,32 @@ module tally_filter_delayedgroup contains + subroutine from_xml(this, node) + class(DelayedGroupFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: i + integer :: n + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % groups(n)) + call get_node_array(node, "bins", this % groups) + + ! Check that bins are all are between 1 and MAX_DELAYED_GROUPS + do i = 1, n + if (this % groups(i) < 1 .or. & + this % groups(i) > MAX_DELAYED_GROUPS) then + call fatal_error("Encountered delayedgroup bin with index " & + // trim(to_str(this % groups(i))) // " that is outside & + &the range of 1 to MAX_DELAYED_GROUPS ( " & + // trim(to_str(MAX_DELAYED_GROUPS)) // ")") + end if + end do + end subroutine from_xml + subroutine get_all_bins_dg(this, p, estimator, match) class(DelayedGroupFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index b36d0035c..7643eca4a 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -11,6 +11,7 @@ module tally_filter_distribcell use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -24,6 +25,7 @@ module tally_filter_distribcell type, public, extends(TallyFilter) :: DistribcellFilter integer :: cell contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_distribcell procedure :: to_statepoint => to_statepoint_distribcell procedure :: text_label => text_label_distribcell @@ -32,6 +34,20 @@ module tally_filter_distribcell contains + subroutine from_xml(this, node) + class(DistribcellFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + n = node_word_count(node, "bins") + if (n /= 1) call fatal_error("Only one cell can be & + &specified per distribcell filter.") + + ! Store bins + call get_node_value(node, "bins", this % cell) + end subroutine from_xml + subroutine get_all_bins_distribcell(this, p, estimator, match) class(DistribcellFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index f5a635e6e..3530621b5 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -8,10 +8,12 @@ module tally_filter_energy use constants use error use hdf5_interface - use mgxs_header, only: num_energy_groups + use mgxs_header, only: num_energy_groups, energy_bins use particle_header, only: Particle + use settings, only: run_CE use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -28,6 +30,7 @@ module tally_filter_energy ! True if transport group number can be used directly to get bin number logical :: matches_transport_groups = .false. contains + procedure :: from_xml => from_xml_energy procedure :: get_all_bins => get_all_bins_energy procedure :: to_statepoint => to_statepoint_energy procedure :: text_label => text_label_energy @@ -41,6 +44,7 @@ module tally_filter_energy type, public, extends(EnergyFilter) :: EnergyoutFilter contains + ! Inherit from_xml from EnergyFilter procedure :: get_all_bins => get_all_bins_energyout procedure :: to_statepoint => to_statepoint_energyout procedure :: text_label => text_label_energyout @@ -52,6 +56,33 @@ contains ! EnergyFilter methods !=============================================================================== + subroutine from_xml_energy(this, node) + class(EnergyFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n - 1 + allocate(this % bins(n)) + call get_node_array(node, "bins", this % bins) + + ! We can save tallying time if we know that the tally bins match + ! the energy group structure. In that case, the matching bin + ! index is simply the group (after flipping for the different + ! ordering of the library and tallying systems). + if (.not. run_CE) then + if (n == num_energy_groups + 1) then + if (all(this % bins == energy_bins(num_energy_groups + 1:1:-1))) & + then + this % matches_transport_groups = .true. + end if + end if + end if + end subroutine from_xml_energy + subroutine get_all_bins_energy(this, p, estimator, match) class(EnergyFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_energyfunc.F90 b/src/tallies/tally_filter_energyfunc.F90 index 6e7245f20..efaabae2e 100644 --- a/src/tallies/tally_filter_energyfunc.F90 +++ b/src/tallies/tally_filter_energyfunc.F90 @@ -9,8 +9,10 @@ module tally_filter_energyfunc use error, only: fatal_error use hdf5_interface use particle_header, only: Particle + use settings, only: run_CE use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -25,6 +27,7 @@ module tally_filter_energyfunc real(8), allocatable :: y(:) contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_energyfunction procedure :: to_statepoint => to_statepoint_energyfunction procedure :: text_label => text_label_energyfunction @@ -32,6 +35,38 @@ module tally_filter_energyfunc contains + subroutine from_xml(this, node) + class(EnergyFunctionFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + this % n_bins = 1 + ! Make sure this is continuous-energy mode. + if (.not. run_CE) then + call fatal_error("EnergyFunction filters are only supported for & + &continuous-energy transport calculations") + end if + + ! Allocate and store energy grid. + if (.not. check_for_node(node, "energy")) then + call fatal_error("Energy grid not specified for EnergyFunction & + &filter.") + end if + n = node_word_count(node, "energy") + allocate(this % energy(n)) + call get_node_array(node, "energy", this % energy) + + ! Allocate and store interpolant values. + if (.not. check_for_node(node, "y")) then + call fatal_error("y values not specified for EnergyFunction & + &filter.") + end if + n = node_word_count(node, "y") + allocate(this % y(n)) + call get_node_array(node, "y", this % y) + end subroutine from_xml + subroutine get_all_bins_energyfunction(this, p, estimator, match) class(EnergyFunctionFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index 32baad3e9..fa229d471 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -7,6 +7,7 @@ module tally_filter_header use error use particle_header, only: Particle use stl_vector, only: VectorInt, VectorReal + use xml_interface, only: XMLNode use hdf5 @@ -40,6 +41,7 @@ module tally_filter_header integer :: id integer :: n_bins = 0 contains + procedure(from_xml_), deferred :: from_xml procedure(get_all_bins_), deferred :: get_all_bins procedure(to_statepoint_), deferred :: to_statepoint procedure(text_label_), deferred :: text_label @@ -48,6 +50,12 @@ module tally_filter_header abstract interface + subroutine from_xml_(this, node) + import TallyFilter, XMLNode + class(TallyFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + end subroutine from_xml_ + !=============================================================================== ! GET_NEXT_BIN gives the index for the next valid filter bin and a weight that ! will be applied to the flux. diff --git a/src/tallies/tally_filter_material.F90 b/src/tallies/tally_filter_material.F90 index fbeb3a4ec..3eacc1fcb 100644 --- a/src/tallies/tally_filter_material.F90 +++ b/src/tallies/tally_filter_material.F90 @@ -12,6 +12,7 @@ module tally_filter_material use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -26,6 +27,7 @@ module tally_filter_material integer, allocatable :: materials(:) type(DictIntInt) :: map contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_material procedure :: to_statepoint => to_statepoint_material procedure :: text_label => text_label_material @@ -34,6 +36,20 @@ module tally_filter_material contains + subroutine from_xml(this, node) + class(MaterialFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % materials(n)) + call get_node_array(node, "bins", this % materials) + end subroutine from_xml + subroutine get_all_bins_material(this, p, estimator, match) class(MaterialFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index bef1cd5fd..cfc793949 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -6,11 +6,12 @@ module tally_filter_mesh use constants use error - use mesh_header, only: RegularMesh, meshes, n_meshes + use mesh_header, only: RegularMesh, meshes, n_meshes, mesh_dict use hdf5_interface use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -25,6 +26,7 @@ module tally_filter_mesh type, public, extends(TallyFilter) :: MeshFilter integer :: mesh contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_mesh procedure :: to_statepoint => to_statepoint_mesh procedure :: text_label => text_label_mesh @@ -32,6 +34,37 @@ module tally_filter_mesh contains + subroutine from_xml(this, node) + class(MeshFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: i_mesh + integer :: id + integer :: n + + n = node_word_count(node, "bins") + + if (n /= 1) call fatal_error("Only one mesh can be & + &specified per mesh filter.") + + ! Determine id of mesh + call get_node_value(node, "bins", id) + + ! Get pointer to mesh + if (mesh_dict % has_key(id)) then + i_mesh = mesh_dict % get_key(id) + else + call fatal_error("Could not find mesh " // trim(to_str(id)) & + // " specified on filter.") + end if + + ! Determine number of bins + this % n_bins = product(meshes(i_mesh) % dimension) + + ! Store the index of the mesh + this % mesh = i_mesh + end subroutine from_xml + subroutine get_all_bins_mesh(this, p, estimator, match) class(MeshFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_mu.F90 b/src/tallies/tally_filter_mu.F90 index 624dbb940..c949289b6 100644 --- a/src/tallies/tally_filter_mu.F90 +++ b/src/tallies/tally_filter_mu.F90 @@ -5,12 +5,13 @@ module tally_filter_mu use hdf5 use algorithm, only: binary_search - use constants, only: ONE, MAX_LINE_LEN, NO_BIN_FOUND + use constants, only: ONE, TWO, MAX_LINE_LEN, NO_BIN_FOUND use error, only: fatal_error use hdf5_interface use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_mu type, public, extends(TallyFilter) :: MuFilter real(8), allocatable :: bins(:) contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_mu procedure :: to_statepoint => to_statepoint_mu procedure :: text_label => text_label_mu @@ -30,6 +32,42 @@ module tally_filter_mu contains + subroutine from_xml(this, node) + class(MuFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: i + integer :: n_angle + integer :: n + real(8) :: d_angle + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n - 1 + allocate(this % bins(n)) + call get_node_array(node, "bins", this % bins) + + ! Allow a user to input a lone number which will mean that you + ! subdivide [-1,1] evenly with the input being the number of bins + if (n == 1) then + n_angle = int(this % bins(1)) + if (n_angle > 1) then + this % n_bins = n_angle + d_angle = TWO / n_angle + deallocate(this % bins) + allocate(this % bins(n_angle + 1)) + do i = 1, n_angle + this % bins(i) = -ONE + (i - 1) * d_angle + end do + this % bins(n_angle + 1) = ONE + else + call fatal_error("Number of bins for mu filter must be& + & greater than 1.") + end if + end if + end subroutine from_xml + subroutine get_all_bins_mu(this, p, estimator, match) class(MuFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_polar.F90 b/src/tallies/tally_filter_polar.F90 index 9e3d9946b..89815c102 100644 --- a/src/tallies/tally_filter_polar.F90 +++ b/src/tallies/tally_filter_polar.F90 @@ -11,6 +11,7 @@ module tally_filter_polar use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_polar type, public, extends(TallyFilter) :: PolarFilter real(8), allocatable :: bins(:) contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_polar procedure :: to_statepoint => to_statepoint_polar procedure :: text_label => text_label_polar @@ -30,6 +32,42 @@ module tally_filter_polar contains + subroutine from_xml(this, node) + class(PolarFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: i + integer :: n_angle + integer :: n + real(8) :: d_angle + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n - 1 + allocate(this % bins(n)) + call get_node_array(node, "bins", this % bins) + + ! Allow a user to input a lone number which will mean that you + ! subdivide [0,pi] evenly with the input being the number of bins + if (n == 1) then + n_angle = int(this % bins(1)) + if (n_angle > 1) then + this % n_bins = n_angle + d_angle = PI / real(n_angle,8) + deallocate(this % bins) + allocate(this % bins(n_angle + 1)) + do i = 1, n_angle + this % bins(i) = (i - 1) * d_angle + end do + this % bins(n_angle + 1) = PI + else + call fatal_error("Number of bins for polar filter must be& + & greater than 1.") + end if + end if + end subroutine from_xml + subroutine get_all_bins_polar(this, p, estimator, match) class(PolarFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_surface.F90 b/src/tallies/tally_filter_surface.F90 index aa8e390bf..9c5341022 100644 --- a/src/tallies/tally_filter_surface.F90 +++ b/src/tallies/tally_filter_surface.F90 @@ -11,6 +11,7 @@ module tally_filter_surface use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -25,6 +26,7 @@ module tally_filter_surface ! True if this filter is used for surface currents logical :: current = .false. contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_surface procedure :: to_statepoint => to_statepoint_surface procedure :: text_label => text_label_surface @@ -33,6 +35,20 @@ module tally_filter_surface contains + subroutine from_xml(this, node) + class(SurfaceFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % surfaces(n)) + call get_node_array(node, "bins", this % surfaces) + end subroutine from_xml + subroutine get_all_bins_surface(this, p, estimator, match) class(SurfaceFilter), intent(in) :: this type(Particle), intent(in) :: p diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 index c48e4e917..195e2544a 100644 --- a/src/tallies/tally_filter_universe.F90 +++ b/src/tallies/tally_filter_universe.F90 @@ -11,6 +11,7 @@ module tally_filter_universe use particle_header, only: Particle use string, only: to_str use tally_filter_header + use xml_interface implicit none private @@ -23,6 +24,7 @@ module tally_filter_universe integer, allocatable :: universes(:) type(DictIntInt) :: map contains + procedure :: from_xml procedure :: get_all_bins => get_all_bins_universe procedure :: to_statepoint => to_statepoint_universe procedure :: text_label => text_label_universe @@ -31,6 +33,20 @@ module tally_filter_universe contains + subroutine from_xml(this, node) + class(UniverseFilter), intent(inout) :: this + type(XMLNode), intent(in) :: node + + integer :: n + + n = node_word_count(node, "bins") + + ! Allocate and store bins + this % n_bins = n + allocate(this % universes(n)) + call get_node_array(node, "bins", this % universes) + end subroutine from_xml + subroutine get_all_bins_universe(this, p, estimator, match) class(UniverseFilter), intent(in) :: this type(Particle), intent(in) :: p From 311d291a8f2ca968e696c278ad09699ba9e28760 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Aug 2017 12:50:53 -0500 Subject: [PATCH 167/229] Use openmc_filter_set_type from input_xml --- src/input_xml.F90 | 43 +++++-------------------------------------- src/string.F90 | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 75ee6168b..b818e5bc0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -31,7 +31,7 @@ module input_xml use stl_vector, only: VectorInt, VectorReal, VectorChar use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & - zero_padded + zero_padded, to_c_string use summary, only: write_summary use tally, only: openmc_tally_set_type use tally_header, only: openmc_extend_tallies @@ -2703,43 +2703,10 @@ contains end select ! Allocate according to the filter type - select case (temp_str) - case ('distribcell') - allocate(DistribcellFilter :: f % obj) - case ('cell') - allocate(CellFilter :: f % obj) - case ('cellfrom') - allocate(CellFromFilter :: f % obj) - case ('cellborn') - allocate(CellbornFilter :: f % obj) - case ('material') - allocate(MaterialFilter :: f % obj) - case ('universe') - allocate(UniverseFilter :: f % obj) - case ('surface') - allocate(SurfaceFilter :: f % obj) - case ('mesh') - allocate(MeshFilter :: f % obj) - case ('energy') - allocate(EnergyFilter :: f % obj) - case ('energyout') - allocate(EnergyoutFilter :: f % obj) - case ('delayedgroup') - allocate(DelayedGroupFilter :: f % obj) - case ('mu') - allocate(MuFilter :: f % obj) - case ('polar') - allocate(PolarFilter :: f % obj) - case ('azimuthal') - allocate(AzimuthalFilter :: f % obj) - case ('energyfunction') - allocate(EnergyFunctionFilter :: f % obj) - case default - ! Specified filter is invalid, raise error - call fatal_error("Unknown filter type '" & - // trim(temp_str) // "' on filter " & - // trim(to_str(filter_id)) // ".") - end select + err = openmc_filter_set_type(i_start + i - 1, to_c_string(temp_str)) + + ! Read filter data from XML + call f % obj % from_xml(node_filt) ! Set filter id err = openmc_filter_set_id(i_start + i - 1, filter_id) diff --git a/src/string.F90 b/src/string.F90 index 2a69eec98..71d9d6e96 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -538,4 +538,23 @@ contains end do end function to_f_string +!=============================================================================== +! TO_C_STRING takes a space-padded Fortran character and turns it into a +! null-terminated C char array. Yay Fortran 2003! +!=============================================================================== + + function to_c_string(f_string) result(c_string) + character(*), intent(in) :: f_string + character(kind=C_CHAR) :: c_string(len_trim(f_string) + 1) + + integer :: i, n + + ! Copy Fortran string character by character + n = len_trim(f_string) + do i = 1, n + c_string(i) = f_string(i:i) + end do + c_string(n + 1) = C_NULL_CHAR + end function to_c_string + end module string From 11cee613cc1135cd48e0f1d8ca0852805addd247 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 26 Aug 2017 10:06:11 -0400 Subject: [PATCH 168/229] Fixed the duplicate code introduced in #910 and fixed a minor bug identified in run_tests.py --- src/physics_mg.F90 | 6 ------ src/tracking.F90 | 4 ++++ tests/run_tests.py | 12 ++++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index b5d34838c..9b18b762b 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -31,12 +31,6 @@ contains type(Particle), intent(inout) :: p - ! Store pre-collision particle properties - p % last_wgt = p % wgt - p % last_g = p % g - p % last_E = p % E - p % last_uvw = p % coord(1) % uvw - ! Add to collision counter for particle p % n_collision = p % n_collision + 1 diff --git a/src/tracking.F90 b/src/tracking.F90 index 90dd9c35e..a5b9386c0 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -112,6 +112,10 @@ contains material_xs % absorption = ZERO material_xs % nu_fission = ZERO end if + + ! Finally, update the particle group while we have already checked for + ! if multi-group + p % last_g = p % g end if ! Find the distance to the nearest boundary diff --git a/tests/run_tests.py b/tests/run_tests.py index cd6c02607..50e9313df 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -416,16 +416,16 @@ for key in iter(tests): # Verify fortran compiler exists if which(test.fc) is None: - self.msg = 'Compiler not found: {0}'.format(test.fc) - self.success = False + test.msg = 'Compiler not found: {0}'.format(test.fc) + test.success = False continue # Verify valgrind command exists if test.valgrind: valgrind_cmd = which('valgrind') if valgrind_cmd is None: - self.msg = 'No valgrind executable found.' - self.success = False + test.msg = 'No valgrind executable found.' + test.success = False continue else: valgrind_cmd = '' @@ -433,8 +433,8 @@ for key in iter(tests): # Verify gcov/lcov exist if test.coverage: if which('gcov') is None: - self.msg = 'No {} executable found.'.format(exe) - self.success = False + test.msg = 'No {} executable found.'.format(exe) + test.success = False continue # Set test specific CTest script vars. Not used in non-script mode From ba83bac786b7df17d63bc9d245883e725c8416cd Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 31 Aug 2017 15:17:17 -0500 Subject: [PATCH 169/229] Initial implementation of new dictionary --- src/api.F90 | 34 +- src/cmfd_input.F90 | 12 +- src/dict_header.F90 | 685 +++++++++++++++++++++------------------- src/geometry.F90 | 12 +- src/geometry_header.F90 | 6 +- src/initialize.F90 | 86 ++--- src/input_xml.F90 | 206 ++++++------ src/mgxs_data.F90 | 4 +- src/nuclide_header.F90 | 2 +- src/sab_header.F90 | 1 - src/tally.F90 | 20 +- src/tally_filter.F90 | 91 ++++-- 12 files changed, 607 insertions(+), 552 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 23aa40587..87886c1bd 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -319,8 +319,8 @@ contains integer(C_INT) :: err if (allocated(cells)) then - if (cell_dict % has_key(id)) then - index = cell_dict % get_key(id) + if (cell_dict % has(id)) then + index = cell_dict % get(id) err = 0 else err = E_CELL_INVALID_ID @@ -341,8 +341,8 @@ contains integer(C_INT) :: err if (allocated(materials)) then - if (material_dict % has_key(id)) then - index = material_dict % get_key(id) + if (material_dict % has(id)) then + index = material_dict % get(id) err = 0 else err = E_MATERIAL_INVALID_ID @@ -368,8 +368,8 @@ contains name_ = to_f_string(name) if (allocated(nuclides)) then - if (nuclide_dict % has_key(to_lower(name_))) then - index = nuclide_dict % get_key(to_lower(name_)) + if (nuclide_dict % has(to_lower(name_))) then + index = nuclide_dict % get(to_lower(name_)) err = 0 else err = E_NUCLIDE_NOT_LOADED @@ -390,8 +390,8 @@ contains integer(C_INT) :: err if (allocated(tallies)) then - if (tally_dict % has_key(id)) then - index = tally_dict % get_key(id) + if (tally_dict % has(id)) then + index = tally_dict % get(id) err = 0 else err = E_TALLY_INVALID_ID @@ -440,8 +440,8 @@ contains name_ = to_f_string(name) err = 0 - if (.not. nuclide_dict % has_key(to_lower(name_))) then - if (library_dict % has_key(to_lower(name_))) then + if (.not. nuclide_dict % has(to_lower(name_))) then + if (library_dict % has(to_lower(name_))) then ! allocate extra space in nuclides array n = n_nuclides_total allocate(new_nuclides(n + 1)) @@ -449,7 +449,7 @@ contains call move_alloc(FROM=new_nuclides, TO=nuclides) n = n + 1 - i_library = library_dict % get_key(to_lower(name_)) + i_library = library_dict % get(to_lower(name_)) ! Open file and make sure version is sufficient file_id = file_open(libraries(i_library) % path, 'r') @@ -464,7 +464,7 @@ contains call file_close(file_id) ! Add entry to nuclide dictionary - call nuclide_dict % add_key(to_lower(name_), n) + call nuclide_dict % add(to_lower(name_), n) n_nuclides_total = n ! Assign resonant scattering data @@ -531,7 +531,7 @@ contains call move_alloc(FROM=new_density, TO=m % atom_density) ! Append new nuclide/density - k = nuclide_dict % get_key(to_lower(name_)) + k = nuclide_dict % get(to_lower(name_)) m % nuclide(n + 1) = k m % atom_density(n + 1) = density m % density = m % density + density @@ -641,12 +641,12 @@ contains call c_f_pointer(name(i), string, [10]) name_ = to_lower(to_f_string(string)) - if (.not. nuclide_dict % has_key(name_)) then + if (.not. nuclide_dict % has(name_)) then err = openmc_load_nuclide(string) if (err < 0) return end if - m % nuclide(i) = nuclide_dict % get_key(name_) + m % nuclide(i) = nuclide_dict % get(name_) m % atom_density(i) = density(i) end do m % n_nuclides = n @@ -841,8 +841,8 @@ contains case ('total') t % nuclide_bins(i) = -1 case default - if (nuclide_dict % has_key(nuclide_)) then - t % nuclide_bins(i) = nuclide_dict % get_key(nuclide_) + if (nuclide_dict % has(nuclide_)) then + t % nuclide_bins(i) = nuclide_dict % get(nuclide_) else err = E_NUCLIDE_NOT_LOADED return diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 68cd94aa6..3467cde8f 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -374,7 +374,7 @@ contains m % volume_frac = ONE/real(product(m % dimension),8) ! Add mesh to dictionary - call mesh_dict % add_key(m % id, n_user_meshes + 1) + call mesh_dict % add(m % id, n_user_meshes + 1) ! Determine number of filters energy_filters = check_for_node(node_mesh, "energy") @@ -392,7 +392,7 @@ contains filt % n_bins = product(m % dimension) filt % mesh = n_user_meshes + 1 ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select if (energy_filters) then @@ -407,7 +407,7 @@ contains allocate(filt % bins(ng)) call get_node_array(node_mesh, "energy", filt % bins) ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select ! Read and set outgoing energy mesh filter @@ -421,7 +421,7 @@ contains allocate(filt % bins(ng)) call get_node_array(node_mesh, "energy", filt % bins) ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select end if @@ -437,7 +437,7 @@ contains filt % n_bins = product(m % dimension + 1) filt % mesh = n_user_meshes + 1 ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select ! Set up surface filter @@ -458,7 +458,7 @@ contains end if filt % current = .true. ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select ! Allocate tallies diff --git a/src/dict_header.F90 b/src/dict_header.F90 index ffe488d52..4a59cfb51 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -5,53 +5,34 @@ module dict_header ! ! This module provides an implementation of a dictionary that has (key,value) ! pairs. This data structure is used to provide lookup features, e.g. cells and -! surfaces by name. -! -! The original version was roughly based on capabilities in the 'flibs' open -! source package. However, it was rewritten from scratch so that it could be -! used stand-alone without relying on the implementation of lists. As with -! lists, it was considered writing a single dictionary used unlimited -! polymorphism, but again compiler support is spotty and doesn't always prevent -! duplication of code. +! surfaces by name. As with lists, it was considered writing a single +! dictionary used unlimited polymorphism, but again compiler support is spotty +! and doesn't always prevent duplication of code. !=============================================================================== implicit none - integer, parameter, private :: HASH_SIZE = 4993 - integer, parameter, private :: HASH_MULTIPLIER = 31 - integer, parameter, private :: DICT_NULL = -huge(0) - integer, parameter :: DICT_KEY_LENGTH = 255 + integer, parameter :: EMPTY = -huge(0) + integer, parameter, private :: DELETED = -huge(0) + 1 + integer, parameter, private :: MIN_SIZE = 8 + integer, parameter, private :: KEY_CHAR_LENGTH = 255 + real(8), parameter, private :: GROWTH_FACTOR = 2 + real(8), parameter, private :: MAX_LOAD_FACTOR = 0.65 !=============================================================================== -! ELEMKEYVALUE* contains (key,value) pairs and a pointer to the next (key,value) -! pair +! DICTENTRY* contains (key,value) pairs !=============================================================================== - type ElemKeyValueCI - type(ElemKeyValueCI), pointer :: next => null() - character(len=DICT_KEY_LENGTH) :: key - integer :: value - end type ElemKeyValueCI + type DictEntryCI + character(len=KEY_CHAR_LENGTH) :: key + integer :: value = EMPTY + integer :: hash = EMPTY + end type DictEntryCI - type ElemKeyValueII - type(ElemKeyValueII), pointer :: next => null() - integer :: key - integer :: value - end type ElemKeyValueII - -!=============================================================================== -! HASHLIST* types contain a single pointer to a linked list of (key,value) -! pairs. This type is necesssary so that the Dict types can be dynamically -! allocated. -!=============================================================================== - - type, private :: HashListCI - type(ElemKeyValueCI), pointer :: list => null() - end type HashListCI - - type, private :: HashListII - type(ElemKeyValueII), pointer :: list => null() - end type HashListII + type DictEntryII + integer :: key = EMPTY + integer :: value = EMPTY + end type DictEntryII !=============================================================================== ! DICT* is a dictionary of (key,value) pairs with convenience methods as @@ -60,385 +41,451 @@ module dict_header !=============================================================================== type, public :: DictCharInt - private - type(HashListCI), pointer :: table(:) => null() + integer, private :: entries = 0 + integer, private :: capacity = 0 + type(DictEntryCI), allocatable, private :: table(:) contains - procedure :: add_key => dict_add_key_ci - procedure :: get_key => dict_get_key_ci - procedure :: has_key => dict_has_key_ci - procedure :: keys => dict_keys_ci - procedure :: clear => dict_clear_ci - procedure, private :: get_elem => dict_get_elem_ci + procedure :: add => add_ci + procedure :: get => get_ci + procedure :: has => has_ci + procedure :: remove => remove_ci + procedure :: next_entry => next_entry_ci + procedure :: clear => clear_ci + procedure :: size => size_ci + procedure, private :: get_entry => get_entry_ci + procedure, private :: resize => resize_ci end type DictCharInt type, public :: DictIntInt - private - type(HashListII), pointer :: table(:) => null() + integer, private :: entries = 0 + integer, private :: capacity = 0 + type(DictEntryII), allocatable, private :: table(:) contains - procedure :: add_key => dict_add_key_ii - procedure :: get_key => dict_get_key_ii - procedure :: has_key => dict_has_key_ii - procedure :: keys => dict_keys_ii - procedure :: clear => dict_clear_ii - procedure, private :: get_elem => dict_get_elem_ii + procedure :: add => add_ii + procedure :: get => get_ii + procedure :: has => has_ii + procedure :: remove => remove_ii + procedure :: next_entry => next_entry_ii + procedure :: clear => clear_ii + procedure :: size => size_ii + procedure, private :: get_entry => get_entry_ii + procedure, private :: resize => resize_ii end type DictIntInt contains !=============================================================================== -! DICT_ADD_KEY adds a (key,value) entry to a dictionary. If the key is already -! in the dictionary, the value is replaced by the new specified value. +! GET_ENTRY returns the index of the (key,value) pair in the table for a given +! key. This method is private. !=============================================================================== - subroutine dict_add_key_ci(this, key, value) + function get_entry_ci(this, key) result(i) - class(DictCharInt) :: this - character(*), intent(in) :: key - integer, intent(in) :: value + class(DictCharInt) :: this + character(*), intent(in) :: key + integer :: i integer :: hash - type(ElemKeyValueCI), pointer :: elem => null() - type(ElemKeyValueCI), pointer :: new_elem => null() - elem => this % get_elem(key) - - if (associated(elem)) then - elem % value = value - else - ! Get hash - hash = dict_hash_key_ci(key) - - ! Create new element - allocate(new_elem) - new_elem % key = key - new_elem % value = value - - ! Add element to front of list - new_elem % next => this % table(hash) % list - this % table(hash) % list => new_elem + if (.not. allocated(this % table)) then + allocate(this % table(MIN_SIZE)) + this % capacity = MIN_SIZE end if - end subroutine dict_add_key_ci + hash = hash_ci(key) + i = 1 + mod(hash, this % capacity) - subroutine dict_add_key_ii(this, key, value) + do + if (this % table(i) % hash == hash .and. & + this % table(i) % key == key) exit - class(DictIntInt) :: this + if (this % table(i) % hash == EMPTY) exit + + ! TODO: use more advanced probing or double hashing to update i + i = 1 + mod(i, this % capacity) + end do + + end function get_entry_ci + + function get_entry_ii(this, key) result(i) + + class(DictIntInt) :: this + integer, intent(in) :: key + integer :: i + + integer :: hash + + if (.not. allocated(this % table)) then + allocate(this % table(MIN_SIZE)) + this % capacity = MIN_SIZE + end if + + hash = hash_ii(key) + i = 1 + mod(hash, this % capacity) + + do + if (this % table(i) % key == key .or. & + this % table(i) % key == EMPTY) exit + + ! TODO: use more advanced probing or double hashing to update i + i = 1 + mod(i, this % capacity) + end do + + end function get_entry_ii + +!=============================================================================== +! RESIZE allocates a new hash table to accomodate the number of entries and +! reinserts all of the entries into the new table. This method is private. +!=============================================================================== + + subroutine resize_ci(this, new_size) + + class(DictCharInt) :: this + integer, intent(in) :: new_size + + type(DictEntryCI), allocatable :: table(:) + integer :: i + + call move_alloc(this % table, table) + allocate(this % table(new_size)) + this % capacity = new_size + this % entries = 0 + + ! Rehash each entry into the new table + do i = 1, size(table) + if (table(i) % hash /= EMPTY .and. table(i) % hash /= DELETED) then + call this % add(table(i) % key, table(i) % value) + end if + end do + + deallocate(table) + + end subroutine resize_ci + + subroutine resize_ii(this, new_size) + + class(DictIntInt) :: this + integer, intent(in) :: new_size + + type(DictEntryII), allocatable :: table(:) + integer :: i + + call move_alloc(this % table, table) + allocate(this % table(new_size)) + this % capacity = new_size + this % entries = 0 + + ! Rehash each entry into the new table + do i = 1, size(table) + if (table(i) % key /= EMPTY .and. table(i) % key /= DELETED) then + call this % add(table(i) % key, table(i) % value) + end if + end do + + deallocate(table) + + end subroutine resize_ii + +!=============================================================================== +! ADD adds a (key,value) entry to a dictionary. If the key is already in the +! dictionary, the value is replaced by the new specified value. +!=============================================================================== + + subroutine add_ci(this, key, value) + + class(DictCharInt) :: this + character(*), intent(in) :: key + integer, intent(in) :: value + + integer :: hash + integer :: i + + if (.not. allocated(this % table)) then + allocate(this % table(MIN_SIZE)) + this % capacity = MIN_SIZE + else if (real(this % entries, 8) / this % capacity > MAX_LOAD_FACTOR) then + call this % resize(int(this % capacity * GROWTH_FACTOR)) + end if + + hash = hash_ci(key) + i = 1 + mod(hash, this % capacity) + + do + if (this % table(i) % hash == EMPTY .or. & + this % table(i) % hash == DELETED) then + this % table(i) % hash = hash + this % table(i) % key = key + this % table(i) % value = value + this % entries = this % entries + 1 + exit + else if (this % table(i) % hash == hash .and. & + this % table(i) % key == key) then + this % table(i) % value = value + exit + end if + + ! TODO: use more advanced probing or double hashing to update i + i = 1 + mod(i, this % capacity) + end do + + end subroutine add_ci + + subroutine add_ii(this, key, value) + + class(DictIntInt) :: this integer, intent(in) :: key integer, intent(in) :: value integer :: hash - type(ElemKeyValueII), pointer :: elem => null() - type(ElemKeyValueII), pointer :: new_elem => null() + integer :: i - elem => this % get_elem(key) - - if (associated(elem)) then - elem % value = value - else - ! Get hash - hash = dict_hash_key_ii(key) - - ! Create new element - allocate(new_elem) - new_elem % key = key - new_elem % value = value - - ! Add element to front of list - new_elem % next => this % table(hash) % list - this % table(hash) % list => new_elem + if (.not. allocated(this % table)) then + allocate(this % table(MIN_SIZE)) + this % capacity = MIN_SIZE + else if (real(this % entries, 8) / this % capacity > MAX_LOAD_FACTOR) then + call this % resize(int(this % capacity * GROWTH_FACTOR)) end if - end subroutine dict_add_key_ii + hash = hash_ii(key) + i = 1 + mod(hash, this % capacity) -!=============================================================================== -! DICT_GET_ELEM returns a pointer to the (key,value) pair for a given key. This -! method is private. -!=============================================================================== + do + if (this % table(i) % key == EMPTY .or. & + this % table(i) % key == DELETED) then + this % table(i) % key = key + this % table(i) % value = value + this % entries = this % entries + 1 + exit + else if (this % table(i) % key == key) then + this % table(i) % value = value + exit + end if - function dict_get_elem_ci(this, key) result(elem) - - class(DictCharInt) :: this - character(*), intent(in) :: key - type(ElemKeyValueCI), pointer :: elem - - integer :: hash - - ! Check for dictionary not being allocated - if (.not. associated(this % table)) then - allocate(this % table(HASH_SIZE)) - end if - - hash = dict_hash_key_ci(key) - elem => this % table(hash) % list - do while (associated(elem)) - if (elem % key == key) exit - elem => elem % next + ! TODO: use more advanced probing or double hashing to update i + i = 1 + mod(i, this % capacity) end do - end function dict_get_elem_ci - - function dict_get_elem_ii(this, key) result(elem) - - class(DictIntInt) :: this - integer, intent(in) :: key - type(ElemKeyValueII), pointer :: elem - - integer :: hash - - ! Check for dictionary not being allocated - if (.not. associated(this % table)) then - allocate(this % table(HASH_SIZE)) - end if - - hash = dict_hash_key_ii(key) - elem => this % table(hash) % list - do while (associated(elem)) - if (elem % key == key) exit - elem => elem % next - end do - - end function dict_get_elem_ii + end subroutine add_ii !=============================================================================== -! DICT_GET_KEY returns the value matching a given key. If the dictionary does -! not contain the key, the value DICT_NULL is returned. +! GET returns the value matching a given key. If the dictionary does not contain +! the key, the value EMPTY is returned. !=============================================================================== - function dict_get_key_ci(this, key) result(value) + function get_ci(this, key) result(value) - class(DictCharInt) :: this + class(DictCharInt) :: this character(*), intent(in) :: key integer :: value - type(ElemKeyValueCI), pointer :: elem + integer :: i - elem => this % get_elem(key) + i = this % get_entry(key) + value = this % table(i) % value - if (associated(elem)) then - value = elem % value - else - value = DICT_NULL - end if + end function get_ci - end function dict_get_key_ci - - function dict_get_key_ii(this, key) result(value) + function get_ii(this, key) result(value) class(DictIntInt) :: this integer, intent(in) :: key integer :: value - type(ElemKeyValueII), pointer :: elem + integer :: i - elem => this % get_elem(key) + i = this % get_entry(key) + value = this % table(i) % value - if (associated(elem)) then - value = elem % value - else - value = DICT_NULL - end if - - end function dict_get_key_ii + end function get_ii !=============================================================================== -! DICT_HAS_KEY determines whether a dictionary has a (key,value) pair with a -! given key. +! HAS determines whether a dictionary has a (key,value) pair with a given key. !=============================================================================== - function dict_has_key_ci(this, key) result(has) + function has_ci(this, key) result(has) - class(DictCharInt) :: this + class(DictCharInt) :: this character(*), intent(in) :: key logical :: has - type(ElemKeyValueCI), pointer :: elem + integer :: i - elem => this % get_elem(key) - has = associated(elem) + i = this % get_entry(key) + has = (this % table(i) % hash /= EMPTY) - end function dict_has_key_ci + end function has_ci - function dict_has_key_ii(this, key) result(has) + function has_ii(this, key) result(has) class(DictIntInt) :: this integer, intent(in) :: key logical :: has - type(ElemKeyValueII), pointer :: elem + integer :: i - elem => this % get_elem(key) - has = associated(elem) + i = this % get_entry(key) + has = (this % table(i) % key /= EMPTY) - end function dict_has_key_ii + end function has_ii !=============================================================================== -! DICT_HASH_KEY returns the hash value for a given key +! REMOVE deletes a (key,value) entry from a dictionary. !=============================================================================== - function dict_hash_key_ci(key) result(val) + subroutine remove_ci(this, key) + class(DictCharInt) :: this character(*), intent(in) :: key - integer :: val integer :: i - val = 0 + i = this % get_entry(key) + if (this % table(i) % hash /= EMPTY) then + this % table(i) % hash = DELETED + this % table(i) % key = "" + this % table(i) % value = EMPTY + this % entries = this % entries - 1 + end if - do i = 1, len_trim(key) - val = HASH_MULTIPLIER * val + ichar(key(i:i)) - end do + end subroutine remove_ci - ! Added the absolute val on val-1 since the sum in the do loop is - ! susceptible to integer overflow - val = 1 + mod(abs(val-1), HASH_SIZE) - - end function dict_hash_key_ci - - function dict_hash_key_ii(key) result(val) + subroutine remove_ii(this, key) + class(DictIntInt) :: this integer, intent(in) :: key - integer :: val - - val = 0 - - ! Added the absolute val on val-1 since the sum in the do loop is - ! susceptible to integer overflow - val = 1 + mod(abs(key-1), HASH_SIZE) - - end function dict_hash_key_ii - -!=============================================================================== -! DICT_KEYS returns a pointer to a linked list of all (key,value) pairs -!=============================================================================== - - function dict_keys_ci(this) result(keys) - class(DictCharInt) :: this - type(ElemKeyValueCI), pointer :: keys integer :: i - type(ElemKeyValueCI), pointer :: current => null() - type(ElemKeyValueCI), pointer :: elem => null() - keys => null() + i = this % get_entry(key) + if (this % table(i) % key /= EMPTY) then + this % table(i) % key = DELETED + this % table(i) % value = EMPTY + this % entries = this % entries - 1 + end if - do i = 1, size(this % table) - ! Get pointer to start of bucket i - elem => this % table(i) % list - - do while (associated(elem)) - ! Allocate (key,value) pair - if (.not. associated(keys)) then - allocate(keys) - current => keys - else - allocate(current % next) - current => current % next - end if - - ! Copy (key,value) pair - current % key = elem % key - current % value = elem % value - - ! Move to next element in bucket i - elem => elem % next - end do - end do - - end function dict_keys_ci - - function dict_keys_ii(this) result(keys) - class(DictIntInt) :: this - type(ElemKeyValueII), pointer :: keys - - integer :: i - type(ElemKeyValueII), pointer :: current => null() - type(ElemKeyValueII), pointer :: elem => null() - - keys => null() - - do i = 1, size(this % table) - ! Get pointer to start of bucket i - elem => this % table(i) % list - - do while (associated(elem)) - ! Allocate (key,value) pair - if (.not. associated(keys)) then - allocate(keys) - current => keys - else - allocate(current % next) - current => current % next - end if - - ! Copy (key,value) pair - current % key = elem % key - current % value = elem % value - - ! Move to next element in bucket i - elem => elem % next - end do - end do - - end function dict_keys_ii + end subroutine remove_ii !=============================================================================== -! DICT_CLEAR Deletes and deallocates the dictionary item +! NEXT_ENTRY finds the next (key,value) pair. The value of current_entry is +! updated with the (key,value) pair, and the value of i is updated with the +! index of the entry in the table. Passing in i = 0 will locate the first entry +! in the dictionary. If there are no more entries, i will be set to 0. !=============================================================================== - subroutine dict_clear_ci(this) + subroutine next_entry_ci(this, current_entry, i) + + class(DictCharInt) :: this + type(DictEntryCI), intent(inout) :: current_entry + integer, intent(inout) :: i + + if (.not. allocated(this % table)) return + + do + i = i + 1 + if (i > size(this % table)) then + i = 0 + exit + else if (this % table(i) % hash /= EMPTY .and. & + this % table(i) % hash /= DELETED) then + current_entry = this % table(i) + exit + end if + end do + + end subroutine next_entry_ci + + subroutine next_entry_ii(this, current_entry, i) + + class(DictIntInt) :: this + type(DictEntryII), intent(inout) :: current_entry + integer, intent(inout) :: i + + if (.not. allocated(this % table)) return + + do + i = i + 1 + if (i > size(this % table)) then + i = 0 + exit + else if (this % table(i) % key /= EMPTY .and. & + this % table(i) % key /= DELETED) then + current_entry = this % table(i) + exit + end if + end do + + end subroutine next_entry_ii + +!=============================================================================== +! CLEAR deletes and deallocates the dictionary item +!=============================================================================== + + subroutine clear_ci(this) class(DictCharInt) :: this - integer :: i - type(ElemKeyValueCI), pointer :: current - type(ElemKeyValueCI), pointer :: next + if (allocated(this % table)) deallocate(this % table) - if (associated(this % table)) then - do i = 1, size(this % table) - current => this % table(i) % list - do while (associated(current)) - if (associated(current % next)) then - next => current % next - else - nullify(next) - end if - deallocate(current) - current => next - end do - if (associated(this % table(i) % list)) & - nullify(this % table(i) % list) - end do - deallocate(this % table) - end if + end subroutine clear_ci - end subroutine dict_clear_ci - - subroutine dict_clear_ii(this) + subroutine clear_ii(this) class(DictIntInt) :: this + if (allocated(this % table)) deallocate(this % table) + + end subroutine clear_ii + +!=============================================================================== +! SIZE returns the number of entries in the dictionary +!=============================================================================== + + pure function size_ci(this) result(size) + + class(DictCharInt), intent(in) :: this + integer :: size + + size = this % entries + + end function size_ci + + pure function size_ii(this) result(size) + + class(DictIntInt), intent(in) :: this + integer :: size + + size = this % entries + + end function size_ii + +!=============================================================================== +! HASH returns the hash value for a given key +!=============================================================================== + + function hash_ci(key) result(hash) + + character(*), intent(in) :: key + integer :: hash + integer :: i - type(ElemKeyValueII), pointer :: current - type(ElemKeyValueII), pointer :: next - if (associated(this % table)) then - do i = 1, size(this % table) - current => this % table(i) % list - do while (associated(current)) - if (associated(current % next)) then - next => current % next - else - nullify(next) - end if - deallocate(current) - current => next - end do - if (associated(this % table(i) % list)) & - nullify(this % table(i) % list) - end do - deallocate(this % table) - end if + hash = 0 - end subroutine dict_clear_ii + do i = 1, len_trim(key) + hash = 31 * hash + ichar(key(i:i)) + end do + + hash = abs(hash - 1) + + end function hash_ci + + function hash_ii(key) result(hash) + + integer, intent(in) :: key + integer :: hash + + hash = abs(key - 1) + + end function hash_ii end module dict_header diff --git a/src/geometry.F90 b/src/geometry.F90 index 7f75a817f..d3a2c74a3 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -1250,8 +1250,8 @@ contains class(Lattice), pointer :: lat ! pointer to current lattice ! Don't research places already checked - if (found(universe_dict % get_key(univ % id), map)) then - count = counts(universe_dict % get_key(univ % id), map) + if (found(universe_dict % get(univ % id), map)) then + count = counts(universe_dict % get(univ % id), map) return end if @@ -1259,8 +1259,8 @@ contains ! Count = 1, then quit if (univ % id == univ_id) then count = 1 - counts(universe_dict % get_key(univ % id), map) = 1 - found(universe_dict % get_key(univ % id), map) = .true. + counts(universe_dict % get(univ % id), map) = 1 + found(universe_dict % get(univ % id), map) = .true. return end if @@ -1356,8 +1356,8 @@ contains end if end do - counts(universe_dict % get_key(univ % id), map) = count - found(universe_dict % get_key(univ % id), map) = .true. + counts(universe_dict % get(univ % id), map) = count + found(universe_dict % get(univ % id), map) = .true. end function count_target diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 0d3ae2640..7ff253b95 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -364,11 +364,11 @@ contains temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN end if - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = material_dict % get(cells(i) % material(j)) associate (mat => materials(i_material)) NUC_NAMES_LOOP: do k = 1, size(mat % names) ! Get index in nuc_temps array - i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k))) + i_nuclide = nuclide_dict % get(to_lower(mat % names(k))) ! Add temperature if it hasn't already been added if (find(nuc_temps(i_nuclide), temperature) == -1) then @@ -380,7 +380,7 @@ contains mat % n_sab > 0) then SAB_NAMES_LOOP: do k = 1, size(mat % sab_names) ! Get index in nuc_temps array - i_sab = sab_dict % get_key(to_lower(mat % sab_names(k))) + i_sab = sab_dict % get(to_lower(mat % sab_names(k))) ! Add temperature if it hasn't already been added if (find(sab_temps(i_sab), temperature) == -1) then diff --git a/src/initialize.F90 b/src/initialize.F90 index 1e29c638c..0db95e524 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -9,7 +9,7 @@ module initialize use bank_header, only: Bank use constants - use dict_header, only: DictIntInt, ElemKeyValueII + use dict_header, only: DictIntInt, DictEntryII use set_header, only: SetInt use error, only: fatal_error, warning use geometry, only: neighbor_lists, count_instance, calc_offsets, & @@ -449,41 +449,41 @@ contains ! ADJUST REGION SPECIFICATION FOR EACH CELL c => cells(i) - do j = 1, size(c%region) - id = c%region(j) + do j = 1, size(c % region) + id = c % region(j) ! Make sure that only regions are checked. Since OP_UNION is the ! operator with the lowest integer value, anything below it must denote ! a half-space if (id < OP_UNION) then - if (surface_dict%has_key(abs(id))) then - i_array = surface_dict%get_key(abs(id)) - c%region(j) = sign(i_array, id) + if (surface_dict % has(abs(id))) then + i_array = surface_dict % get(abs(id)) + c % region(j) = sign(i_array, id) else call fatal_error("Could not find surface " // trim(to_str(abs(id)))& - &// " specified on cell " // trim(to_str(c%id))) + &// " specified on cell " // trim(to_str(c % id))) end if end if end do ! Also adjust the indices in the reverse Polish notation - do j = 1, size(c%rpn) - id = c%rpn(j) + do j = 1, size(c % rpn) + id = c % rpn(j) ! Again, make sure that only regions are checked if (id < OP_UNION) then - i_array = surface_dict%get_key(abs(id)) - c%rpn(j) = sign(i_array, id) + i_array = surface_dict % get(abs(id)) + c % rpn(j) = sign(i_array, id) end if end do ! ======================================================================= ! ADJUST UNIVERSE INDEX FOR EACH CELL - id = c%universe - if (universe_dict%has_key(id)) then - c%universe = universe_dict%get_key(id) + id = c % universe + if (universe_dict % has(id)) then + c % universe = universe_dict % get(id) else call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c%id))) + &// " specified on cell " // trim(to_str(c % id))) end if ! ======================================================================= @@ -491,11 +491,11 @@ contains if (c % material(1) == NONE) then id = c % fill - if (universe_dict % has_key(id)) then + if (universe_dict % has(id)) then c % type = FILL_UNIVERSE - c % fill = universe_dict % get_key(id) - elseif (lattice_dict % has_key(id)) then - lid = lattice_dict % get_key(id) + c % fill = universe_dict % get(id) + elseif (lattice_dict % has(id)) then + lid = lattice_dict % get(id) c % type = FILL_LATTICE c % fill = lid else @@ -508,9 +508,9 @@ contains id = c % material(j) if (id == MATERIAL_VOID) then c % type = FILL_MATERIAL - else if (material_dict % has_key(id)) then + else if (material_dict % has(id)) then c % type = FILL_MATERIAL - c % material(j) = material_dict % get_key(id) + c % material(j) = material_dict % get(id) else call fatal_error("Could not find material " // trim(to_str(id)) & // " specified on cell " // trim(to_str(c % id))) @@ -523,41 +523,41 @@ contains ! ADJUST UNIVERSE INDICES FOR EACH LATTICE do i = 1, n_lattices - lat => lattices(i)%obj + lat => lattices(i) % obj select type (lat) type is (RectLattice) - do m = 1, lat%n_cells(3) - do k = 1, lat%n_cells(2) - do j = 1, lat%n_cells(1) - id = lat%universes(j,k,m) - if (universe_dict%has_key(id)) then - lat%universes(j,k,m) = universe_dict%get_key(id) + do m = 1, lat % n_cells(3) + do k = 1, lat % n_cells(2) + do j = 1, lat % n_cells(1) + id = lat % universes(j,k,m) + if (universe_dict % has(id)) then + lat % universes(j,k,m) = universe_dict % get(id) else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat%id))) + &// trim(to_str(lat % id))) end if end do end do end do type is (HexLattice) - do m = 1, lat%n_axial - do k = 1, 2*lat%n_rings - 1 - do j = 1, 2*lat%n_rings - 1 - if (j + k < lat%n_rings + 1) then + do m = 1, lat % n_axial + do k = 1, 2*lat % n_rings - 1 + do j = 1, 2*lat % n_rings - 1 + if (j + k < lat % n_rings + 1) then cycle - else if (j + k > 3*lat%n_rings - 1) then + else if (j + k > 3*lat % n_rings - 1) then cycle end if - id = lat%universes(j, k, m) - if (universe_dict%has_key(id)) then - lat%universes(j, k, m) = universe_dict%get_key(id) + id = lat % universes(j, k, m) + if (universe_dict % has(id)) then + lat % universes(j, k, m) = universe_dict % get(id) else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat%id))) + &// trim(to_str(lat % id))) end if end do end do @@ -565,13 +565,13 @@ contains end select - if (lat%outer /= NO_OUTER_UNIVERSE) then - if (universe_dict%has_key(lat%outer)) then - lat%outer = universe_dict%get_key(lat%outer) + if (lat % outer /= NO_OUTER_UNIVERSE) then + if (universe_dict % has(lat % outer)) then + lat % outer = universe_dict % get(lat % outer) else call fatal_error("Invalid universe number " & - &// trim(to_str(lat%outer)) & - &// " specified on lattice " // trim(to_str(lat%id))) + &// trim(to_str(lat % outer)) & + &// " specified on lattice " // trim(to_str(lat % id))) end if end if diff --git a/src/input_xml.F90 b/src/input_xml.F90 index efdc3e523..66b9dc5be 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3,7 +3,7 @@ module input_xml use algorithm, only: find use cmfd_input, only: configure_cmfd use constants - use dict_header, only: DictIntInt, DictCharInt, ElemKeyValueCI + use dict_header, only: DictIntInt, DictCharInt, DictEntryCI use distribution_multivariate use distribution_univariate use endf, only: reaction_name @@ -1183,7 +1183,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (cell_dict % has_key(c % id)) then + if (cell_dict % has(c % id)) then call fatal_error("Two or more cells use the same unique ID: " & // to_str(c % id)) end if @@ -1368,21 +1368,21 @@ contains end if ! Add cell to dictionary - call cell_dict % add_key(c % id, i) + call cell_dict % add(c % id, i) ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the ! specified universe univ_id = c % universe - if (.not. cells_in_univ_dict % has_key(univ_id)) then + if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 n_cells_in_univ = 1 - call universe_dict % add_key(univ_id, n_universes) + call universe_dict % add(univ_id, n_universes) call univ_ids % push_back(univ_id) else - n_cells_in_univ = 1 + cells_in_univ_dict % get_key(univ_id) + n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) end if - call cells_in_univ_dict % add_key(univ_id, n_cells_in_univ) + call cells_in_univ_dict % add(univ_id, n_cells_in_univ) end do @@ -1473,7 +1473,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (surface_dict % has_key(s%id)) then + if (surface_dict % has(s%id)) then call fatal_error("Two or more surfaces use the same unique ID: " & // to_str(s%id)) end if @@ -1604,7 +1604,7 @@ contains &"' specified on surface " // trim(to_str(s%id))) end select ! Add surface to dictionary - call surface_dict % add_key(s%id, i) + call surface_dict % add(s%id, i) end do ! Check to make sure a boundary condition was applied to at least one @@ -1630,7 +1630,7 @@ contains &interior surface.") end if else - surf % i_periodic = surface_dict % get_key(surf % i_periodic) + surf % i_periodic = surface_dict % get(surf % i_periodic) end if type is (SurfaceYPlane) @@ -1644,7 +1644,7 @@ contains &interior surface.") end if else - surf % i_periodic = surface_dict % get_key(surf % i_periodic) + surf % i_periodic = surface_dict % get(surf % i_periodic) end if type is (SurfaceZPlane) @@ -1658,7 +1658,7 @@ contains &interior surface.") end if else - surf % i_periodic = surface_dict % get_key(surf % i_periodic) + surf % i_periodic = surface_dict % get(surf % i_periodic) end if type is (SurfacePlane) @@ -1667,7 +1667,7 @@ contains &periodic boundary condition on surface " // & trim(to_str(surf % id)) // ".") else - surf % i_periodic = surface_dict % get_key(surf % i_periodic) + surf % i_periodic = surface_dict % get(surf % i_periodic) end if class default @@ -1715,7 +1715,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (lattice_dict % has_key(lat % id)) then + if (lattice_dict % has(lat % id)) then call fatal_error("Two or more lattices use the same unique ID: " & // to_str(lat % id)) end if @@ -1825,7 +1825,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % add_key(lat % id, i) + call lattice_dict % add(lat % id, i) end select end do RECT_LATTICES @@ -1847,7 +1847,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (lattice_dict % has_key(lat % id)) then + if (lattice_dict % has(lat % id)) then call fatal_error("Two or more lattices use the same unique ID: " & // to_str(lat % id)) end if @@ -2012,7 +2012,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % add_key(lat % id, n_rlats + i) + call lattice_dict % add(lat % id, n_rlats + i) end select end do HEX_LATTICES @@ -2027,7 +2027,7 @@ contains u % id = univ_ids % data(i) ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get_key(u % id) + n_cells_in_univ = cells_in_univ_dict % get(u % id) allocate(u % cells(n_cells_in_univ)) u % cells(:) = 0 @@ -2046,7 +2046,7 @@ contains do i = 1, n_cells ! Get index in universes array - j = universe_dict % get_key(cells(i) % universe) + j = universe_dict % get(cells(i) % universe) ! Set the first zero entry in the universe cells array to the index in the ! global cells array @@ -2056,7 +2056,7 @@ contains end do ! Clear dictionary - call cells_in_univ_dict%clear() + call cells_in_univ_dict % clear() ! Close geometry XML file call doc % clear() @@ -2166,14 +2166,14 @@ contains ! Creating dictionary that maps the name of the material to the entry do i = 1, size(libraries) do j = 1, size(libraries(i) % materials) - call library_dict % add_key(to_lower(libraries(i) % materials(j)), i) + call library_dict % add(to_lower(libraries(i) % materials(j)), i) end do end do ! Check that 0K nuclides are listed in the cross_sections.xml file if (allocated(res_scat_nuclides)) then do i = 1, size(res_scat_nuclides) - if (.not. library_dict % has_key(to_lower(res_scat_nuclides(i)))) then + if (.not. library_dict % has(to_lower(res_scat_nuclides(i)))) then call fatal_error("Could not find resonant scatterer " & // trim(res_scat_nuclides(i)) // " in cross_sections.xml file!") end if @@ -2278,7 +2278,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (material_dict % has_key(mat % id)) then + if (material_dict % has(mat % id)) then call fatal_error("Two or more materials use the same unique ID: " & // to_str(mat % id)) end if @@ -2487,11 +2487,11 @@ contains ALL_NUCLIDES: do j = 1, mat % n_nuclides ! Check that this nuclide is listed in the cross_sections.xml file name = trim(names % data(j)) - if (.not. library_dict % has_key(to_lower(name))) then + if (.not. library_dict % has(to_lower(name))) then call fatal_error("Could not find nuclide " // trim(name) & // " in cross_sections data file!") end if - i_library = library_dict % get_key(to_lower(name)) + i_library = library_dict % get(to_lower(name)) if (run_CE) then ! Check to make sure cross-section is continuous energy neutron table @@ -2503,13 +2503,13 @@ contains ! If this nuclide hasn't been encountered yet, we need to add its name ! and alias to the nuclide_dict - if (.not. nuclide_dict % has_key(to_lower(name))) then + if (.not. nuclide_dict % has(to_lower(name))) then index_nuclide = index_nuclide + 1 mat % nuclide(j) = index_nuclide - call nuclide_dict % add_key(to_lower(name), index_nuclide) + call nuclide_dict % add(to_lower(name), index_nuclide) else - mat % nuclide(j) = nuclide_dict % get_key(to_lower(name)) + mat % nuclide(j) = nuclide_dict % get(to_lower(name)) end if ! Copy name and atom/weight percent @@ -2582,14 +2582,14 @@ contains end if ! Check that this nuclide is listed in the cross_sections.xml file - if (.not. library_dict % has_key(to_lower(name))) then + if (.not. library_dict % has(to_lower(name))) then call fatal_error("Could not find S(a,b) table " // trim(name) & // " in cross_sections.xml file!") end if ! Find index in xs_listing and set the name and alias according to the ! listing - i_library = library_dict % get_key(to_lower(name)) + i_library = library_dict % get(to_lower(name)) if (run_CE) then ! Check to make sure cross-section is continuous energy neutron table @@ -2601,19 +2601,19 @@ contains ! If this S(a,b) table hasn't been encountered yet, we need to add its ! name and alias to the sab_dict - if (.not. sab_dict % has_key(to_lower(name))) then + if (.not. sab_dict % has(to_lower(name))) then index_sab = index_sab + 1 mat % i_sab_tables(j) = index_sab - call sab_dict % add_key(to_lower(name), index_sab) + call sab_dict % add(to_lower(name), index_sab) else - mat % i_sab_tables(j) = sab_dict % get_key(to_lower(name)) + mat % i_sab_tables(j) = sab_dict % get(to_lower(name)) end if end do end if end if ! Add material to dictionary - call material_dict % add_key(mat % id, i) + call material_dict % add(mat % id, i) end do ! Set total number of nuclides and S(a,b) tables @@ -2642,6 +2642,7 @@ contains integer :: i_mesh ! index in meshes array integer :: i_filt ! index in filters array integer :: i_filter_mesh ! index of mesh filter + integer :: i_elem ! index of entry in dictionary integer :: n ! size of arrays in mesh specification integer :: n_words ! number of words read integer :: n_filter ! number of filters @@ -2669,7 +2670,6 @@ contains character(MAX_WORD_LEN) :: temp_str character(MAX_WORD_LEN), allocatable :: sarray(:) type(DictCharInt) :: trigger_scores - type(ElemKeyValueCI), pointer :: pair_list type(TallyObject), pointer :: t type(TallyFilterContainer), pointer :: f type(RegularMesh), pointer :: m @@ -2685,8 +2685,7 @@ contains type(XMLNode), allocatable :: node_filt_list(:) type(XMLNode), allocatable :: node_trigger_list(:) type(XMLNode), allocatable :: node_deriv_list(:) - type(ElemKeyValueCI), pointer :: scores - type(ElemKeyValueCI), pointer :: next + type(DictEntryCI) :: elem ! Check if tallies.xml exists filename = trim(path_input) // "tallies.xml" @@ -2771,7 +2770,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (mesh_dict % has_key(m % id)) then + if (mesh_dict % has(m % id)) then call fatal_error("Two or more meshes use the same unique ID: " & // to_str(m % id)) end if @@ -2877,7 +2876,7 @@ contains m % volume_frac = ONE/real(product(m % dimension),8) ! Add mesh to dictionary - call mesh_dict % add_key(m % id, i) + call mesh_dict % add(m % id, i) end do ! We only need the mesh info for plotting @@ -2943,26 +2942,27 @@ contains call get_node_value(node_deriv, "nuclide", word) word = trim(to_lower(word)) - pair_list => nuclide_dict % keys() - do while (associated(pair_list)) - if (starts_with(pair_list % key, word)) then - word = pair_list % key(1:150) + + i_elem = 0 + do + ! Get next entry in dictionary + call nuclide_dict % next_entry(elem, i_elem) + + if (i_elem == 0) exit + if (starts_with(elem % key, word)) then + word = elem % key(1:150) exit end if - - ! Advance to next - pair_list => pair_list % next end do ! Check if no nuclide was found - if (.not. associated(pair_list)) then + if (i_elem == 0) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in derivative " & // trim(to_str(deriv % id)) // " in any material.") end if - deallocate(pair_list) - deriv % diff_nuclide = nuclide_dict % get_key(word) + deriv % diff_nuclide = nuclide_dict % get(word) case("temperature") deriv % variable = DIFF_TEMPERATURE @@ -2988,7 +2988,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (filter_dict % has_key(filter_id)) then + if (filter_dict % has(filter_id)) then call fatal_error("Two or more filters use the same unique ID: " & // to_str(filter_id)) end if @@ -3106,8 +3106,8 @@ contains call get_node_value(node_filt, "bins", id) ! Get pointer to mesh - if (mesh_dict % has_key(id)) then - i_mesh = mesh_dict % get_key(id) + if (mesh_dict % has(id)) then + i_mesh = mesh_dict % get(id) m => meshes(i_mesh) else call fatal_error("Could not find mesh " // trim(to_str(id)) & @@ -3330,7 +3330,7 @@ contains f % obj % id = filter_id ! Add filter to dictionary - call filter_dict % add_key(filter_id, i) + call filter_dict % add(filter_id, i) end do READ_FILTERS @@ -3363,7 +3363,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (tally_dict % has_key(t % id)) then + if (tally_dict % has(t % id)) then call fatal_error("Two or more tallies use the same unique ID: " & // to_str(t % id)) end if @@ -3399,8 +3399,8 @@ contains do j = 1, n_filter ! Get pointer to filter - if (filter_dict % has_key(temp_filter(j))) then - i_filt = filter_dict % get_key(temp_filter(j)) + if (filter_dict % has(temp_filter(j))) then + i_filt = filter_dict % get(temp_filter(j)) f => filters(i_filt) else call fatal_error("Could not find filter " & @@ -3492,27 +3492,27 @@ contains word = to_lower(sarray(j)) ! Search through nuclides - pair_list => nuclide_dict % keys() - do while (associated(pair_list)) - if (trim(pair_list % key) == trim(word)) then - word = pair_list % key(1:150) + i_elem = 0 + do + ! Get next entry in dictionary + call nuclide_dict % next_entry(elem, i_elem) + + if (i_elem == 0) exit + if (trim(elem % key) == trim(word)) then + word = elem % key(1:150) exit end if - - ! Advance to next - pair_list => pair_list % next end do ! Check if no nuclide was found - if (.not. associated(pair_list)) then + if (i_elem == 0) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in tally " & // trim(to_str(t % id)) // " in any material.") end if - deallocate(pair_list) ! Set bin to index in nuclides array - t % nuclide_bins(j) = nuclide_dict % get_key(word) + t % nuclide_bins(j) = nuclide_dict % get(word) end do ! Set number of nuclide bins @@ -3550,7 +3550,7 @@ contains score_name = trim(sarray(j)) ! Append the score to the list of possible trigger scores - if (trigger_on) call trigger_scores % add_key(trim(score_name), j) + if (trigger_on) call trigger_scores % add(trim(score_name), j) do imomstr = 1, size(MOMENT_STRS) if (starts_with(score_name,trim(MOMENT_STRS(imomstr)))) then @@ -3896,7 +3896,7 @@ contains filt % n_bins = product(m % dimension + 1) ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select t % filter(t % find_filter(FILTER_MESH)) = i_filt @@ -3923,7 +3923,7 @@ contains filt % current = .true. ! Add filter to dictionary - call filter_dict % add_key(filt % id, i_filt) + call filter_dict % add(filt % id, i_filt) end select t % find_filter(FILTER_SURFACE) = n_filter t % filter(n_filter) = i_filt @@ -4144,15 +4144,7 @@ contains score_name = trim(to_lower(sarray(j))) if (score_name == "all") then - scores => trigger_scores % keys() - - do while (associated(scores)) - next => scores % next - deallocate(scores) - scores => next - t % n_triggers = t % n_triggers + 1 - end do - + t % n_triggers = trigger_scores % size() else t % n_triggers = t % n_triggers + 1 end if @@ -4211,16 +4203,19 @@ contains ! Expand "all" to include TriggerObjects for each score in tally if (score_name == "all") then - scores => trigger_scores % keys() ! Loop over all tally scores - do while (associated(scores)) - score_name = trim(scores % key) + i_elem = 0 + do + ! Move to next score + call trigger_scores % next_entry(elem, i_elem) + if (i_elem == 0) exit + + score_name = trim(elem % key) ! Store the score name and index in the trigger - t % triggers(trig_ind) % score_name = trim(score_name) - t % triggers(trig_ind) % score_index = & - trigger_scores % get_key(trim(score_name)) + t % triggers(trig_ind) % score_name = score_name + t % triggers(trig_ind) % score_index = elem % value ! Set the trigger convergence threshold type select case (temp_str) @@ -4238,11 +4233,6 @@ contains ! Store the trigger convergence threshold t % triggers(trig_ind) % threshold = threshold - ! Move to next score - next => scores % next - deallocate(scores) - scores => next - ! Increment the overall trigger index trig_ind = trig_ind + 1 end do @@ -4253,7 +4243,7 @@ contains ! Store the score name and index t % triggers(trig_ind) % score_name = trim(score_name) t % triggers(trig_ind) % score_index = & - trigger_scores % get_key(trim(score_name)) + trigger_scores % get(trim(score_name)) ! Check if an invalid score was set for the trigger if (t % triggers(trig_ind) % score_index == 0) then @@ -4330,7 +4320,7 @@ contains end if ! Add tally to dictionary - call tally_dict % add_key(t % id, i) + call tally_dict % add(t % id, i) end do READ_TALLIES @@ -4402,7 +4392,7 @@ contains end if ! Check to make sure 'id' hasn't been used - if (plot_dict % has_key(pl % id)) then + if (plot_dict % has(pl % id)) then call fatal_error("Two or more plots use the same unique ID: " & // to_str(pl % id)) end if @@ -4587,8 +4577,8 @@ contains ! Add RGB if (pl % color_by == PLOT_COLOR_CELLS) then - if (cell_dict % has_key(col_id)) then - col_id = cell_dict % get_key(col_id) + if (cell_dict % has(col_id)) then + col_id = cell_dict % get(col_id) call get_node_array(node_col, "rgb", pl % colors(col_id) % rgb) else call fatal_error("Could not find cell " // trim(to_str(col_id)) & @@ -4597,8 +4587,8 @@ contains else if (pl % color_by == PLOT_COLOR_MATS) then - if (material_dict % has_key(col_id)) then - col_id = material_dict % get_key(col_id) + if (material_dict % has(col_id)) then + col_id = material_dict % get(col_id) call get_node_array(node_col, "rgb", pl % colors(col_id) % rgb) else call fatal_error("Could not find material " & @@ -4712,8 +4702,8 @@ contains end if ! Check if the specified tally mesh exists - if (mesh_dict % has_key(meshid)) then - pl % meshlines_mesh => meshes(mesh_dict % get_key(meshid)) + if (mesh_dict % has(meshid)) then + pl % meshlines_mesh => meshes(mesh_dict % get(meshid)) if (meshes(meshid) % type /= LATTICE_RECT) then call fatal_error("Non-rectangular mesh specified in & &meshlines for plot " // trim(to_str(pl % id))) @@ -4772,8 +4762,8 @@ contains if (pl % color_by == PLOT_COLOR_CELLS) then - if (cell_dict % has_key(col_id)) then - iarray(j) = cell_dict % get_key(col_id) + if (cell_dict % has(col_id)) then + iarray(j) = cell_dict % get(col_id) else call fatal_error("Could not find cell " & // trim(to_str(col_id)) // " specified in the mask in & @@ -4782,8 +4772,8 @@ contains else if (pl % color_by == PLOT_COLOR_MATS) then - if (material_dict % has_key(col_id)) then - iarray(j) = material_dict % get_key(col_id) + if (material_dict % has(col_id)) then + iarray(j) = material_dict % get(col_id) else call fatal_error("Could not find material " & // trim(to_str(col_id)) // " specified in the mask in & @@ -4811,7 +4801,7 @@ contains end if ! Add plot to dictionary - call plot_dict % add_key(pl % id, i) + call plot_dict % add(pl % id, i) end do READ_PLOTS @@ -5192,8 +5182,8 @@ contains name = materials(i) % names(j) if (.not. already_read % contains(name)) then - i_library = library_dict % get_key(to_lower(name)) - i_nuclide = nuclide_dict % get_key(to_lower(name)) + i_library = library_dict % get(to_lower(name)) + i_nuclide = nuclide_dict % get(to_lower(name)) call write_message('Reading ' // trim(name) // ' from ' // & trim(libraries(i_library) % path), 6) @@ -5252,8 +5242,8 @@ contains name = materials(i) % sab_names(j) if (.not. already_read % contains(name)) then - i_library = library_dict % get_key(to_lower(name)) - i_sab = sab_dict % get_key(to_lower(name)) + i_library = library_dict % get(to_lower(name)) + i_sab = sab_dict % get(to_lower(name)) call write_message('Reading ' // trim(name) // ' from ' // & trim(libraries(i_library) % path), 6) @@ -5335,7 +5325,7 @@ contains end if ! Use material default or global default temperature - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = material_dict % get(cells(i) % material(j)) if (material_temps(i_material) /= ERROR_REAL) then cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * & material_temps(i_material)) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index ad20aca83..952cd12e2 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -85,7 +85,7 @@ contains name = mat % names(j) if (.not. already_read % contains(name)) then - i_xsdata = xsdata_dict % get_key(to_lower(name)) + i_xsdata = xsdata_dict % get(to_lower(name)) i_nuclide = mat % nuclide(j) call write_message("Loading " // trim(name) // " data...", 6) @@ -234,7 +234,7 @@ contains kT = cells(i) % sqrtkT(1)**2 end if - i_material = material_dict % get_key(cells(i) % material(j)) + i_material = material_dict % get(cells(i) % material(j)) ! Add temperature if it hasn't already been added if (find(kTs(i_material), kT) == -1) then diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index bf1ea97b2..570e8f4d4 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -508,7 +508,7 @@ module nuclide_header do i = 1, size(this % reactions) call MTs % push_back(this % reactions(i) % MT) - call this % reaction_index % add_key(this % reactions(i) % MT, i) + call this % reaction_index % add(this % reactions(i) % MT, i) associate (rx => this % reactions(i)) ! Skip total inelastic level scattering, gas production cross sections diff --git a/src/sab_header.F90 b/src/sab_header.F90 index e0b79f248..4f7883a22 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -4,7 +4,6 @@ module sab_header use algorithm, only: find, sort use constants - use dict_header, only: DictIntInt use distribution_univariate, only: Tabular use error, only: warning, fatal_error use hdf5, only: HID_T, HSIZE_T, SIZE_T diff --git a/src/tally.F90 b/src/tally.F90 index ee2fc992f..3aa53cf7a 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -5,6 +5,7 @@ module tally use algorithm, only: binary_search use constants use cross_section, only: multipole_deriv_eval + use dict_header, only: EMPTY use error, only: fatal_error use geometry_header use global @@ -245,8 +246,7 @@ contains ! multiplicities of one. score = p % last_wgt * flux else - m = nuclides(p % event_nuclide) % reaction_index % & - get_key(p % event_MT) + m = nuclides(p % event_nuclide) % reaction_index % get(p % event_MT) ! Get yield and apply to score associate (rxn => nuclides(p % event_nuclide) % reactions(m)) @@ -272,8 +272,7 @@ contains ! multiplicities of one. score = p % last_wgt * flux else - m = nuclides(p%event_nuclide)%reaction_index% & - get_key(p % event_MT) + m = nuclides(p % event_nuclide) % reaction_index % get(p % event_MT) ! Get yield and apply to score associate (rxn => nuclides(p % event_nuclide) % reactions(m)) @@ -299,8 +298,7 @@ contains ! multiplicities of one. score = p % last_wgt * flux else - m = nuclides(p%event_nuclide)%reaction_index% & - get_key(p % event_MT) + m = nuclides(p % event_nuclide) % reaction_index % get(p % event_MT) ! Get yield and apply to score associate (rxn => nuclides(p%event_nuclide)%reactions(m)) @@ -1149,9 +1147,8 @@ contains score = ZERO if (i_nuclide > 0) then - if (nuclides(i_nuclide)%reaction_index%has_key(score_bin)) then - m = nuclides(i_nuclide)%reaction_index%get_key(score_bin) - + m = nuclides(i_nuclide) % reaction_index % get(score_bin) + if (m /= EMPTY) then ! Retrieve temperature and energy grid index and interpolation ! factor i_temp = micro_xs(i_nuclide) % index_temp @@ -1189,9 +1186,8 @@ contains ! Get index in nuclides array i_nuc = materials(p % material) % nuclide(l) - if (nuclides(i_nuc)%reaction_index%has_key(score_bin)) then - m = nuclides(i_nuc)%reaction_index%get_key(score_bin) - + m = nuclides(i_nuc) % reaction_index % get(score_bin) + if (m /= EMPTY) then ! Retrieve temperature and energy grid index and ! interpolation factor i_temp = micro_xs(i_nuc) % index_temp diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index eb83b319c..0b3f1927b 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -2,7 +2,7 @@ module tally_filter use algorithm, only: binary_search use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION, ERROR_REAL - use dict_header, only: DictIntInt + use dict_header, only: DictIntInt, EMPTY use geometry_header, only: root_universe, RectLattice, HexLattice use global use hdf5_interface @@ -462,12 +462,13 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Iterate over coordinate levels to see which universes match do i = 1, p % n_coord - if (this % map % has_key(p % coord(i) % universe)) then - call match % bins % push_back(this % map % get_key(p % coord(i) & - % universe)) + val = this % map % get(p % coord(i) % universe) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if end do @@ -495,12 +496,14 @@ contains class(UniverseFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % universes(i) - if (universe_dict % has_key(id)) then - this % universes(i) = universe_dict % get_key(id) + val = universe_dict % get(id) + if (val /= EMPTY) then + this % universes(i) = val else call fatal_error("Could not find universe " // trim(to_str(id)) & &// " specified on a tally filter.") @@ -509,7 +512,7 @@ contains ! Generate mapping from universe indices to filter bins. do i = 1, this % n_bins - call this % map % add_key(this % universes(i), i) + call this % map % add(this % universes(i), i) end do end subroutine initialize_universe @@ -528,12 +531,15 @@ contains class(MaterialFilter), intent(in) :: this type(Particle), intent(in) :: p integer, intent(in) :: estimator - type(TallyFilterMatch), intent(inout) :: match + type(TallyFilterMatch), intent(inout) :: match - if (this % map % has_key(p % material)) then - call match % bins % push_back(this % map % get_key(p % material)) - call match % weights % push_back(ONE) - end if + integer :: val + + val = this % map % get(p % material) + if (val /= EMPTY) then + call match % bins % push_back(val) + call match % weights % push_back(ONE) + end if end subroutine get_all_bins_material @@ -558,12 +564,14 @@ contains class(MaterialFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % materials(i) - if (material_dict % has_key(id)) then - this % materials(i) = material_dict % get_key(id) + val = material_dict % get(id) + if (val /= EMPTY) then + this % materials(i) = val else call fatal_error("Could not find material " // trim(to_str(id)) & &// " specified on a tally filter.") @@ -572,7 +580,7 @@ contains ! Generate mapping from material indices to filter bins. do i = 1, this % n_bins - call this % map % add_key(this % materials(i), i) + call this % map % add(this % materials(i), i) end do end subroutine initialize_material @@ -594,11 +602,13 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Iterate over coordinate levels to see with cells match do i = 1, p % n_coord - if (this % map % has_key(p % coord(i) % cell)) then - call match % bins % push_back(this % map % get_key(p % coord(i) % cell)) + val = this % map % get(p % coord(i) % cell) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if end do @@ -626,12 +636,14 @@ contains class(CellFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cells(i) = val else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") @@ -640,7 +652,7 @@ contains ! Generate mapping from cell indices to filter bins. do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) + call this % map % add(this % cells(i), i) end do end subroutine initialize_cell @@ -662,12 +674,14 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Iterate over coordinate levels to see with cells match do i = 1, p % last_n_coord - if (this % map % has_key(p % last_cell(i))) then - call match % bins % push_back(this % map % get_key(p % last_cell(i))) + val = this % map % get(p % last_cell(i)) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if end do @@ -750,11 +764,13 @@ contains class(DistribcellFilter), intent(inout) :: this integer :: id + integer :: val ! Convert id to index. id = this % cell - if (cell_dict % has_key(id)) then - this % cell = cell_dict % get_key(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cell = val else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") @@ -785,10 +801,13 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - if (this % map % has_key(p % cell_born)) then - call match % bins % push_back(this % map % get_key(p % cell_born)) - call match % weights % push_back(ONE) - end if + integer :: val + + val = this % map % get(p % cell_born) + if (val /= EMPTY) then + call match % bins % push_back(val) + call match % weights % push_back(ONE) + end if end subroutine get_all_bins_cellborn @@ -812,12 +831,14 @@ contains class(CellbornFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) - if (cell_dict % has_key(id)) then - this % cells(i) = cell_dict % get_key(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cells(i) = val else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") @@ -826,7 +847,7 @@ contains ! Generate mapping from cell indices to filter bins. do i = 1, this % n_bins - call this % map % add_key(this % cells(i), i) + call this % map % add(this % cells(i), i) end do end subroutine initialize_cellborn @@ -876,12 +897,14 @@ contains class(SurfaceFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % surfaces(i) - if (surface_dict % has_key(id)) then - this % surfaces(i) = surface_dict % get_key(id) + val = surface_dict % get(id) + if (val /= EMPTY) then + this % surfaces(i) = val else call fatal_error("Could not find surface " // trim(to_str(id)) & &// " specified on tally filter.") @@ -1288,7 +1311,7 @@ contains n = size(univ % cells) ! Write to the geometry stack - i_univ = universe_dict % get_key(univ % id) + i_univ = universe_dict % get(univ % id) if (i_univ == root_universe) then path = trim(path) // "u" // to_str(univ%id) else From 4af186cd1327601c215caf7421b068107d4efaef Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 1 Sep 2017 14:59:15 -0500 Subject: [PATCH 170/229] Move tally derivatives into their own header file and add from_xml() --- CMakeLists.txt | 1 + src/global.F90 | 1 + src/input_xml.F90 | 74 +------------------- src/tallies/tally_derivative_header.F90 | 91 +++++++++++++++++++++++++ src/tallies/tally_header.F90 | 15 ---- 5 files changed, 96 insertions(+), 86 deletions(-) create mode 100644 src/tallies/tally_derivative_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fbaf3c2e..90fd3ced4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ set(LIBOPENMC_FORTRAN_SRC src/volume_header.F90 src/xml_interface.F90 src/tallies/tally.F90 + src/tallies/tally_derivative_header.F90 src/tallies/tally_filter.F90 src/tallies/tally_filter_header.F90 src/tallies/tally_filter_azimuthal.F90 diff --git a/src/global.F90 b/src/global.F90 index 28b035e4b..09652f294 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -16,6 +16,7 @@ module global use surface_header use tally_filter_header use tally_header + use tally_derivative_header use timer_header use trigger_header use volume_header diff --git a/src/input_xml.F90 b/src/input_xml.F90 index b818e5bc0..71c699c89 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2493,7 +2493,6 @@ contains type(XMLNode) :: node_tal type(XMLNode) :: node_filt type(XMLNode) :: node_trigger - type(XMLNode) :: node_deriv type(XMLNode), allocatable :: node_mesh_list(:) type(XMLNode), allocatable :: node_tal_list(:) type(XMLNode), allocatable :: node_filt_list(:) @@ -2582,75 +2581,10 @@ contains ! Read derivative attributes. do i = 1, size(node_deriv_list) - associate(deriv => tally_derivs(i)) - ! Get pointer to derivative node. - node_deriv = node_deriv_list(i) + call tally_derivs(i) % from_xml(node_deriv_list(i)) - ! Copy the derivative id. - if (check_for_node(node_deriv, "id")) then - call get_node_value(node_deriv, "id", deriv % id) - else - call fatal_error("Must specify an ID for elements in the& - & tally XML file") - end if - - ! Make sure the id is > 0. - if (deriv % id <= 0) then - call fatal_error(" IDs must be an integer greater than & - &zero") - end if - - ! Make sure this id has not already been used. - do j = 1, i-1 - if (tally_derivs(j) % id == deriv % id) then - call fatal_error("Two or more 's use the same unique & - &ID: " // trim(to_str(deriv % id))) - end if - end do - - ! Read the independent variable name. - temp_str = "" - call get_node_value(node_deriv, "variable", temp_str) - temp_str = to_lower(temp_str) - - select case(temp_str) - - case("density") - deriv % variable = DIFF_DENSITY - call get_node_value(node_deriv, "material", deriv % diff_material) - - case("nuclide_density") - deriv % variable = DIFF_NUCLIDE_DENSITY - call get_node_value(node_deriv, "material", deriv % diff_material) - - call get_node_value(node_deriv, "nuclide", word) - word = trim(to_lower(word)) - pair_list => nuclide_dict % keys() - do while (associated(pair_list)) - if (starts_with(pair_list % key, word)) then - word = pair_list % key(1:150) - exit - end if - - ! Advance to next - pair_list => pair_list % next - end do - - ! Check if no nuclide was found - if (.not. associated(pair_list)) then - call fatal_error("Could not find the nuclide " & - // trim(word) // " specified in derivative " & - // trim(to_str(deriv % id)) // " in any material.") - end if - deallocate(pair_list) - - deriv % diff_nuclide = nuclide_dict % get_key(word) - - case("temperature") - deriv % variable = DIFF_TEMPERATURE - call get_node_value(node_deriv, "material", deriv % diff_material) - end select - end associate + ! Update tally derivative dictionary + call tally_deriv_dict % add_key(tally_derivs(i) % id, i) end do ! ========================================================================== @@ -2693,13 +2627,11 @@ contains if (.not. check_for_node(node_filt, "bins")) then call fatal_error("Bins not set in filter " // trim(to_str(filter_id))) end if - n_words = node_word_count(node_filt, "bins") case ("mesh", "universe", "material", "cell", "distribcell", & "cellborn", "cellfrom", "surface", "delayedgroup") if (.not. check_for_node(node_filt, "bins")) then call fatal_error("Bins not set in filter " // trim(to_str(filter_id))) end if - n_words = node_word_count(node_filt, "bins") end select ! Allocate according to the filter type diff --git a/src/tallies/tally_derivative_header.F90 b/src/tallies/tally_derivative_header.F90 new file mode 100644 index 000000000..004db98ba --- /dev/null +++ b/src/tallies/tally_derivative_header.F90 @@ -0,0 +1,91 @@ +module tally_derivative_header + + use constants + use dict_header, only: DictIntInt + use error, only: fatal_error + use nuclide_header, only: nuclide_dict + use string, only: to_str, to_lower + use xml_interface + + implicit none + private + +!=============================================================================== +! TALLYDERIVATIVE describes a first-order derivative that can be applied to +! tallies. +!=============================================================================== + + type, public :: TallyDerivative + integer :: id + integer :: variable + integer :: diff_material + integer :: diff_nuclide + real(8) :: flux_deriv + contains + procedure :: from_xml + end type TallyDerivative + + type(TallyDerivative), public, allocatable :: tally_derivs(:) +!$omp threadprivate(tally_derivs) + + ! Dictionary that maps user IDs to indices in 'tally_derivs' + type(DictIntInt), public :: tally_deriv_dict + +contains + + subroutine from_xml(this, node) + class(TallyDerivative), intent(inout) :: this + type(XMLNode), intent(in) :: node + + character(MAX_WORD_LEN) :: temp_str + character(MAX_WORD_LEN) :: word + + ! Copy the derivative id. + if (check_for_node(node, "id")) then + call get_node_value(node, "id", this % id) + else + call fatal_error("Must specify an ID for elements in the& + & tally XML file") + end if + + ! Make sure the id is > 0. + if (this % id <= 0) then + call fatal_error(" IDs must be an integer greater than & + &zero") + end if + + ! Make sure this id has not already been used. + if (tally_deriv_dict % has_key(this % id)) then + call fatal_error("Two or more 's use the same unique & + &ID: " // trim(to_str(this % id))) + end if + + ! Read the independent variable name. + call get_node_value(node, "variable", temp_str) + temp_str = to_lower(temp_str) + + select case(temp_str) + case("density") + this % variable = DIFF_DENSITY + + case("nuclide_density") + this % variable = DIFF_NUCLIDE_DENSITY + + call get_node_value(node, "nuclide", word) + word = trim(to_lower(word)) + if (.not. nuclide_dict % has_key(word)) then + call fatal_error("Could not find the nuclide " & + // trim(word) // " specified in derivative " & + // trim(to_str(this % id)) // " in any material.") + end if + this % diff_nuclide = nuclide_dict % get_key(word) + + case("temperature") + this % variable = DIFF_TEMPERATURE + end select + + call get_node_value(node, "material", this % diff_material) + + end subroutine from_xml + +end module tally_derivative_header diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 9c6e69f84..f053e6cac 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -30,19 +30,6 @@ module tally_header public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores -!=============================================================================== -! TALLYDERIVATIVE describes a first-order derivative that can be applied to -! tallies. -!=============================================================================== - - type, public :: TallyDerivative - integer :: id - integer :: variable - integer :: diff_material - integer :: diff_nuclide - real(8) :: flux_deriv - end type TallyDerivative - !=============================================================================== ! TALLYOBJECT describes a user-specified tally. The region of phase space to ! tally in is given by the TallyFilters and the results are stored in a @@ -124,8 +111,6 @@ module tally_header integer(C_INT32_T), public, bind(C) :: n_tallies = 0 ! # of tallies type(TallyContainer), public, allocatable, target :: tallies(:) - type(TallyDerivative), public, allocatable :: tally_derivs(:) -!$omp threadprivate(tally_derivs) ! Dictionary that maps user IDs to indices in 'tallies' type(DictIntInt), public :: tally_dict From 67cb58d39fc65c76f81dbdce9e574e0c30aeb2d3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 1 Sep 2017 15:07:20 -0500 Subject: [PATCH 171/229] Get rid of pair_list in read_tallies_xml --- src/input_xml.F90 | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 71c699c89..c7e80fe98 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2485,7 +2485,6 @@ contains character(MAX_WORD_LEN) :: temp_str character(MAX_WORD_LEN), allocatable :: sarray(:) type(DictCharInt) :: trigger_scores - type(ElemKeyValueCI), pointer :: pair_list type(TallyFilterContainer), pointer :: f type(RegularMesh), pointer :: m type(XMLDocument) :: doc @@ -2772,24 +2771,11 @@ contains word = to_lower(sarray(j)) ! Search through nuclides - pair_list => nuclide_dict % keys() - do while (associated(pair_list)) - if (trim(pair_list % key) == trim(word)) then - word = pair_list % key(1:150) - exit - end if - - ! Advance to next - pair_list => pair_list % next - end do - - ! Check if no nuclide was found - if (.not. associated(pair_list)) then + if (.not. nuclide_dict % has_key(word)) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in tally " & // trim(to_str(t % id)) // " in any material.") end if - deallocate(pair_list) ! Set bin to index in nuclides array t % nuclide_bins(j) = nuclide_dict % get_key(word) From 9765fe73bb090a0159abdf83cdd77defaa13fccd Mon Sep 17 00:00:00 2001 From: amandalund Date: Tue, 5 Sep 2017 12:08:56 -0500 Subject: [PATCH 172/229] Implemented double hashing collision resolution --- src/dict_header.F90 | 467 ++++++++++++++++++++++++-------------------- 1 file changed, 253 insertions(+), 214 deletions(-) diff --git a/src/dict_header.F90 b/src/dict_header.F90 index 4a59cfb51..7cf75fae6 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -5,56 +5,57 @@ module dict_header ! ! This module provides an implementation of a dictionary that has (key,value) ! pairs. This data structure is used to provide lookup features, e.g. cells and -! surfaces by name. As with lists, it was considered writing a single -! dictionary used unlimited polymorphism, but again compiler support is spotty -! and doesn't always prevent duplication of code. +! surfaces by name. +! +! The implementation is based on Algorithm D from Knuth Vol. 3 Sec. 6.4 (open +! addressing with double hashing). Hash tables sizes M are chosen such that M +! and M - 2 are twin primes, which helps reduce clustering. An upper limit is +! placed on the load factor to prevent exponential performance degradation as +! the number of entries approaches the number of buckets. !=============================================================================== implicit none integer, parameter :: EMPTY = -huge(0) integer, parameter, private :: DELETED = -huge(0) + 1 - integer, parameter, private :: MIN_SIZE = 8 integer, parameter, private :: KEY_CHAR_LENGTH = 255 - real(8), parameter, private :: GROWTH_FACTOR = 2 + integer, parameter, private :: TABLE_SIZES(30) = & + [5, 7, 13, 19, 43, 73, 151, 283, 571, 1153, 2269, 4519, 9013, 18043, & + 36109, 72091, 144409, 288361, 576883, 1153459, 2307163, 4613893, & + 9227641, 18455029, 36911011, 73819861, 147639589, 295279081, & + 590559793, 1181116273] real(8), parameter, private :: MAX_LOAD_FACTOR = 0.65 !=============================================================================== -! DICTENTRY* contains (key,value) pairs +! DICTENTRY* contains (key,value) pairs. !=============================================================================== - type DictEntryCI - character(len=KEY_CHAR_LENGTH) :: key - integer :: value = EMPTY - integer :: hash = EMPTY - end type DictEntryCI - type DictEntryII integer :: key = EMPTY integer :: value = EMPTY end type DictEntryII + type DictEntryCI + character(len=KEY_CHAR_LENGTH) :: key + integer :: value = EMPTY + end type DictEntryCI + !=============================================================================== -! DICT* is a dictionary of (key,value) pairs with convenience methods as -! type-bound procedures. DictCharInt has character(*) keys and integer values, -! and DictIntInt has integer keys and values. +! BUCKET* contains an allocatable DictEntry object for storing a (key,value) +! pair and the hash value for fast comparisons. Integer (key,value) pairs are +! stored directly in the hash table since their memory requirement is small. !=============================================================================== - type, public :: DictCharInt - integer, private :: entries = 0 - integer, private :: capacity = 0 - type(DictEntryCI), allocatable, private :: table(:) - contains - procedure :: add => add_ci - procedure :: get => get_ci - procedure :: has => has_ci - procedure :: remove => remove_ci - procedure :: next_entry => next_entry_ci - procedure :: clear => clear_ci - procedure :: size => size_ci - procedure, private :: get_entry => get_entry_ci - procedure, private :: resize => resize_ci - end type DictCharInt + type, private :: BucketCI + type(DictEntryCI), allocatable :: entry + integer :: hash = EMPTY + end type BucketCI + +!=============================================================================== +! DICT* is a dictionary of (key,value) pairs with convenience methods as +! type-bound procedures. DictIntInt has integer keys and values, and +! DictCharInt has character(*) keys and integer values. +!=============================================================================== type, public :: DictIntInt integer, private :: entries = 0 @@ -72,6 +73,22 @@ module dict_header procedure, private :: resize => resize_ii end type DictIntInt + type, public :: DictCharInt + integer, private :: entries = 0 + integer, private :: capacity = 0 + type(BucketCI), allocatable, private :: table(:) + contains + procedure :: add => add_ci + procedure :: get => get_ci + procedure :: has => has_ci + procedure :: remove => remove_ci + procedure :: next_entry => next_entry_ci + procedure :: clear => clear_ci + procedure :: size => size_ci + procedure, private :: get_entry => get_entry_ci + procedure, private :: resize => resize_ci + end type DictCharInt + contains !=============================================================================== @@ -79,34 +96,6 @@ contains ! key. This method is private. !=============================================================================== - function get_entry_ci(this, key) result(i) - - class(DictCharInt) :: this - character(*), intent(in) :: key - integer :: i - - integer :: hash - - if (.not. allocated(this % table)) then - allocate(this % table(MIN_SIZE)) - this % capacity = MIN_SIZE - end if - - hash = hash_ci(key) - i = 1 + mod(hash, this % capacity) - - do - if (this % table(i) % hash == hash .and. & - this % table(i) % key == key) exit - - if (this % table(i) % hash == EMPTY) exit - - ! TODO: use more advanced probing or double hashing to update i - i = 1 + mod(i, this % capacity) - end do - - end function get_entry_ci - function get_entry_ii(this, key) result(i) class(DictIntInt) :: this @@ -114,62 +103,73 @@ contains integer :: i integer :: hash + integer :: c if (.not. allocated(this % table)) then - allocate(this % table(MIN_SIZE)) - this % capacity = MIN_SIZE + allocate(this % table(TABLE_SIZES(1))) + this % capacity = TABLE_SIZES(1) end if hash = hash_ii(key) i = 1 + mod(hash, this % capacity) + c = 2 + mod(hash, this % capacity - 2) do if (this % table(i) % key == key .or. & this % table(i) % key == EMPTY) exit - ! TODO: use more advanced probing or double hashing to update i - i = 1 + mod(i, this % capacity) + i = 1 + mod(i + c - 1, this % capacity) end do end function get_entry_ii + function get_entry_ci(this, key) result(i) + + class(DictCharInt) :: this + character(*), intent(in) :: key + integer :: i + + integer :: hash + integer :: c + + if (.not. allocated(this % table)) then + allocate(this % table(TABLE_SIZES(1))) + this % capacity = TABLE_SIZES(1) + end if + + hash = hash_ci(key) + i = 1 + mod(hash, this % capacity) + c = 2 + mod(hash, this % capacity - 2) + + do + if (this % table(i) % hash == hash .and. & + this % table(i) % entry % key == key) exit + + if (this % table(i) % hash == EMPTY) exit + + i = 1 + mod(i + c - 1, this % capacity) + end do + + end function get_entry_ci + !=============================================================================== ! RESIZE allocates a new hash table to accomodate the number of entries and ! reinserts all of the entries into the new table. This method is private. !=============================================================================== - subroutine resize_ci(this, new_size) - - class(DictCharInt) :: this - integer, intent(in) :: new_size - - type(DictEntryCI), allocatable :: table(:) - integer :: i - - call move_alloc(this % table, table) - allocate(this % table(new_size)) - this % capacity = new_size - this % entries = 0 - - ! Rehash each entry into the new table - do i = 1, size(table) - if (table(i) % hash /= EMPTY .and. table(i) % hash /= DELETED) then - call this % add(table(i) % key, table(i) % value) - end if - end do - - deallocate(table) - - end subroutine resize_ci - - subroutine resize_ii(this, new_size) + subroutine resize_ii(this) class(DictIntInt) :: this - integer, intent(in) :: new_size type(DictEntryII), allocatable :: table(:) + integer :: new_size integer :: i + do i = 1, size(TABLE_SIZES) + if (TABLE_SIZES(i) > this % capacity) exit + end do + new_size = TABLE_SIZES(i) + call move_alloc(this % table, table) allocate(this % table(new_size)) this % capacity = new_size @@ -186,50 +186,40 @@ contains end subroutine resize_ii + subroutine resize_ci(this) + + class(DictCharInt) :: this + + type(BucketCI), allocatable :: table(:) + integer :: new_size + integer :: i + + do i = 1, size(TABLE_SIZES) + if (TABLE_SIZES(i) > this % capacity) exit + end do + new_size = TABLE_SIZES(i) + + call move_alloc(this % table, table) + allocate(this % table(new_size)) + this % capacity = new_size + this % entries = 0 + + ! Rehash each entry into the new table + do i = 1, size(table) + if (table(i) % hash /= EMPTY .and. table(i) % hash /= DELETED) then + call this % add(table(i) % entry % key, table(i) % entry % value) + end if + end do + + deallocate(table) + + end subroutine resize_ci + !=============================================================================== ! ADD adds a (key,value) entry to a dictionary. If the key is already in the ! dictionary, the value is replaced by the new specified value. !=============================================================================== - subroutine add_ci(this, key, value) - - class(DictCharInt) :: this - character(*), intent(in) :: key - integer, intent(in) :: value - - integer :: hash - integer :: i - - if (.not. allocated(this % table)) then - allocate(this % table(MIN_SIZE)) - this % capacity = MIN_SIZE - else if (real(this % entries, 8) / this % capacity > MAX_LOAD_FACTOR) then - call this % resize(int(this % capacity * GROWTH_FACTOR)) - end if - - hash = hash_ci(key) - i = 1 + mod(hash, this % capacity) - - do - if (this % table(i) % hash == EMPTY .or. & - this % table(i) % hash == DELETED) then - this % table(i) % hash = hash - this % table(i) % key = key - this % table(i) % value = value - this % entries = this % entries + 1 - exit - else if (this % table(i) % hash == hash .and. & - this % table(i) % key == key) then - this % table(i) % value = value - exit - end if - - ! TODO: use more advanced probing or double hashing to update i - i = 1 + mod(i, this % capacity) - end do - - end subroutine add_ci - subroutine add_ii(this, key, value) class(DictIntInt) :: this @@ -238,16 +228,18 @@ contains integer :: hash integer :: i + integer :: c if (.not. allocated(this % table)) then - allocate(this % table(MIN_SIZE)) - this % capacity = MIN_SIZE - else if (real(this % entries, 8) / this % capacity > MAX_LOAD_FACTOR) then - call this % resize(int(this % capacity * GROWTH_FACTOR)) + allocate(this % table(TABLE_SIZES(1))) + this % capacity = TABLE_SIZES(1) + else if (real(this % entries + 1, 8) / this % capacity > MAX_LOAD_FACTOR) then + call this % resize() end if hash = hash_ii(key) i = 1 + mod(hash, this % capacity) + c = 2 + mod(hash, this % capacity - 2) do if (this % table(i) % key == EMPTY .or. & @@ -261,30 +253,59 @@ contains exit end if - ! TODO: use more advanced probing or double hashing to update i - i = 1 + mod(i, this % capacity) + i = 1 + mod(i + c - 1, this % capacity) end do end subroutine add_ii + subroutine add_ci(this, key, value) + + class(DictCharInt) :: this + character(*), intent(in) :: key + integer, intent(in) :: value + + integer :: hash + integer :: i + integer :: c + + if (.not. allocated(this % table)) then + allocate(this % table(TABLE_SIZES(1))) + this % capacity = TABLE_SIZES(1) + else if (real(this % entries + 1, 8) / this % capacity > MAX_LOAD_FACTOR) then + call this % resize() + end if + + hash = hash_ci(key) + i = 1 + mod(hash, this % capacity) + c = 2 + mod(hash, this % capacity - 2) + + do + if (this % table(i) % hash == EMPTY .or. & + this % table(i) % hash == DELETED) then + if (.not. allocated(this % table(i) % entry)) then + allocate(this % table(i) % entry) + end if + this % table(i) % hash = hash + this % table(i) % entry % key = key + this % table(i) % entry % value = value + this % entries = this % entries + 1 + exit + else if (this % table(i) % hash == hash .and. & + this % table(i) % entry % key == key) then + this % table(i) % entry % value = value + exit + end if + + i = 1 + mod(i + c - 1, this % capacity) + end do + + end subroutine add_ci + !=============================================================================== ! GET returns the value matching a given key. If the dictionary does not contain ! the key, the value EMPTY is returned. !=============================================================================== - function get_ci(this, key) result(value) - - class(DictCharInt) :: this - character(*), intent(in) :: key - integer :: value - - integer :: i - - i = this % get_entry(key) - value = this % table(i) % value - - end function get_ci - function get_ii(this, key) result(value) class(DictIntInt) :: this @@ -298,22 +319,22 @@ contains end function get_ii -!=============================================================================== -! HAS determines whether a dictionary has a (key,value) pair with a given key. -!=============================================================================== - - function has_ci(this, key) result(has) + function get_ci(this, key) result(value) class(DictCharInt) :: this character(*), intent(in) :: key - logical :: has + integer :: value integer :: i i = this % get_entry(key) - has = (this % table(i) % hash /= EMPTY) + value = this % table(i) % entry % value - end function has_ci + end function get_ci + +!=============================================================================== +! HAS determines whether a dictionary has a (key,value) pair with a given key. +!=============================================================================== function has_ii(this, key) result(has) @@ -328,26 +349,22 @@ contains end function has_ii -!=============================================================================== -! REMOVE deletes a (key,value) entry from a dictionary. -!=============================================================================== - - subroutine remove_ci(this, key) + function has_ci(this, key) result(has) class(DictCharInt) :: this character(*), intent(in) :: key + logical :: has integer :: i i = this % get_entry(key) - if (this % table(i) % hash /= EMPTY) then - this % table(i) % hash = DELETED - this % table(i) % key = "" - this % table(i) % value = EMPTY - this % entries = this % entries - 1 - end if + has = (this % table(i) % hash /= EMPTY) - end subroutine remove_ci + end function has_ci + +!=============================================================================== +! REMOVE deletes a (key,value) entry from a dictionary. +!=============================================================================== subroutine remove_ii(this, key) @@ -365,6 +382,24 @@ contains end subroutine remove_ii + subroutine remove_ci(this, key) + + class(DictCharInt) :: this + character(*), intent(in) :: key + + integer :: i + + i = this % get_entry(key) + if (this % table(i) % hash /= EMPTY) then + this % table(i) % hash = DELETED + if (allocated(this % table(i) % entry)) then + deallocate(this % table(i) % entry) + end if + this % entries = this % entries - 1 + end if + + end subroutine remove_ci + !=============================================================================== ! NEXT_ENTRY finds the next (key,value) pair. The value of current_entry is ! updated with the (key,value) pair, and the value of i is updated with the @@ -372,28 +407,6 @@ contains ! in the dictionary. If there are no more entries, i will be set to 0. !=============================================================================== - subroutine next_entry_ci(this, current_entry, i) - - class(DictCharInt) :: this - type(DictEntryCI), intent(inout) :: current_entry - integer, intent(inout) :: i - - if (.not. allocated(this % table)) return - - do - i = i + 1 - if (i > size(this % table)) then - i = 0 - exit - else if (this % table(i) % hash /= EMPTY .and. & - this % table(i) % hash /= DELETED) then - current_entry = this % table(i) - exit - end if - end do - - end subroutine next_entry_ci - subroutine next_entry_ii(this, current_entry, i) class(DictIntInt) :: this @@ -416,39 +429,56 @@ contains end subroutine next_entry_ii + subroutine next_entry_ci(this, current_entry, i) + + class(DictCharInt) :: this + type(DictEntryCI), intent(inout) :: current_entry + integer, intent(inout) :: i + + if (.not. allocated(this % table)) return + + do + i = i + 1 + if (i > size(this % table)) then + i = 0 + exit + else if (this % table(i) % hash /= EMPTY .and. & + this % table(i) % hash /= DELETED) then + current_entry = this % table(i) % entry + exit + end if + end do + + end subroutine next_entry_ci + !=============================================================================== ! CLEAR deletes and deallocates the dictionary item !=============================================================================== - subroutine clear_ci(this) - - class(DictCharInt) :: this - - if (allocated(this % table)) deallocate(this % table) - - end subroutine clear_ci - subroutine clear_ii(this) class(DictIntInt) :: this if (allocated(this % table)) deallocate(this % table) + this % entries = 0 + this % capacity = 0 end subroutine clear_ii + subroutine clear_ci(this) + + class(DictCharInt) :: this + + if (allocated(this % table)) deallocate(this % table) + this % entries = 0 + this % capacity = 0 + + end subroutine clear_ci + !=============================================================================== ! SIZE returns the number of entries in the dictionary !=============================================================================== - pure function size_ci(this) result(size) - - class(DictCharInt), intent(in) :: this - integer :: size - - size = this % entries - - end function size_ci - pure function size_ii(this) result(size) class(DictIntInt), intent(in) :: this @@ -458,10 +488,28 @@ contains end function size_ii + pure function size_ci(this) result(size) + + class(DictCharInt), intent(in) :: this + integer :: size + + size = this % entries + + end function size_ci + !=============================================================================== ! HASH returns the hash value for a given key !=============================================================================== + function hash_ii(key) result(hash) + + integer, intent(in) :: key + integer :: hash + + hash = abs(key - 1) + + end function hash_ii + function hash_ci(key) result(hash) character(*), intent(in) :: key @@ -479,13 +527,4 @@ contains end function hash_ci - function hash_ii(key) result(hash) - - integer, intent(in) :: key - integer :: hash - - hash = abs(key - 1) - - end function hash_ii - end module dict_header From e0dd2264a3767f09e9f298e7994f371bcb559e6a Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 6 Sep 2017 23:37:43 -0500 Subject: [PATCH 173/229] Fix n_triggers --- src/input_xml.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 66b9dc5be..206e5ca65 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4144,7 +4144,7 @@ contains score_name = trim(to_lower(sarray(j))) if (score_name == "all") then - t % n_triggers = trigger_scores % size() + t % n_triggers = t % n_triggers + trigger_scores % size() else t % n_triggers = t % n_triggers + 1 end if From c768666aa3ba2758372d127b13dd3b5e043a1578 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 14 Sep 2017 12:52:37 -0500 Subject: [PATCH 174/229] Fix installing openmc.capi package --- CMakeLists.txt | 2 +- docs/source/capi/index.rst | 2 +- openmc/capi/__init__.py | 2 +- setup.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90fd3ced4..a0a54aac5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,7 +429,7 @@ target_link_libraries(${program} ${ldflags} libopenmc) add_custom_command(TARGET libopenmc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_CURRENT_SOURCE_DIR}/openmc/capi/_$ + ${CMAKE_CURRENT_SOURCE_DIR}/openmc/capi/$ COMMENT "Copying libopenmc to Python module directory") #=============================================================================== diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index 1e30eacf1..bc94fd6a0 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -4,7 +4,7 @@ C API ===== -.. c:function:: void openmc_calculate_voumes() +.. c:function:: void openmc_calculate_volumes() Run a stochastic volume calculation diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 4cea121f7..148070757 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -27,7 +27,7 @@ else: # Open shared library _filename = pkg_resources.resource_filename( - __name__, '_libopenmc.{}'.format(_suffix)) + __name__, 'libopenmc.{}'.format(_suffix)) _dll = CDLL(_filename) from .error import * diff --git a/setup.py b/setup.py index 67bc73403..7ca824ab0 100755 --- a/setup.py +++ b/setup.py @@ -30,13 +30,13 @@ with open('openmc/__init__.py', 'r') as f: kwargs = {'name': 'openmc', 'version': version, - 'packages': ['openmc', 'openmc.data', 'openmc.mgxs', 'openmc.model', - 'openmc.stats'], + 'packages': ['openmc', 'openmc.capi', 'openmc.data', 'openmc.mgxs', + 'openmc.model', 'openmc.stats'], 'scripts': glob.glob('scripts/openmc-*'), # Data files and librarries 'package_data': { - 'openmc': ['_libopenmc.{}'.format(suffix)], + 'openmc.capi': ['libopenmc.{}'.format(suffix)], 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] }, From c60e4084af16697e79c0006ea210c54e55e97dc1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 15 Sep 2017 14:00:12 -0500 Subject: [PATCH 175/229] Add global error message that C API can use (not used yet) --- src/error.F90 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/error.F90 b/src/error.F90 index 4e707c567..93c56ec61 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -37,8 +37,31 @@ module error integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 integer(C_INT), public, bind(C) :: W_ABOVE_MAX_BOUND = 2 + ! Error message + character(kind=C_CHAR), public, bind(C) :: openmc_err_msg(256) + + public :: set_errmsg + contains +!=============================================================================== +! SET_ERRMSG sets the 'openmc_err_msg' module variable that is exposed via the C +! API +!=============================================================================== + + subroutine set_errmsg(f_string) + character(*), intent(in) :: f_string + + integer :: i, n + + ! Copy Fortran string to null-terminated C char array + n = len_trim(f_string) + do i = 1, n + openmc_err_msg(i) = f_string(i:i) + end do + openmc_err_msg(n + 1) = C_NULL_CHAR + end subroutine set_errmsg + !=============================================================================== ! WARNING issues a warning to the user in the log file and the standard output ! stream. From 7f66b4694cc57b728663e15e3f70148c4dfe7bed Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 15 Sep 2017 14:04:31 -0500 Subject: [PATCH 176/229] Get rid of n_active global, allow a few settings to be controlled from openmc.capi --- openmc/capi/__init__.py | 1 + openmc/capi/settings.py | 65 +++++++++++++++++++++++++++++++++++++++++ src/input_xml.F90 | 5 +--- src/output.F90 | 2 ++ src/settings.F90 | 15 +++++----- 5 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 openmc/capi/settings.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 148070757..88a69df34 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -37,3 +37,4 @@ from .material import * from .cell import * from .filter import * from .tally import * +from .settings import settings diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py new file mode 100644 index 000000000..40d1768cf --- /dev/null +++ b/openmc/capi/settings.py @@ -0,0 +1,65 @@ +from ctypes import c_int, c_int32, c_int64, c_double, c_char_p, POINTER + +from . import _dll +from .error import _error_handler + +_RUN_MODES = {1: 'fixed source', + 2: 'eigenvalue', + 3: 'plot', + 4: 'particle restart', + 5: 'volume'} + + +class _Settings(object): + @property + def batches(self): + return c_int32.in_dll(_dll, 'n_batches').value + + @batches.setter + def batches(self, n): + _dll.openmc_set_batches(n) + + @property + def generations_per_batch(self): + return c_int32.in_dll(_dll, 'gen_per_batch').value + + @generations_per_batch.setter + def generations_per_batch(self, n): + _dll.openmc_set_generations_per_batch(n) + + @property + def inactive(self): + return c_int32.in_dll(_dll, 'n_inactive').value + + @inactive.setter + def inactive(self, n): + _dll.openmc_set_inactive_batches(n) + + @property + def particles(self): + return c_int64.in_dll(_dll, 'n_particles').value + + @particles.setter + def particles(self, n): + _dll.openmc_set_particles(n) + + @property + def run_mode(self): + i = c_int.in_dll(_dll, 'run_mode').value + try: + return _RUN_MODES[i] + except KeyError: + return None + + @run_mode.setter + def run_mode(self, mode): + current_idx = c_int.in_dll(_dll, 'run_mode') + for idx, mode_value in _RUN_MODES.items(): + if mode_value == mode: + current_idx.value = idx + break + else: + raise ValueError('Invalid run mode: {}'.format(mode)) + + +settings = _Settings() diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c7e80fe98..0ef4d2b30 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -322,7 +322,7 @@ contains call get_run_parameters(node_mode) ! Check number of active batches, inactive batches, and particles - if (n_active <= 0) then + if (n_batches <= n_inactive) then call fatal_error("Number of active batches must be greater than zero.") elseif (n_inactive < 0) then call fatal_error("Number of inactive batches must be non-negative.") @@ -891,9 +891,6 @@ contains end if end if - ! Determine number of active batches - n_active = n_batches - n_inactive - end subroutine get_run_parameters !=============================================================================== diff --git a/src/output.F90 b/src/output.F90 index 215942bfe..e3d2b8ac1 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -532,6 +532,7 @@ contains subroutine print_runtime() + integer :: n_active real(8) :: speed_inactive ! # of neutrons/second in inactive batches real(8) :: speed_active ! # of neutrons/second in active batches character(15) :: string @@ -564,6 +565,7 @@ contains write(ou,100) "Total time elapsed", time_total % elapsed ! Calculate particle rate in active/inactive batches + n_active = n_batches - n_inactive if (restart_run) then if (restart_batch < n_inactive) then speed_inactive = real(n_particles * (n_inactive - restart_batch) * & diff --git a/src/settings.F90 b/src/settings.F90 index d1d41a75c..add7f5b90 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -1,12 +1,14 @@ module settings + use, intrinsic :: ISO_C_BINDING + use constants use set_header, only: SetInt use source_header implicit none - ! ============================================================================ + ! ============================================================================ ! ENERGY TREATMENT RELATED VARIABLES logical :: run_CE = .true. ! Run in CE mode? @@ -46,11 +48,10 @@ module settings ! ============================================================================ ! SIMULATION VARIABLES - integer(8) :: n_particles = 0 ! # of particles per generation - integer :: n_batches ! # of batches - integer :: n_inactive ! # of inactive batches - integer :: n_active ! # of active batches - integer :: gen_per_batch = 1 ! # of generations per batch + integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation + integer(C_INT32_T), bind(C) :: n_batches ! # of batches + integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches + integer(C_INT32_T), bind(C) :: gen_per_batch = 1 ! # of generations per batch integer :: n_max_batches ! max # of batches integer :: n_batch_interval = 1 ! batch interval for triggers @@ -75,7 +76,7 @@ module settings real(8) :: weight_survive = ONE ! Mode to run in (fixed source, eigenvalue, plotting, etc) - integer :: run_mode = NONE + integer(C_INT), bind(C) :: run_mode = NONE ! Restart run logical :: restart_run = .false. From c70ce9dd02cdc0867a2a287bdb3b2f600ddac9b7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 15 Sep 2017 15:51:59 -0500 Subject: [PATCH 177/229] Move most of external source sampling to source_header -- requiring removing a lot of 'use global's, hooray! --- openmc/stats/multivariate.py | 4 + openmc/stats/univariate.py | 4 + src/cross_section.F90 | 7 +- src/eigenvalue.F90 | 7 +- src/geometry.F90 | 7 +- src/global.F90 | 10 +-- src/main.F90 | 2 +- src/mesh.F90 | 2 +- src/multipole.F90 | 3 +- src/output.F90 | 15 ++-- src/particle_restart.F90 | 6 +- src/particle_restart_write.F90 | 5 +- src/physics_common.F90 | 2 +- src/settings.F90 | 1 - src/simulation_header.F90 | 12 +++ src/source.F90 | 83 ++--------------- src/source_header.F90 | 157 ++++++++++++++++++++++++++++++++- src/tallies/tally.F90 | 9 +- 18 files changed, 222 insertions(+), 114 deletions(-) diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index 0ab11b7c5..b738dc43d 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -12,6 +12,10 @@ import openmc.checkvalue as cv from openmc.stats.univariate import Univariate, Uniform +__all__ = ['UnitSphere', 'PolarAzimuthal', 'Isotropic', 'Monodirectional', + 'Spatial', 'CartesianIndependent', 'Box', 'Point'] + + @add_metaclass(ABCMeta) class UnitSphere(object): """Distribution of points on the unit sphere. diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index c0476ce45..185b22204 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -11,6 +11,10 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin +__all__ = ['Univariate', 'Discrete', 'Uniform', 'Maxwell', 'Watt', 'Tabular', + 'Legendre', 'Mixture'] + + _INTERPOLATION_SCHEMES = ['histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'] diff --git a/src/cross_section.F90 b/src/cross_section.F90 index 83cb4ea25..0bdadd87e 100644 --- a/src/cross_section.F90 +++ b/src/cross_section.F90 @@ -3,9 +3,8 @@ module cross_section use algorithm, only: binary_search use constants use error, only: fatal_error - use global use list_header, only: ListElemInt - use material_header, only: Material + use material_header, only: Material, materials use math, only: faddeeva, w_derivative, broaden_wmp_polynomials use multipole_header, only: FORM_RM, FORM_MLBW, MP_EA, RM_RT, RM_RA, RM_RF, & MLBW_RT, MLBW_RX, MLBW_RA, MLBW_RF, FIT_T, FIT_A,& @@ -13,7 +12,9 @@ module cross_section use nuclide_header use particle_header, only: Particle use random_lcg, only: prn, future_prn, prn_set_stream - use sab_header, only: SAlphaBeta + use sab_header, only: SAlphaBeta, sab_tables + use settings + use simulation_header implicit none diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 588cfea38..5f99d1580 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -5,13 +5,16 @@ module eigenvalue use algorithm, only: binary_search use constants, only: ZERO use error, only: fatal_error, warning - use global use math, only: t_percentile use mesh, only: count_bank_sites - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use message_passing use random_lcg, only: prn, set_particle_seed, advance_prn_seed + use settings + use simulation_header use string, only: to_str + use tally_header + use timer_header implicit none diff --git a/src/geometry.F90 b/src/geometry.F90 index e27ceeedb..3a325dfd9 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -2,16 +2,17 @@ module geometry use constants use error, only: fatal_error, warning - use geometry_header, only: Cell, Universe, Lattice, & - &RectLattice, HexLattice - use global + use geometry_header use output, only: write_message use particle_header, only: LocalCoord, Particle use particle_restart_write, only: write_particle_restart + use simulation_header + use settings use surface_header use stl_vector, only: VectorInt use string, only: to_str use tally, only: score_surface_current + use tally_header implicit none diff --git a/src/global.F90 b/src/global.F90 index 09652f294..999a5a676 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -13,6 +13,7 @@ module global use sab_header use settings use simulation_header + use source_header use surface_header use tally_filter_header use tally_header @@ -131,13 +132,4 @@ contains end subroutine free_memory -!=============================================================================== -! OVERALL_GENERATION determines the overall generation number -!=============================================================================== - - pure function overall_generation() result(gen) - integer :: gen - gen = gen_per_batch*(current_batch - 1) + current_gen - end function overall_generation - end module global diff --git a/src/main.F90 b/src/main.F90 index fadf9f3bb..d8e52643c 100644 --- a/src/main.F90 +++ b/src/main.F90 @@ -1,11 +1,11 @@ program main use constants - use global use message_passing use openmc_api, only: openmc_init, openmc_finalize, openmc_run, & openmc_plot_geometry, openmc_calculate_volumes use particle_restart, only: run_particle_restart + use settings, only: run_mode implicit none diff --git a/src/mesh.F90 b/src/mesh.F90 index 785d7761c..e997890a4 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -1,8 +1,8 @@ module mesh use algorithm, only: binary_search + use bank_header, only: bank use constants - use global use mesh_header use message_passing diff --git a/src/multipole.F90 b/src/multipole.F90 index c59f94727..0282adb7d 100644 --- a/src/multipole.F90 +++ b/src/multipole.F90 @@ -3,10 +3,11 @@ module multipole use hdf5 use constants - use global + use error, only: fatal_error use hdf5_interface use multipole_header, only: MultipoleArray, FIT_T, FIT_A, FIT_F, & MP_FISS, FORM_MLBW, FORM_RM + use nuclide_header, only: nuclides implicit none diff --git a/src/output.F90 b/src/output.F90 index e3d2b8ac1..34134168b 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -3,25 +3,30 @@ module output use, intrinsic :: ISO_C_BINDING use, intrinsic :: ISO_FORTRAN_ENV + use cmfd_header use constants use eigenvalue, only: openmc_get_keff use endf, only: reaction_name use error, only: fatal_error, warning - use geometry_header, only: Cell, Universe, Lattice, RectLattice, & - HexLattice - use global + use geometry_header use math, only: t_percentile - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use message_passing, only: master, n_procs + use mgxs_header, only: nuclides_MG use nuclide_header use particle_header, only: LocalCoord, Particle use plot_header use sab_header, only: SAlphaBeta + use settings + use simulation_header + use surface_header, only: surfaces use string, only: to_upper, to_str - use tally_header, only: TallyObject + use tally_header + use tally_derivative_header use tally_filter use tally_filter_mesh, only: MeshFilter use tally_filter_header, only: TallyFilterMatch + use timer_header implicit none diff --git a/src/particle_restart.F90 b/src/particle_restart.F90 index 35b16224d..53332c794 100644 --- a/src/particle_restart.F90 +++ b/src/particle_restart.F90 @@ -4,11 +4,15 @@ module particle_restart use bank_header, only: Bank use constants - use global use hdf5_interface, only: file_open, file_close, read_dataset + use mgxs_header, only: energy_bin_avg + use nuclide_header, only: micro_xs, n_nuclides use output, only: write_message, print_particle use particle_header, only: Particle use random_lcg, only: set_particle_seed + use settings + use simulation_header + use tally_header, only: n_tallies use tracking, only: transport use hdf5, only: HID_T diff --git a/src/particle_restart_write.F90 b/src/particle_restart_write.F90 index 08e80ea1b..5addf6056 100644 --- a/src/particle_restart_write.F90 +++ b/src/particle_restart_write.F90 @@ -1,9 +1,10 @@ module particle_restart_write - use bank_header, only: Bank - use global + use bank_header, only: Bank, source_bank use hdf5_interface use particle_header, only: Particle + use settings + use simulation_header use string, only: to_str use hdf5 diff --git a/src/physics_common.F90 b/src/physics_common.F90 index 98d240c07..63bf62ce6 100644 --- a/src/physics_common.F90 +++ b/src/physics_common.F90 @@ -1,9 +1,9 @@ module physics_common use constants - use global, only: weight_cutoff, weight_survive use particle_header, only: Particle use random_lcg, only: prn + use settings, only: weight_cutoff, weight_survive implicit none diff --git a/src/settings.F90 b/src/settings.F90 index add7f5b90..10b7ea958 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -4,7 +4,6 @@ module settings use constants use set_header, only: SetInt - use source_header implicit none diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index e47c2dd04..3918307a1 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -2,6 +2,7 @@ module simulation_header use bank_header use constants + use settings, only: gen_per_batch implicit none @@ -67,4 +68,15 @@ module simulation_header !$omp threadprivate(trace, thread_id, current_work) +contains + +!=============================================================================== +! OVERALL_GENERATION determines the overall generation number +!=============================================================================== + + pure function overall_generation() result(gen) + integer :: gen + gen = gen_per_batch*(current_batch - 1) + current_gen + end function overall_generation + end module simulation_header diff --git a/src/source.F90 b/src/source.F90 index 517715b56..fe7a451cb 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -103,14 +103,7 @@ contains integer :: i ! dummy loop index integer :: n_source ! number of source distributions real(8) :: c ! cumulative frequency - real(8) :: r(3) ! sampled coordinates - logical :: found ! Does the source particle exist within geometry? - type(Particle) :: p ! Temporary particle for using find_cell - integer, save :: n_accept = 0 ! Number of samples accepted - integer, save :: n_reject = 0 ! Number of samples rejected - - ! Set weight to one by default - site % wgt = ONE + real(8) :: xi ! Set the random number generator to the source stream. call prn_set_stream(STREAM_SOURCE) @@ -118,84 +111,18 @@ contains ! Sample from among multiple source distributions n_source = size(external_source) if (n_source > 1) then - r(1) = prn()*sum(external_source(:) % strength) + xi = prn()*sum(external_source(:) % strength) c = ZERO do i = 1, n_source c = c + external_source(i) % strength - if (r(1) < c) exit + if (xi < c) exit end do else i = 1 end if - ! Repeat sampling source location until a good site has been found - found = .false. - do while (.not. found) - ! Set particle defaults - call p % initialize() - - ! Sample spatial distribution - site % xyz(:) = external_source(i) % space % sample() - - ! Fill p with needed data - p % coord(1) % xyz(:) = site % xyz - p % coord(1) % uvw(:) = [ ONE, ZERO, ZERO ] - - ! Now search to see if location exists in geometry - call find_cell(p, found) - - ! Check if spatial site is in fissionable material - if (found) then - select type (space => external_source(i) % space) - type is (SpatialBox) - if (space % only_fissionable) then - if (p % material == MATERIAL_VOID) then - found = .false. - elseif (.not. materials(p % material) % fissionable) then - found = .false. - end if - end if - end select - end if - - ! Check for rejection - if (.not. found) then - n_reject = n_reject + 1 - if (n_reject >= EXTSRC_REJECT_THRESHOLD .and. & - real(n_accept, 8)/n_reject <= EXTSRC_REJECT_FRACTION) then - call fatal_error("More than 95% of external source sites sampled & - &were rejected. Please check your external source definition.") - end if - end if - end do - - ! Increment number of accepted samples - n_accept = n_accept + 1 - - call p % clear() - - ! Sample angle - site % uvw(:) = external_source(i) % angle % sample() - - ! Check for monoenergetic source above maximum neutron energy - select type (energy => external_source(i) % energy) - type is (Discrete) - if (any(energy % x >= energy_max_neutron)) then - call fatal_error("Source energy above range of energies of at least & - &one cross section table") - end if - end select - - do - ! Sample energy spectrum - site % E = external_source(i) % energy % sample() - - ! resample if energy is greater than maximum neutron energy - if (site % E < energy_max_neutron) exit - end do - - ! Set delayed group - site % delayed_group = 0 + ! Sample source site from i-th source distribution + site = external_source(i) % sample() ! If running in MG, convert site % E to group if (.not. run_CE) then diff --git a/src/source_header.F90 b/src/source_header.F90 index 3ae3aca96..76723212c 100644 --- a/src/source_header.F90 +++ b/src/source_header.F90 @@ -1,15 +1,25 @@ module source_header + use, intrinsic :: ISO_C_BINDING + + use bank_header, only: Bank use constants use distribution_univariate use distribution_multivariate - use error, only: fatal_error + use error + use geometry, only: find_cell + use material_header, only: materials + use nuclide_header, only: energy_max_neutron + use particle_header, only: Particle use string, only: to_lower use xml_interface implicit none private + integer :: n_accept = 0 ! Number of samples accepted + integer :: n_reject = 0 ! Number of samples rejected + !=============================================================================== ! SOURCEDISTRIBUTION describes an external source of particles for a ! fixed-source problem or for the starting source in a k eigenvalue problem @@ -21,15 +31,19 @@ module source_header class(UnitSphereDistribution), allocatable :: angle ! angle distribution class(Distribution), allocatable :: energy ! energy distribution contains - procedure :: from_xml => source_from_xml + procedure :: from_xml + procedure :: sample end type SourceDistribution + ! Number of external source distributions + integer(C_INT32_T), public, bind(C) :: n_sources = 0 + ! External source distributions type(SourceDistribution), public, allocatable :: external_source(:) contains - subroutine source_from_xml(this, node, path_source) + subroutine from_xml(this, node, path_source) class(SourceDistribution), intent(inout) :: this type(XMLNode), intent(in) :: node character(MAX_FILE_LEN), intent(out) :: path_source @@ -196,6 +210,141 @@ contains end if end if - end subroutine source_from_xml + end subroutine from_xml + + function sample(this) result(site) + class(SourceDistribution), intent(in) :: this + type(Bank) :: site + + real(8) :: r(3) ! sampled coordinates + logical :: found ! Does the source particle exist within geometry? + type(Particle) :: p ! Temporary particle for using find_cell + + ! Set weight to one by default + site % wgt = ONE + + ! Repeat sampling source location until a good site has been found + found = .false. + do while (.not. found) + ! Set particle defaults + call p % initialize() + + ! Sample spatial distribution + site % xyz(:) = this % space % sample() + + ! Fill p with needed data + p % coord(1) % xyz(:) = site % xyz + p % coord(1) % uvw(:) = [ ONE, ZERO, ZERO ] + + ! Now search to see if location exists in geometry + call find_cell(p, found) + + ! Check if spatial site is in fissionable material + if (found) then + select type (space => this % space) + type is (SpatialBox) + if (space % only_fissionable) then + if (p % material == MATERIAL_VOID) then + found = .false. + elseif (.not. materials(p % material) % fissionable) then + found = .false. + end if + end if + end select + end if + + ! Check for rejection + if (.not. found) then + n_reject = n_reject + 1 + if (n_reject >= EXTSRC_REJECT_THRESHOLD .and. & + real(n_accept, 8)/n_reject <= EXTSRC_REJECT_FRACTION) then + call fatal_error("More than 95% of external source sites sampled & + &were rejected. Please check your external source definition.") + end if + end if + end do + + ! Increment number of accepted samples + n_accept = n_accept + 1 + + call p % clear() + + ! Sample angle + site % uvw(:) = this % angle % sample() + + ! Check for monoenergetic source above maximum neutron energy + select type (energy => this % energy) + type is (Discrete) + if (any(energy % x >= energy_max_neutron)) then + call fatal_error("Source energy above range of energies of at least & + &one cross section table") + end if + end select + + do + ! Sample energy spectrum + site % E = this % energy % sample() + + ! resample if energy is greater than maximum neutron energy + if (site % E < energy_max_neutron) exit + end do + + ! Set delayed group + site % delayed_group = 0 + + end function sample + +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_extend_sources(n, index_start, index_end) result(err) bind(C) + ! Extend the external_source array by n elements + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), optional, intent(out) :: index_start + integer(C_INT32_T), optional, intent(out) :: index_end + integer(C_INT) :: err + + integer :: i + type(SourceDistribution), allocatable :: temp(:) ! temporary array + + if (n_sources == 0) then + ! Allocate external_source array + allocate(external_source(n)) + else + ! Allocate external_source array with increased size + allocate(temp(n_sources + n)) + + ! Copy original source array to temporary array + temp(1:n_sources) = external_source + + ! Move allocation from temporary array + call move_alloc(FROM=temp, TO=external_source) + end if + + ! Return indices in external_source array + if (present(index_start)) index_start = n_sources + 1 + if (present(index_end)) index_end = n_sources + n + n_sources = n_sources + n + + err = 0 + end function openmc_extend_sources + + function openmc_source_set_strength(index, strength) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index + real(C_DOUBLE), value, intent(in) :: strength + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= n_sources) then + if (strength > ZERO) then + external_source(index) % strength = strength + err = 0 + end if + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_source_set_strength + end module source_header diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 2a948a869..bb228e892 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -7,14 +7,19 @@ module tally use cross_section, only: multipole_deriv_eval use error, only: fatal_error use geometry_header - use global use math, only: t_percentile, calc_pn, calc_rn - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use message_passing + use mgxs_header + use nuclide_header use output, only: header use particle_header, only: LocalCoord, Particle + use settings + use simulation_header use string, only: to_str + use tally_derivative_header, only: tally_derivs use tally_filter + use tally_header implicit none From 2cae2cecf8f0011eaccb9ec412ea8deedd6229bb Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 15 Sep 2017 16:20:23 -0500 Subject: [PATCH 178/229] Remove more 'use global' statements --- src/initialize.F90 | 4 +++- src/input_xml.F90 | 17 +++++++++++------ src/mgxs_data.F90 | 8 +++++--- src/physics.F90 | 8 ++++++-- src/physics_mg.F90 | 11 ++++++++--- src/source.F90 | 9 ++++++--- src/track_output.F90 | 8 +++++--- src/tracking.F90 | 9 +++++++-- 8 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index 258ac3b30..c3fc6b0e8 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -14,7 +14,6 @@ module initialize use error, only: fatal_error, warning use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,& root_universe - use global use hdf5_interface, only: file_open, read_attribute, file_close, & hdf5_bank_t, hdf5_integer8_t use input_xml, only: read_input_xml @@ -23,9 +22,12 @@ module initialize use mgxs_data, only: read_mgxs, create_macro_xs use output, only: print_version, write_message, print_usage use random_lcg, only: initialize_prng + use settings + use simulation_header, only: n_threads use string, only: to_str, starts_with, ends_with, str_to_int use tally_header, only: TallyObject use tally_filter + use timer_header implicit none diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 0ef4d2b30..7bc345da4 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -13,12 +13,11 @@ module input_xml use error, only: fatal_error, warning use geometry, only: calc_offsets, maximum_levels, count_instance, & neighbor_lists - use geometry_header, only: Cell, Lattice, RectLattice, HexLattice, & - get_temperatures, root_universe - use global + use geometry_header use hdf5_interface use list_header, only: ListChar, ListInt, ListReal - use mesh_header, only: RegularMesh + use material_header + use mesh_header use message_passing use mgxs_data, only: create_macro_xs, read_mgxs use mgxs_header @@ -28,15 +27,21 @@ module input_xml use random_lcg, only: prn, seed, initialize_prng use surface_header use set_header, only: SetChar + use settings + use source_header use stl_vector, only: VectorInt, VectorReal, VectorChar use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & zero_padded, to_c_string use summary, only: write_summary - use tally, only: openmc_tally_set_type + use tally use tally_header, only: openmc_extend_tallies - use tally_filter_header, only: TallyFilterContainer + use tally_derivative_header + use tally_filter_header use tally_filter + use timer_header, only: time_read_xs + use trigger_header + use volume_header use xml_interface implicit none diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index a111bc1c4..00b5fc46a 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -2,14 +2,16 @@ module mgxs_data use constants use algorithm, only: find + use dict_header, only: DictCharInt use error, only: fatal_error - use geometry_header, only: get_temperatures - use global + use geometry_header, only: get_temperatures, cells use hdf5_interface - use material_header, only: Material + use material_header, only: Material, materials, n_materials use mgxs_header + use nuclide_header, only: n_nuclides use output, only: write_message use set_header, only: SetChar + use settings use stl_vector, only: VectorReal use string, only: to_lower implicit none diff --git a/src/physics.F90 b/src/physics.F90 index b57ac292e..cb309f93a 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -5,9 +5,9 @@ module physics use cross_section, only: elastic_xs_0K use endf, only: reaction_name use error, only: fatal_error, warning - use global - use material_header, only: Material + use material_header, only: Material, materials use math + use mesh_header, only: meshes use message_passing use nuclide_header use output, only: write_message @@ -16,8 +16,12 @@ module physics use physics_common use random_lcg, only: prn, advance_prn_seed, prn_set_stream use reaction_header, only: Reaction + use sab_header, only: sab_tables use secondary_uncorrelated, only: UncorrelatedAngleEnergy + use settings + use simulation_header use string, only: to_str + use tally_header implicit none diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 29cdc447f..ecf6980e3 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -2,20 +2,25 @@ module physics_mg ! This module contains the multi-group specific physics routines so as to not ! hinder performance of the CE versions with multiple if-thens. + use bank_header use constants use error, only: fatal_error, warning - use global - use material_header, only: Material + use material_header, only: Material, materials use math, only: rotate_angle - use mgxs_header, only: Mgxs, MgxsContainer + use mesh_header, only: meshes + use mgxs_header use message_passing + use nuclide_header, only: material_xs use output, only: write_message use particle_header, only: Particle use particle_restart_write, only: write_particle_restart use physics_common use random_lcg, only: prn use scattdata_header + use settings + use simulation_header use string, only: to_str + use tally_header implicit none diff --git a/src/source.F90 b/src/source.F90 index fe7a451cb..0689cb403 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -6,20 +6,23 @@ module source #endif use algorithm, only: binary_search - use bank_header, only: Bank + use bank_header, only: Bank, source_bank use constants use distribution_univariate, only: Discrete use distribution_multivariate, only: SpatialBox use error, only: fatal_error use geometry, only: find_cell - use global use hdf5_interface, only: file_create, file_open, file_close, read_dataset + use math use message_passing, only: rank + use mgxs_header, only: energy_bins, num_energy_groups use output, only: write_message use particle_header, only: Particle use random_lcg, only: prn, set_particle_seed, prn_set_stream + use settings + use simulation_header + use source_header, only: external_source use string, only: to_str - use math use state_point, only: read_source_bank, write_source_bank implicit none diff --git a/src/track_output.F90 b/src/track_output.F90 index bdef9579c..244bf182e 100644 --- a/src/track_output.F90 +++ b/src/track_output.F90 @@ -5,13 +5,15 @@ module track_output - use global + use hdf5 + + use constants use hdf5_interface use particle_header, only: Particle + use settings, only: path_output + use simulation_header use string, only: to_str - use hdf5 - implicit none private diff --git a/src/tracking.F90 b/src/tracking.F90 index 90dd9c35e..518a97f7c 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -1,18 +1,23 @@ module tracking - use constants, only: MODE_EIGENVALUE + use constants use cross_section, only: calculate_xs use error, only: fatal_error, warning + use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_surface, & cross_lattice, check_cell_overlap - use global use output, only: write_message use message_passing + use mgxs_header + use nuclide_header use particle_header, only: LocalCoord, Particle use physics, only: collision use physics_mg, only: collision_mg use random_lcg, only: prn + use settings + use simulation_header use string, only: to_str + use tally_header use tally, only: score_analog_tally, score_tracklength_tally, & score_collision_tally, score_surface_current, & score_track_derivative, score_surface_tally, & From b867d640da88c43e0c25664f0ffc88feb548357b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 16 Sep 2017 14:46:13 -0500 Subject: [PATCH 179/229] The global module is finally gone --- CMakeLists.txt | 1 - src/api.F90 | 126 ++++++++++++++++++++++++++++++++++++- src/cmfd_data.F90 | 2 +- src/cmfd_execute.F90 | 11 ++-- src/cmfd_input.F90 | 6 +- src/cmfd_solver.F90 | 4 +- src/global.F90 | 135 ---------------------------------------- src/plot.F90 | 5 +- src/simulation.F90 | 13 +++- src/state_point.F90 | 12 +++- src/summary.F90 | 8 +-- src/tallies/trigger.F90 | 9 ++- src/volume_calc.F90 | 6 +- 13 files changed, 175 insertions(+), 163 deletions(-) delete mode 100644 src/global.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index a0a54aac5..905555a05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -322,7 +322,6 @@ set(LIBOPENMC_FORTRAN_SRC src/error.F90 src/geometry.F90 src/geometry_header.F90 - src/global.F90 src/hdf5_interface.F90 src/initialize.F90 src/input_xml.F90 diff --git a/src/api.F90 b/src/api.F90 index 247410d2b..04bb2b1e9 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -8,21 +8,26 @@ module openmc_api use eigenvalue, only: k_sum, openmc_get_keff use error use geometry, only: find_cell - use geometry_header, only: root_universe - use global + use geometry_header use hdf5_interface + use material_header + use mesh_header use message_passing + use nuclide_header use initialize, only: openmc_init use input_xml, only: assign_0K_elastic_scattering, check_data_version use particle_header, only: Particle use plot, only: openmc_plot_geometry use random_lcg, only: seed, initialize_prng + use settings + use simulation_header use tally_header use tally_filter_header use tally_filter use tally, only: openmc_tally_set_type use simulation, only: openmc_run use string, only: to_f_string + use timer_header use volume_calc, only: openmc_calculate_volumes implicit none @@ -719,4 +724,121 @@ contains end subroutine openmc_reset +!=============================================================================== +! FREE_MEMORY deallocates and clears all global allocatable arrays in the +! program +!=============================================================================== + + subroutine free_memory() + + use cmfd_header + use mgxs_header + use plot_header + use sab_header + use settings + use source_header + use surface_header + use tally_derivative_header + use trigger_header + use volume_header + + integer :: i ! Loop Index + + ! Deallocate cells, surfaces, materials + if (allocated(cells)) deallocate(cells) + if (allocated(universes)) deallocate(universes) + if (allocated(lattices)) deallocate(lattices) + if (allocated(surfaces)) deallocate(surfaces) + if (allocated(materials)) deallocate(materials) + if (allocated(plots)) deallocate(plots) + if (allocated(volume_calcs)) deallocate(volume_calcs) + + ! Deallocate geometry debugging information + if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) + + ! Deallocate cross section data, listings, and cache + if (allocated(nuclides)) then + ! First call the clear routines + do i = 1, size(nuclides) + call nuclides(i) % clear() + end do + deallocate(nuclides) + end if + if (allocated(libraries)) deallocate(libraries) + + if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides) + + if (allocated(nuclides_MG)) deallocate(nuclides_MG) + + if (allocated(macro_xs)) deallocate(macro_xs) + + if (allocated(sab_tables)) deallocate(sab_tables) + + ! Deallocate external source + if (allocated(external_source)) deallocate(external_source) + + ! Deallocate k and entropy + if (allocated(k_generation)) deallocate(k_generation) + if (allocated(entropy)) deallocate(entropy) + if (allocated(entropy_p)) deallocate(entropy_p) + + ! Deallocate tally-related arrays + if (allocated(global_tallies)) deallocate(global_tallies) + if (allocated(meshes)) deallocate(meshes) + if (allocated(filters)) deallocate(filters) + if (allocated(tallies)) deallocate(tallies) + + ! Deallocate fission and source bank and entropy +!$omp parallel + if (allocated(fission_bank)) deallocate(fission_bank) + if (allocated(tally_derivs)) deallocate(tally_derivs) +!$omp end parallel +#ifdef _OPENMP + if (allocated(master_fission_bank)) deallocate(master_fission_bank) +#endif + if (allocated(source_bank)) deallocate(source_bank) + + ! Deallocate array of work indices + if (allocated(work_index)) deallocate(work_index) + + if (allocated(energy_bins)) deallocate(energy_bins) + if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) + + ! Deallocate CMFD + call deallocate_cmfd(cmfd) + + ! Deallocate tally node lists + call active_analog_tallies % clear() + call active_tracklength_tallies % clear() + call active_current_tallies % clear() + call active_collision_tallies % clear() + call active_surface_tallies % clear() + call active_tallies % clear() + + ! Deallocate track_identifiers + if (allocated(track_identifiers)) deallocate(track_identifiers) + + ! Deallocate dictionaries + call cell_dict % clear() + call universe_dict % clear() + call lattice_dict % clear() + call surface_dict % clear() + call material_dict % clear() + call mesh_dict % clear() + call filter_dict % clear() + call tally_dict % clear() + call plot_dict % clear() + call nuclide_dict % clear() + call sab_dict % clear() + call library_dict % clear() + + ! Clear statepoint and sourcepoint batch set + call statepoint_batch % clear() + call sourcepoint_batch % clear() + + ! Deallocate ufs + if (allocated(source_frac)) deallocate(source_frac) + + end subroutine free_memory + end module openmc_api diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index 3a6e965ac..5eb2158e9 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -394,7 +394,7 @@ contains subroutine neutron_balance() use constants, only: ONE, ZERO, CMFD_NOACCEL, CMFD_NORES - use global, only: keff, current_batch + use simulation_header, only: keff, current_batch integer :: nx ! number of mesh cells in x direction integer :: ny ! number of mesh cells in y direction diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 307f6ab9a..140166e0a 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -5,9 +5,9 @@ module cmfd_execute ! cross section generation, diffusion calculation, and source re-weighting !============================================================================== - use cmfd_header, only: cmfd_begin, cmfd_on, cmfd_reset, cmfd, cmfd_coremap, & - cmfd_mesh - use global + use cmfd_header + use settings + use simulation_header implicit none private @@ -65,8 +65,6 @@ contains subroutine cmfd_init_batch() - use global, only: cmfd_run, current_batch - ! Check to activate CMFD diffusion and possible feedback ! this guarantees that when cmfd begins at least one batch of tallies are ! accumulated @@ -91,7 +89,6 @@ contains subroutine calc_fission_source() use constants, only: CMFD_NOACCEL, ZERO, TWO - use global, only: entropy_on, current_batch use message_passing use string, only: to_str @@ -214,9 +211,9 @@ contains subroutine cmfd_reweight(new_weights) use algorithm, only: binary_search + use bank_header, only: source_bank use constants, only: ZERO, ONE use error, only: warning, fatal_error - use global, only: source_bank, work use mesh_header, only: RegularMesh use mesh, only: count_bank_sites use message_passing diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index f44048665..fe94fac33 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -3,7 +3,11 @@ module cmfd_input use, intrinsic :: ISO_C_BINDING use cmfd_header - use global + use mesh_header, only: mesh_dict + use mgxs_header, only: energy_bins + use tally + use tally_header + use timer_header implicit none private diff --git a/src/cmfd_solver.F90 b/src/cmfd_solver.F90 index 42d93f02f..99d482480 100644 --- a/src/cmfd_solver.F90 +++ b/src/cmfd_solver.F90 @@ -101,7 +101,7 @@ contains use constants, only: ONE, ZERO use cmfd_header, only: cmfd_shift, cmfd_ktol, cmfd_stol, cmfd_write_matrices - use global, only: keff + use simulation_header, only: keff logical, intent(in) :: adjoint @@ -694,7 +694,7 @@ contains subroutine extract_results() use cmfd_header, only: cmfd, cmfd_write_matrices - use global, only: current_batch + use simulation_header, only: current_batch character(len=25) :: filename ! name of file to write data integer :: n ! problem size diff --git a/src/global.F90 b/src/global.F90 deleted file mode 100644 index 999a5a676..000000000 --- a/src/global.F90 +++ /dev/null @@ -1,135 +0,0 @@ -module global - - use, intrinsic :: ISO_C_BINDING - - ! Inherit module variables from other modules - use cmfd_header - use geometry_header - use material_header - use mesh_header - use mgxs_header - use nuclide_header - use plot_header - use sab_header - use settings - use simulation_header - use source_header - use surface_header - use tally_filter_header - use tally_header - use tally_derivative_header - use timer_header - use trigger_header - use volume_header - - implicit none - -contains - -!=============================================================================== -! FREE_MEMORY deallocates and clears all global allocatable arrays in the -! program -!=============================================================================== - - subroutine free_memory() - - integer :: i ! Loop Index - - ! Deallocate cells, surfaces, materials - if (allocated(cells)) deallocate(cells) - if (allocated(universes)) deallocate(universes) - if (allocated(lattices)) deallocate(lattices) - if (allocated(surfaces)) deallocate(surfaces) - if (allocated(materials)) deallocate(materials) - if (allocated(plots)) deallocate(plots) - if (allocated(volume_calcs)) deallocate(volume_calcs) - - ! Deallocate geometry debugging information - if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) - - ! Deallocate cross section data, listings, and cache - if (allocated(nuclides)) then - ! First call the clear routines - do i = 1, size(nuclides) - call nuclides(i) % clear() - end do - deallocate(nuclides) - end if - if (allocated(libraries)) deallocate(libraries) - - if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides) - - if (allocated(nuclides_MG)) deallocate(nuclides_MG) - - if (allocated(macro_xs)) deallocate(macro_xs) - - if (allocated(sab_tables)) deallocate(sab_tables) - - ! Deallocate external source - if (allocated(external_source)) deallocate(external_source) - - ! Deallocate k and entropy - if (allocated(k_generation)) deallocate(k_generation) - if (allocated(entropy)) deallocate(entropy) - if (allocated(entropy_p)) deallocate(entropy_p) - - ! Deallocate tally-related arrays - if (allocated(global_tallies)) deallocate(global_tallies) - if (allocated(meshes)) deallocate(meshes) - if (allocated(filters)) deallocate(filters) - if (allocated(tallies)) deallocate(tallies) - - ! Deallocate fission and source bank and entropy -!$omp parallel - if (allocated(fission_bank)) deallocate(fission_bank) - if (allocated(tally_derivs)) deallocate(tally_derivs) -!$omp end parallel -#ifdef _OPENMP - if (allocated(master_fission_bank)) deallocate(master_fission_bank) -#endif - if (allocated(source_bank)) deallocate(source_bank) - - ! Deallocate array of work indices - if (allocated(work_index)) deallocate(work_index) - - if (allocated(energy_bins)) deallocate(energy_bins) - if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) - - ! Deallocate CMFD - call deallocate_cmfd(cmfd) - - ! Deallocate tally node lists - call active_analog_tallies % clear() - call active_tracklength_tallies % clear() - call active_current_tallies % clear() - call active_collision_tallies % clear() - call active_surface_tallies % clear() - call active_tallies % clear() - - ! Deallocate track_identifiers - if (allocated(track_identifiers)) deallocate(track_identifiers) - - ! Deallocate dictionaries - call cell_dict % clear() - call universe_dict % clear() - call lattice_dict % clear() - call surface_dict % clear() - call material_dict % clear() - call mesh_dict % clear() - call filter_dict % clear() - call tally_dict % clear() - call plot_dict % clear() - call nuclide_dict % clear() - call sab_dict % clear() - call library_dict % clear() - - ! Clear statepoint and sourcepoint batch set - call statepoint_batch % clear() - call sourcepoint_batch % clear() - - ! Deallocate ufs - if (allocated(source_frac)) deallocate(source_frac) - - end subroutine free_memory - -end module global diff --git a/src/plot.F90 b/src/plot.F90 index b8ac3cfe6..fe2ddd13b 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -7,13 +7,14 @@ module plot use constants use error, only: fatal_error use geometry, only: find_cell, check_cell_overlap - use geometry_header, only: Cell, root_universe - use global + use geometry_header, only: Cell, root_universe, cells use hdf5_interface use output, only: write_message, time_stamp + use material_header, only: materials use particle_header, only: LocalCoord, Particle use plot_header use progress_header, only: ProgressBar + use settings, only: check_overlaps use string, only: to_str implicit none diff --git a/src/simulation.F90 b/src/simulation.F90 index f6ffcf24b..4eada2d68 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -6,7 +6,9 @@ module simulation use omp_lib #endif + use bank_header, only: source_bank use cmfd_execute, only: cmfd_init_batch, execute_cmfd + use cmfd_header, only: cmfd_on use constants, only: ZERO use eigenvalue, only: count_source_for_ufs, calculate_average_keff, & calculate_generation_keff, shannon_entropy, & @@ -14,19 +16,26 @@ module simulation #ifdef _OPENMP use eigenvalue, only: join_bank_from_threads #endif - use global + use error, only: fatal_error use message_passing + use mgxs_header, only: energy_bins, energy_bin_avg + use nuclide_header, only: micro_xs, n_nuclides use output, only: write_message, header, print_columns, & print_batch_keff, print_generation, print_runtime, & print_results, print_overlap_check, write_tallies use particle_header, only: Particle use random_lcg, only: set_particle_seed + use settings + use simulation_header use source, only: initialize_source, sample_external_source use state_point, only: write_state_point, write_source_point, load_state_point use string, only: to_str use tally, only: accumulate_tallies, setup_active_tallies, & init_tally_routines - use tally_header, only: configure_tallies + use tally_header + use tally_filter_header, only: filter_matches, n_filters + use tally_derivative_header, only: tally_derivs + use timer_header use trigger, only: check_triggers use tracking, only: transport diff --git a/src/state_point.F90 b/src/state_point.F90 index 29356beef..5dde708aa 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -15,17 +15,25 @@ module state_point use hdf5 + use cmfd_header use constants use eigenvalue, only: openmc_get_keff use endf, only: reaction_name use error, only: fatal_error, warning - use global use hdf5_interface - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes, n_meshes use message_passing + use mgxs_header, only: nuclides_MG + use nuclide_header, only: nuclides use output, only: write_message, time_stamp use random_lcg, only: seed + use settings + use simulation_header use string, only: to_str, count_digits, zero_padded + use tally_header + use tally_filter_header + use tally_derivative_header, only: tally_derivs + use timer_header implicit none diff --git a/src/summary.F90 b/src/summary.F90 index 6ee8b2e78..e271fbaba 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -4,15 +4,15 @@ module summary use constants use endf, only: reaction_name - use geometry_header, only: root_universe, Cell, Universe, Lattice, & - RectLattice, HexLattice - use global + use geometry_header use hdf5_interface - use material_header, only: Material + use material_header, only: Material, n_materials use mesh_header, only: RegularMesh use message_passing + use mgxs_header, only: nuclides_MG use nuclide_header use output, only: time_stamp + use settings, only: run_CE use surface_header use string, only: to_str use tally_header, only: TallyObject diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 643e6fae4..772e739ba 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -8,14 +8,17 @@ module trigger use constants use eigenvalue, only: openmc_get_keff - use global use string, only: to_str use output, only: warning, write_message - use mesh_header, only: RegularMesh + use mesh_header, only: RegularMesh, meshes use message_passing, only: master - use trigger_header, only: TriggerObject + use settings + use simulation_header + use trigger_header use tally, only: TallyObject use tally_filter_mesh, only: MeshFilter + use tally_filter_header, only: filter_matches, filters + use tally_header, only: tallies, n_tallies implicit none diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index f8cf4085a..48f93f0e6 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -9,14 +9,18 @@ module volume_calc use constants use geometry, only: find_cell - use global + use geometry_header, only: universes, cells use hdf5_interface, only: file_create, file_close, write_attribute, & create_group, close_group, write_dataset use output, only: write_message, header, time_stamp + use material_header, only: materials use message_passing + use nuclide_header, only: nuclides use particle_header, only: Particle use random_lcg, only: prn, prn_set_stream, set_particle_seed + use settings, only: path_output use stl_vector, only: VectorInt, VectorReal + use string, only: to_str use timer_header, only: Timer use volume_header From 1bb4eef41632edb015faf7975bb73d9334c1112b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 16 Sep 2017 15:15:10 -0500 Subject: [PATCH 180/229] Fix MPI/OpenMP-related compile issues --- src/initialize.F90 | 2 ++ src/simulation.F90 | 1 + src/source_header.F90 | 2 -- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index c3fc6b0e8..1720f2adf 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -23,7 +23,9 @@ module initialize use output, only: print_version, write_message, print_usage use random_lcg, only: initialize_prng use settings +#ifdef _OPENMP use simulation_header, only: n_threads +#endif use string, only: to_str, starts_with, ends_with, str_to_int use tally_header, only: TallyObject use tally_filter diff --git a/src/simulation.F90 b/src/simulation.F90 index 4eada2d68..a240f55b0 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -17,6 +17,7 @@ module simulation use eigenvalue, only: join_bank_from_threads #endif use error, only: fatal_error + use geometry_header, only: n_cells use message_passing use mgxs_header, only: energy_bins, energy_bin_avg use nuclide_header, only: micro_xs, n_nuclides diff --git a/src/source_header.F90 b/src/source_header.F90 index 76723212c..fa489853e 100644 --- a/src/source_header.F90 +++ b/src/source_header.F90 @@ -216,7 +216,6 @@ contains class(SourceDistribution), intent(in) :: this type(Bank) :: site - real(8) :: r(3) ! sampled coordinates logical :: found ! Does the source particle exist within geometry? type(Particle) :: p ! Temporary particle for using find_cell @@ -305,7 +304,6 @@ contains integer(C_INT32_T), optional, intent(out) :: index_end integer(C_INT) :: err - integer :: i type(SourceDistribution), allocatable :: temp(:) ! temporary array if (n_sources == 0) then From 2e78305b02bd4c3f995f60d47124908bbf07527e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Sep 2017 07:35:18 -0500 Subject: [PATCH 181/229] Separate deallocation of global variables into respective modules --- src/api.F90 | 111 ++++-------------------- src/bank_header.F90 | 19 ++++ src/geometry_header.F90 | 20 +++++ src/material_header.F90 | 10 +++ src/mesh_header.F90 | 11 +++ src/mgxs_header.F90 | 11 +++ src/nuclide_header.F90 | 24 +++++ src/plot_header.F90 | 12 +++ src/sab_header.F90 | 13 ++- src/settings.F90 | 14 +++ src/simulation_header.F90 | 13 +++ src/source_header.F90 | 10 +++ src/surface_header.F90 | 10 +++ src/tallies/tally_derivative_header.F90 | 11 +++ src/tallies/tally_filter_header.F90 | 11 +++ src/tallies/tally_header.F90 | 21 +++++ src/volume_header.F90 | 8 ++ 17 files changed, 233 insertions(+), 96 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 04bb2b1e9..4a2dc8b68 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -214,8 +214,6 @@ contains legendre_to_tabular = .true. legendre_to_tabular_points = 33 n_batch_interval = 1 - n_filters = 0 - n_meshes = 0 n_particles = 0 n_source_points = 0 n_state_points = 0 @@ -742,103 +740,26 @@ contains use trigger_header use volume_header - integer :: i ! Loop Index - - ! Deallocate cells, surfaces, materials - if (allocated(cells)) deallocate(cells) - if (allocated(universes)) deallocate(universes) - if (allocated(lattices)) deallocate(lattices) - if (allocated(surfaces)) deallocate(surfaces) - if (allocated(materials)) deallocate(materials) - if (allocated(plots)) deallocate(plots) - if (allocated(volume_calcs)) deallocate(volume_calcs) - - ! Deallocate geometry debugging information - if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) - - ! Deallocate cross section data, listings, and cache - if (allocated(nuclides)) then - ! First call the clear routines - do i = 1, size(nuclides) - call nuclides(i) % clear() - end do - deallocate(nuclides) - end if - if (allocated(libraries)) deallocate(libraries) - - if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides) - - if (allocated(nuclides_MG)) deallocate(nuclides_MG) - - if (allocated(macro_xs)) deallocate(macro_xs) - - if (allocated(sab_tables)) deallocate(sab_tables) - - ! Deallocate external source - if (allocated(external_source)) deallocate(external_source) - - ! Deallocate k and entropy - if (allocated(k_generation)) deallocate(k_generation) - if (allocated(entropy)) deallocate(entropy) - if (allocated(entropy_p)) deallocate(entropy_p) - - ! Deallocate tally-related arrays - if (allocated(global_tallies)) deallocate(global_tallies) - if (allocated(meshes)) deallocate(meshes) - if (allocated(filters)) deallocate(filters) - if (allocated(tallies)) deallocate(tallies) - - ! Deallocate fission and source bank and entropy -!$omp parallel - if (allocated(fission_bank)) deallocate(fission_bank) - if (allocated(tally_derivs)) deallocate(tally_derivs) -!$omp end parallel -#ifdef _OPENMP - if (allocated(master_fission_bank)) deallocate(master_fission_bank) -#endif - if (allocated(source_bank)) deallocate(source_bank) - - ! Deallocate array of work indices - if (allocated(work_index)) deallocate(work_index) - - if (allocated(energy_bins)) deallocate(energy_bins) - if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) + call free_memory_geometry() + call free_memory_surfaces() + call free_memory_material() + call free_memory_plot() + call free_memory_volume() + call free_memory_simulation() + call free_memory_nuclide() + call free_memory_settings() + call free_memory_mgxs() + call free_memory_sab() + call free_memory_source() + call free_memory_mesh() + call free_memory_tally() + call free_memory_tally_filter() + call free_memory_tally_derivative() + call free_memory_bank() ! Deallocate CMFD call deallocate_cmfd(cmfd) - ! Deallocate tally node lists - call active_analog_tallies % clear() - call active_tracklength_tallies % clear() - call active_current_tallies % clear() - call active_collision_tallies % clear() - call active_surface_tallies % clear() - call active_tallies % clear() - - ! Deallocate track_identifiers - if (allocated(track_identifiers)) deallocate(track_identifiers) - - ! Deallocate dictionaries - call cell_dict % clear() - call universe_dict % clear() - call lattice_dict % clear() - call surface_dict % clear() - call material_dict % clear() - call mesh_dict % clear() - call filter_dict % clear() - call tally_dict % clear() - call plot_dict % clear() - call nuclide_dict % clear() - call sab_dict % clear() - call library_dict % clear() - - ! Clear statepoint and sourcepoint batch set - call statepoint_batch % clear() - call sourcepoint_batch % clear() - - ! Deallocate ufs - if (allocated(source_frac)) deallocate(source_frac) - end subroutine free_memory end module openmc_api diff --git a/src/bank_header.F90 b/src/bank_header.F90 index f20c67385..961824a40 100644 --- a/src/bank_header.F90 +++ b/src/bank_header.F90 @@ -29,4 +29,23 @@ module bank_header !$omp threadprivate(fission_bank, n_bank) +contains + +!=============================================================================== +! FREE_MEMORY_BANK deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_bank() + + ! Deallocate fission and source bank and entropy +!$omp parallel + if (allocated(fission_bank)) deallocate(fission_bank) +!$omp end parallel +#ifdef _OPENMP + if (allocated(master_fission_bank)) deallocate(master_fission_bank) +#endif + if (allocated(source_bank)) deallocate(source_bank) + + end subroutine free_memory_bank + end module bank_header diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index c277d8582..5a5cf2c26 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -402,4 +402,24 @@ contains end subroutine get_temperatures +!=============================================================================== +! FREE_MEMORY_GEOMETRY deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_geometry() + + n_cells = 0 + n_universes = 0 + n_lattices = 0 + + if (allocated(cells)) deallocate(cells) + if (allocated(universes)) deallocate(universes) + if (allocated(lattices)) deallocate(lattices) + + call cell_dict % clear() + call universe_dict % clear() + call lattice_dict % clear() + + end subroutine free_memory_geometry + end module geometry_header diff --git a/src/material_header.F90 b/src/material_header.F90 index f80c36b5c..e55272cce 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -212,4 +212,14 @@ contains if (allocated(this % names)) deallocate(this % names) end subroutine material_assign_sab_tables +!=============================================================================== +! FREE_MEMORY_MATERIAL deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_material() + n_materials = 0 + if (allocated(materials)) deallocate(materials) + call material_dict % clear() + end subroutine free_memory_material + end module material_header diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 1bef22181..a7aa31b05 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -13,6 +13,7 @@ module mesh_header implicit none private + public :: free_memory_mesh public :: openmc_extend_meshes !=============================================================================== @@ -546,6 +547,16 @@ contains call close_group(mesh_group) end subroutine regular_to_hdf5 +!=============================================================================== +! FREE_MEMORY_MESH deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_mesh() + n_meshes = 0 + if (allocated(meshes)) deallocate(meshes) + call mesh_dict % clear() + end subroutine free_memory_mesh + !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index a00a3756d..b28239724 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -3551,4 +3551,15 @@ contains end subroutine find_angle +!=============================================================================== +! FREE_MEMORY_MGXS deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_mgxs() + if (allocated(nuclides_MG)) deallocate(nuclides_MG) + if (allocated(macro_xs)) deallocate(macro_xs) + if (allocated(energy_bins)) deallocate(energy_bins) + if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) + end subroutine free_memory_mgxs + end module mgxs_header diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 1ed2fee9e..efef69535 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -742,4 +742,28 @@ contains end subroutine nuclide_init_grid +!=============================================================================== +! FREE_MEMORY_NUCLIDE deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_nuclide() + integer :: i + + ! Deallocate cross section data, listings, and cache + if (allocated(nuclides)) then + ! First call the clear routines + do i = 1, size(nuclides) + call nuclides(i) % clear() + end do + deallocate(nuclides) + end if + n_nuclides = 0 + + if (allocated(libraries)) deallocate(libraries) + + call nuclide_dict % clear() + call library_dict % clear() + + end subroutine free_memory_nuclide + end module nuclide_header diff --git a/src/plot_header.F90 b/src/plot_header.F90 index 06b4919ad..1091bd73a 100644 --- a/src/plot_header.F90 +++ b/src/plot_header.F90 @@ -60,4 +60,16 @@ module plot_header ! Dictionary that maps user IDs to indices in 'plots' type(DictIntInt) :: plot_dict +contains + +!=============================================================================== +! FREE_MEMORY_PLOT deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_plot() + n_plots = 0 + if (allocated(plots)) deallocate(plots) + call plot_dict % clear() + end subroutine free_memory_plot + end module plot_header diff --git a/src/sab_header.F90 b/src/sab_header.F90 index 8e783a741..6dd617790 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -1,5 +1,6 @@ module sab_header + use, intrinsic :: ISO_C_BINDING use, intrinsic :: ISO_FORTRAN_ENV use algorithm, only: find, sort @@ -80,7 +81,7 @@ module sab_header ! S(a,b) tables type(SAlphaBeta), allocatable, target :: sab_tables(:) - integer :: n_sab_tables + integer(C_INT), bind(C) :: n_sab_tables type(DictCharInt) :: sab_dict contains @@ -359,4 +360,14 @@ contains call close_group(kT_group) end subroutine salphabeta_from_hdf5 +!=============================================================================== +! FREE_MEMORY_SAB deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_sab() + n_sab_tables = 0 + if (allocated(sab_tables)) deallocate(sab_tables) + call sab_dict % clear() + end subroutine free_memory_sab + end module sab_header diff --git a/src/settings.F90 b/src/settings.F90 index 10b7ea958..7e81872a0 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -138,4 +138,18 @@ module settings ! No reduction at end of batch logical :: reduce_tallies = .true. +contains + +!=============================================================================== +! FREE_MEMORY_SETTINGS deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_settings() + if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides) + if (allocated(track_identifiers)) deallocate(track_identifiers) + + call statepoint_batch % clear() + call sourcepoint_batch % clear() + end subroutine free_memory_settings + end module settings diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 3918307a1..cfb75b449 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -79,4 +79,17 @@ contains gen = gen_per_batch*(current_batch - 1) + current_gen end function overall_generation +!=============================================================================== +! FREE_MEMORY_SIMULATION deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_simulation() + if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) + if (allocated(k_generation)) deallocate(k_generation) + if (allocated(entropy)) deallocate(entropy) + if (allocated(entropy_p)) deallocate(entropy_p) + if (allocated(source_frac)) deallocate(source_frac) + if (allocated(work_index)) deallocate(work_index) + end subroutine free_memory_simulation + end module simulation_header diff --git a/src/source_header.F90 b/src/source_header.F90 index fa489853e..c664316c7 100644 --- a/src/source_header.F90 +++ b/src/source_header.F90 @@ -16,6 +16,7 @@ module source_header implicit none private + public :: free_memory_source integer :: n_accept = 0 ! Number of samples accepted integer :: n_reject = 0 ! Number of samples rejected @@ -293,6 +294,15 @@ contains end function sample +!=============================================================================== +! FREE_MEMORY_SOURCE deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_source() + n_sources = 0 + if (allocated(external_source)) deallocate(external_source) + end subroutine free_memory_source + !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/surface_header.F90 b/src/surface_header.F90 index d1c045233..ed4ef86e0 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -1060,4 +1060,14 @@ contains end associate end function quadric_normal +!=============================================================================== +! FREE_MEMORY_SURFACES deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_surfaces() + n_surfaces = 0 + if (allocated(surfaces)) deallocate(surfaces) + call surface_dict % clear() + end subroutine free_memory_surfaces + end module surface_header diff --git a/src/tallies/tally_derivative_header.F90 b/src/tallies/tally_derivative_header.F90 index 004db98ba..fcf4a203b 100644 --- a/src/tallies/tally_derivative_header.F90 +++ b/src/tallies/tally_derivative_header.F90 @@ -9,6 +9,7 @@ module tally_derivative_header implicit none private + public :: free_memory_tally_derivative !=============================================================================== ! TALLYDERIVATIVE describes a first-order derivative that can be applied to @@ -88,4 +89,14 @@ contains end subroutine from_xml +!=============================================================================== +! FREE_MEMORY_TALLY_DERIVATIVE deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_tally_derivative() +!$omp parallel + if (allocated(tally_derivs)) deallocate(tally_derivs) +!$omp end parallel + end subroutine free_memory_tally_derivative + end module tally_derivative_header diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index fa229d471..9ece9116a 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -13,6 +13,7 @@ module tally_filter_header implicit none private + public :: free_memory_tally_filter public :: openmc_extend_filters public :: openmc_filter_get_id public :: openmc_filter_set_id @@ -129,6 +130,16 @@ contains class(TallyFilter), intent(inout) :: this end subroutine filter_initialize +!=============================================================================== +! FREE_MEMORY_TALLY_FILTER deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_tally_filter() + n_filters = 0 + if (allocated(filters)) deallocate(filters) + call filter_dict % clear() + end subroutine free_memory_tally_filter + !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index f053e6cac..a1ba6288d 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -19,6 +19,7 @@ module tally_header implicit none private public :: configure_tallies + public :: free_memory_tally public :: openmc_extend_tallies public :: openmc_get_tally public :: openmc_tally_get_id @@ -387,6 +388,26 @@ contains end subroutine configure_tallies +!=============================================================================== +! FREE_MEMORY_TALLY deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_tally() + n_tallies = 0 + if (allocated(tallies)) deallocate(tallies) + call tally_dict % clear() + + if (allocated(global_tallies)) deallocate(global_tallies) + + ! Deallocate tally node lists + call active_analog_tallies % clear() + call active_tracklength_tallies % clear() + call active_current_tallies % clear() + call active_collision_tallies % clear() + call active_surface_tallies % clear() + call active_tallies % clear() + end subroutine free_memory_tally + !=============================================================================== ! C API FUNCTIONS !=============================================================================== diff --git a/src/volume_header.F90 b/src/volume_header.F90 index 13c3299bb..59a579a5f 100644 --- a/src/volume_header.F90 +++ b/src/volume_header.F90 @@ -58,4 +58,12 @@ contains call get_node_value(node_vol, "samples", this % samples) end subroutine volume_from_xml +!=============================================================================== +! FREE_MEMORY_VOLUME deallocates global arrays defined in this module +!=============================================================================== + + subroutine free_memory_volume() + if (allocated(volume_calcs)) deallocate(volume_calcs) + end subroutine free_memory_volume + end module volume_header From 9674f1ce2ecacd16ed6e0b7cebb4ed38fb389d0d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 19 Sep 2017 21:49:25 -0500 Subject: [PATCH 182/229] Move many procedures out of api.F90 into modules where they belong. Also move assign_0K_elastic_scattering and check_data_version to nuclide_header --- src/api.F90 | 453 ---------------------------------------- src/geometry_header.F90 | 128 ++++++++++++ src/input_xml.F90 | 82 +------- src/material_header.F90 | 213 ++++++++++++++++++- src/nuclide_header.F90 | 197 ++++++++++++++++- 5 files changed, 532 insertions(+), 541 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 4a2dc8b68..901dcaeb6 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -15,7 +15,6 @@ module openmc_api use message_passing use nuclide_header use initialize, only: openmc_init - use input_xml, only: assign_0K_elastic_scattering, check_data_version use particle_header, only: Particle use plot, only: openmc_plot_geometry use random_lcg, only: seed, initialize_prng @@ -78,116 +77,6 @@ module openmc_api contains -!=============================================================================== -! OPENMC_CELL_GET_ID returns the ID of a cell -!=============================================================================== - - function openmc_cell_get_id(index, id) result(err) bind(C) - integer(C_INT32_T), value :: index - integer(C_INT32_T), intent(out) :: id - integer(C_INT) :: err - - if (index >= 1 .and. index <= size(cells)) then - id = cells(index) % id - err = 0 - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_cell_get_id - -!=============================================================================== -! OPENMC_CELL_SET_TEMPERATURE sets the temperature of a cell -!=============================================================================== - - function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index ! cell index in cells - real(C_DOUBLE), value, intent(in) :: T ! temperature - integer(C_INT32_T), optional, intent(in) :: instance ! cell instance - - integer(C_INT) :: err ! error code - integer :: j ! looping variable - integer :: n ! number of cell instances - integer :: material_index ! material index in materials array - integer :: num_nuclides ! num nuclides in material - integer :: nuclide_index ! index of nuclide in nuclides array - real(8) :: min_temp ! min common-denominator avail temp - real(8) :: max_temp ! max common-denominator avail temp - real(8) :: temp ! actual temp we'll assign - logical :: outside_low ! lower than available data - logical :: outside_high ! higher than available data - - outside_low = .false. - outside_high = .false. - - err = E_UNASSIGNED - - if (index >= 1 .and. index <= size(cells)) then - - ! error if the cell is filled with another universe - if (cells(index) % fill /= NONE) then - err = E_CELL_NO_MATERIAL - else - ! find which material is associated with this cell (material_index - ! is the index into the materials array) - if (present(instance)) then - material_index = cells(index) % material(instance) - else - material_index = cells(index) % material(1) - end if - - ! number of nuclides associated with this material - num_nuclides = size(materials(material_index) % nuclide) - - min_temp = ZERO - max_temp = INFINITY - - do j = 1, num_nuclides - nuclide_index = materials(material_index) % nuclide(j) - min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs)) - max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs)) - end do - - ! adjust the temperature to be within bounds if necessary - if (K_BOLTZMANN * T < min_temp) then - outside_low = .true. - temp = min_temp / K_BOLTZMANN - else if (K_BOLTZMANN * T > max_temp) then - outside_high = .true. - temp = max_temp / K_BOLTZMANN - else - temp = T - end if - - associate (c => cells(index)) - if (allocated(c % sqrtkT)) then - n = size(c % sqrtkT) - if (present(instance) .and. n > 1) then - if (instance >= 0 .and. instance < n) then - c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp) - err = 0 - end if - else - c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp) - err = 0 - end if - end if - end associate - - ! Assign error codes for outside of temperature bounds provided the - ! temperature was changed correctly. This needs to be done after - ! changing the temperature based on the logical structure above. - if (err == 0) then - if (outside_low) err = W_BELOW_MIN_BOUND - if (outside_high) err = W_ABOVE_MAX_BOUND - end if - - end if - - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_cell_set_temperature - !=============================================================================== ! OPENMC_FINALIZE frees up memory by deallocating arrays and resetting global ! variables @@ -309,76 +198,6 @@ contains end function openmc_find -!=============================================================================== -! OPENMC_GET_CELL returns the index in the cells array of a cell with a given ID -!=============================================================================== - - function openmc_get_cell(id, index) result(err) bind(C) - integer(C_INT32_T), value :: id - integer(C_INT32_T), intent(out) :: index - integer(C_INT) :: err - - if (allocated(cells)) then - if (cell_dict % has_key(id)) then - index = cell_dict % get_key(id) - err = 0 - else - err = E_CELL_INVALID_ID - end if - else - err = E_CELL_NOT_ALLOCATED - end if - end function openmc_get_cell - -!=============================================================================== -! OPENMC_GET_MATERIAL returns the index in the materials array of a material -! with a given ID -!=============================================================================== - - function openmc_get_material(id, index) result(err) bind(C) - integer(C_INT32_T), value :: id - integer(C_INT32_T), intent(out) :: index - integer(C_INT) :: err - - if (allocated(materials)) then - if (material_dict % has_key(id)) then - index = material_dict % get_key(id) - err = 0 - else - err = E_MATERIAL_INVALID_ID - end if - else - err = E_MATERIAL_NOT_ALLOCATED - end if - end function openmc_get_material - -!=============================================================================== -! OPENMC_GET_NUCLIDE returns the index in the nuclides array of a nuclide -! with a given name -!=============================================================================== - - function openmc_get_nuclide(name, index) result(err) bind(C) - character(kind=C_CHAR), intent(in) :: name(*) - integer(C_INT), intent(out) :: index - integer(C_INT) :: err - - character(:), allocatable :: name_ - - ! Copy array of C_CHARs to normal Fortran string - name_ = to_f_string(name) - - if (allocated(nuclides)) then - if (nuclide_dict % has_key(to_lower(name_))) then - index = nuclide_dict % get_key(to_lower(name_)) - err = 0 - else - err = E_NUCLIDE_NOT_LOADED - end if - else - err = E_NUCLIDE_NOT_ALLOCATED - end if - end function openmc_get_nuclide - !=============================================================================== ! OPENMC_HARD_RESET reset tallies and timers as well as the pseudorandom ! generator state @@ -397,278 +216,6 @@ contains call initialize_prng() end subroutine openmc_hard_reset -!=============================================================================== -! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library -!=============================================================================== - - function openmc_load_nuclide(name) result(err) bind(C) - character(kind=C_CHAR), intent(in) :: name(*) - integer(C_INT) :: err - - integer :: i_library - integer :: n - integer(HID_T) :: file_id - integer(HID_T) :: group_id - character(:), allocatable :: name_ - real(8) :: minmax(2) = [ZERO, INFINITY] - type(VectorReal) :: temperature - type(Nuclide), allocatable :: new_nuclides(:) - - ! Copy array of C_CHARs to normal Fortran string - name_ = to_f_string(name) - - err = 0 - if (.not. nuclide_dict % has_key(to_lower(name_))) then - if (library_dict % has_key(to_lower(name_))) then - ! allocate extra space in nuclides array - n = n_nuclides - allocate(new_nuclides(n + 1)) - new_nuclides(1:n) = nuclides(:) - call move_alloc(FROM=new_nuclides, TO=nuclides) - n = n + 1 - - i_library = library_dict % get_key(to_lower(name_)) - - ! Open file and make sure version is sufficient - file_id = file_open(libraries(i_library) % path, 'r') - call check_data_version(file_id) - - ! Read nuclide data from HDF5 - group_id = open_group(file_id, name_) - call nuclides(n) % from_hdf5(group_id, temperature, & - temperature_method, temperature_tolerance, minmax, & - master) - call close_group(group_id) - call file_close(file_id) - - ! Add entry to nuclide dictionary - call nuclide_dict % add_key(to_lower(name_), n) - n_nuclides = n - - ! Assign resonant scattering data - if (res_scat_on) call assign_0K_elastic_scattering(nuclides(n)) - - ! Initialize nuclide grid - call nuclides(n) % init_grid(energy_min_neutron, & - energy_max_neutron, n_log_bins) - else - err = E_NUCLIDE_NOT_IN_LIBRARY - end if - end if - - end function openmc_load_nuclide - -!=============================================================================== -! OPENMC_MATERIAL_ADD_NUCLIDE -!=============================================================================== - - function openmc_material_add_nuclide(index, name, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index - character(kind=C_CHAR) :: name(*) - real(C_DOUBLE), value, intent(in) :: density - integer(C_INT) :: err - - integer :: j, k, n - real(8) :: awr - integer, allocatable :: new_nuclide(:) - real(8), allocatable :: new_density(:) - character(:), allocatable :: name_ - - name_ = to_f_string(name) - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(materials)) then - associate (m => materials(index)) - ! Check if nuclide is already in material - do j = 1, size(m % nuclide) - k = m % nuclide(j) - if (nuclides(k) % name == name_) then - awr = nuclides(k) % awr - m % density = m % density + density - m % atom_density(j) - m % density_gpcc = m % density_gpcc + (density - & - m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO - m % atom_density(j) = density - err = 0 - end if - end do - - ! If nuclide wasn't found, extend nuclide/density arrays - if (err /= 0) then - ! If nuclide hasn't been loaded, load it now - err = openmc_load_nuclide(name) - - if (err == 0) then - ! Extend arrays - n = size(m % nuclide) - allocate(new_nuclide(n + 1)) - new_nuclide(1:n) = m % nuclide - call move_alloc(FROM=new_nuclide, TO=m % nuclide) - - allocate(new_density(n + 1)) - new_density(1:n) = m % atom_density - call move_alloc(FROM=new_density, TO=m % atom_density) - - ! Append new nuclide/density - k = nuclide_dict % get_key(to_lower(name_)) - m % nuclide(n + 1) = k - m % atom_density(n + 1) = density - m % density = m % density + density - m % density_gpcc = m % density_gpcc + & - density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO - m % n_nuclides = n + 1 - end if - end if - end associate - else - err = E_OUT_OF_BOUNDS - end if - - end function openmc_material_add_nuclide - -!=============================================================================== -! OPENMC_MATERIAL_GET_DENSITIES returns an array of nuclide densities in a -! material -!=============================================================================== - - function openmc_material_get_densities(index, nuclides, densities, n) & - result(err) bind(C) - integer(C_INT32_T), value :: index - type(C_PTR), intent(out) :: nuclides - type(C_PTR), intent(out) :: densities - integer(C_INT), intent(out) :: n - integer(C_INT) :: err - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(materials)) then - associate (m => materials(index)) - if (allocated(m % atom_density)) then - nuclides = C_LOC(m % nuclide(1)) - densities = C_LOC(m % atom_density(1)) - n = size(m % atom_density) - err = 0 - end if - end associate - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_material_get_densities - -!=============================================================================== -! OPENMC_MATERIAL_GET_ID returns the ID of a material -!=============================================================================== - - function openmc_material_get_id(index, id) result(err) bind(C) - integer(C_INT32_T), value :: index - integer(C_INT32_T), intent(out) :: id - integer(C_INT) :: err - - if (index >= 1 .and. index <= size(materials)) then - id = materials(index) % id - err = 0 - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_material_get_id - -!=============================================================================== -! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm -!=============================================================================== - - function openmc_material_set_density(index, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index - real(C_DOUBLE), value, intent(in) :: density - integer(C_INT) :: err - - err = E_UNASSIGNED - if (index >= 1 .and. index <= size(materials)) then - associate (m => materials(index)) - err = m % set_density(density) - end associate - else - err = E_OUT_OF_BOUNDS - end if - end function openmc_material_set_density - -!=============================================================================== -! OPENMC_MATERIAL_SET_DENSITIES sets the densities for a list of nuclides in a -! material. If the nuclides don't already exist in the material, they will be -! added -!=============================================================================== - - function openmc_material_set_densities(index, n, name, density) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index - integer(C_INT), value, intent(in) :: n - type(C_PTR), intent(in) :: name(n) - real(C_DOUBLE), intent(in) :: density(n) - integer(C_INT) :: err - - integer :: i - character(C_CHAR), pointer :: string(:) - character(len=:, kind=C_CHAR), allocatable :: name_ - - if (index >= 1 .and. index <= size(materials)) then - associate (m => materials(index)) - ! If nuclide/density arrays are not correct size, reallocate - if (n /= size(m % nuclide)) then - deallocate(m % nuclide, m % atom_density, m % p0) - allocate(m % nuclide(n), m % atom_density(n), m % p0(n)) - end if - - do i = 1, n - ! Convert C string to Fortran string - call c_f_pointer(name(i), string, [10]) - name_ = to_lower(to_f_string(string)) - - if (.not. nuclide_dict % has_key(name_)) then - err = openmc_load_nuclide(string) - if (err < 0) return - end if - - m % nuclide(i) = nuclide_dict % get_key(name_) - m % atom_density(i) = density(i) - end do - m % n_nuclides = n - - ! Set isotropic flags to flags - m % p0(:) = .false. - - ! Set total density to the sum of the vector - err = m % set_density(sum(density)) - - ! Assign S(a,b) tables - call m % assign_sab_tables() - end associate - else - err = E_OUT_OF_BOUNDS - end if - - end function openmc_material_set_densities - -!=============================================================================== -! OPENMC_NUCLIDE_NAME returns the name of a nuclide with a given index -!=============================================================================== - - function openmc_nuclide_name(index, name) result(err) bind(C) - integer(C_INT), value, intent(in) :: index - type(c_ptr), intent(out) :: name - integer(C_INT) :: err - - character(C_CHAR), pointer :: name_ - - err = E_UNASSIGNED - if (allocated(nuclides)) then - if (index >= 1 .and. index <= size(nuclides)) then - name_ => nuclides(index) % name(1:1) - name = C_LOC(name_) - err = 0 - else - err = E_OUT_OF_BOUNDS - end if - else - err = E_NUCLIDE_NOT_ALLOCATED - end if - end function openmc_nuclide_name - !=============================================================================== ! OPENMC_RESET resets tallies and timers !=============================================================================== diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 5a5cf2c26..aaea8aa5b 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -422,4 +422,132 @@ contains end subroutine free_memory_geometry +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_get_cell(id, index) result(err) bind(C) + ! Return the index in the cells array of a cell with a given ID + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(cells)) then + if (cell_dict % has_key(id)) then + index = cell_dict % get_key(id) + err = 0 + else + err = E_CELL_INVALID_ID + end if + else + err = E_CELL_NOT_ALLOCATED + end if + end function openmc_get_cell + + + function openmc_cell_get_id(index, id) result(err) bind(C) + ! Return the ID of a cell + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(cells)) then + id = cells(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_cell_get_id + + + function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) + ! Set the temperature of a cell + integer(C_INT32_T), value, intent(in) :: index ! cell index in cells + real(C_DOUBLE), value, intent(in) :: T ! temperature + integer(C_INT32_T), optional, intent(in) :: instance ! cell instance + + integer(C_INT) :: err ! error code + integer :: j ! looping variable + integer :: n ! number of cell instances + integer :: material_index ! material index in materials array + integer :: num_nuclides ! num nuclides in material + integer :: nuclide_index ! index of nuclide in nuclides array + real(8) :: min_temp ! min common-denominator avail temp + real(8) :: max_temp ! max common-denominator avail temp + real(8) :: temp ! actual temp we'll assign + logical :: outside_low ! lower than available data + logical :: outside_high ! higher than available data + + outside_low = .false. + outside_high = .false. + + err = E_UNASSIGNED + + if (index >= 1 .and. index <= size(cells)) then + + ! error if the cell is filled with another universe + if (cells(index) % fill /= NONE) then + err = E_CELL_NO_MATERIAL + else + ! find which material is associated with this cell (material_index + ! is the index into the materials array) + if (present(instance)) then + material_index = cells(index) % material(instance) + else + material_index = cells(index) % material(1) + end if + + ! number of nuclides associated with this material + num_nuclides = size(materials(material_index) % nuclide) + + min_temp = ZERO + max_temp = INFINITY + + do j = 1, num_nuclides + nuclide_index = materials(material_index) % nuclide(j) + min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs)) + max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs)) + end do + + ! adjust the temperature to be within bounds if necessary + if (K_BOLTZMANN * T < min_temp) then + outside_low = .true. + temp = min_temp / K_BOLTZMANN + else if (K_BOLTZMANN * T > max_temp) then + outside_high = .true. + temp = max_temp / K_BOLTZMANN + else + temp = T + end if + + associate (c => cells(index)) + if (allocated(c % sqrtkT)) then + n = size(c % sqrtkT) + if (present(instance) .and. n > 1) then + if (instance >= 0 .and. instance < n) then + c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp) + err = 0 + end if + else + c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp) + err = 0 + end if + end if + end associate + + ! Assign error codes for outside of temperature bounds provided the + ! temperature was changed correctly. This needs to be done after + ! changing the temperature based on the logical structure above. + if (err == 0) then + if (outside_low) err = W_BELOW_MIN_BOUND + if (outside_high) err = W_ABOVE_MAX_BOUND + end if + + end if + + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_cell_set_temperature + end module geometry_header diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7bc345da4..545c7e351 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -22,6 +22,7 @@ module input_xml use mgxs_data, only: create_macro_xs, read_mgxs use mgxs_header use multipole, only: multipole_read + use nuclide_header use output, only: write_message, title, header, print_plot use plot_header use random_lcg, only: prn, seed, initialize_prng @@ -4455,7 +4456,7 @@ contains call file_close(file_id) ! Assign resonant scattering data - if (res_scat_on) call assign_0K_elastic_scattering(nuclides(i_nuclide)) + if (res_scat_on) call nuclides(i_nuclide) % assign_0K_elastic_scattering() ! Determine if minimum/maximum energy for this nuclide is greater/less ! than the previous @@ -4590,60 +4591,6 @@ contains end do end subroutine assign_temperatures -!=============================================================================== -! ASSIGN_0K_ELASTIC_SCATTERING -!=============================================================================== - - subroutine assign_0K_elastic_scattering(nuc) - type(Nuclide), intent(inout) :: nuc - - integer :: i - real(8) :: xs_cdf_sum - - nuc % resonant = .false. - if (allocated(res_scat_nuclides)) then - ! If resonant nuclides were specified, check the list explicitly - do i = 1, size(res_scat_nuclides) - if (nuc % name == res_scat_nuclides(i)) then - nuc % resonant = .true. - - ! Make sure nuclide has 0K data - if (.not. allocated(nuc % energy_0K)) then - call fatal_error("Cannot treat " // trim(nuc % name) // " as a & - &resonant scatterer because 0 K elastic scattering data is & - ¬ present.") - end if - - exit - end if - end do - else - ! Otherwise, assume that any that have 0 K elastic scattering data are - ! resonant - nuc % resonant = allocated(nuc % energy_0K) - end if - - if (nuc % resonant) then - ! Build CDF for 0K elastic scattering - xs_cdf_sum = ZERO - allocate(nuc % xs_cdf(0:size(nuc % energy_0K))) - nuc % xs_cdf(0) = ZERO - - associate (E => nuc % energy_0K, xs => nuc % elastic_0K) - do i = 1, size(E) - 1 - ! Negative cross sections result in a CDF that is not monotonically - ! increasing. Set all negative xs values to zero. - if (xs(i) < ZERO) xs(i) = ZERO - - ! build xs cdf - xs_cdf_sum = xs_cdf_sum + (sqrt(E(i))*xs(i) + sqrt(E(i+1))*xs(i+1))& - / TWO * (E(i+1) - E(i)) - nuc % xs_cdf(i) = xs_cdf_sum - end do - end associate - end if - end subroutine assign_0K_elastic_scattering - !=============================================================================== ! READ_MULTIPOLE_DATA checks for the existence of a multipole library in the ! directory and loads it using multipole_read @@ -4693,31 +4640,6 @@ contains end subroutine read_multipole_data -!=============================================================================== -! CHECK_DATA_VERSION checks for the right version of nuclear data within HDF5 -! files -!=============================================================================== - - subroutine check_data_version(file_id) - integer(HID_T), intent(in) :: file_id - - integer, allocatable :: version(:) - - if (attribute_exists(file_id, 'version')) then - call read_attribute(version, file_id, 'version') - if (version(1) /= HDF5_VERSION(1)) then - call fatal_error("HDF5 data format uses version " // trim(to_str(& - version(1))) // "." // trim(to_str(version(2))) // " whereas & - &your installation of OpenMC expects version " // trim(to_str(& - HDF5_VERSION(1))) // ".x data.") - end if - else - call fatal_error("HDF5 data does not indicate a version. Your & - &installation of OpenMC expects version " // trim(to_str(& - HDF5_VERSION(1))) // ".x data.") - end if - end subroutine check_data_version - !=============================================================================== ! ADJUST_INDICES changes the values for 'surfaces' for each cell and the ! material index assigned to each to the indices in the surfaces and material diff --git a/src/material_header.F90 b/src/material_header.F90 index e55272cce..e716247fe 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -12,11 +12,20 @@ module material_header implicit none + private + public :: free_memory_material + public :: openmc_get_material + public :: openmc_material_add_nuclide + public :: openmc_material_get_id + public :: openmc_material_get_densities + public :: openmc_material_set_density + public :: openmc_material_set_densities + !=============================================================================== ! MATERIAL describes a material by its constituent nuclides !=============================================================================== - type Material + type, public :: Material integer :: id ! unique identifier character(len=104) :: name = "" ! User-defined name integer :: n_nuclides ! number of nuclides @@ -54,12 +63,12 @@ module material_header procedure :: assign_sab_tables => material_assign_sab_tables end type Material - integer(C_INT32_T), bind(C) :: n_materials ! # of materials + integer(C_INT32_T), public, bind(C) :: n_materials ! # of materials - type(Material), allocatable, target :: materials(:) + type(Material), public, allocatable, target :: materials(:) ! Dictionary that maps user IDs to indices in 'materials' - type(DictIntInt) :: material_dict + type(DictIntInt), public :: material_dict contains @@ -222,4 +231,200 @@ contains call material_dict % clear() end subroutine free_memory_material +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_get_material(id, index) result(err) bind(C) + ! Returns the index in the materials array of a material with a given ID + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(materials)) then + if (material_dict % has_key(id)) then + index = material_dict % get_key(id) + err = 0 + else + err = E_MATERIAL_INVALID_ID + end if + else + err = E_MATERIAL_NOT_ALLOCATED + end if + end function openmc_get_material + + + function openmc_material_add_nuclide(index, name, density) result(err) bind(C) + ! Add a nuclide at a specified density in atom/b-cm to a material + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR) :: name(*) + real(C_DOUBLE), value, intent(in) :: density + integer(C_INT) :: err + + integer :: j, k, n + real(8) :: awr + integer, allocatable :: new_nuclide(:) + real(8), allocatable :: new_density(:) + character(:), allocatable :: name_ + + name_ = to_f_string(name) + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + ! Check if nuclide is already in material + do j = 1, size(m % nuclide) + k = m % nuclide(j) + if (nuclides(k) % name == name_) then + awr = nuclides(k) % awr + m % density = m % density + density - m % atom_density(j) + m % density_gpcc = m % density_gpcc + (density - & + m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO + m % atom_density(j) = density + err = 0 + end if + end do + + ! If nuclide wasn't found, extend nuclide/density arrays + if (err /= 0) then + ! If nuclide hasn't been loaded, load it now + err = openmc_load_nuclide(name) + + if (err == 0) then + ! Extend arrays + n = size(m % nuclide) + allocate(new_nuclide(n + 1)) + new_nuclide(1:n) = m % nuclide + call move_alloc(FROM=new_nuclide, TO=m % nuclide) + + allocate(new_density(n + 1)) + new_density(1:n) = m % atom_density + call move_alloc(FROM=new_density, TO=m % atom_density) + + ! Append new nuclide/density + k = nuclide_dict % get_key(to_lower(name_)) + m % nuclide(n + 1) = k + m % atom_density(n + 1) = density + m % density = m % density + density + m % density_gpcc = m % density_gpcc + & + density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO + m % n_nuclides = n + 1 + end if + end if + end associate + else + err = E_OUT_OF_BOUNDS + end if + + end function openmc_material_add_nuclide + + + function openmc_material_get_densities(index, nuclides, densities, n) & + result(err) bind(C) + ! returns an array of nuclide densities in a material + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: nuclides + type(C_PTR), intent(out) :: densities + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + if (allocated(m % atom_density)) then + nuclides = C_LOC(m % nuclide(1)) + densities = C_LOC(m % atom_density(1)) + n = size(m % atom_density) + err = 0 + end if + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_get_densities + + + function openmc_material_get_id(index, id) result(err) bind(C) + ! returns the ID of a material + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(materials)) then + id = materials(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_get_id + + + function openmc_material_set_density(index, density) result(err) bind(C) + ! Set the total density of a material in atom/b-cm + integer(C_INT32_T), value, intent(in) :: index + real(C_DOUBLE), value, intent(in) :: density + integer(C_INT) :: err + + err = E_UNASSIGNED + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + err = m % set_density(density) + end associate + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_material_set_density + + + function openmc_material_set_densities(index, n, name, density) result(err) bind(C) + ! Sets the densities for a list of nuclides in a material. If the nuclides + ! don't already exist in the material, they will be added + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), value, intent(in) :: n + type(C_PTR), intent(in) :: name(n) + real(C_DOUBLE), intent(in) :: density(n) + integer(C_INT) :: err + + integer :: i + character(C_CHAR), pointer :: string(:) + character(len=:, kind=C_CHAR), allocatable :: name_ + + if (index >= 1 .and. index <= size(materials)) then + associate (m => materials(index)) + ! If nuclide/density arrays are not correct size, reallocate + if (n /= size(m % nuclide)) then + deallocate(m % nuclide, m % atom_density, m % p0) + allocate(m % nuclide(n), m % atom_density(n), m % p0(n)) + end if + + do i = 1, n + ! Convert C string to Fortran string + call c_f_pointer(name(i), string, [10]) + name_ = to_lower(to_f_string(string)) + + if (.not. nuclide_dict % has_key(name_)) then + err = openmc_load_nuclide(string) + if (err < 0) return + end if + + m % nuclide(i) = nuclide_dict % get_key(name_) + m % atom_density(i) = density(i) + end do + m % n_nuclides = n + + ! Set isotropic flags to flags + m % p0(:) = .false. + + ! Set total density to the sum of the vector + err = m % set_density(sum(density)) + + ! Assign S(a,b) tables + call m % assign_sab_tables() + end associate + else + err = E_OUT_OF_BOUNDS + end if + + end function openmc_material_set_densities + end module material_header diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index efef69535..a2f3d5022 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -10,16 +10,16 @@ module nuclide_header use dict_header, only: DictIntInt, DictCharInt use endf, only: reaction_name, is_fission, is_disappearance use endf_header, only: Function1D, Polynomial, Tabulated1D - use error, only: fatal_error, warning - use hdf5_interface, only: read_attribute, open_group, close_group, & - open_dataset, read_dataset, close_dataset, get_shape, get_datasets, & - object_exists, get_name, get_groups + use error + use hdf5_interface use list_header, only: ListInt use math, only: evaluate_legendre + use message_passing use multipole_header, only: MultipoleArray use product_header, only: AngleEnergyContainer use reaction_header, only: Reaction use secondary_uncorrelated, only: UncorrelatedAngleEnergy + use settings use stl_vector, only: VectorInt, VectorReal use string use urr_header, only: UrrData @@ -95,6 +95,7 @@ module nuclide_header class(Function1D), allocatable :: fission_q_recov ! neutrons, gammas, betas contains + procedure :: assign_0K_elastic_scattering procedure :: clear => nuclide_clear procedure :: from_hdf5 => nuclide_from_hdf5 procedure :: init_grid => nuclide_init_grid @@ -177,6 +178,60 @@ module nuclide_header contains +!=============================================================================== +! ASSIGN_0K_ELASTIC_SCATTERING +!=============================================================================== + + subroutine assign_0K_elastic_scattering(this) + class(Nuclide), intent(inout) :: this + + integer :: i + real(8) :: xs_cdf_sum + + this % resonant = .false. + if (allocated(res_scat_nuclides)) then + ! If resonant nuclides were specified, check the list explicitly + do i = 1, size(res_scat_nuclides) + if (this % name == res_scat_nuclides(i)) then + this % resonant = .true. + + ! Make sure nuclide has 0K data + if (.not. allocated(this % energy_0K)) then + call fatal_error("Cannot treat " // trim(this % name) // " as a & + &resonant scatterer because 0 K elastic scattering data is & + ¬ present.") + end if + + exit + end if + end do + else + ! Otherwise, assume that any that have 0 K elastic scattering data are + ! resonant + this % resonant = allocated(this % energy_0K) + end if + + if (this % resonant) then + ! Build CDF for 0K elastic scattering + xs_cdf_sum = ZERO + allocate(this % xs_cdf(0:size(this % energy_0K))) + this % xs_cdf(0) = ZERO + + associate (E => this % energy_0K, xs => this % elastic_0K) + do i = 1, size(E) - 1 + ! Negative cross sections result in a CDF that is not monotonically + ! increasing. Set all negative xs values to zero. + if (xs(i) < ZERO) xs(i) = ZERO + + ! build xs cdf + xs_cdf_sum = xs_cdf_sum + (sqrt(E(i))*xs(i) + sqrt(E(i+1))*xs(i+1))& + / TWO * (E(i+1) - E(i)) + this % xs_cdf(i) = xs_cdf_sum + end do + end associate + end if + end subroutine assign_0K_elastic_scattering + !=============================================================================== ! NUCLIDE_CLEAR resets and deallocates data in Nuclide !=============================================================================== @@ -742,6 +797,31 @@ contains end subroutine nuclide_init_grid +!=============================================================================== +! CHECK_DATA_VERSION checks for the right version of nuclear data within HDF5 +! files +!=============================================================================== + + subroutine check_data_version(file_id) + integer(HID_T), intent(in) :: file_id + + integer, allocatable :: version(:) + + if (attribute_exists(file_id, 'version')) then + call read_attribute(version, file_id, 'version') + if (version(1) /= HDF5_VERSION(1)) then + call fatal_error("HDF5 data format uses version " // trim(to_str(& + version(1))) // "." // trim(to_str(version(2))) // " whereas & + &your installation of OpenMC expects version " // trim(to_str(& + HDF5_VERSION(1))) // ".x data.") + end if + else + call fatal_error("HDF5 data does not indicate a version. Your & + &installation of OpenMC expects version " // trim(to_str(& + HDF5_VERSION(1))) // ".x data.") + end if + end subroutine check_data_version + !=============================================================================== ! FREE_MEMORY_NUCLIDE deallocates global arrays defined in this module !=============================================================================== @@ -766,4 +846,113 @@ contains end subroutine free_memory_nuclide +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_get_nuclide(name, index) result(err) bind(C) + ! Return the index in the nuclides array of a nuclide with a given name + character(kind=C_CHAR), intent(in) :: name(*) + integer(C_INT), intent(out) :: index + integer(C_INT) :: err + + character(:), allocatable :: name_ + + ! Copy array of C_CHARs to normal Fortran string + name_ = to_f_string(name) + + if (allocated(nuclides)) then + if (nuclide_dict % has_key(to_lower(name_))) then + index = nuclide_dict % get_key(to_lower(name_)) + err = 0 + else + err = E_NUCLIDE_NOT_LOADED + end if + else + err = E_NUCLIDE_NOT_ALLOCATED + end if + end function openmc_get_nuclide + + + function openmc_load_nuclide(name) result(err) bind(C) + ! Load a nuclide from the cross section library + character(kind=C_CHAR), intent(in) :: name(*) + integer(C_INT) :: err + + integer :: i_library + integer :: n + integer(HID_T) :: file_id + integer(HID_T) :: group_id + character(:), allocatable :: name_ + real(8) :: minmax(2) = [ZERO, INFINITY] + type(VectorReal) :: temperature + type(Nuclide), allocatable :: new_nuclides(:) + + ! Copy array of C_CHARs to normal Fortran string + name_ = to_f_string(name) + + err = 0 + if (.not. nuclide_dict % has_key(to_lower(name_))) then + if (library_dict % has_key(to_lower(name_))) then + ! allocate extra space in nuclides array + n = n_nuclides + allocate(new_nuclides(n + 1)) + new_nuclides(1:n) = nuclides(:) + call move_alloc(FROM=new_nuclides, TO=nuclides) + n = n + 1 + + i_library = library_dict % get_key(to_lower(name_)) + + ! Open file and make sure version is sufficient + file_id = file_open(libraries(i_library) % path, 'r') + call check_data_version(file_id) + + ! Read nuclide data from HDF5 + group_id = open_group(file_id, name_) + call nuclides(n) % from_hdf5(group_id, temperature, & + temperature_method, temperature_tolerance, minmax, & + master) + call close_group(group_id) + call file_close(file_id) + + ! Add entry to nuclide dictionary + call nuclide_dict % add_key(to_lower(name_), n) + n_nuclides = n + + ! Assign resonant scattering data + if (res_scat_on) call nuclides(n) % assign_0K_elastic_scattering() + + ! Initialize nuclide grid + call nuclides(n) % init_grid(energy_min_neutron, & + energy_max_neutron, n_log_bins) + else + err = E_NUCLIDE_NOT_IN_LIBRARY + end if + end if + + end function openmc_load_nuclide + + + function openmc_nuclide_name(index, name) result(err) bind(C) + ! Return the name of a nuclide with a given index + integer(C_INT), value, intent(in) :: index + type(c_ptr), intent(out) :: name + integer(C_INT) :: err + + character(C_CHAR), pointer :: name_ + + err = E_UNASSIGNED + if (allocated(nuclides)) then + if (index >= 1 .and. index <= size(nuclides)) then + name_ => nuclides(index) % name(1:1) + name = C_LOC(name_) + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + else + err = E_NUCLIDE_NOT_ALLOCATED + end if + end function openmc_nuclide_name + end module nuclide_header From 0d67240f2f2ca9fac67e8c2faae338e855d0829e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 22 Sep 2017 10:16:39 -0500 Subject: [PATCH 183/229] Wrap yield in run_in_memory @contextmanager in a try/finally --- openmc/capi/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index fe5416dd6..4302a94f4 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -153,5 +153,7 @@ def run_in_memory(intracomm=None): """ init(intracomm) - yield - finalize() + try: + yield + finally: + finalize() From f4f344bd51c9395cb28a5c043f80bf749af34c97 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 26 Sep 2017 23:02:43 -0500 Subject: [PATCH 184/229] Rename openmc_get_* to openmc_get_*_index --- docs/source/capi/index.rst | 8 ++++---- openmc/capi/cell.py | 8 ++++---- openmc/capi/filter.py | 8 ++++---- openmc/capi/material.py | 8 ++++---- openmc/capi/nuclide.py | 8 ++++---- openmc/capi/tally.py | 8 ++++---- src/api.F90 | 9 +++++---- src/geometry_header.F90 | 4 ++-- src/material_header.F90 | 6 +++--- src/nuclide_header.F90 | 4 ++-- src/tallies/tally_filter_header.F90 | 5 +++-- src/tallies/tally_header.F90 | 6 +++--- 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index bc94fd6a0..581f358d4 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -52,7 +52,7 @@ C API cell that was found and zero otherwise. :type instance: int32_t* -.. c:function:: int openmc_get_cell(int32_t id, int32_t* index) +.. c:function:: int openmc_get_cell_index(int32_t id, int32_t* index) Get the index in the cells array for a cell with a given ID @@ -70,7 +70,7 @@ C API :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_get_nuclide(char name[], int* index) +.. c:function:: int openmc_get_nuclide_index(char name[], int* index) Get the index in the nuclides array for a nuclide with a given name @@ -81,7 +81,7 @@ C API :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_get_tally(int32_t id, int32_t* index) +.. c:function:: int openmc_get_tally_index(int32_t id, int32_t* index) Get the index in the tallies array for a tally with a given ID @@ -92,7 +92,7 @@ C API :return: Return status (negative if an error occurs) :rtype: int -.. c:function:: int openmc_get_material(int32_t id, int32_t* index) +.. c:function:: int openmc_get_material_index(int32_t id, int32_t* index) Get the index in the materials array for a material with a given ID diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index f519d2f6d..3e767caf3 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -17,9 +17,9 @@ _dll.openmc_cell_set_temperature.argtypes = [ c_int32, c_double, POINTER(c_int32)] _dll.openmc_cell_set_temperature.restype = c_int _dll.openmc_cell_set_temperature.errcheck = _error_handler -_dll.openmc_get_cell.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_cell.restype = c_int -_dll.openmc_get_cell.errcheck = _error_handler +_dll.openmc_get_cell_index.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_cell_index.restype = c_int +_dll.openmc_get_cell_index.errcheck = _error_handler class CellView(object): @@ -74,7 +74,7 @@ class CellView(object): class _CellMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_cell(key, index) + _dll.openmc_get_cell_index(key, index) return CellView(index.value) def __iter__(self): diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 0bcab1110..28d95a37c 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -41,9 +41,9 @@ _dll.openmc_filter_set_id.errcheck = _error_handler _dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_set_type.restype = c_int _dll.openmc_filter_set_type.errcheck = _error_handler -_dll.openmc_get_filter.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_filter.restype = c_int -_dll.openmc_get_filter.errcheck = _error_handler +_dll.openmc_get_filter_index.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_filter_index.restype = c_int +_dll.openmc_get_filter_index.errcheck = _error_handler _dll.openmc_material_filter_get_bins.argtypes = [ c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_material_filter_get_bins.restype = c_int @@ -205,7 +205,7 @@ def _get_filter(index): class _FilterMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_filter(key, index) + _dll.openmc_get_filter_index(key, index) return _get_filter(index.value) def __iter__(self): diff --git a/openmc/capi/material.py b/openmc/capi/material.py index d07d7aa8a..728caa356 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -12,9 +12,9 @@ from .error import _error_handler __all__ = ['MaterialView', 'materials'] # Material functions -_dll.openmc_get_material.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_material.restype = c_int -_dll.openmc_get_material.errcheck = _error_handler +_dll.openmc_get_material_index.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_material_index.restype = c_int +_dll.openmc_get_material_index.errcheck = _error_handler _dll.openmc_material_add_nuclide.argtypes = [ c_int32, c_char_p, c_double] _dll.openmc_material_add_nuclide.restype = c_int @@ -157,7 +157,7 @@ class MaterialView(object): class _MaterialMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_material(key, index) + _dll.openmc_get_material_index(key, index) return MaterialView(index.value) def __iter__(self): diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 4c6248d6b..26a98e32e 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -12,9 +12,9 @@ from .error import _error_handler __all__ = ['NuclideView', 'nuclides', 'load_nuclide'] # Nuclide functions -_dll.openmc_get_nuclide.argtypes = [c_char_p, POINTER(c_int)] -_dll.openmc_get_nuclide.restype = c_int -_dll.openmc_get_nuclide.errcheck = _error_handler +_dll.openmc_get_nuclide_index.argtypes = [c_char_p, POINTER(c_int)] +_dll.openmc_get_nuclide_index.restype = c_int +_dll.openmc_get_nuclide_index.errcheck = _error_handler _dll.openmc_load_nuclide.argtypes = [c_char_p] _dll.openmc_load_nuclide.restype = c_int _dll.openmc_load_nuclide.errcheck = _error_handler @@ -80,7 +80,7 @@ class _NuclideMapping(Mapping): """Provide mapping from nuclide name to index in nuclides array.""" def __getitem__(self, key): index = c_int() - _dll.openmc_get_nuclide(key.encode(), index) + _dll.openmc_get_nuclide_index(key.encode(), index) return NuclideView(index) def __iter__(self): diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 6a62fb8bd..3d056c283 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -12,9 +12,9 @@ from .filter import _get_filter __all__ = ['TallyView', 'tallies'] # Tally functions -_dll.openmc_get_tally.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_get_tally.restype = c_int -_dll.openmc_get_tally.errcheck = _error_handler +_dll.openmc_get_tally_index.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_tally_index.restype = c_int +_dll.openmc_get_tally_index.errcheck = _error_handler _dll.openmc_extend_tallies.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_extend_tallies.restype = c_int _dll.openmc_extend_tallies.errcheck = _error_handler @@ -152,7 +152,7 @@ class TallyView(object): class _TallyMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_tally(key, index) + _dll.openmc_get_tally_index(key, index) return TallyView(index.value) def __iter__(self): diff --git a/src/api.F90 b/src/api.F90 index 901dcaeb6..c451920ac 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -45,11 +45,12 @@ module openmc_api public :: openmc_filter_set_type public :: openmc_finalize public :: openmc_find - public :: openmc_get_cell + public :: openmc_get_cell_index public :: openmc_get_keff - public :: openmc_get_material - public :: openmc_get_nuclide - public :: openmc_get_tally + public :: openmc_get_filter_index + public :: openmc_get_material_index + public :: openmc_get_nuclide_index + public :: openmc_get_tally_index public :: openmc_hard_reset public :: openmc_init public :: openmc_load_nuclide diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index aaea8aa5b..32b8fc915 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -426,7 +426,7 @@ contains ! C API FUNCTIONS !=============================================================================== - function openmc_get_cell(id, index) result(err) bind(C) + function openmc_get_cell_index(id, index) result(err) bind(C) ! Return the index in the cells array of a cell with a given ID integer(C_INT32_T), value :: id integer(C_INT32_T), intent(out) :: index @@ -442,7 +442,7 @@ contains else err = E_CELL_NOT_ALLOCATED end if - end function openmc_get_cell + end function openmc_get_cell_index function openmc_cell_get_id(index, id) result(err) bind(C) diff --git a/src/material_header.F90 b/src/material_header.F90 index e716247fe..44bfdd25b 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -14,7 +14,7 @@ module material_header private public :: free_memory_material - public :: openmc_get_material + public :: openmc_get_material_index public :: openmc_material_add_nuclide public :: openmc_material_get_id public :: openmc_material_get_densities @@ -235,7 +235,7 @@ contains ! C API FUNCTIONS !=============================================================================== - function openmc_get_material(id, index) result(err) bind(C) + function openmc_get_material_index(id, index) result(err) bind(C) ! Returns the index in the materials array of a material with a given ID integer(C_INT32_T), value :: id integer(C_INT32_T), intent(out) :: index @@ -251,7 +251,7 @@ contains else err = E_MATERIAL_NOT_ALLOCATED end if - end function openmc_get_material + end function openmc_get_material_index function openmc_material_add_nuclide(index, name, density) result(err) bind(C) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index a2f3d5022..0c0dcff72 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -850,7 +850,7 @@ contains ! C API FUNCTIONS !=============================================================================== - function openmc_get_nuclide(name, index) result(err) bind(C) + function openmc_get_nuclide_index(name, index) result(err) bind(C) ! Return the index in the nuclides array of a nuclide with a given name character(kind=C_CHAR), intent(in) :: name(*) integer(C_INT), intent(out) :: index @@ -871,7 +871,7 @@ contains else err = E_NUCLIDE_NOT_ALLOCATED end if - end function openmc_get_nuclide + end function openmc_get_nuclide_index function openmc_load_nuclide(name) result(err) bind(C) diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index 9ece9116a..638e0e8a2 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -17,6 +17,7 @@ module tally_filter_header public :: openmc_extend_filters public :: openmc_filter_get_id public :: openmc_filter_set_id + public :: openmc_get_filter_index !=============================================================================== ! TALLYFILTERMATCH stores every valid bin and weight for a filter @@ -213,7 +214,7 @@ contains end function openmc_filter_set_id - function openmc_get_filter(id, index) result(err) bind(C) + function openmc_get_filter_index(id, index) result(err) bind(C) ! Returns the index in the filters array of a filter with a given ID integer(C_INT32_T), value :: id integer(C_INT32_T), intent(out) :: index @@ -229,6 +230,6 @@ contains else err = E_FILTER_NOT_ALLOCATED end if - end function openmc_get_filter + end function openmc_get_filter_index end module tally_filter_header diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index a1ba6288d..1ffd071f3 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -21,7 +21,7 @@ module tally_header public :: configure_tallies public :: free_memory_tally public :: openmc_extend_tallies - public :: openmc_get_tally + public :: openmc_get_tally_index public :: openmc_tally_get_id public :: openmc_tally_get_filters public :: openmc_tally_get_nuclides @@ -447,7 +447,7 @@ contains end function openmc_extend_tallies - function openmc_get_tally(id, index) result(err) bind(C) + function openmc_get_tally_index(id, index) result(err) bind(C) ! Returns the index in the tallies array of a tally with a given ID integer(C_INT32_T), value :: id integer(C_INT32_T), intent(out) :: index @@ -463,7 +463,7 @@ contains else err = E_TALLY_NOT_ALLOCATED end if - end function openmc_get_tally + end function openmc_get_tally_index function openmc_tally_get_id(index, id) result(err) bind(C) From d4c7b58a4b97a33838aae71ebe41b09d4acadbfe Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 27 Sep 2017 11:24:33 -0500 Subject: [PATCH 185/229] Change how error codes/messages are handled between C API and Python --- openmc/capi/core.py | 13 +++ openmc/capi/error.py | 109 ++++++++++++++------------ openmc/capi/nuclide.py | 2 +- openmc/capi/settings.py | 38 ++------- src/api.F90 | 5 +- src/error.F90 | 30 +++---- src/geometry_header.F90 | 23 ++++-- src/material_header.F90 | 19 ++++- src/nuclide_header.F90 | 15 +++- src/settings.F90 | 2 +- src/source_header.F90 | 7 +- src/tallies/tally.F90 | 5 +- src/tallies/tally_filter.F90 | 9 ++- src/tallies/tally_filter_energy.F90 | 14 +++- src/tallies/tally_filter_header.F90 | 12 ++- src/tallies/tally_filter_material.F90 | 16 +++- src/tallies/tally_filter_mesh.F90 | 8 +- src/tallies/tally_header.F90 | 47 ++++++++--- 18 files changed, 227 insertions(+), 147 deletions(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 4302a94f4..4335bcc46 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -157,3 +157,16 @@ def run_in_memory(intracomm=None): yield finally: finalize() + + +class _DLLGlobal(object): + """Data descriptor that exposes global variables from libopenmc.""" + def __init__(self, ctype, name): + self.ctype = ctype + self.name = name + + def __get__(self, instance, owner): + return self.ctype.in_dll(_dll, self.name).value + + def __set__(self, instance, value): + self.ctype.in_dll(_dll, self.name).value = value diff --git a/openmc/capi/error.py b/openmc/capi/error.py index 2058ceb20..8e37ea089 100644 --- a/openmc/capi/error.py +++ b/openmc/capi/error.py @@ -1,10 +1,45 @@ -from ctypes import c_int +from ctypes import c_int, c_char from . import _dll -class GeometryError(Exception): - pass +class Error(Exception): + """Root exception class for OpenMC.""" + + +class GeometryError(Error): + """Geometry-related error""" + + +class InvalidIDError(Error): + """Use of an ID that is invalid.""" + + +class AllocationError(Error): + """Error related to memory allocation.""" + + +class OutOfBoundsError(Error): + """Index in array out of bounds.""" + + +class DataError(Error): + """Error relating to nuclear data.""" + + +class PhysicsError(Error): + """Error relating to performing physics.""" + + +class InvalidArgumentError(Error): + """Argument passed was invalid.""" + + +class InvalidTypeError(Error): + """Tried to perform an operation on the wrong type.""" + + +_errmsg = (c_char*256).in_dll(_dll, 'openmc_err_msg') def _error_handler(err, func, args): @@ -14,53 +49,27 @@ def _error_handler(err, func, args): def errcode(s): return c_int.in_dll(_dll, s).value - if err == errcode('e_out_of_bounds'): - raise IndexError('Array index out of bounds.') - - elif err == errcode('e_cell_not_allocated'): - raise MemoryError("Memory has not been allocated for cells.") - - elif err == errcode('e_cell_invalid_id'): - raise KeyError("No cell exists with ID={}.".format(args[0])) - - elif err == errcode('e_cell_not_found'): - raise GeometryError("Could not find cell at position ({}, {}, {})" - .format(*args[0])) - - elif err == errcode('e_nuclide_not_allocated'): - raise MemoryError("Memory has not been allocated for nuclides.") - - elif err == errcode('e_nuclide_not_loaded'): - raise KeyError("No nuclide named '{}' has been loaded.") - - elif err == errcode('e_nuclide_not_in_library'): - raise KeyError("Specified nuclide doesn't exist in the cross " - "section library.") - - elif err == errcode('e_material_not_allocated'): - raise MemoryError("Memory has not been allocated for materials.") - - elif err == errcode('e_material_invalid_id'): - raise KeyError("No material exists with ID={}.".format(args[0])) - - elif err == errcode('e_tally_not_allocated'): - raise MemoryError("Memory has not been allocated for tallies.") - - elif err == errcode('e_tally_invalid_id'): - raise KeyError("No tally exists with ID={}.".format(args[0])) - - elif err == errcode('e_invalid_size'): - raise MemoryError("Array size mismatch with memory allocated.") - - elif err == errcode('e_cell_no_material'): - raise GeometryError("Operation on cell requires that it be filled" - " with a material.") - - elif err == errcode('w_below_min_bound'): - warn("Data has not been loaded beyond lower bound of {}.".format(args[0])) - - elif err == errcode('w_above_max_bound'): - warn("Data has not been loaded beyond upper bound of {}.".format(args[0])) + # Get error message set by OpenMC library + msg = _errmsg.value.decode() + # Raise exception type corresponding to error code + if err == errcode('e_allocate'): + raise AllocationError(msg) + elif err == errcode('e_out_of_bounds'): + raise OutOfBoundsError(msg) + elif err == errcode('e_invalid_argument'): + raise InvalidArgumentError(msg) + elif err == errcode('e_invalid_type'): + raise InvalidTypeError(msg) + if err == errcode('e_invalid_id'): + raise IDError(msg) + elif err == errcode('e_geometry'): + raise GeometryError(msg) + elif err == errcode('e_data'): + raise DataError(msg) + elif err == errcode('e_physics'): + raise PhysicsError(msg) + elif err == errcode('e_warning'): + warn(msg) elif err < 0: raise Exception("Unknown error encountered (code {}).".format(err)) diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 26a98e32e..6e3245e9e 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -81,7 +81,7 @@ class _NuclideMapping(Mapping): def __getitem__(self, key): index = c_int() _dll.openmc_get_nuclide_index(key.encode(), index) - return NuclideView(index) + return NuclideView(index.value) def __iter__(self): for i in range(len(self)): diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py index 40d1768cf..11b0eacef 100644 --- a/openmc/capi/settings.py +++ b/openmc/capi/settings.py @@ -1,6 +1,7 @@ from ctypes import c_int, c_int32, c_int64, c_double, c_char_p, POINTER from . import _dll +from .core import _DLLGlobal from .error import _error_handler _RUN_MODES = {1: 'fixed source', @@ -11,37 +12,12 @@ _RUN_MODES = {1: 'fixed source', class _Settings(object): - @property - def batches(self): - return c_int32.in_dll(_dll, 'n_batches').value - - @batches.setter - def batches(self, n): - _dll.openmc_set_batches(n) - - @property - def generations_per_batch(self): - return c_int32.in_dll(_dll, 'gen_per_batch').value - - @generations_per_batch.setter - def generations_per_batch(self, n): - _dll.openmc_set_generations_per_batch(n) - - @property - def inactive(self): - return c_int32.in_dll(_dll, 'n_inactive').value - - @inactive.setter - def inactive(self, n): - _dll.openmc_set_inactive_batches(n) - - @property - def particles(self): - return c_int64.in_dll(_dll, 'n_particles').value - - @particles.setter - def particles(self, n): - _dll.openmc_set_particles(n) + # Attributes that are accessed through a descriptor + batches = _DLLGlobal(c_int32, 'n_batches') + generations_per_batch = _DLLGlobal(c_int32, 'gen_per_batch') + inactive = _DLLGlobal(c_int32, 'n_inactive') + particles = _DLLGlobal(c_int64, 'n_particles') + verbosity = _DLLGlobal(c_int, 'verbosity') @property def run_mode(self): diff --git a/src/api.F90 b/src/api.F90 index c451920ac..1c995806b 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -194,7 +194,10 @@ contains instance = p % cell_instance - 1 err = 0 else - err = E_CELL_NOT_FOUND + err = E_GEOMETRY + call set_errmsg("Could not find cell/material at position (" // & + trim(to_str(xyz(1))) // "," // trim(to_str(xyz(2))) // "," // & + trim(to_str(xyz(3))) // ").") end if end function openmc_find diff --git a/src/error.F90 b/src/error.F90 index 93c56ec61..92902a04c 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -14,28 +14,18 @@ module error ! Error codes integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1 - integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -2 - integer(C_INT), public, bind(C) :: E_CELL_NOT_ALLOCATED = -3 - integer(C_INT), public, bind(C) :: E_CELL_INVALID_ID = -4 - integer(C_INT), public, bind(C) :: E_CELL_NOT_FOUND = -5 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_ALLOCATED = -6 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_LOADED = -7 - integer(C_INT), public, bind(C) :: E_NUCLIDE_NOT_IN_LIBRARY = -8 - integer(C_INT), public, bind(C) :: E_MATERIAL_NOT_ALLOCATED = -9 - integer(C_INT), public, bind(C) :: E_MATERIAL_INVALID_ID = -10 - integer(C_INT), public, bind(C) :: E_TALLY_NOT_ALLOCATED = -11 - integer(C_INT), public, bind(C) :: E_TALLY_INVALID_ID = -12 - integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -13 - integer(C_INT), public, bind(C) :: E_CELL_NO_MATERIAL = -14 - integer(C_INT), public, bind(C) :: E_ALREADY_ALLOCATED = -15 - integer(C_INT), public, bind(C) :: E_ARGUMENT_INVALID = -16 - integer(C_INT), public, bind(C) :: E_WRONG_TYPE = -17 - integer(C_INT), public, bind(C) :: E_FILTER_NOT_ALLOCATED = -18 - integer(C_INT), public, bind(C) :: E_FILTER_INVALID_ID = -19 + integer(C_INT), public, bind(C) :: E_ALLOCATE = -2 + integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -3 + integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -4 + integer(C_INT), public, bind(C) :: E_INVALID_ARGUMENT = -5 + integer(C_INT), public, bind(C) :: E_INVALID_TYPE = -6 + integer(C_INT), public, bind(C) :: E_INVALID_ID = -7 + integer(C_INT), public, bind(C) :: E_GEOMETRY = -8 + integer(C_INT), public, bind(C) :: E_DATA = -9 + integer(C_INT), public, bind(C) :: E_PHYSICS = -10 ! Warning codes - integer(C_INT), public, bind(C) :: W_BELOW_MIN_BOUND = 1 - integer(C_INT), public, bind(C) :: W_ABOVE_MAX_BOUND = 2 + integer(C_INT), public, bind(C) :: E_WARNING = 1 ! Error message character(kind=C_CHAR), public, bind(C) :: openmc_err_msg(256) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 32b8fc915..4d77b45e3 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -437,10 +437,12 @@ contains index = cell_dict % get_key(id) err = 0 else - err = E_CELL_INVALID_ID + err = E_INVALID_ID + call set_errmsg("No cell exists with ID=" // trim(to_str(id)) // ".") end if else - err = E_CELL_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory has not been allocated for cells.") end if end function openmc_get_cell_index @@ -456,6 +458,7 @@ contains err = 0 else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in cells array is out of bounds.") end if end function openmc_cell_get_id @@ -487,7 +490,9 @@ contains ! error if the cell is filled with another universe if (cells(index) % fill /= NONE) then - err = E_CELL_NO_MATERIAL + err = E_GEOMETRY + call set_errmsg("Cannot set temperature on a cell filled & + &with a universe.") else ! find which material is associated with this cell (material_index ! is the index into the materials array) @@ -539,14 +544,22 @@ contains ! temperature was changed correctly. This needs to be done after ! changing the temperature based on the logical structure above. if (err == 0) then - if (outside_low) err = W_BELOW_MIN_BOUND - if (outside_high) err = W_ABOVE_MAX_BOUND + if (outside_low) then + err = E_WARNING + call set_errmsg("Nuclear data has not been loaded beyond lower & + &bound of T=" // trim(to_str(T)) // " K.") + else if (outside_high) then + err = E_WARNING + call set_errmsg("Nuclear data has not been loaded beyond upper & + &bound of T=" // trim(to_str(T)) // " K.") + end if end if end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in cells array is out of bounds.") end if end function openmc_cell_set_temperature diff --git a/src/material_header.F90 b/src/material_header.F90 index 44bfdd25b..1846551a7 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -85,7 +85,6 @@ contains real(8) :: sum_percent real(8) :: awr - err = E_UNASSIGNED if (allocated(m % atom_density)) then ! Set total density based on value provided m % density = density @@ -105,6 +104,9 @@ contains + m % atom_density(i) * awr * MASS_NEUTRON / N_AVOGADRO end do err = 0 + else + err = E_ALLOCATE + call set_errmsg("Material atom density array hasn't been allocated.") end if end function material_set_density @@ -246,10 +248,12 @@ contains index = material_dict % get_key(id) err = 0 else - err = E_MATERIAL_INVALID_ID + err = E_INVALID_ID + call set_errmsg("No material exists with ID=" // trim(to_str(id)) // ".") end if else - err = E_MATERIAL_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory has not been allocated for materials.") end if end function openmc_get_material_index @@ -314,6 +318,7 @@ contains end associate else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") end if end function openmc_material_add_nuclide @@ -328,7 +333,6 @@ contains integer(C_INT), intent(out) :: n integer(C_INT) :: err - err = E_UNASSIGNED if (index >= 1 .and. index <= size(materials)) then associate (m => materials(index)) if (allocated(m % atom_density)) then @@ -336,10 +340,14 @@ contains densities = C_LOC(m % atom_density(1)) n = size(m % atom_density) err = 0 + else + err = E_ALLOCATE + call set_errmsg("Material atom density array has not been allocated.") end if end associate else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") end if end function openmc_material_get_densities @@ -355,6 +363,7 @@ contains err = 0 else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") end if end function openmc_material_get_id @@ -372,6 +381,7 @@ contains end associate else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") end if end function openmc_material_set_density @@ -423,6 +433,7 @@ contains end associate else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") end if end function openmc_material_set_densities diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 0c0dcff72..f2b4a6951 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -866,10 +866,13 @@ contains index = nuclide_dict % get_key(to_lower(name_)) err = 0 else - err = E_NUCLIDE_NOT_LOADED + err = E_DATA + call set_errmsg("No nuclide named '" // trim(name_) // & + "' has been loaded.") end if else - err = E_NUCLIDE_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory for nuclides has not been allocated.") end if end function openmc_get_nuclide_index @@ -926,7 +929,9 @@ contains call nuclides(n) % init_grid(energy_min_neutron, & energy_max_neutron, n_log_bins) else - err = E_NUCLIDE_NOT_IN_LIBRARY + err = E_DATA + call set_errmsg("Nuclide '" // trim(name_) // "' is not present & + &in library.") end if end if @@ -949,9 +954,11 @@ contains err = 0 else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in nuclides array is out of bounds.") end if else - err = E_NUCLIDE_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory for nuclides has not been allocated yet.") end if end function openmc_nuclide_name diff --git a/src/settings.F90 b/src/settings.F90 index 7e81872a0..83aebce86 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -82,7 +82,7 @@ module settings ! The verbosity controls how much information will be printed to the screen ! and in logs - integer :: verbosity = 7 + integer(C_INT), bind(C) :: verbosity = 7 logical :: check_overlaps = .false. diff --git a/src/source_header.F90 b/src/source_header.F90 index c664316c7..a60696996 100644 --- a/src/source_header.F90 +++ b/src/source_header.F90 @@ -338,21 +338,24 @@ contains err = 0 end function openmc_extend_sources + function openmc_source_set_strength(index, strength) result(err) bind(C) integer(C_INT32_T), value, intent(in) :: index real(C_DOUBLE), value, intent(in) :: strength integer(C_INT) :: err - err = E_UNASSIGNED if (index >= 1 .and. index <= n_sources) then if (strength > ZERO) then external_source(index) % strength = strength err = 0 + else + err = E_INVALID_ARGUMENT + call set_errmsg("Source strength must be positive.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in external source array is out of bounds.") end if end function openmc_source_set_strength - end module source_header diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index bb228e892..9e40bfd6c 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4410,13 +4410,15 @@ contains err = 0 if (index >= 1 .and. index <= n_tallies) then if (allocated(tallies(index) % obj)) then - err = E_ALREADY_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Tally type has already been set.") else select case (type_) case ('generic') allocate(TallyObject :: tallies(index) % obj) case default err = E_UNASSIGNED + call set_errmsg("Unknown tally type: " // trim(type_)) end select ! When a tally is allocated, set it to have 0 filters @@ -4424,6 +4426,7 @@ contains end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in tallies array is out of bounds.") end if end function openmc_tally_set_type diff --git a/src/tallies/tally_filter.F90 b/src/tallies/tally_filter.F90 index 3b96cade3..587f8dd90 100644 --- a/src/tallies/tally_filter.F90 +++ b/src/tallies/tally_filter.F90 @@ -86,10 +86,12 @@ contains err = 0 else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array is out of bounds.") end if end function openmc_filter_get_type @@ -108,7 +110,8 @@ contains err = 0 if (index >= 1 .and. index <= n_filters) then if (allocated(filters(index) % obj)) then - err = E_ALREADY_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has already been set.") else select case (type_) case ('azimuthal') @@ -143,10 +146,12 @@ contains allocate(UniverseFilter :: filters(index) % obj) case default err = E_UNASSIGNED + call set_errmsg("Unknown filter type: " // trim(type_)) end select end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array is out of bounds.") end if end function openmc_filter_set_type diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index 3530621b5..7f9655280 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -212,13 +212,16 @@ contains n = size(f % bins) err = 0 class default - err = E_WRONG_TYPE + err = E_INVALID_TYPE + call set_errmsg("Tried to get energy bins on a non-energy filter.") end select else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_energy_filter_get_bins @@ -240,13 +243,16 @@ contains allocate(f % bins(n)) f % bins(:) = energies class default - err = E_WRONG_TYPE + err = E_INVALID_TYPE + call set_errmsg("Tried to get energy bins on a non-energy filter.") end select else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_energy_filter_set_bins diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index 638e0e8a2..e6a6f20c3 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -7,6 +7,7 @@ module tally_filter_header use error use particle_header, only: Particle use stl_vector, only: VectorInt, VectorReal + use string, only: to_str use xml_interface, only: XMLNode use hdf5 @@ -189,6 +190,7 @@ contains err = 0 else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_filter_get_id @@ -206,10 +208,12 @@ contains err = 0 else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_filter_set_id @@ -225,10 +229,12 @@ contains index = filter_dict % get_key(id) err = 0 else - err = E_FILTER_INVALID_ID + err = E_INVALID_ID + call set_errmsg("No filter exists with ID=" // trim(to_str(id)) // ".") end if else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory has not been allocated for filters.") end if end function openmc_get_filter_index diff --git a/src/tallies/tally_filter_material.F90 b/src/tallies/tally_filter_material.F90 index 3eacc1fcb..14afdc842 100644 --- a/src/tallies/tally_filter_material.F90 +++ b/src/tallies/tally_filter_material.F90 @@ -129,13 +129,17 @@ contains n = size(f % materials) err = 0 class default - err = E_WRONG_TYPE + err = E_INVALID_TYPE + call set_errmsg("Tried to get material filter bins on a & + &non-material filter.") end select else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_material_filter_get_bins @@ -166,13 +170,17 @@ contains end do class default - err = E_WRONG_TYPE + err = E_INVALID_TYPE + call set_errmsg("Tried to set material filter bins on a & + &non-material filter.") end select else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_material_filter_set_bins diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index cfc793949..0428973c4 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -296,15 +296,19 @@ contains f % n_bins = product(meshes(index_mesh) % dimension) else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in 'meshes' array is out of bounds.") end if class default - err = E_WRONG_TYPE + err = E_INVALID_TYPE + call set_errmsg("Tried to set mesh on a non-mesh filter.") end select else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Filter type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg("Index in filters array out of bounds.") end if end function openmc_mesh_filter_set_mesh diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 1ffd071f3..a823b7df5 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -11,7 +11,7 @@ module tally_header use nuclide_header, only: nuclide_dict use settings, only: reduce_tallies use stl_vector, only: VectorInt - use string, only: to_lower, to_f_string, str_to_int + use string, only: to_lower, to_f_string, str_to_int, to_str use tally_filter_header, only: TallyFilterContainer, filters, n_filters use tally_filter use trigger_header, only: TriggerObject @@ -301,6 +301,7 @@ contains k = filter_indices(i) if (k < 1 .or. k > n_filters) then err = E_OUT_OF_BOUNDS + call set_errmsg("Index in tally filter array out of bounds.") exit end if @@ -458,10 +459,12 @@ contains index = tally_dict % get_key(id) err = 0 else - err = E_TALLY_INVALID_ID + err = E_INVALID_ID + call set_errmsg("No tally exists with ID=" // trim(to_str(id)) // ".") end if else - err = E_TALLY_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Memory has not been allocated for tallies.") end if end function openmc_get_tally_index @@ -477,28 +480,32 @@ contains err = 0 else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_get_id function openmc_tally_get_filters(index, filter_indices, n) result(err) bind(C) - ! Return the list of nuclides assigned to a tally + ! Return the list of filters assigned to a tally integer(C_INT32_T), value :: index type(C_PTR), intent(out) :: filter_indices integer(C_INT), intent(out) :: n integer(C_INT) :: err - err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then associate (t => tallies(index) % obj) if (allocated(t % filter)) then filter_indices = C_LOC(t % filter(1)) n = size(t % filter) err = 0 + else + err = E_ALLOCATE + call set_errmsg("Tally filters have not been allocated yet.") end if end associate else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_get_filters @@ -510,17 +517,20 @@ contains integer(C_INT), intent(out) :: n integer(C_INT) :: err - err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then associate (t => tallies(index) % obj) if (allocated(t % nuclide_bins)) then nuclides = C_LOC(t % nuclide_bins(1)) n = size(t % nuclide_bins) err = 0 + else + err = E_ALLOCATE + call set_errmsg("Tally nuclides have not been allocated yet.") end if end associate else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_get_nuclides @@ -533,17 +543,20 @@ contains integer(C_INT), intent(out) :: shape_(3) integer(C_INT) :: err - err = E_UNASSIGNED if (index >= 1 .and. index <= size(tallies)) then associate (t => tallies(index) % obj) if (allocated(t % results)) then ptr = C_LOC(t % results(1,1,1)) shape_(:) = shape(t % results) err = 0 + else + err = E_ALLOCATE + call set_errmsg("Tally results have not been allocated yet.") end if end associate else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_results @@ -560,10 +573,12 @@ contains if (allocated(tallies(index) % obj)) then err = tallies(index) % obj % set_filters(filter_indices) else - err = E_TALLY_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Tally type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_set_filters @@ -581,10 +596,12 @@ contains err = 0 else - err = E_FILTER_NOT_ALLOCATED + err = E_ALLOCATE + call set_errmsg("Tally type has not been set yet.") end if else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_set_id @@ -619,7 +636,9 @@ contains if (nuclide_dict % has_key(nuclide_)) then t % nuclide_bins(i) = nuclide_dict % get_key(nuclide_) else - err = E_NUCLIDE_NOT_LOADED + err = E_DATA + call set_errmsg("Nuclide '" // trim(to_f_string(string)) // & + "' has not been loaded yet.") return end if end select @@ -629,6 +648,7 @@ contains end associate else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_set_nuclides @@ -778,11 +798,13 @@ contains if (MT > 1) then t % score_bins(i) = MT else - err = E_ARGUMENT_INVALID + err = E_INVALID_ARGUMENT + call set_errmsg("Negative MT number cannot be used as a score.") end if else - err = E_ARGUMENT_INVALID + err = E_INVALID_ARGUMENT + call set_errmsg("Unknown score: " // trim(score_) // ".") end if end select @@ -792,6 +814,7 @@ contains end associate else err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') end if end function openmc_tally_set_scores From a1eb39d8fc7ebac26af3822d472b0f19ca271253 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 27 Sep 2017 11:45:00 -0500 Subject: [PATCH 186/229] Improve repr() for Python classes exposing C API --- openmc/capi/cell.py | 9 +++++---- openmc/capi/core.py | 8 ++++++++ openmc/capi/filter.py | 9 +++++---- openmc/capi/material.py | 15 +++++---------- openmc/capi/nuclide.py | 9 +++++---- openmc/capi/tally.py | 9 +++++---- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 3e767caf3..81bdfdc40 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -5,6 +5,7 @@ from weakref import WeakValueDictionary import numpy as np from . import _dll +from .core import _View from .error import _error_handler __all__ = ['CellView', 'cells'] @@ -22,7 +23,7 @@ _dll.openmc_get_cell_index.restype = c_int _dll.openmc_get_cell_index.errcheck = _error_handler -class CellView(object): +class CellView(_View): """View of a cell. This class exposes a cell that is stored internally in the OpenMC solver. To @@ -48,9 +49,6 @@ class CellView(object): cls.__instances[args] = instance return cls.__instances[args] - def __init__(self, index): - self._index = index - @property def id(self): cell_id = c_int32() @@ -84,4 +82,7 @@ class _CellMapping(Mapping): def __len__(self): return c_int32.in_dll(_dll, 'n_cells').value + def __repr__(self): + return repr(dict(self)) + cells = _CellMapping() diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 4335bcc46..2234fac64 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -170,3 +170,11 @@ class _DLLGlobal(object): def __set__(self, instance, value): self.ctype.in_dll(_dll, self.name).value = value + + +class _View(object): + def __init__(self, index): + self._index = index + + def __repr__(self): + return "{}[{}]".format(type(self).__name__, self._index) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 28d95a37c..dc59560e0 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -7,6 +7,7 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll +from .core import _View from .error import _error_handler from .material import MaterialView @@ -56,7 +57,7 @@ _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler -class FilterView(object): +class FilterView(_View): __instances = WeakValueDictionary() def __new__(cls, *args): @@ -65,9 +66,6 @@ class FilterView(object): cls.__instances[args] = instance return cls.__instances[args] - def __init__(self, index): - self._index = index - @property def id(self): filter_id = c_int32() @@ -215,4 +213,7 @@ class _FilterMapping(Mapping): def __len__(self): return c_int32.in_dll(_dll, 'n_filters').value + def __repr__(self): + return repr(dict(self)) + filters = _FilterMapping() diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 728caa356..81c47f5f9 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -6,6 +6,7 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll, NuclideView +from .core import _View from .error import _error_handler @@ -36,7 +37,7 @@ _dll.openmc_material_set_densities.restype = c_int _dll.openmc_material_set_densities.errcheck = _error_handler -class MaterialView(object): +class MaterialView(_View): """View of a material. This class exposes a material that is stored internally in the OpenMC @@ -60,15 +61,6 @@ class MaterialView(object): """ __instances = WeakValueDictionary() - def __new__(cls, *args): - if args not in cls.__instances: - instance = super().__new__(cls) - cls.__instances[args] = instance - return cls.__instances[args] - - def __init__(self, index): - self._index = index - @property def id(self): mat_id = c_int32() @@ -167,4 +159,7 @@ class _MaterialMapping(Mapping): def __len__(self): return c_int32.in_dll(_dll, 'n_materials').value + def __repr__(self): + return repr(dict(self)) + materials = _MaterialMapping() diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 6e3245e9e..16bb71acc 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -6,6 +6,7 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll +from .core import _View from .error import _error_handler @@ -35,7 +36,7 @@ def load_nuclide(name): _dll.openmc_load_nuclide(name.encode()) -class NuclideView(object): +class NuclideView(_View): """View of a nuclide. This class exposes a nuclide that is stored internally in the OpenMC @@ -61,9 +62,6 @@ class NuclideView(object): cls.__instances[args] = instance return cls.__instances[args] - def __init__(self, index): - self._index = index - @property def name(self): name = c_char_p() @@ -90,4 +88,7 @@ class _NuclideMapping(Mapping): def __len__(self): return c_int.in_dll(_dll, 'n_nuclides').value + def __repr__(self): + return repr(dict(self)) + nuclides = _NuclideMapping() diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 3d056c283..db32f98f8 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -5,6 +5,7 @@ from weakref import WeakValueDictionary from numpy.ctypeslib import as_array from . import _dll, NuclideView +from .core import _View from .error import _error_handler from .filter import _get_filter @@ -50,7 +51,7 @@ _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler -class TallyView(object): +class TallyView(_View): """View of a tally. This class exposes a tally that is stored internally in the OpenMC @@ -82,9 +83,6 @@ class TallyView(object): cls.__instances[args] = instance return cls.__instances[args] - def __init__(self, index): - self._index = index - @property def id(self): tally_id = c_int32() @@ -162,4 +160,7 @@ class _TallyMapping(Mapping): def __len__(self): return c_int32.in_dll(_dll, 'n_tallies').value + def __repr__(self): + return repr(dict(self)) + tallies = _TallyMapping() From bc84687378c1371f482c2bafbe683dbae571fcb0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 27 Sep 2017 15:44:40 -0500 Subject: [PATCH 187/229] Allow materials to be created/assigned from C API bindings. Fix a few errors. --- openmc/capi/cell.py | 38 +++++++++++++++++++- openmc/capi/error.py | 2 +- openmc/capi/filter.py | 7 +++- openmc/capi/material.py | 24 ++++++++++++- openmc/capi/tally.py | 10 ++++-- src/api.F90 | 4 +++ src/geometry_header.F90 | 78 +++++++++++++++++++++++++++++++++++++++-- src/material_header.F90 | 71 +++++++++++++++++++++++++++++++++---- 8 files changed, 219 insertions(+), 15 deletions(-) diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 81bdfdc40..11b0e2199 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -1,12 +1,14 @@ -from collections import Mapping +from collections import Mapping, Iterable from ctypes import c_int, c_int32, c_double, c_char_p, POINTER from weakref import WeakValueDictionary import numpy as np +from numpy.ctypeslib import as_array from . import _dll from .core import _View from .error import _error_handler +from .material import MaterialView __all__ = ['CellView', 'cells'] @@ -14,6 +16,12 @@ __all__ = ['CellView', 'cells'] _dll.openmc_cell_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_cell_get_id.restype = c_int _dll.openmc_cell_get_id.errcheck = _error_handler +_dll.openmc_cell_get_fill.argtypes = [ + c_int32, POINTER(c_int), POINTER(POINTER(c_int32)), POINTER(c_int32)] +_dll.openmc_cell_set_fill.argtypes = [ + c_int32, c_int, c_int32, POINTER(c_int32)] +_dll.openmc_cell_set_fill.restype = c_int +_dll.openmc_cell_set_fill.errcheck = _error_handler _dll.openmc_cell_set_temperature.argtypes = [ c_int32, c_double, POINTER(c_int32)] _dll.openmc_cell_set_temperature.restype = c_int @@ -55,6 +63,34 @@ class CellView(_View): _dll.openmc_cell_get_id(self._index, cell_id) return cell_id.value + @property + def fill(self): + fill_type = c_int() + indices = POINTER(c_int32)() + n = c_int32() + _dll.openmc_cell_get_fill(self._index, fill_type, indices, n) + + if fill_type.value == 1: + if n.value > 1: + return [MaterialView(i) for i in indices[:n.value]] + else: + return MaterialView(indices[0]) + else: + raise NotImplementedError + + @fill.setter + def fill(self, fill): + if isinstance(fill, Iterable): + n = len(fill) + indices = (c_int*n)(*(m._index for m in fill)) + _dll.openmc_cell_set_fill(self._index, 1, 1, indices) + elif isinstance(fill, MaterialView): + materials = [fill] + indices = (c_int*1)(fill._index) + _dll.openmc_cell_set_fill(self._index, 1, 1, indices) + else: + raise NotImplementedError + def set_temperature(self, T, instance=None): """Set the temperature of a cell diff --git a/openmc/capi/error.py b/openmc/capi/error.py index 8e37ea089..7ebf2cb64 100644 --- a/openmc/capi/error.py +++ b/openmc/capi/error.py @@ -62,7 +62,7 @@ def _error_handler(err, func, args): elif err == errcode('e_invalid_type'): raise InvalidTypeError(msg) if err == errcode('e_invalid_id'): - raise IDError(msg) + raise InvalidIDError(msg) elif err == errcode('e_geometry'): raise GeometryError(msg) elif err == errcode('e_data'): diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index dc59560e0..e171e05bd 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -144,11 +144,16 @@ class MaterialFilterView(FilterView): _dll.openmc_material_filter_set_bins(self._index, n, bins) @classmethod - def new(cls, bins=None): + def new(cls, bins=None, filter_id=None): + # Determine filter ID to assign + if filter_id is None: + filter_id = max(filters) + 1 + index = c_int32() _dll.openmc_extend_filters(1, index, None) _dll.openmc_filter_set_type(index, b'material') f = cls(index.value) + f.id = filter_id if bins is not None: f.bins = bins return f diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 81c47f5f9..ba4b65089 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -13,6 +13,9 @@ from .error import _error_handler __all__ = ['MaterialView', 'materials'] # Material functions +_dll.openmc_extend_materials.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] +_dll.openmc_extend_materials.restype = c_int +_dll.openmc_extend_materials.errcheck = _error_handler _dll.openmc_get_material_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_material_index.restype = c_int _dll.openmc_get_material_index.errcheck = _error_handler @@ -35,6 +38,9 @@ _dll.openmc_material_set_densities.argtypes = [ c_int32, c_int, POINTER(c_char_p), POINTER(c_double)] _dll.openmc_material_set_densities.restype = c_int _dll.openmc_material_set_densities.errcheck = _error_handler +_dll.openmc_material_set_id.argtypes = [c_int32, c_int32] +_dll.openmc_material_set_id.restype = c_int +_dll.openmc_material_set_id.errcheck = _error_handler class MaterialView(_View): @@ -67,6 +73,10 @@ class MaterialView(_View): _dll.openmc_material_get_id(self._index, mat_id) return mat_id.value + @id.setter + def id(self, mat_id): + _dll.openmc_material_set_id(self._index, mat_id) + @property def nuclides(self): return self._get_densities()[0] @@ -100,7 +110,7 @@ class MaterialView(_View): density_array = as_array(densities, (n.value,)) return nuclide_list, density_array - def add_nuclide(name, density): + def add_nuclide(self, name, density): """Add a nuclide to a material. Parameters @@ -113,6 +123,18 @@ class MaterialView(_View): """ _dll.openmc_material_add_nuclide(self._index, name.encode(), density) + @classmethod + def new(cls, material_id=None): + # Determine ID to assign + if material_id is None: + material_id = max(materials) + 1 + + index = c_int32() + _dll.openmc_extend_materials(1, index, None) + mat = cls(index.value) + mat.id = material_id + return mat + def set_density(self, density): """Set density of a material. diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index db32f98f8..335cbb8e7 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -140,11 +140,17 @@ class TallyView(_View): _dll.openmc_tally_set_scores(self._index, len(scores), scores_) @classmethod - def new(cls): + def new(cls, tally_id=None): + # Determine ID to assign + if tally_id is None: + tally_id = max(tallies) + 1 + index = c_int32() _dll.openmc_extend_tallies(1, index, None) _dll.openmc_tally_set_type(index, b'generic') - return cls(index.value) + tally = cls(index.value) + tally.id = tally_id + return tally class _TallyMapping(Mapping): diff --git a/src/api.F90 b/src/api.F90 index 1c995806b..3b2fdacad 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -34,10 +34,13 @@ module openmc_api private public :: openmc_calculate_volumes public :: openmc_cell_get_id + public :: openmc_cell_get_fill + public :: openmc_cell_set_fill public :: openmc_cell_set_temperature public :: openmc_energy_filter_get_bins public :: openmc_energy_filter_set_bins public :: openmc_extend_filters + public :: openmc_extend_materials public :: openmc_extend_tallies public :: openmc_filter_get_id public :: openmc_filter_get_type @@ -59,6 +62,7 @@ module openmc_api public :: openmc_material_get_densities public :: openmc_material_set_density public :: openmc_material_set_densities + public :: openmc_material_set_id public :: openmc_material_filter_get_bins public :: openmc_material_filter_set_bins public :: openmc_mesh_filter_set_mesh diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 4d77b45e3..b6499f822 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -6,7 +6,7 @@ module geometry_header use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & MATERIAL_VOID, NONE use dict_header, only: DictCharInt, DictIntInt - use material_header, only: Material, materials, material_dict + use material_header, only: Material, materials, material_dict, n_materials use nuclide_header use sab_header use stl_vector, only: VectorReal @@ -447,6 +447,33 @@ contains end function openmc_get_cell_index + function openmc_cell_get_fill(index, type, indices, n) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), intent(out) :: type + integer(C_INT32_T), intent(out) :: n + type(C_PTR), intent(out) :: indices + integer(C_INT) :: err + + err = 0 + if (index >= 1 .and. index <= size(cells)) then + associate (c => cells(index)) + type = c % type + select case (type) + case (FILL_MATERIAL) + n = size(c % material) + indices = C_LOC(c % material(1)) + case (FILL_UNIVERSE, FILL_LATTICE) + n = 1 + indices = C_LOC(c % fill) + end select + end associate + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in cells array is out of bounds.") + end if + end function openmc_cell_get_fill + + function openmc_cell_get_id(index, id) result(err) bind(C) ! Return the ID of a cell integer(C_INT32_T), value :: index @@ -463,9 +490,56 @@ contains end function openmc_cell_get_id + function openmc_cell_set_fill(index, type, n, indices) result(err) bind(C) + ! Set the fill for a fill + integer(C_INT32_T), value, intent(in) :: index ! index in cells + integer(C_INT), value, intent(in) :: type + integer(c_INT32_T), value, intent(in) :: n + integer(C_INT32_T), intent(in) :: indices(n) + integer(C_INT) :: err + + integer :: i, j + + err = 0 + if (index >= 1 .and. index <= size(cells)) then + associate (c => cells(index)) + select case (type) + case (FILL_MATERIAL) + if (allocated(c % material)) deallocate(c % material) + allocate(c % material(n)) + + c % type = FILL_MATERIAL + do i = 1, n + j = indices(i) + if (j == 0) then + c % material(i) = MATERIAL_VOID + else + if (j >= 1 .and. j <= n_materials) then + c % material(i) = j + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index " // trim(to_str(j)) // " in the & + &materials array is out of bounds.") + end if + end if + end do + case (FILL_UNIVERSE) + c % type = FILL_UNIVERSE + case (FILL_LATTICE) + c % type = FILL_LATTICE + end select + end associate + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in cells array is out of bounds.") + end if + + end function openmc_cell_set_fill + + function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) ! Set the temperature of a cell - integer(C_INT32_T), value, intent(in) :: index ! cell index in cells + integer(C_INT32_T), value, intent(in) :: index ! index in cells real(C_DOUBLE), value, intent(in) :: T ! temperature integer(C_INT32_T), optional, intent(in) :: instance ! cell instance diff --git a/src/material_header.F90 b/src/material_header.F90 index 1846551a7..eac5ab546 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -14,12 +14,14 @@ module material_header private public :: free_memory_material + public :: openmc_extend_materials public :: openmc_get_material_index public :: openmc_material_add_nuclide public :: openmc_material_get_id public :: openmc_material_get_densities public :: openmc_material_set_density public :: openmc_material_set_densities + public :: openmc_material_set_id !=============================================================================== ! MATERIAL describes a material by its constituent nuclides @@ -28,7 +30,7 @@ module material_header type, public :: Material integer :: id ! unique identifier character(len=104) :: name = "" ! User-defined name - integer :: n_nuclides ! number of nuclides + integer :: n_nuclides = 0 ! number of nuclides integer, allocatable :: nuclide(:) ! index in nuclides array real(8) :: density ! total atom density in atom/b-cm real(8), allocatable :: atom_density(:) ! nuclide atom density in atom/b-cm @@ -237,6 +239,37 @@ contains ! C API FUNCTIONS !=============================================================================== + function openmc_extend_materials(n, index_start, index_end) result(err) bind(C) + ! Extend the materials array by n elements + integer(C_INT32_T), value, intent(in) :: n + integer(C_INT32_T), optional, intent(out) :: index_start + integer(C_INT32_T), optional, intent(out) :: index_end + integer(C_INT) :: err + + type(Material), allocatable :: temp(:) ! temporary materials array + + if (n_materials == 0) then + ! Allocate materials array + allocate(materials(n)) + else + ! Allocate materials array with increased size + allocate(temp(n_materials + n)) + + ! Move original materials to temporary array + temp(1:n_materials) = materials(:) + + ! Move allocation from temporary array + call move_alloc(FROM=temp, TO=materials) + end if + + ! Return indices in materials array + if (present(index_start)) index_start = n_materials + 1 + if (present(index_end)) index_end = n_materials + n + n_materials = n_materials + n + + err = 0 + end function openmc_extend_materials + function openmc_get_material_index(id, index) result(err) bind(C) ! Returns the index in the materials array of a material with a given ID integer(C_INT32_T), value :: id @@ -269,6 +302,7 @@ contains real(8) :: awr integer, allocatable :: new_nuclide(:) real(8), allocatable :: new_density(:) + logical, allocatable :: new_p0(:) character(:), allocatable :: name_ name_ = to_f_string(name) @@ -277,7 +311,7 @@ contains if (index >= 1 .and. index <= size(materials)) then associate (m => materials(index)) ! Check if nuclide is already in material - do j = 1, size(m % nuclide) + do j = 1, m % n_nuclides k = m % nuclide(j) if (nuclides(k) % name == name_) then awr = nuclides(k) % awr @@ -296,15 +330,20 @@ contains if (err == 0) then ! Extend arrays - n = size(m % nuclide) + n = m % n_nuclides allocate(new_nuclide(n + 1)) - new_nuclide(1:n) = m % nuclide + if (n > 0) new_nuclide(1:n) = m % nuclide call move_alloc(FROM=new_nuclide, TO=m % nuclide) allocate(new_density(n + 1)) - new_density(1:n) = m % atom_density + if (n > 0) new_density(1:n) = m % atom_density call move_alloc(FROM=new_density, TO=m % atom_density) + allocate(new_p0(n + 1)) + if (n > 0) new_p0(1:n) = m % p0 + new_p0(n + 1) = .false. + call move_alloc(FROM=new_p0, TO=m % p0) + ! Append new nuclide/density k = nuclide_dict % get_key(to_lower(name_)) m % nuclide(n + 1) = k @@ -368,6 +407,23 @@ contains end function openmc_material_get_id + function openmc_material_set_id(index, id) result(err) bind(C) + ! Set the ID of a material + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= n_materials) then + materials(index) % id = id + call material_dict % add_key(id, index) + err = 0 + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") + end if + end function openmc_material_set_id + + function openmc_material_set_density(index, density) result(err) bind(C) ! Set the total density of a material in atom/b-cm integer(C_INT32_T), value, intent(in) :: index @@ -396,14 +452,15 @@ contains integer(C_INT) :: err integer :: i + integer :: stat character(C_CHAR), pointer :: string(:) character(len=:, kind=C_CHAR), allocatable :: name_ if (index >= 1 .and. index <= size(materials)) then associate (m => materials(index)) ! If nuclide/density arrays are not correct size, reallocate - if (n /= size(m % nuclide)) then - deallocate(m % nuclide, m % atom_density, m % p0) + if (n /= m % n_nuclides) then + deallocate(m % nuclide, m % atom_density, m % p0, STAT=stat) allocate(m % nuclide(n), m % atom_density(n), m % p0(n)) end if From a43b5eac911ac60a5577301985aa49e84d788722 Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 28 Sep 2017 15:56:45 -0500 Subject: [PATCH 188/229] Fixed bug in get_ci when key not in dictionary --- src/dict_header.F90 | 6 +++++- src/mgxs_data.F90 | 3 --- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dict_header.F90 b/src/dict_header.F90 index 7cf75fae6..631bf0499 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -328,7 +328,11 @@ contains integer :: i i = this % get_entry(key) - value = this % table(i) % entry % value + if (allocated(this % table(i) % entry)) then + value = this % table(i) % entry % value + else + value = EMPTY + end if end function get_ci diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 952cd12e2..64dfcbcae 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -24,7 +24,6 @@ contains subroutine read_mgxs() integer :: i ! index in materials array integer :: j ! index over nuclides in material - integer :: i_xsdata ! index in list integer :: i_nuclide ! index in nuclides array character(20) :: name ! name of library to load integer :: representation ! Data representation @@ -34,7 +33,6 @@ contains integer(HID_T) :: file_id integer(HID_T) :: xsdata_group logical :: file_exists - type(DictCharInt) :: xsdata_dict type(VectorReal), allocatable :: temps(:) character(MAX_WORD_LEN) :: word integer, allocatable :: array(:) @@ -85,7 +83,6 @@ contains name = mat % names(j) if (.not. already_read % contains(name)) then - i_xsdata = xsdata_dict % get(to_lower(name)) i_nuclide = mat % nuclide(j) call write_message("Loading " // trim(name) // " data...", 6) From a15aa56633092613a7d9e58b8e156fa40fb2e44f Mon Sep 17 00:00:00 2001 From: amandalund Date: Thu, 28 Sep 2017 19:33:47 -0500 Subject: [PATCH 189/229] add -> set --- src/api.F90 | 2 +- src/cmfd_input.F90 | 12 ++++++------ src/dict_header.F90 | 18 +++++++++--------- src/input_xml.F90 | 34 +++++++++++++++++----------------- src/nuclide_header.F90 | 2 +- src/tally_filter.F90 | 8 ++++---- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index 87886c1bd..23e626c27 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -464,7 +464,7 @@ contains call file_close(file_id) ! Add entry to nuclide dictionary - call nuclide_dict % add(to_lower(name_), n) + call nuclide_dict % set(to_lower(name_), n) n_nuclides_total = n ! Assign resonant scattering data diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 3467cde8f..fa7315940 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -374,7 +374,7 @@ contains m % volume_frac = ONE/real(product(m % dimension),8) ! Add mesh to dictionary - call mesh_dict % add(m % id, n_user_meshes + 1) + call mesh_dict % set(m % id, n_user_meshes + 1) ! Determine number of filters energy_filters = check_for_node(node_mesh, "energy") @@ -392,7 +392,7 @@ contains filt % n_bins = product(m % dimension) filt % mesh = n_user_meshes + 1 ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select if (energy_filters) then @@ -407,7 +407,7 @@ contains allocate(filt % bins(ng)) call get_node_array(node_mesh, "energy", filt % bins) ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select ! Read and set outgoing energy mesh filter @@ -421,7 +421,7 @@ contains allocate(filt % bins(ng)) call get_node_array(node_mesh, "energy", filt % bins) ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select end if @@ -437,7 +437,7 @@ contains filt % n_bins = product(m % dimension + 1) filt % mesh = n_user_meshes + 1 ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select ! Set up surface filter @@ -458,7 +458,7 @@ contains end if filt % current = .true. ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select ! Allocate tallies diff --git a/src/dict_header.F90 b/src/dict_header.F90 index 631bf0499..c960e0619 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -62,7 +62,7 @@ module dict_header integer, private :: capacity = 0 type(DictEntryII), allocatable, private :: table(:) contains - procedure :: add => add_ii + procedure :: set => set_ii procedure :: get => get_ii procedure :: has => has_ii procedure :: remove => remove_ii @@ -78,7 +78,7 @@ module dict_header integer, private :: capacity = 0 type(BucketCI), allocatable, private :: table(:) contains - procedure :: add => add_ci + procedure :: set => set_ci procedure :: get => get_ci procedure :: has => has_ci procedure :: remove => remove_ci @@ -178,7 +178,7 @@ contains ! Rehash each entry into the new table do i = 1, size(table) if (table(i) % key /= EMPTY .and. table(i) % key /= DELETED) then - call this % add(table(i) % key, table(i) % value) + call this % set(table(i) % key, table(i) % value) end if end do @@ -207,7 +207,7 @@ contains ! Rehash each entry into the new table do i = 1, size(table) if (table(i) % hash /= EMPTY .and. table(i) % hash /= DELETED) then - call this % add(table(i) % entry % key, table(i) % entry % value) + call this % set(table(i) % entry % key, table(i) % entry % value) end if end do @@ -216,11 +216,11 @@ contains end subroutine resize_ci !=============================================================================== -! ADD adds a (key,value) entry to a dictionary. If the key is already in the +! SET adds a (key,value) entry to a dictionary. If the key is already in the ! dictionary, the value is replaced by the new specified value. !=============================================================================== - subroutine add_ii(this, key, value) + subroutine set_ii(this, key, value) class(DictIntInt) :: this integer, intent(in) :: key @@ -256,9 +256,9 @@ contains i = 1 + mod(i + c - 1, this % capacity) end do - end subroutine add_ii + end subroutine set_ii - subroutine add_ci(this, key, value) + subroutine set_ci(this, key, value) class(DictCharInt) :: this character(*), intent(in) :: key @@ -299,7 +299,7 @@ contains i = 1 + mod(i + c - 1, this % capacity) end do - end subroutine add_ci + end subroutine set_ci !=============================================================================== ! GET returns the value matching a given key. If the dictionary does not contain diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 206e5ca65..978978d0d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1368,7 +1368,7 @@ contains end if ! Add cell to dictionary - call cell_dict % add(c % id, i) + call cell_dict % set(c % id, i) ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the @@ -1377,12 +1377,12 @@ contains if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 n_cells_in_univ = 1 - call universe_dict % add(univ_id, n_universes) + call universe_dict % set(univ_id, n_universes) call univ_ids % push_back(univ_id) else n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) end if - call cells_in_univ_dict % add(univ_id, n_cells_in_univ) + call cells_in_univ_dict % set(univ_id, n_cells_in_univ) end do @@ -1604,7 +1604,7 @@ contains &"' specified on surface " // trim(to_str(s%id))) end select ! Add surface to dictionary - call surface_dict % add(s%id, i) + call surface_dict % set(s%id, i) end do ! Check to make sure a boundary condition was applied to at least one @@ -1825,7 +1825,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % add(lat % id, i) + call lattice_dict % set(lat % id, i) end select end do RECT_LATTICES @@ -2012,7 +2012,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % add(lat % id, n_rlats + i) + call lattice_dict % set(lat % id, n_rlats + i) end select end do HEX_LATTICES @@ -2166,7 +2166,7 @@ contains ! Creating dictionary that maps the name of the material to the entry do i = 1, size(libraries) do j = 1, size(libraries(i) % materials) - call library_dict % add(to_lower(libraries(i) % materials(j)), i) + call library_dict % set(to_lower(libraries(i) % materials(j)), i) end do end do @@ -2507,7 +2507,7 @@ contains index_nuclide = index_nuclide + 1 mat % nuclide(j) = index_nuclide - call nuclide_dict % add(to_lower(name), index_nuclide) + call nuclide_dict % set(to_lower(name), index_nuclide) else mat % nuclide(j) = nuclide_dict % get(to_lower(name)) end if @@ -2604,7 +2604,7 @@ contains if (.not. sab_dict % has(to_lower(name))) then index_sab = index_sab + 1 mat % i_sab_tables(j) = index_sab - call sab_dict % add(to_lower(name), index_sab) + call sab_dict % set(to_lower(name), index_sab) else mat % i_sab_tables(j) = sab_dict % get(to_lower(name)) end if @@ -2613,7 +2613,7 @@ contains end if ! Add material to dictionary - call material_dict % add(mat % id, i) + call material_dict % set(mat % id, i) end do ! Set total number of nuclides and S(a,b) tables @@ -2876,7 +2876,7 @@ contains m % volume_frac = ONE/real(product(m % dimension),8) ! Add mesh to dictionary - call mesh_dict % add(m % id, i) + call mesh_dict % set(m % id, i) end do ! We only need the mesh info for plotting @@ -3330,7 +3330,7 @@ contains f % obj % id = filter_id ! Add filter to dictionary - call filter_dict % add(filter_id, i) + call filter_dict % set(filter_id, i) end do READ_FILTERS @@ -3550,7 +3550,7 @@ contains score_name = trim(sarray(j)) ! Append the score to the list of possible trigger scores - if (trigger_on) call trigger_scores % add(trim(score_name), j) + if (trigger_on) call trigger_scores % set(trim(score_name), j) do imomstr = 1, size(MOMENT_STRS) if (starts_with(score_name,trim(MOMENT_STRS(imomstr)))) then @@ -3896,7 +3896,7 @@ contains filt % n_bins = product(m % dimension + 1) ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select t % filter(t % find_filter(FILTER_MESH)) = i_filt @@ -3923,7 +3923,7 @@ contains filt % current = .true. ! Add filter to dictionary - call filter_dict % add(filt % id, i_filt) + call filter_dict % set(filt % id, i_filt) end select t % find_filter(FILTER_SURFACE) = n_filter t % filter(n_filter) = i_filt @@ -4320,7 +4320,7 @@ contains end if ! Add tally to dictionary - call tally_dict % add(t % id, i) + call tally_dict % set(t % id, i) end do READ_TALLIES @@ -4801,7 +4801,7 @@ contains end if ! Add plot to dictionary - call plot_dict % add(pl % id, i) + call plot_dict % set(pl % id, i) end do READ_PLOTS diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 570e8f4d4..536e03408 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -508,7 +508,7 @@ module nuclide_header do i = 1, size(this % reactions) call MTs % push_back(this % reactions(i) % MT) - call this % reaction_index % add(this % reactions(i) % MT, i) + call this % reaction_index % set(this % reactions(i) % MT, i) associate (rx => this % reactions(i)) ! Skip total inelastic level scattering, gas production cross sections diff --git a/src/tally_filter.F90 b/src/tally_filter.F90 index 0b3f1927b..8ef771ccc 100644 --- a/src/tally_filter.F90 +++ b/src/tally_filter.F90 @@ -512,7 +512,7 @@ contains ! Generate mapping from universe indices to filter bins. do i = 1, this % n_bins - call this % map % add(this % universes(i), i) + call this % map % set(this % universes(i), i) end do end subroutine initialize_universe @@ -580,7 +580,7 @@ contains ! Generate mapping from material indices to filter bins. do i = 1, this % n_bins - call this % map % add(this % materials(i), i) + call this % map % set(this % materials(i), i) end do end subroutine initialize_material @@ -652,7 +652,7 @@ contains ! Generate mapping from cell indices to filter bins. do i = 1, this % n_bins - call this % map % add(this % cells(i), i) + call this % map % set(this % cells(i), i) end do end subroutine initialize_cell @@ -847,7 +847,7 @@ contains ! Generate mapping from cell indices to filter bins. do i = 1, this % n_bins - call this % map % add(this % cells(i), i) + call this % map % set(this % cells(i), i) end do end subroutine initialize_cellborn From c46d0a76814636c5e1d320a53b4ad86d5fe5b4cf Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 29 Sep 2017 09:26:14 -0500 Subject: [PATCH 190/229] Remove __all__ from openmc.stats modules --- openmc/stats/multivariate.py | 4 ---- openmc/stats/univariate.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index b738dc43d..0ab11b7c5 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -12,10 +12,6 @@ import openmc.checkvalue as cv from openmc.stats.univariate import Univariate, Uniform -__all__ = ['UnitSphere', 'PolarAzimuthal', 'Isotropic', 'Monodirectional', - 'Spatial', 'CartesianIndependent', 'Box', 'Point'] - - @add_metaclass(ABCMeta) class UnitSphere(object): """Distribution of points on the unit sphere. diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 185b22204..c0476ce45 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -11,10 +11,6 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -__all__ = ['Univariate', 'Discrete', 'Uniform', 'Maxwell', 'Watt', 'Tabular', - 'Legendre', 'Mixture'] - - _INTERPOLATION_SCHEMES = ['histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'] From 7f58aa933b2fbf5d5de1d402941149dabeb6010b Mon Sep 17 00:00:00 2001 From: johnnyliu27 Date: Mon, 2 Oct 2017 11:51:54 -0400 Subject: [PATCH 191/229] Changing parentheses into square brackets for creating materials_file --- examples/jupyter/post-processing.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jupyter/post-processing.ipynb b/examples/jupyter/post-processing.ipynb index 72fb73758..b0e955298 100644 --- a/examples/jupyter/post-processing.ipynb +++ b/examples/jupyter/post-processing.ipynb @@ -105,7 +105,7 @@ "outputs": [], "source": [ "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials((fuel, water, zircaloy))\n", + "materials_file = openmc.Materials([fuel, water, zircaloy])\n", "\n", "# Export to \"materials.xml\"\n", "materials_file.export_to_xml()" From c18cdcffd8afea072446919d1e44cc3097f0d16d Mon Sep 17 00:00:00 2001 From: johnnyliu27 Date: Mon, 2 Oct 2017 12:09:59 -0400 Subject: [PATCH 192/229] More fixes of changing parentheses into square brackets --- examples/jupyter/mgxs-part-ii.ipynb | 2 +- examples/jupyter/mgxs-part-iii.ipynb | 2 +- examples/jupyter/pandas-dataframes.ipynb | 2 +- examples/jupyter/search.ipynb | 2 +- examples/jupyter/tally-arithmetic.ipynb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/jupyter/mgxs-part-ii.ipynb b/examples/jupyter/mgxs-part-ii.ipynb index b12cc4143..b03838477 100644 --- a/examples/jupyter/mgxs-part-ii.ipynb +++ b/examples/jupyter/mgxs-part-ii.ipynb @@ -131,7 +131,7 @@ "outputs": [], "source": [ "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials((fuel, water, zircaloy))\n", + "materials_file = openmc.Materials([fuel, water, zircaloy])\n", "\n", "# Export to \"materials.xml\"\n", "materials_file.export_to_xml()" diff --git a/examples/jupyter/mgxs-part-iii.ipynb b/examples/jupyter/mgxs-part-iii.ipynb index 65d8a069f..addca822f 100644 --- a/examples/jupyter/mgxs-part-iii.ipynb +++ b/examples/jupyter/mgxs-part-iii.ipynb @@ -134,7 +134,7 @@ "outputs": [], "source": [ "# Instantiate a Materials object\n", - "materials_file = openmc.Materials((fuel, water, zircaloy))\n", + "materials_file = openmc.Materials([fuel, water, zircaloy])\n", "\n", "# Export to \"materials.xml\"\n", "materials_file.export_to_xml()" diff --git a/examples/jupyter/pandas-dataframes.ipynb b/examples/jupyter/pandas-dataframes.ipynb index 8c409822e..72d5d7313 100644 --- a/examples/jupyter/pandas-dataframes.ipynb +++ b/examples/jupyter/pandas-dataframes.ipynb @@ -79,7 +79,7 @@ "outputs": [], "source": [ "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials((fuel, water, zircaloy))\n", + "materials_file = openmc.Materials([fuel, water, zircaloy])\n", "\n", "# Export to \"materials.xml\"\n", "materials_file.export_to_xml()" diff --git a/examples/jupyter/search.ipynb b/examples/jupyter/search.ipynb index b84411e20..5c754049a 100644 --- a/examples/jupyter/search.ipynb +++ b/examples/jupyter/search.ipynb @@ -71,7 +71,7 @@ " water.add_element('B', ppm_Boron * 1E-6)\n", " \n", " # Instantiate a Materials object\n", - " materials = openmc.Materials((fuel, zircaloy, water))\n", + " materials = openmc.Materials([fuel, zircaloy, water])\n", " \n", " # Create cylinders for the fuel and clad\n", " fuel_outer_radius = openmc.ZCylinder(R=0.39218)\n", diff --git a/examples/jupyter/tally-arithmetic.ipynb b/examples/jupyter/tally-arithmetic.ipynb index 1b189769d..70cabc7ef 100644 --- a/examples/jupyter/tally-arithmetic.ipynb +++ b/examples/jupyter/tally-arithmetic.ipynb @@ -105,7 +105,7 @@ "outputs": [], "source": [ "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials((fuel, water, zircaloy))\n", + "materials_file = openmc.Materials([fuel, water, zircaloy])\n", "\n", "# Export to \"materials.xml\"\n", "materials_file.export_to_xml()" From a6540b167d2eadd3068be66b5d3d58b297a5cf69 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 09:53:47 -0500 Subject: [PATCH 193/229] Improve handling of units on division for tally arithmetic. Closes #549. --- openmc/tallies.py | 37 +++++++++++++------- tests/test_filter_energyfun/results_true.dat | 4 +-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 6853db494..f9d2e3d10 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -4,7 +4,7 @@ from collections import Iterable, MutableSequence import copy import re from functools import partial -import itertools +from itertools import product from numbers import Integral, Real import warnings from xml.etree import ElementTree as ET @@ -1329,7 +1329,7 @@ class Tally(IDManagerMixin): if isinstance(self_filter, openmc.MeshFilter): dimension = self_filter.mesh.dimension xyz = [range(1, x+1) for x in dimension] - bins = list(itertools.product(*xyz)) + bins = list(product(*xyz)) # Create list of 2-tuples for energy boundary bins elif isinstance(self_filter, (openmc.EnergyFilter, @@ -1364,7 +1364,7 @@ class Tally(IDManagerMixin): indices *= self_filter.num_bins # Apply outer product sum between all filter bin indices - filter_indices = list(map(sum, itertools.product(*filter_indices))) + filter_indices = list(map(sum, product(*filter_indices))) # If user did not specify any specific Filters, use them all else: @@ -1880,7 +1880,7 @@ class Tally(IDManagerMixin): new_tally.filters.append(self_filter) else: all_filters = [self_copy.filters, other_copy.filters] - for self_filter, other_filter in itertools.product(*all_filters): + for self_filter, other_filter in product(*all_filters): new_filter = openmc.CrossFilter(self_filter, other_filter, binary_op) new_tally.filters.append(new_filter) @@ -1891,20 +1891,31 @@ class Tally(IDManagerMixin): new_tally.nuclides.append(self_nuclide) else: all_nuclides = [self_copy.nuclides, other_copy.nuclides] - for self_nuclide, other_nuclide in itertools.product(*all_nuclides): - new_nuclide = \ - openmc.CrossNuclide(self_nuclide, other_nuclide, binary_op) + for self_nuclide, other_nuclide in product(*all_nuclides): + new_nuclide = openmc.CrossNuclide(self_nuclide, other_nuclide, + binary_op) new_tally.nuclides.append(new_nuclide) + # Define helper function that handles score units appropriately + # depending on the binary operator + def cross_score(score1, score2, binary_op): + if binary_op == '+' or binary_op == '-': + if score1 == score2: + return score1 + else: + return openmc.CrossScore(score1, score2, binary_op) + else: + return openmc.CrossScore(score1, score2, binary_op) + # Add scores to the new tally if score_product == 'entrywise': for self_score in self_copy.scores: - new_tally.scores.append(self_score) + new_score = cross_score(self_score, self_score, binary_op) + new_tally.scores.append(new_score) else: all_scores = [self_copy.scores, other_copy.scores] - for self_score, other_score in itertools.product(*all_scores): - new_score = openmc.CrossScore(self_score, other_score, - binary_op) + for self_score, other_score in product(*all_scores): + new_score = cross_score(self_score, other_score, binary_op) new_tally.scores.append(new_score) # Update the new tally's filter strides @@ -2142,7 +2153,7 @@ class Tally(IDManagerMixin): std_dev = {} # Store the data from the misaligned structure - for i, (bin1, bin2) in enumerate(itertools.product(filter1_bins, filter2_bins)): + for i, (bin1, bin2) in enumerate(product(filter1_bins, filter2_bins)): filter_bins = [(bin1,), (bin2,)] if self.mean is not None: @@ -2163,7 +2174,7 @@ class Tally(IDManagerMixin): self._update_filter_strides() # Realign the data - for i, (bin1, bin2) in enumerate(itertools.product(filter1_bins, filter2_bins)): + for i, (bin1, bin2) in enumerate(product(filter1_bins, filter2_bins)): filter_bins = [(bin1,), (bin2,)] indices = self.get_filter_indices(filters, filter_bins) diff --git a/tests/test_filter_energyfun/results_true.dat b/tests/test_filter_energyfun/results_true.dat index 4c9f5ec0a..110038edf 100644 --- a/tests/test_filter_energyfun/results_true.dat +++ b/tests/test_filter_energyfun/results_true.dat @@ -1,2 +1,2 @@ - energyfunction nuclide score mean std. dev. -0 02180f5f310ee4 Am241 (n,gamma) 1.00e-01 9.97e-03 + energyfunction nuclide score mean std. dev. +0 02180f5f310ee4 Am241 ((n,gamma) / (n,gamma)) 1.00e-01 9.97e-03 From a41a4d1feb2d8d6e48a5ae8aa81467f7224da9e1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 14:15:13 -0500 Subject: [PATCH 194/229] Update correlation used for U weight fractions based on enrichment --- openmc/element.py | 14 ++++++++++++-- tests/test_enrichment/test_enrichment.py | 8 ++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index edfbee136..fc019a5d3 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -124,6 +124,15 @@ class Element(object): is a tuple consisting of an openmc.Nuclide instance and the natural abundance of the isotope. + Notes + ----- + When the `enrichment` argument is specified, a correlation from + `ORNL/CSD/TM-244 `_ is used to + calculate the weight fractions of U234, U235, U236, and U238. Namely, + the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%, + respectively, of the U235 weight fraction. The remainder of the isotopic + weight is assigned to U238. + """ # Get the nuclides present in nature @@ -217,9 +226,10 @@ class Element(object): if enrichment is not None: # Calculate the mass fractions of isotopes - abundances['U234'] = 0.008 * enrichment + abundances['U234'] = 0.0089 * enrichment abundances['U235'] = enrichment - abundances['U238'] = 100.0 - 1.008 * enrichment + abundances['U236'] = 0.0046 * enrichment + abundances['U238'] = 100.0 - 1.0135 * enrichment # Convert the mass fractions to mole fractions for nuclide in abundances.keys(): diff --git a/tests/test_enrichment/test_enrichment.py b/tests/test_enrichment/test_enrichment.py index 48416885b..87dd5dab9 100644 --- a/tests/test_enrichment/test_enrichment.py +++ b/tests/test_enrichment/test_enrichment.py @@ -21,7 +21,7 @@ if __name__ == '__main__': sum_densities = 0. for nuc in densities.keys(): - assert nuc in ('U234', 'U235', 'U238') + assert nuc in ('U234', 'U235', 'U236', 'U238') sum_densities += densities[nuc][1] # Compute the weight percent U235 @@ -30,4 +30,8 @@ if __name__ == '__main__': # Compute the ratio of U234/U235 u234_to_u235 = densities['U234'][1] / densities['U235'][1] - assert np.isclose(u234_to_u235, 0.008, rtol=1.e-8) + assert np.isclose(u234_to_u235, 0.0089, rtol=1.e-8) + + # Compute the ratio of U234/U235 + u234_to_u235 = densities['U236'][1] / densities['U235'][1] + assert np.isclose(u234_to_u235, 0.0046, rtol=1.e-8) From 18ca81e8d628aa526fd7583e4aa08e5a43b22a19 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 14:43:18 -0500 Subject: [PATCH 195/229] Fix copy/paste error in enrichment test --- tests/test_enrichment/test_enrichment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_enrichment/test_enrichment.py b/tests/test_enrichment/test_enrichment.py index 87dd5dab9..7d6fd7333 100644 --- a/tests/test_enrichment/test_enrichment.py +++ b/tests/test_enrichment/test_enrichment.py @@ -33,5 +33,5 @@ if __name__ == '__main__': assert np.isclose(u234_to_u235, 0.0089, rtol=1.e-8) # Compute the ratio of U234/U235 - u234_to_u235 = densities['U236'][1] / densities['U235'][1] - assert np.isclose(u234_to_u235, 0.0046, rtol=1.e-8) + u236_to_u235 = densities['U236'][1] / densities['U235'][1] + assert np.isclose(u236_to_u235, 0.0046, rtol=1.e-8) From 6b3ed544ff038dd5424878f312368ca7572d6092 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 14:43:51 -0500 Subject: [PATCH 196/229] Fix error in creating Fortran-backed objects from C API Python bindings when no objects exist. --- openmc/capi/filter.py | 5 ++++- openmc/capi/material.py | 5 ++++- openmc/capi/tally.py | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index e171e05bd..b7cc42fb0 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -147,7 +147,10 @@ class MaterialFilterView(FilterView): def new(cls, bins=None, filter_id=None): # Determine filter ID to assign if filter_id is None: - filter_id = max(filters) + 1 + try: + filter_id = max(filters) + 1 + except ValueError: + filter_id = 1 index = c_int32() _dll.openmc_extend_filters(1, index, None) diff --git a/openmc/capi/material.py b/openmc/capi/material.py index ba4b65089..56040bdef 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -127,7 +127,10 @@ class MaterialView(_View): def new(cls, material_id=None): # Determine ID to assign if material_id is None: - material_id = max(materials) + 1 + try: + material_id = max(materials) + 1 + except ValueError: + material_id = 1 index = c_int32() _dll.openmc_extend_materials(1, index, None) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 335cbb8e7..a4c0b6d4a 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -143,7 +143,10 @@ class TallyView(_View): def new(cls, tally_id=None): # Determine ID to assign if tally_id is None: - tally_id = max(tallies) + 1 + try: + tally_id = max(tallies) + 1 + except ValueError: + tally_id = 1 index = c_int32() _dll.openmc_extend_tallies(1, index, None) From ce8b09781297a2afb8490a99507c9d92efc97af2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 21:06:28 -0500 Subject: [PATCH 197/229] Fix comment in enrichment test --- tests/test_enrichment/test_enrichment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_enrichment/test_enrichment.py b/tests/test_enrichment/test_enrichment.py index 7d6fd7333..fa65d6dce 100644 --- a/tests/test_enrichment/test_enrichment.py +++ b/tests/test_enrichment/test_enrichment.py @@ -32,6 +32,6 @@ if __name__ == '__main__': u234_to_u235 = densities['U234'][1] / densities['U235'][1] assert np.isclose(u234_to_u235, 0.0089, rtol=1.e-8) - # Compute the ratio of U234/U235 + # Compute the ratio of U236/U235 u236_to_u235 = densities['U236'][1] / densities['U235'][1] assert np.isclose(u236_to_u235, 0.0046, rtol=1.e-8) From 95a4f4c0f580edcafc4270433966f91933ab089b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 Oct 2017 22:43:09 -0500 Subject: [PATCH 198/229] Allow C API View objects to be created (new) using normal constructor --- openmc/capi/__init__.py | 3 + openmc/capi/core.py | 12 +++- openmc/capi/filter.py | 121 ++++++++++++++++++++++++++-------------- openmc/capi/material.py | 68 ++++++++++++++-------- openmc/capi/nuclide.py | 11 +++- openmc/capi/tally.py | 58 +++++++++++++++---- 6 files changed, 191 insertions(+), 82 deletions(-) diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index 88a69df34..e0f1c8b27 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -38,3 +38,6 @@ from .cell import * from .filter import * from .tally import * from .settings import settings + +warn("The Python bindings to OpenMC's C API are still unstable " + "and may change substantially in future releases.", FutureWarning) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 2234fac64..3d74ad5cd 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -173,8 +173,14 @@ class _DLLGlobal(object): class _View(object): - def __init__(self, index): - self._index = index - def __repr__(self): return "{}[{}]".format(type(self).__name__, self._index) + + +class _ViewWithID(_View): + def __init__(self, uid=None, new=True, index=None): + # Creating the object has already been handled by __new__. In the + # initializer, all we do is make sure that the object returned has an ID + # assigned. If the array index of the object is out of bounds, an + # OutOfBoundsError will be raised here by virtue of referencing self.id + self.id diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index b7cc42fb0..1fce75702 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -7,8 +7,8 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll -from .core import _View -from .error import _error_handler +from .core import _ViewWithID +from .error import _error_handler, AllocationError, InvalidIDError from .material import MaterialView @@ -57,14 +57,39 @@ _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler -class FilterView(_View): +class FilterView(_ViewWithID): __instances = WeakValueDictionary() - def __new__(cls, *args): - if args not in cls.__instances: + def __new__(cls, filter_type, uid=None, new=True, index=None): + mapping = filters + if index is None: + if new: + # Determine ID to assign + if uid is None: + try: + uid = max(mapping) + 1 + except ValueError: + uid = 1 + else: + if uid in mapping: + raise AllocationError('A filter with ID={} has already ' + 'been allocated.'.format(uid)) + + index = c_int32() + _dll.openmc_extend_filters(1, index, None) + _dll.openmc_filter_set_type(index, filter_type) + index = index.value + else: + index = mapping[uid]._index + + if index not in cls.__instances: instance = super().__new__(cls) - cls.__instances[args] = instance - return cls.__instances[args] + instance._index = index + if uid is not None: + instance.id = uid + cls.__instances[index] = instance + + return cls.__instances[index] @property def id(self): @@ -78,6 +103,9 @@ class FilterView(_View): class EnergyFilterView(FilterView): + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'energy', uid, new, index) + @property def bins(self): energies = POINTER(c_double)() @@ -96,44 +124,60 @@ class EnergyFilterView(FilterView): class EnergyoutFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'energyout', uid, new, index) class AzimuthalFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'azimuthal', uid, new, index) class CellFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'cell', uid, new, index) class CellbornFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'cellborn', uid, new, index) class CellfromFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'cellfrom', uid, new, index) class DelayedGroupFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'delayedgroup', uid, new, index) class DistribcellFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'distribcell', uid, new, index) class EnergyFunctionFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'energyfunction', uid, new, index) class MaterialFilterView(FilterView): + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'material', uid, new, index) + + def __init__(self, bins=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if bins is not None: + self.bins = bins + @property def bins(self): materials = POINTER(c_int32)() n = c_int32() _dll.openmc_material_filter_get_bins(self._index, materials, n) - return [MaterialView(materials[i]) for i in range(n.value)] + return [MaterialView(index=materials[i]) for i in range(n.value)] @bins.setter def bins(self, materials): @@ -143,46 +187,33 @@ class MaterialFilterView(FilterView): _dll.openmc_material_filter_set_bins(self._index, n, bins) - @classmethod - def new(cls, bins=None, filter_id=None): - # Determine filter ID to assign - if filter_id is None: - try: - filter_id = max(filters) + 1 - except ValueError: - filter_id = 1 - - index = c_int32() - _dll.openmc_extend_filters(1, index, None) - _dll.openmc_filter_set_type(index, b'material') - f = cls(index.value) - f.id = filter_id - if bins is not None: - f.bins = bins - return f - class MeshFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'mesh', uid, new, index) class MuFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'mu', uid, new, index) class PolarFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'polar', uid, new, index) class SurfaceFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'surface', uid, new, index) class UniverseFilterView(FilterView): - pass + def __new__(cls, bins=None, uid=None, new=True, index=None): + return super().__new__(cls, b'universe', uid, new, index) -_filter_type_map = { +_FILTER_TYPE_MAP = { 'azimuthal': AzimuthalFilterView, 'cell': CellFilterView, 'cellborn': CellbornFilterView, @@ -205,18 +236,22 @@ def _get_filter(index): filter_type = create_string_buffer(20) _dll.openmc_filter_get_type(index, filter_type) filter_type = filter_type.value.decode() - return _filter_type_map[filter_type](index) + return _FILTER_TYPE_MAP[filter_type](index=index) class _FilterMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_filter_index(key, index) + try: + _dll.openmc_get_filter_index(key, index) + except (AllocationError, InvalidIDError) as e: + # __contains__ expects a KeyError to work correctly + raise KeyError(str(e)) return _get_filter(index.value) def __iter__(self): for i in range(len(self)): - yield TallyView(i + 1).id + yield _get_filter(i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_filters').value diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 56040bdef..2f2f7b3f8 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -6,8 +6,8 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll, NuclideView -from .core import _View -from .error import _error_handler +from .core import _ViewWithID +from .error import _error_handler, AllocationError, InvalidIDError __all__ = ['MaterialView', 'materials'] @@ -43,7 +43,7 @@ _dll.openmc_material_set_id.restype = c_int _dll.openmc_material_set_id.errcheck = _error_handler -class MaterialView(_View): +class MaterialView(_ViewWithID): """View of a material. This class exposes a material that is stored internally in the OpenMC @@ -52,7 +52,12 @@ class MaterialView(_View): Parameters ---------- - index : int + uid : int or None + Unique ID of the tally + new : bool + When `index` is None, this argument controls whether a new object is + created or a view to an existing object is returned. + index : int or None Index in the `materials` array. Attributes @@ -67,6 +72,36 @@ class MaterialView(_View): """ __instances = WeakValueDictionary() + def __new__(cls, uid=None, new=True, index=None): + mapping = materials + if index is None: + if new: + # Determine ID to assign + if uid is None: + try: + uid = max(mapping) + 1 + except ValueError: + uid = 1 + else: + if uid in mapping: + raise AllocationError('A material with ID={} has already ' + 'been allocated.'.format(uid)) + + index = c_int32() + _dll.openmc_extend_materials(1, index, None) + index = index.value + else: + index = mapping[uid]._index + + if index not in cls.__instances: + instance = super().__new__(cls) + instance._index = index + if uid is not None: + instance.id = uid + cls.__instances[index] = instance + + return cls.__instances[index] + @property def id(self): mat_id = c_int32() @@ -123,21 +158,6 @@ class MaterialView(_View): """ _dll.openmc_material_add_nuclide(self._index, name.encode(), density) - @classmethod - def new(cls, material_id=None): - # Determine ID to assign - if material_id is None: - try: - material_id = max(materials) + 1 - except ValueError: - material_id = 1 - - index = c_int32() - _dll.openmc_extend_materials(1, index, None) - mat = cls(index.value) - mat.id = material_id - return mat - def set_density(self, density): """Set density of a material. @@ -174,12 +194,16 @@ class MaterialView(_View): class _MaterialMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_material_index(key, index) - return MaterialView(index.value) + try: + _dll.openmc_get_material_index(key, index) + except InvalidIDError as e: + # __contains__ expects a KeyError to work correctly + raise KeyError(str(e)) + return MaterialView(index=index.value) def __iter__(self): for i in range(len(self)): - yield MaterialView(i + 1).id + yield MaterialView(index=i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_materials').value diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 16bb71acc..c5b61a623 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -7,7 +7,7 @@ from numpy.ctypeslib import as_array from . import _dll from .core import _View -from .error import _error_handler +from .error import _error_handler, DataError, AllocationError __all__ = ['NuclideView', 'nuclides', 'load_nuclide'] @@ -62,6 +62,9 @@ class NuclideView(_View): cls.__instances[args] = instance return cls.__instances[args] + def __init__(self, index): + self._index = index + @property def name(self): name = c_char_p() @@ -78,7 +81,11 @@ class _NuclideMapping(Mapping): """Provide mapping from nuclide name to index in nuclides array.""" def __getitem__(self, key): index = c_int() - _dll.openmc_get_nuclide_index(key.encode(), index) + try: + _dll.openmc_get_nuclide_index(key.encode(), index) + except (DataError, AllocationError) as e: + # __contains__ expects a KeyError to work correctly + raise KeyError(str(e)) return NuclideView(index.value) def __iter__(self): diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index a4c0b6d4a..89816e039 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -5,8 +5,8 @@ from weakref import WeakValueDictionary from numpy.ctypeslib import as_array from . import _dll, NuclideView -from .core import _View -from .error import _error_handler +from .core import _ViewWithID +from .error import _error_handler, AllocationError, InvalidIDError from .filter import _get_filter @@ -51,7 +51,7 @@ _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler -class TallyView(_View): +class TallyView(_ViewWithID): """View of a tally. This class exposes a tally that is stored internally in the OpenMC @@ -60,8 +60,13 @@ class TallyView(_View): Parameters ---------- - index : int - Index in the `tallies` array. + uid : int or None + Unique ID of the tally + new : bool + When `index` is None, this argument controls whether a new object is + created or a view to an existing object is returned. + index : int or None + Index in the `tallies` array. Attributes ---------- @@ -77,11 +82,36 @@ class TallyView(_View): """ __instances = WeakValueDictionary() - def __new__(cls, *args): - if args not in cls.__instances: + def __new__(cls, uid=None, new=True, index=None): + mapping = tallies + if index is None: + if new: + # Determine ID to assign + if uid is None: + try: + uid = max(mapping) + 1 + except ValueError: + uid = 1 + else: + if uid in mapping: + raise AllocationError('A tally with ID={} has already ' + 'been allocated.'.format(uid)) + + index = c_int32() + _dll.openmc_extend_tallies(1, index, None) + _dll.openmc_tally_set_type(index, b'generic') + index = index.value + else: + index = mapping[uid]._index + + if index not in cls.__instances: instance = super().__new__(cls) - cls.__instances[args] = instance - return cls.__instances[args] + instance._index = index + if uid is not None: + instance.id = uid + cls.__instances[index] = instance + + return cls.__instances[index] @property def id(self): @@ -159,12 +189,16 @@ class TallyView(_View): class _TallyMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_tally_index(key, index) - return TallyView(index.value) + try: + _dll.openmc_get_tally_index(key, index) + except InvalidIDError as e: + # __contains__ expects a KeyError to work correctly + raise KeyError(str(e)) + return TallyView(index=index.value) def __iter__(self): for i in range(len(self)): - yield TallyView(i + 1).id + yield TallyView(index=i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_tallies').value From 02b8f4ec098ba4d09ea48cf3a1b259019c27132b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 5 Oct 2017 10:52:29 -0500 Subject: [PATCH 199/229] Change names of openmc.capi classes. Hopefully fix RTD docs build. --- docs/source/pythonapi/capi.rst | 10 +++-- openmc/arithmetic.py | 12 ++--- openmc/capi/__init__.py | 20 +++++++-- openmc/capi/cell.py | 30 +++++++------ openmc/capi/core.py | 4 +- openmc/capi/error.py | 6 +-- openmc/capi/filter.py | 80 +++++++++++++++++----------------- openmc/capi/material.py | 20 ++++----- openmc/capi/nuclide.py | 12 ++--- openmc/capi/tally.py | 24 +++++----- openmc/mgxs/library.py | 6 +-- openmc/mgxs/mdgxs.py | 14 +++--- openmc/mgxs/mgxs.py | 32 +++++++------- openmc/tallies.py | 2 +- 14 files changed, 144 insertions(+), 128 deletions(-) diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index 6e4e860fa..457f05320 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -33,7 +33,9 @@ Classes :nosignatures: :template: myclass.rst - openmc.capi.CellView - openmc.capi.MaterialView - openmc.capi.NuclideView - openmc.capi.TallyView + openmc.capi.Cell + openmc.capi.EnergyFilter + openmc.capi.MaterialFilter + openmc.capi.Material + openmc.capi.Nuclide + openmc.capi.Tally diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 57afacac3..6a781cb5a 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -108,9 +108,9 @@ class CrossNuclide(object): Parameters ---------- - left_nuclide : Nuclide or CrossNuclide + left_nuclide : openmc.Nuclide or CrossNuclide The left nuclide in the outer product - right_nuclide : Nuclide or CrossNuclide + right_nuclide : openmc.Nuclide or CrossNuclide The right nuclide in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -118,9 +118,9 @@ class CrossNuclide(object): Attributes ---------- - left_nuclide : Nuclide or CrossNuclide + left_nuclide : openmc.Nuclide or CrossNuclide The left nuclide in the outer product - right_nuclide : Nuclide or CrossNuclide + right_nuclide : openmc.Nuclide or CrossNuclide The right nuclide in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -510,7 +510,7 @@ class AggregateNuclide(object): Parameters ---------- - nuclides : Iterable of str or Nuclide or CrossNuclide + nuclides : Iterable of str or openmc.Nuclide or CrossNuclide The nuclides included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used @@ -518,7 +518,7 @@ class AggregateNuclide(object): Attributes ---------- - nuclides : Iterable of str or Nuclide or CrossNuclide + nuclides : Iterable of str or openmc.Nuclide or CrossNuclide The nuclides included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index e0f1c8b27..d302001c9 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -13,6 +13,7 @@ objects in the :mod:`openmc.capi` subpackage, for example: """ from ctypes import CDLL +import os import sys from warnings import warn @@ -25,10 +26,21 @@ if sys.platform == 'darwin': else: _suffix = 'so' -# Open shared library -_filename = pkg_resources.resource_filename( - __name__, 'libopenmc.{}'.format(_suffix)) -_dll = CDLL(_filename) +if os.environ.get('READTHEDOCS', None) != 'True': + # Open shared library + _filename = pkg_resources.resource_filename( + __name__, 'libopenmc.{}'.format(_suffix)) + _dll = CDLL(_filename) +else: + # For documentation builds, we don't actually have the shared library + # available. Instead, we create a mock object so that when the modules + # within the openmc.capi package try to configure arguments and return + # values for symbols, no errors occur + try: + from unittest.mock import Mock + except ImportError: + from mock import Mock + _dll = Mock() from .error import * from .core import * diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 11b0e2199..62823c0ba 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -6,11 +6,11 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll -from .core import _View +from .core import _FortranObjectWithID from .error import _error_handler -from .material import MaterialView +from .material import Material -__all__ = ['CellView', 'cells'] +__all__ = ['Cell', 'cells'] # Cell functions _dll.openmc_cell_get_id.argtypes = [c_int32, POINTER(c_int32)] @@ -31,11 +31,11 @@ _dll.openmc_get_cell_index.restype = c_int _dll.openmc_get_cell_index.errcheck = _error_handler -class CellView(_View): - """View of a cell. +class Cell(_FortranObjectWithID): + """Cell stored internally. - This class exposes a cell that is stored internally in the OpenMC solver. To - obtain a view of a cell with a given ID, use the + This class exposes a cell that is stored internally in the OpenMC + library. To obtain a view of a cell with a given ID, use the :data:`openmc.capi.nuclides` mapping. Parameters @@ -72,9 +72,9 @@ class CellView(_View): if fill_type.value == 1: if n.value > 1: - return [MaterialView(i) for i in indices[:n.value]] + return [Material(index=i) for i in indices[:n.value]] else: - return MaterialView(indices[0]) + return Material(index=indices[0]) else: raise NotImplementedError @@ -84,7 +84,7 @@ class CellView(_View): n = len(fill) indices = (c_int*n)(*(m._index for m in fill)) _dll.openmc_cell_set_fill(self._index, 1, 1, indices) - elif isinstance(fill, MaterialView): + elif isinstance(fill, Material): materials = [fill] indices = (c_int*1)(fill._index) _dll.openmc_cell_set_fill(self._index, 1, 1, indices) @@ -108,12 +108,16 @@ class CellView(_View): class _CellMapping(Mapping): def __getitem__(self, key): index = c_int32() - _dll.openmc_get_cell_index(key, index) - return CellView(index.value) + try: + _dll.openmc_get_cell_index(key, index) + except (AllocationError, InvalidIDError) as e: + # __contains__ expects a KeyError to work correctly + raise KeyError(str(e)) + return Cell(index.value) def __iter__(self): for i in range(len(self)): - yield CellView(i + 1).id + yield Cell(i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_cells').value diff --git a/openmc/capi/core.py b/openmc/capi/core.py index 3d74ad5cd..0d8ff5c43 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -172,12 +172,12 @@ class _DLLGlobal(object): self.ctype.in_dll(_dll, self.name).value = value -class _View(object): +class _FortranObject(object): def __repr__(self): return "{}[{}]".format(type(self).__name__, self._index) -class _ViewWithID(_View): +class _FortranObjectWithID(_FortranObject): def __init__(self, uid=None, new=True, index=None): # Creating the object has already been handled by __new__. In the # initializer, all we do is make sure that the object returned has an ID diff --git a/openmc/capi/error.py b/openmc/capi/error.py index 7ebf2cb64..98d43ae46 100644 --- a/openmc/capi/error.py +++ b/openmc/capi/error.py @@ -39,9 +39,6 @@ class InvalidTypeError(Error): """Tried to perform an operation on the wrong type.""" -_errmsg = (c_char*256).in_dll(_dll, 'openmc_err_msg') - - def _error_handler(err, func, args): """Raise exception according to error code.""" @@ -50,7 +47,8 @@ def _error_handler(err, func, args): return c_int.in_dll(_dll, s).value # Get error message set by OpenMC library - msg = _errmsg.value.decode() + errmsg = (c_char*256).in_dll(_dll, 'openmc_err_msg') + msg = errmsg.value.decode() # Raise exception type corresponding to error code if err == errcode('e_allocate'): diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 1fce75702..ac9de8a43 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -7,17 +7,17 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll -from .core import _ViewWithID +from .core import _FortranObjectWithID from .error import _error_handler, AllocationError, InvalidIDError -from .material import MaterialView +from .material import Material -__all__ = ['FilterView', 'AzimuthalFilterView', 'CellFilterView', - 'CellbornFilterView', 'CellfromFilterView', 'DistribcellFilterView', - 'DelayedGroupFilterView', 'EnergyFilterView', 'EnergyoutFilterView', - 'EnergyFunctionFilterView', 'MaterialFilterView', 'MeshFilterView', - 'MuFilterView', 'PolarFilterView', 'SurfaceFilterView', - 'UniverseFilterView', 'filters'] +__all__ = ['Filter', 'AzimuthalFilter', 'CellFilter', + 'CellbornFilter', 'CellfromFilter', 'DistribcellFilter', + 'DelayedGroupFilter', 'EnergyFilter', 'EnergyoutFilter', + 'EnergyFunctionFilter', 'MaterialFilter', 'MeshFilter', + 'MuFilter', 'PolarFilter', 'SurfaceFilter', + 'UniverseFilter', 'filters'] # Tally functions _dll.openmc_energy_filter_get_bins.argtypes = [ @@ -57,7 +57,7 @@ _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler -class FilterView(_ViewWithID): +class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() def __new__(cls, filter_type, uid=None, new=True, index=None): @@ -102,7 +102,7 @@ class FilterView(_ViewWithID): _dll.openmc_filter_set_id(self._index, filter_id) -class EnergyFilterView(FilterView): +class EnergyFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'energy', uid, new, index) @@ -123,47 +123,47 @@ class EnergyFilterView(FilterView): self._index, len(energies), energies_p) -class EnergyoutFilterView(FilterView): +class EnergyoutFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'energyout', uid, new, index) -class AzimuthalFilterView(FilterView): +class AzimuthalFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'azimuthal', uid, new, index) -class CellFilterView(FilterView): +class CellFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'cell', uid, new, index) -class CellbornFilterView(FilterView): +class CellbornFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'cellborn', uid, new, index) -class CellfromFilterView(FilterView): +class CellfromFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'cellfrom', uid, new, index) -class DelayedGroupFilterView(FilterView): +class DelayedGroupFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'delayedgroup', uid, new, index) -class DistribcellFilterView(FilterView): +class DistribcellFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'distribcell', uid, new, index) -class EnergyFunctionFilterView(FilterView): +class EnergyFunctionFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'energyfunction', uid, new, index) -class MaterialFilterView(FilterView): +class MaterialFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'material', uid, new, index) @@ -177,7 +177,7 @@ class MaterialFilterView(FilterView): materials = POINTER(c_int32)() n = c_int32() _dll.openmc_material_filter_get_bins(self._index, materials, n) - return [MaterialView(index=materials[i]) for i in range(n.value)] + return [Material(index=materials[i]) for i in range(n.value)] @bins.setter def bins(self, materials): @@ -188,47 +188,47 @@ class MaterialFilterView(FilterView): _dll.openmc_material_filter_set_bins(self._index, n, bins) -class MeshFilterView(FilterView): +class MeshFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'mesh', uid, new, index) -class MuFilterView(FilterView): +class MuFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'mu', uid, new, index) -class PolarFilterView(FilterView): +class PolarFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'polar', uid, new, index) -class SurfaceFilterView(FilterView): +class SurfaceFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'surface', uid, new, index) -class UniverseFilterView(FilterView): +class UniverseFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super().__new__(cls, b'universe', uid, new, index) _FILTER_TYPE_MAP = { - 'azimuthal': AzimuthalFilterView, - 'cell': CellFilterView, - 'cellborn': CellbornFilterView, - 'cellfrom': CellfromFilterView, - 'delayedgroup': DelayedGroupFilterView, - 'distribcell': DistribcellFilterView, - 'energy': EnergyFilterView, - 'energyout': EnergyoutFilterView, - 'energyfunction': EnergyFunctionFilterView, - 'material': MaterialFilterView, - 'mesh': MeshFilterView, - 'mu': MuFilterView, - 'polar': PolarFilterView, - 'surface': SurfaceFilterView, - 'universe': UniverseFilterView, + 'azimuthal': AzimuthalFilter, + 'cell': CellFilter, + 'cellborn': CellbornFilter, + 'cellfrom': CellfromFilter, + 'delayedgroup': DelayedGroupFilter, + 'distribcell': DistribcellFilter, + 'energy': EnergyFilter, + 'energyout': EnergyoutFilter, + 'energyfunction': EnergyFunctionFilter, + 'material': MaterialFilter, + 'mesh': MeshFilter, + 'mu': MuFilter, + 'polar': PolarFilter, + 'surface': SurfaceFilter, + 'universe': UniverseFilter, } diff --git a/openmc/capi/material.py b/openmc/capi/material.py index 2f2f7b3f8..a9cc9c148 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -5,12 +5,12 @@ from weakref import WeakValueDictionary import numpy as np from numpy.ctypeslib import as_array -from . import _dll, NuclideView -from .core import _ViewWithID +from . import _dll, Nuclide +from .core import _FortranObjectWithID from .error import _error_handler, AllocationError, InvalidIDError -__all__ = ['MaterialView', 'materials'] +__all__ = ['Material', 'materials'] # Material functions _dll.openmc_extend_materials.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] @@ -43,11 +43,11 @@ _dll.openmc_material_set_id.restype = c_int _dll.openmc_material_set_id.errcheck = _error_handler -class MaterialView(_ViewWithID): - """View of a material. +class Material(_FortranObjectWithID): + """Material stored internally. This class exposes a material that is stored internally in the OpenMC - solver. To obtain a view of a material with a given ID, use the + library. To obtain a view of a material with a given ID, use the :data:`openmc.capi.materials` mapping. Parameters @@ -141,7 +141,7 @@ class MaterialView(_ViewWithID): _dll.openmc_material_get_densities(self._index, nuclides, densities, n) # Convert to appropriate types and return - nuclide_list = [NuclideView(nuclides[i]).name for i in range(n.value)] + nuclide_list = [Nuclide(nuclides[i]).name for i in range(n.value)] density_array = as_array(densities, (n.value,)) return nuclide_list, density_array @@ -196,14 +196,14 @@ class _MaterialMapping(Mapping): index = c_int32() try: _dll.openmc_get_material_index(key, index) - except InvalidIDError as e: + except (AllocationError, InvalidIDError) as e: # __contains__ expects a KeyError to work correctly raise KeyError(str(e)) - return MaterialView(index=index.value) + return Material(index=index.value) def __iter__(self): for i in range(len(self)): - yield MaterialView(index=i + 1).id + yield Material(index=i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_materials').value diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index c5b61a623..54d131498 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -6,11 +6,11 @@ import numpy as np from numpy.ctypeslib import as_array from . import _dll -from .core import _View +from .core import _FortranObject from .error import _error_handler, DataError, AllocationError -__all__ = ['NuclideView', 'nuclides', 'load_nuclide'] +__all__ = ['Nuclide', 'nuclides', 'load_nuclide'] # Nuclide functions _dll.openmc_get_nuclide_index.argtypes = [c_char_p, POINTER(c_int)] @@ -36,8 +36,8 @@ def load_nuclide(name): _dll.openmc_load_nuclide(name.encode()) -class NuclideView(_View): - """View of a nuclide. +class Nuclide(_FortranObject): + """Nuclide stored internally. This class exposes a nuclide that is stored internally in the OpenMC solver. To obtain a view of a nuclide with a given name, use the @@ -86,11 +86,11 @@ class _NuclideMapping(Mapping): except (DataError, AllocationError) as e: # __contains__ expects a KeyError to work correctly raise KeyError(str(e)) - return NuclideView(index.value) + return Nuclide(index.value) def __iter__(self): for i in range(len(self)): - yield NuclideView(i + 1).name + yield Nuclide(i + 1).name def __len__(self): return c_int.in_dll(_dll, 'n_nuclides').value diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 89816e039..cb37e6971 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -4,13 +4,13 @@ from weakref import WeakValueDictionary from numpy.ctypeslib import as_array -from . import _dll, NuclideView -from .core import _ViewWithID +from . import _dll, Nuclide +from .core import _FortranObjectWithID from .error import _error_handler, AllocationError, InvalidIDError from .filter import _get_filter -__all__ = ['TallyView', 'tallies'] +__all__ = ['Tally', 'tallies'] # Tally functions _dll.openmc_get_tally_index.argtypes = [c_int32, POINTER(c_int32)] @@ -51,11 +51,11 @@ _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler -class TallyView(_ViewWithID): - """View of a tally. +class Tally(_FortranObjectWithID): + """Tally stored internally. This class exposes a tally that is stored internally in the OpenMC - solver. To obtain a view of a tally with a given ID, use the + library. To obtain a view of a tally with a given ID, use the :data:`openmc.capi.tallies` mapping. Parameters @@ -64,7 +64,7 @@ class TallyView(_ViewWithID): Unique ID of the tally new : bool When `index` is None, this argument controls whether a new object is - created or a view to an existing object is returned. + created or a view of an existing object is returned. index : int or None Index in the `tallies` array. @@ -73,7 +73,7 @@ class TallyView(_ViewWithID): id : int ID of the tally filters : list - List of views to tally filters + List of tally filters nuclides : list of str List of nuclides to score results for results : numpy.ndarray @@ -135,7 +135,7 @@ class TallyView(_ViewWithID): nucs = POINTER(c_int)() n = c_int() _dll.openmc_tally_get_nuclides(self._index, nucs, n) - return [NuclideView(nucs[i]).name if nucs[i] > 0 else 'total' + return [Nuclide(nucs[i]).name if nucs[i] > 0 else 'total' for i in range(n.value)] @property @@ -191,14 +191,14 @@ class _TallyMapping(Mapping): index = c_int32() try: _dll.openmc_get_tally_index(key, index) - except InvalidIDError as e: + except (AllocationError, InvalidIDError) as e: # __contains__ expects a KeyError to work correctly raise KeyError(str(e)) - return TallyView(index=index.value) + return Tally(index=index.value) def __iter__(self): for i in range(len(self)): - yield TallyView(index=i + 1).id + yield Tally(index=i + 1).id def __len__(self): return c_int32.in_dll(_dll, 'n_tallies').value diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 7ebe6cb8c..3cdd0fbf5 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -606,7 +606,7 @@ class Library(object): Parameters ---------- - domain : Material or Cell or Universe or Integral + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh or Integral The material, cell, or universe object of interest (or its ID) mgxs_type : {'total', 'transport', 'nu-transport', 'absorption', 'capture', 'fission', 'nu-fission', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'multiplicity matrix', 'nu-fission matrix', chi', 'chi-prompt', 'inverse-velocity', 'prompt-nu-fission', 'prompt-nu-fission matrix', 'delayed-nu-fission', 'delayed-nu-fission matrix', 'chi-delayed', 'beta'} The type of multi-group cross section object to return @@ -668,7 +668,7 @@ class Library(object): Returns ------- - Library + openmc.mgxs.Library A new multi-group cross section library condensed to the group structure of interest @@ -880,7 +880,7 @@ class Library(object): Returns ------- - Library + openmc.mgxs.Library A Library object loaded from the pickle binary file See also diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 055bf267d..d3f1a0646 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -71,7 +71,7 @@ class MDGXS(MGXS): Reaction type (e.g., 'chi-delayed', 'beta', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -948,7 +948,7 @@ class ChiDelayed(MDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -1462,7 +1462,7 @@ class DelayedNuFissionXS(MDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -1598,7 +1598,7 @@ class Beta(MDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -1782,7 +1782,7 @@ class DecayRate(MDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -1959,7 +1959,7 @@ class MatrixMDGXS(MDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2551,7 +2551,7 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 3325e0b15..192f484a5 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -154,7 +154,7 @@ class MGXS(object): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2018,7 +2018,7 @@ class MatrixMGXS(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2512,7 +2512,7 @@ class TotalXS(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2649,7 +2649,7 @@ class TransportXS(MGXS): If True, the cross section data will include neutron multiplication by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2858,7 +2858,7 @@ class AbsorptionXS(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -2986,7 +2986,7 @@ class CaptureXS(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -3140,7 +3140,7 @@ class FissionXS(MGXS): If true, computes cross sections which only includes prompt neutrons by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -3309,7 +3309,7 @@ class KappaFissionXS(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -3441,7 +3441,7 @@ class ScatterXS(MGXS): If True, the cross section data will include neutron multiplication by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -3658,7 +3658,7 @@ class ScatterMatrixXS(MatrixMGXS): If True, the cross section data will include neutron multiplication by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -4020,7 +4020,7 @@ class ScatterMatrixXS(MatrixMGXS): # Override the nuclides for tally arithmetic correction.nuclides = scatter_p1.nuclides self._xs_tally -= correction - + self._compute_xs() return self._xs_tally @@ -4749,7 +4749,7 @@ class MultiplicityMatrixXS(MatrixMGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -4915,7 +4915,7 @@ class ScatterProbabilityMatrix(MatrixMGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -5088,7 +5088,7 @@ class NuFissionMatrixXS(MatrixMGXS): If true, computes cross sections which only includes prompt neutrons by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -5245,7 +5245,7 @@ class Chi(MGXS): If true, computes cross sections which only includes prompt neutrons by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization @@ -5823,7 +5823,7 @@ class InverseVelocity(MGXS): Reaction type (e.g., 'total', 'nu-fission', etc.) by_nuclide : bool If true, computes cross sections for each nuclide in domain - domain : Material or Cell or Universe or Mesh + domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh Domain for spatial homogenization domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} Domain type for spatial homogenization diff --git a/openmc/tallies.py b/openmc/tallies.py index 6853db494..9c656d56d 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -502,7 +502,7 @@ class Tally(IDManagerMixin): Parameters ---------- - nuclide : str, Nuclide, CrossNuclide or AggregateNuclide + nuclide : str, openmc.Nuclide, CrossNuclide or AggregateNuclide Nuclide to add to the tally. The nuclide should be a Nuclide object when a user is adding nuclides to a Tally for input file generation. The nuclide is a str when a Tally is created from a StatePoint file From 12841f11afa303a77432d5361dae575c39cbd36b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 5 Oct 2017 11:34:43 -0500 Subject: [PATCH 200/229] Make super() Py2 compatible --- openmc/capi/cell.py | 2 +- openmc/capi/filter.py | 44 +++++++++++++++++++++++++---------------- openmc/capi/material.py | 2 +- openmc/capi/nuclide.py | 2 +- openmc/capi/tally.py | 2 +- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 62823c0ba..fe3382589 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -53,7 +53,7 @@ class Cell(_FortranObjectWithID): def __new__(cls, *args): if args not in cls.__instances: - instance = super().__new__(cls) + instance = super(Cell, self).__new__(cls) cls.__instances[args] = instance return cls.__instances[args] diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index ac9de8a43..d15e4dc14 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -83,7 +83,7 @@ class Filter(_FortranObjectWithID): index = mapping[uid]._index if index not in cls.__instances: - instance = super().__new__(cls) + instance = super(Filter, cls).__new__(cls) instance._index = index if uid is not None: instance.id = uid @@ -104,7 +104,7 @@ class Filter(_FortranObjectWithID): class EnergyFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'energy', uid, new, index) + return super(EnergyFilter, cls).__new__(cls, b'energy', uid, new, index) @property def bins(self): @@ -125,50 +125,58 @@ class EnergyFilter(Filter): class EnergyoutFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'energyout', uid, new, index) + return super(Energyoutfilter, cls).__new__(cls, b'energyout', + uid, new, index) class AzimuthalFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'azimuthal', uid, new, index) + return super(AzimuthalFilter, cls).__new__(cls, b'azimuthal', + uid, new, index) class CellFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'cell', uid, new, index) + return super(CellFilter, cls).__new__(cls, b'cell', uid, new, index) class CellbornFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'cellborn', uid, new, index) + return super(CellbornFilter, cls).__new__(cls, b'cellborn', uid, + new, index) class CellfromFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'cellfrom', uid, new, index) + return super(CellfromFilter, cls).__new__(cls, b'cellfrom', uid, + new, index) class DelayedGroupFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'delayedgroup', uid, new, index) + return super(DelayedGroupFilter, cls).__new__(cls, b'delayedgroup', + uid, new, index) class DistribcellFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'distribcell', uid, new, index) + return super(DistribcellFilter, cls).__new__(cls, b'distribcell', + uid, new, index) class EnergyFunctionFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'energyfunction', uid, new, index) + return super(EnergyFunctionFilter, cls).__new__( + cls, b'energyfunction', uid, new, index) class MaterialFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'material', uid, new, index) + return super(MaterialFilter, cls).__new__(cls, b'material', + uid, new, index) def __init__(self, bins=None, uid=None, new=True, index=None): - super().__init__(uid, new, index) + super(MaterialFilter, self).__init__(uid, new, index) if bins is not None: self.bins = bins @@ -190,27 +198,29 @@ class MaterialFilter(Filter): class MeshFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'mesh', uid, new, index) + return super(MeshFilter, cls).__new__(cls, b'mesh', uid, new, index) class MuFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'mu', uid, new, index) + return super(MuFilter, cls).__new__(cls, b'mu', uid, new, index) class PolarFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'polar', uid, new, index) + return super(PolarFilter, cls).__new__(cls, b'polar', uid, new, index) class SurfaceFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'surface', uid, new, index) + return super(SurfaceFilter, cls).__new__(cls, b'surface', uid, + new, index) class UniverseFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super().__new__(cls, b'universe', uid, new, index) + return super(UniverseFilter, cls).__new__(cls, b'universe', uid, + new, index) _FILTER_TYPE_MAP = { diff --git a/openmc/capi/material.py b/openmc/capi/material.py index a9cc9c148..af0e9893e 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -94,7 +94,7 @@ class Material(_FortranObjectWithID): index = mapping[uid]._index if index not in cls.__instances: - instance = super().__new__(cls) + instance = super(Material, cls).__new__(cls) instance._index = index if uid is not None: instance.id = uid diff --git a/openmc/capi/nuclide.py b/openmc/capi/nuclide.py index 54d131498..e07872e58 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/capi/nuclide.py @@ -58,7 +58,7 @@ class Nuclide(_FortranObject): def __new__(cls, *args): if args not in cls.__instances: - instance = super().__new__(cls) + instance = super(Nuclide, cls).__new__(cls) cls.__instances[args] = instance return cls.__instances[args] diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index cb37e6971..799cb42ee 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -105,7 +105,7 @@ class Tally(_FortranObjectWithID): index = mapping[uid]._index if index not in cls.__instances: - instance = super().__new__(cls) + instance = super(Tally, cls).__new__(cls) instance._index = index if uid is not None: instance.id = uid From 4d5ca78ba64c3494bf69a05698f299ea0c9c1bca Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 5 Oct 2017 12:33:12 -0500 Subject: [PATCH 201/229] Improve how PRN seed is exposed to Python --- openmc/capi/settings.py | 12 +++++ src/api.F90 | 7 +-- src/initialize.F90 | 6 ++- src/input_xml.F90 | 5 +- src/random_lcg.F90 | 109 ++++++++++++++++++++-------------------- 5 files changed, 77 insertions(+), 62 deletions(-) diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py index 11b0eacef..eede6cf47 100644 --- a/openmc/capi/settings.py +++ b/openmc/capi/settings.py @@ -10,6 +10,10 @@ _RUN_MODES = {1: 'fixed source', 4: 'particle restart', 5: 'volume'} +_dll.openmc_set_seed.argtypes = [c_int64] +_dll.openmc_set_seed.restype = c_int +_dll.openmc_set_seed.errcheck = _error_handler + class _Settings(object): # Attributes that are accessed through a descriptor @@ -37,5 +41,13 @@ class _Settings(object): else: raise ValueError('Invalid run mode: {}'.format(mode)) + @property + def seed(self): + return c_int64.in_dll(_dll, 'seed').value + + @seed.setter + def seed(self, seed): + _dll.openmc_set_seed(seed) + settings = _Settings() diff --git a/src/api.F90 b/src/api.F90 index 3b2fdacad..4410f2fe4 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -17,7 +17,7 @@ module openmc_api use initialize, only: openmc_init use particle_header, only: Particle use plot, only: openmc_plot_geometry - use random_lcg, only: seed, initialize_prng + use random_lcg, only: seed, openmc_set_seed use settings use simulation_header use tally_header @@ -212,6 +212,8 @@ contains !=============================================================================== subroutine openmc_hard_reset() bind(C) + integer :: err + ! Reset all tallies and timers call openmc_reset() @@ -220,8 +222,7 @@ contains total_gen = 0 ! Reset the random number generator state - seed = 1_8 - call initialize_prng() + err = openmc_set_seed(1_8) end subroutine openmc_hard_reset !=============================================================================== diff --git a/src/initialize.F90 b/src/initialize.F90 index 1720f2adf..a5ead1e83 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -21,7 +21,7 @@ module initialize use message_passing use mgxs_data, only: read_mgxs, create_macro_xs use output, only: print_version, write_message, print_usage - use random_lcg, only: initialize_prng + use random_lcg, only: openmc_set_seed, seed use settings #ifdef _OPENMP use simulation_header, only: n_threads @@ -45,6 +45,8 @@ contains subroutine openmc_init(intracomm) bind(C) integer, intent(in), optional :: intracomm ! MPI intracommunicator + integer :: err + ! Copy the communicator to a new variable. This is done to avoid changing ! the signature of this subroutine. If MPI is being used but no communicator ! was passed, assume MPI_COMM_WORLD. @@ -83,7 +85,7 @@ contains ! Initialize random number generator -- if the user specifies a seed, it ! will be re-initialized later - call initialize_prng() + err = openmc_set_seed(seed) ! Read XML input files call read_input_xml() diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 545c7e351..402e030c4 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -25,7 +25,7 @@ module input_xml use nuclide_header use output, only: write_message, title, header, print_plot use plot_header - use random_lcg, only: prn, seed, initialize_prng + use random_lcg, only: prn, openmc_set_seed use surface_header use set_header, only: SetChar use settings @@ -151,6 +151,7 @@ contains integer :: temp_int integer :: temp_int_array3(3) integer(C_INT32_T) :: i_start, i_end + integer(C_INT64_T) :: seed integer(C_INT) :: err integer, allocatable :: temp_int_array(:) integer :: n_tracks @@ -340,7 +341,7 @@ contains ! Copy random number seed if specified if (check_for_node(root, "seed")) then call get_node_value(root, "seed", seed) - call initialize_prng() + err = openmc_set_seed(seed) end if ! Number of bins for logarithmic grid diff --git a/src/random_lcg.F90 b/src/random_lcg.F90 index 287bbba6d..685557f07 100644 --- a/src/random_lcg.F90 +++ b/src/random_lcg.F90 @@ -1,5 +1,7 @@ module random_lcg + use, intrinsic :: ISO_C_BINDING + use constants implicit none @@ -7,28 +9,29 @@ module random_lcg private save - ! Random number seed - integer(8), public :: seed = 1_8 + ! Starting seed + integer(C_INT64_T), public, bind(C) :: seed = 1_8 - integer(8) :: prn_seed0 ! original seed - integer(8) :: prn_seed(N_STREAMS) ! current seed - integer(8) :: prn_mult ! multiplication factor, g - integer(8) :: prn_add ! additive factor, c - integer :: prn_bits ! number of bits, M - integer(8) :: prn_mod ! 2^M - integer(8) :: prn_mask ! 2^M - 1 - integer(8) :: prn_stride ! stride between particles - real(8) :: prn_norm ! 2^(-M) - integer :: stream ! current RNG stream + ! LCG parameters + integer(C_INT64_T), parameter :: prn_mult = 2806196910506780709_8 ! multiplication factor, g + integer(C_INT64_T), parameter :: prn_add = 1_8 ! additive factor, c + integer, parameter :: prn_bits = 63 ! number of bits, M + integer(C_INT64_T), parameter :: prn_mod = ibset(0_8, prn_bits) ! 2^M + integer(C_INT64_T), parameter :: prn_mask = not(prn_mod) ! 2^M - 1 + integer(C_INT64_T), parameter :: prn_stride = 152917_8 ! stride between particles + real(C_DOUBLE), parameter :: prn_norm = 2._8**(-prn_bits) ! 2^(-M) + ! Current PRNG state + integer(C_INT64_T) :: prn_seed(N_STREAMS) ! current seed + integer :: stream ! current RNG stream !$omp threadprivate(prn_seed, stream) public :: prn public :: future_prn - public :: initialize_prng public :: set_particle_seed public :: advance_prn_seed public :: prn_set_stream + public :: openmc_set_seed contains @@ -38,10 +41,10 @@ contains function prn() result(pseudo_rn) - real(8) :: pseudo_rn + real(C_DOUBLE) :: pseudo_rn - ! This algorithm uses bit-masking to find the next integer(8) value to be - ! used to calculate the random number + ! This algorithm uses bit-masking to find the next integer(C_INT64_T) value + ! to be used to calculate the random number prn_seed(stream) = iand(prn_mult*prn_seed(stream) + prn_add, prn_mask) @@ -59,40 +62,14 @@ contains function future_prn(n) result(pseudo_rn) - integer(8), intent(in) :: n ! number of prns to skip + integer(C_INT64_T), intent(in) :: n ! number of prns to skip - real(8) :: pseudo_rn + real(C_DOUBLE) :: pseudo_rn pseudo_rn = future_seed(n, prn_seed(stream)) * prn_norm end function future_prn -!=============================================================================== -! INITIALIZE_PRNG sets up the random number generator, determining the seed and -! values for g, c, and m. -!=============================================================================== - - subroutine initialize_prng() - - integer :: i - - prn_seed0 = seed -!$omp parallel - do i = 1, N_STREAMS - prn_seed(i) = prn_seed0 + i - 1 - end do - stream = STREAM_TRACKING -!$omp end parallel - prn_mult = 2806196910506780709_8 - prn_add = 1_8 - prn_bits = 63 - prn_mod = ibset(0_8, prn_bits) ! clever way of calculating 2**bits - prn_mask = prn_mod - 1_8 - prn_stride = 152917_8 - prn_norm = 2._8**(-prn_bits) - - end subroutine initialize_prng - !=============================================================================== ! SET_PARTICLE_SEED sets the seed to a unique value based on the ID of the ! particle @@ -100,12 +77,12 @@ contains subroutine set_particle_seed(id) - integer(8), intent(in) :: id + integer(C_INT64_T), intent(in) :: id integer :: i do i = 1, N_STREAMS - prn_seed(i) = future_seed(id*prn_stride, prn_seed0 + i - 1) + prn_seed(i) = future_seed(id*prn_stride, seed + i - 1) end do end subroutine set_particle_seed @@ -117,7 +94,7 @@ contains subroutine advance_prn_seed(n) - integer(8), intent(in) :: n ! number of seeds to skip + integer(C_INT64_T), intent(in) :: n ! number of seeds to skip prn_seed(stream) = future_seed(n, prn_seed(stream)) @@ -132,15 +109,15 @@ contains function future_seed(n, seed) result(new_seed) - integer(8), intent(in) :: n ! number of seeds to skip - integer(8), intent(in) :: seed ! original seed - integer(8) :: new_seed ! new seed + integer(C_INT64_T), intent(in) :: n ! number of seeds to skip + integer(C_INT64_T), intent(in) :: seed ! original seed + integer(C_INT64_T) :: new_seed ! new seed - integer(8) :: nskip ! positive number of seeds to skip - integer(8) :: g ! original multiplicative constant - integer(8) :: c ! original additive constnat - integer(8) :: g_new ! new effective multiplicative constant - integer(8) :: c_new ! new effective additive constant + integer(C_INT64_T) :: nskip ! positive number of seeds to skip + integer(C_INT64_T) :: g ! original multiplicative constant + integer(C_INT64_T) :: c ! original additive constnat + integer(C_INT64_T) :: g_new ! new effective multiplicative constant + integer(C_INT64_T) :: c_new ! new effective additive constant ! In cases where we want to skip backwards, we add the period of the random ! number generator until the number of PRNs to skip is positive since @@ -198,4 +175,26 @@ contains end subroutine prn_set_stream +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_set_seed(new_seed) result(err) bind(C) + ! Saves the starting seed and sets up the PRNG thread state + integer(C_INT64_T), value, intent(in) :: new_seed + integer(C_INT) :: err + + integer :: i + + err = 0 + seed = new_seed +!$omp parallel + do i = 1, N_STREAMS + prn_seed(i) = seed + i - 1 + end do + stream = STREAM_TRACKING +!$omp end parallel + + end function openmc_set_seed + end module random_lcg From c53b7b90f41203f9c10769a7d66d3f8edbdcf7c8 Mon Sep 17 00:00:00 2001 From: amandalund Date: Mon, 9 Oct 2017 14:16:32 -0500 Subject: [PATCH 202/229] Eliminate dictionary call to 'has' before 'get' in get_all_bins --- src/tallies/tally_derivative_header.F90 | 8 +++++--- src/tallies/tally_filter_cell.F90 | 13 +++++++++---- src/tallies/tally_filter_cellborn.F90 | 14 ++++++++++---- src/tallies/tally_filter_cellfrom.F90 | 7 +++++-- src/tallies/tally_filter_distribcell.F90 | 7 +++++-- src/tallies/tally_filter_material.F90 | 19 ++++++++++++------- src/tallies/tally_filter_mesh.F90 | 7 +++++-- src/tallies/tally_filter_surface.F90 | 7 +++++-- src/tallies/tally_filter_universe.F90 | 14 +++++++++----- 9 files changed, 65 insertions(+), 31 deletions(-) diff --git a/src/tallies/tally_derivative_header.F90 b/src/tallies/tally_derivative_header.F90 index 2f6bb2456..304ae5e45 100644 --- a/src/tallies/tally_derivative_header.F90 +++ b/src/tallies/tally_derivative_header.F90 @@ -1,7 +1,7 @@ module tally_derivative_header use constants - use dict_header, only: DictIntInt + use dict_header, only: DictIntInt, EMPTY use error, only: fatal_error use nuclide_header, only: nuclide_dict use string, only: to_str, to_lower @@ -40,6 +40,7 @@ contains character(MAX_WORD_LEN) :: temp_str character(MAX_WORD_LEN) :: word + integer :: val ! Copy the derivative id. if (check_for_node(node, "id")) then @@ -74,12 +75,13 @@ contains call get_node_value(node, "nuclide", word) word = trim(to_lower(word)) - if (.not. nuclide_dict % has(word)) then + val = nuclide_dict % get(word) + if (val == EMPTY) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in derivative " & // trim(to_str(this % id)) // " in any material.") end if - this % diff_nuclide = nuclide_dict % get(word) + this % diff_nuclide = val case("temperature") this % variable = DIFF_TEMPERATURE diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 index cf6d43495..8d2b93d28 100644 --- a/src/tallies/tally_filter_cell.F90 +++ b/src/tallies/tally_filter_cell.F90 @@ -5,6 +5,7 @@ module tally_filter_cell use hdf5 use constants, only: ONE, MAX_LINE_LEN + use dict_header, only: EMPTY use error, only: fatal_error use hdf5_interface use geometry_header @@ -55,11 +56,13 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Iterate over coordinate levels to see with cells match do i = 1, p % n_coord - if (this % map % has(p % coord(i) % cell)) then - call match % bins % push_back(this % map % get(p % coord(i) % cell)) + val = this % map % get(p % coord(i) % cell) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if end do @@ -87,12 +90,14 @@ contains class(CellFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) - if (cell_dict % has(id)) then - this % cells(i) = cell_dict % get(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cells(i) = val else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") diff --git a/src/tallies/tally_filter_cellborn.F90 b/src/tallies/tally_filter_cellborn.F90 index cced39620..450858b6b 100644 --- a/src/tallies/tally_filter_cellborn.F90 +++ b/src/tallies/tally_filter_cellborn.F90 @@ -5,6 +5,7 @@ module tally_filter_cellborn use hdf5 use constants, only: ONE, MAX_LINE_LEN + use dict_header, only: EMPTY use error, only: fatal_error use hdf5_interface use geometry_header @@ -54,8 +55,11 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - if (this % map % has(p % cell_born)) then - call match % bins % push_back(this % map % get(p % cell_born)) + integer :: val + + val = this % map % get(p % cell_born) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if @@ -81,12 +85,14 @@ contains class(CellbornFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % cells(i) - if (cell_dict % has(id)) then - this % cells(i) = cell_dict % get(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cells(i) = val else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") diff --git a/src/tallies/tally_filter_cellfrom.F90 b/src/tallies/tally_filter_cellfrom.F90 index 2000d8571..16cb294d5 100644 --- a/src/tallies/tally_filter_cellfrom.F90 +++ b/src/tallies/tally_filter_cellfrom.F90 @@ -5,6 +5,7 @@ module tally_filter_cellfrom use hdf5 use constants, only: ONE, MAX_LINE_LEN + use dict_header, only: EMPTY use error, only: fatal_error use hdf5_interface use geometry_header @@ -39,11 +40,13 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Starting one coordinate level deeper, find the next bin. do i = 1, p % last_n_coord - if (this % map % has(p % last_cell(i))) then - call match % bins % push_back(this % map % get(p % last_cell(i))) + val = this % map % get(p % last_cell(i)) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) exit end if diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index e65167f08..3cb34efe4 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -5,6 +5,7 @@ module tally_filter_distribcell use hdf5, only: HID_T use constants + use dict_header, only: EMPTY use error use geometry_header use hdf5_interface @@ -96,11 +97,13 @@ contains class(DistribcellFilter), intent(inout) :: this integer :: id + integer :: val ! Convert id to index. id = this % cell - if (cell_dict % has(id)) then - this % cell = cell_dict % get(id) + val = cell_dict % get(id) + if (val /= EMPTY) then + this % cell = val this % n_bins = cells(this % cell) % instances else call fatal_error("Could not find cell " // trim(to_str(id)) & diff --git a/src/tallies/tally_filter_material.F90 b/src/tallies/tally_filter_material.F90 index 1eeb4f1eb..778fec4b6 100644 --- a/src/tallies/tally_filter_material.F90 +++ b/src/tallies/tally_filter_material.F90 @@ -5,7 +5,7 @@ module tally_filter_material use hdf5, only: HID_T use constants - use dict_header, only: DictIntInt + use dict_header, only: DictIntInt, EMPTY use error use hdf5_interface use material_header, only: materials, material_dict @@ -56,10 +56,13 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - if (this % map % has(p % material)) then - call match % bins % push_back(this % map % get(p % material)) - call match % weights % push_back(ONE) - end if + integer :: val + + val = this % map % get(p % material) + if (val /= EMPTY) then + call match % bins % push_back(val) + call match % weights % push_back(ONE) + end if end subroutine get_all_bins_material @@ -84,12 +87,14 @@ contains class(MaterialFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % materials(i) - if (material_dict % has(id)) then - this % materials(i) = material_dict % get(id) + val = material_dict % get(id) + if (val /= EMPTY) then + this % materials(i) = val else call fatal_error("Could not find material " // trim(to_str(id)) & &// " specified on a tally filter.") diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index eae5d1c17..2092e7e71 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -5,6 +5,7 @@ module tally_filter_mesh use hdf5 use constants + use dict_header, only: EMPTY use error use mesh_header, only: RegularMesh, meshes, n_meshes, mesh_dict use hdf5_interface @@ -41,6 +42,7 @@ contains integer :: i_mesh integer :: id integer :: n + integer :: val n = node_word_count(node, "bins") @@ -51,8 +53,9 @@ contains call get_node_value(node, "bins", id) ! Get pointer to mesh - if (mesh_dict % has(id)) then - i_mesh = mesh_dict % get(id) + val = mesh_dict % get(id) + if (val /= EMPTY) then + i_mesh = val else call fatal_error("Could not find mesh " // trim(to_str(id)) & // " specified on filter.") diff --git a/src/tallies/tally_filter_surface.F90 b/src/tallies/tally_filter_surface.F90 index 91956355b..daecd8891 100644 --- a/src/tallies/tally_filter_surface.F90 +++ b/src/tallies/tally_filter_surface.F90 @@ -5,6 +5,7 @@ module tally_filter_surface use hdf5 use constants, only: ONE, MAX_LINE_LEN + use dict_header, only: EMPTY use error, only: fatal_error use hdf5_interface use surface_header @@ -84,12 +85,14 @@ contains class(SurfaceFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % surfaces(i) - if (surface_dict % has(id)) then - this % surfaces(i) = surface_dict % get(id) + val = surface_dict % get(id) + if (val /= EMPTY) then + this % surfaces(i) = val else call fatal_error("Could not find surface " // trim(to_str(id)) & &// " specified on tally filter.") diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 index e00b53148..742152232 100644 --- a/src/tallies/tally_filter_universe.F90 +++ b/src/tallies/tally_filter_universe.F90 @@ -5,6 +5,7 @@ module tally_filter_universe use hdf5 use constants, only: ONE, MAX_LINE_LEN + use dict_header, only: EMPTY use error, only: fatal_error use hdf5_interface use geometry_header @@ -54,12 +55,13 @@ contains type(TallyFilterMatch), intent(inout) :: match integer :: i + integer :: val ! Iterate over coordinate levels to see which universes match do i = 1, p % n_coord - if (this % map % has(p % coord(i) % universe)) then - call match % bins % push_back(this % map % get(p % coord(i) & - % universe)) + val = this % map % get(p % coord(i) % universe) + if (val /= EMPTY) then + call match % bins % push_back(val) call match % weights % push_back(ONE) end if end do @@ -87,12 +89,14 @@ contains class(UniverseFilter), intent(inout) :: this integer :: i, id + integer :: val ! Convert ids to indices. do i = 1, this % n_bins id = this % universes(i) - if (universe_dict % has(id)) then - this % universes(i) = universe_dict % get(id) + val = universe_dict % get(id) + if (val /= EMPTY) then + this % universes(i) = val else call fatal_error("Could not find universe " // trim(to_str(id)) & &// " specified on a tally filter.") From b73c042c5d03c9dc545e70a54456a6ade748c41f Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 11 Oct 2017 11:59:54 -0500 Subject: [PATCH 203/229] Address #921 comments --- src/dict_header.F90 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dict_header.F90 b/src/dict_header.F90 index c960e0619..9153981ee 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -8,7 +8,7 @@ module dict_header ! surfaces by name. ! ! The implementation is based on Algorithm D from Knuth Vol. 3 Sec. 6.4 (open -! addressing with double hashing). Hash tables sizes M are chosen such that M +! addressing with double hashing). Hash table sizes M are chosen such that M ! and M - 2 are twin primes, which helps reduce clustering. An upper limit is ! placed on the load factor to prevent exponential performance degradation as ! the number of entries approaches the number of buckets. @@ -142,8 +142,11 @@ contains c = 2 + mod(hash, this % capacity - 2) do - if (this % table(i) % hash == hash .and. & - this % table(i) % entry % key == key) exit + if (this % table(i) % hash == hash) then + if (allocated(this % table(i) % entry)) then + if (this % table(i) % entry % key == key) exit + end if + end if if (this % table(i) % hash == EMPTY) exit @@ -408,7 +411,7 @@ contains ! NEXT_ENTRY finds the next (key,value) pair. The value of current_entry is ! updated with the (key,value) pair, and the value of i is updated with the ! index of the entry in the table. Passing in i = 0 will locate the first entry -! in the dictionary. If there are no more entries, i will be set to 0. +! in the dictionary. If there are no more entries, i will be set to 0. !=============================================================================== subroutine next_entry_ii(this, current_entry, i) @@ -505,7 +508,7 @@ contains ! HASH returns the hash value for a given key !=============================================================================== - function hash_ii(key) result(hash) + pure function hash_ii(key) result(hash) integer, intent(in) :: key integer :: hash @@ -514,7 +517,7 @@ contains end function hash_ii - function hash_ci(key) result(hash) + pure function hash_ci(key) result(hash) character(*), intent(in) :: key integer :: hash From 3fb12a33a336226e554c9dbf95b243e80cc32893 Mon Sep 17 00:00:00 2001 From: amandalund Date: Wed, 11 Oct 2017 12:23:36 -0500 Subject: [PATCH 204/229] Added source of hash table sizes in comments --- src/dict_header.F90 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dict_header.F90 b/src/dict_header.F90 index 9153981ee..d2bf71721 100644 --- a/src/dict_header.F90 +++ b/src/dict_header.F90 @@ -9,9 +9,13 @@ module dict_header ! ! The implementation is based on Algorithm D from Knuth Vol. 3 Sec. 6.4 (open ! addressing with double hashing). Hash table sizes M are chosen such that M -! and M - 2 are twin primes, which helps reduce clustering. An upper limit is -! placed on the load factor to prevent exponential performance degradation as -! the number of entries approaches the number of buckets. +! and M - 2 are twin primes, which helps reduce clustering. The sequence of +! twin primes used for the table sizes comes from +! https://github.com/anholt/hash_table/blob/master/hash_table.c. These values +! were selected so that the table would grow by approximately a factor of two +! each time the maximum load factor is exceeded. An upper limit is placed on +! the load factor to prevent exponential performance degradation as the number +! of entries approaches the number of buckets. !=============================================================================== implicit none From 645b740d12496ec633d4817fa29526dc319671f8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 11 Oct 2017 13:47:30 -0500 Subject: [PATCH 205/229] Fix typo, add __init__ for capi.EnergyFilter --- openmc/capi/filter.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index d15e4dc14..402ac4d68 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -106,6 +106,11 @@ class EnergyFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): return super(EnergyFilter, cls).__new__(cls, b'energy', uid, new, index) + def __init__(self, bins=None, uid=None, new=True, index=None): + super(EnergyFilter, self).__init__(uid, new, index) + if bins is not None: + self.bins = bins + @property def bins(self): energies = POINTER(c_double)() @@ -125,7 +130,7 @@ class EnergyFilter(Filter): class EnergyoutFilter(Filter): def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(Energyoutfilter, cls).__new__(cls, b'energyout', + return super(EnergyoutFilter, cls).__new__(cls, b'energyout', uid, new, index) From e27e1f3003a430ea6943962da1bfb3df2cfdc7ad Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 11 Oct 2017 14:05:28 -0500 Subject: [PATCH 206/229] Use class attribute in capi.Filter.__new__ to avoid the need to define __new__ in subclasses. --- openmc/capi/filter.py | 63 +++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 402ac4d68..1b52af6db 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -60,7 +60,7 @@ _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() - def __new__(cls, filter_type, uid=None, new=True, index=None): + def __new__(cls, obj=None, uid=None, new=True, index=None): mapping = filters if index is None: if new: @@ -75,9 +75,13 @@ class Filter(_FortranObjectWithID): raise AllocationError('A filter with ID={} has already ' 'been allocated.'.format(uid)) + # Resize internal array index = c_int32() _dll.openmc_extend_filters(1, index, None) - _dll.openmc_filter_set_type(index, filter_type) + + # Set the filter type -- note that the filter_type attribute + # only exists on subclasses! + _dll.openmc_filter_set_type(index, cls.filter_type.encode()) index = index.value else: index = mapping[uid]._index @@ -103,8 +107,7 @@ class Filter(_FortranObjectWithID): class EnergyFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(EnergyFilter, cls).__new__(cls, b'energy', uid, new, index) + filter_type = 'energy' def __init__(self, bins=None, uid=None, new=True, index=None): super(EnergyFilter, self).__init__(uid, new, index) @@ -129,56 +132,39 @@ class EnergyFilter(Filter): class EnergyoutFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(EnergyoutFilter, cls).__new__(cls, b'energyout', - uid, new, index) + filter_type = 'energyout' class AzimuthalFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(AzimuthalFilter, cls).__new__(cls, b'azimuthal', - uid, new, index) + filter_type = 'azimuthal' class CellFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(CellFilter, cls).__new__(cls, b'cell', uid, new, index) + filter_type = 'cell' class CellbornFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(CellbornFilter, cls).__new__(cls, b'cellborn', uid, - new, index) + filter_type = 'cellborn' class CellfromFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(CellfromFilter, cls).__new__(cls, b'cellfrom', uid, - new, index) + filter_type = 'cellfrom' class DelayedGroupFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(DelayedGroupFilter, cls).__new__(cls, b'delayedgroup', - uid, new, index) + filter_type = 'delayedgroup' class DistribcellFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(DistribcellFilter, cls).__new__(cls, b'distribcell', - uid, new, index) + filter_type = 'distribcell' class EnergyFunctionFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(EnergyFunctionFilter, cls).__new__( - cls, b'energyfunction', uid, new, index) + filter_type = 'energyfunction' class MaterialFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(MaterialFilter, cls).__new__(cls, b'material', - uid, new, index) + filter_type = 'material' def __init__(self, bins=None, uid=None, new=True, index=None): super(MaterialFilter, self).__init__(uid, new, index) @@ -202,30 +188,23 @@ class MaterialFilter(Filter): class MeshFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(MeshFilter, cls).__new__(cls, b'mesh', uid, new, index) + filter_type = 'mesh' class MuFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(MuFilter, cls).__new__(cls, b'mu', uid, new, index) + filter_type = 'mu' class PolarFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(PolarFilter, cls).__new__(cls, b'polar', uid, new, index) + filter_type = 'polar' class SurfaceFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(SurfaceFilter, cls).__new__(cls, b'surface', uid, - new, index) + filter_type = 'surface' class UniverseFilter(Filter): - def __new__(cls, bins=None, uid=None, new=True, index=None): - return super(UniverseFilter, cls).__new__(cls, b'universe', uid, - new, index) + filter_type = 'universe' _FILTER_TYPE_MAP = { From 7653be0a5e1ce0fece431711129faad45083c72c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 29 Sep 2017 09:45:42 -0500 Subject: [PATCH 207/229] Use argparse in run_tests.py instead of optparse --- tests/run_tests.py | 78 +++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/tests/run_tests.py b/tests/run_tests.py index 50e9313df..a3320823a 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -10,35 +10,35 @@ import glob import socket from subprocess import call, check_output from collections import OrderedDict -from optparse import OptionParser +from argparse import ArgumentParser # Command line parsing -parser = OptionParser() -parser.add_option('-j', '--parallel', dest='n_procs', default='1', +parser = ArgumentParser() +parser.add_argument('-j', '--parallel', dest='n_procs', default='1', help="Number of parallel jobs.") -parser.add_option('-R', '--tests-regex', dest='regex_tests', +parser.add_argument('-R', '--tests-regex', dest='regex_tests', help="Run tests matching regular expression. \ Test names are the directories present in tests folder.\ This uses standard regex syntax to select tests.") -parser.add_option('-C', '--build-config', dest='build_config', +parser.add_argument('-C', '--build-config', dest='build_config', help="Build configurations matching regular expression. \ Specific build configurations can be printed out with \ optional argument -p, --print. This uses standard \ regex syntax to select build configurations.") -parser.add_option('-l', '--list', action="store_true", +parser.add_argument('-l', '--list', action="store_true", dest="list_build_configs", default=False, help="List out build configurations.") -parser.add_option("-p", "--project", dest="project", default="", +parser.add_argument("-p", "--project", dest="project", default="", help="project name for build") -parser.add_option("-D", "--dashboard", dest="dash", +parser.add_argument("-D", "--dashboard", dest="dash", help="Dash name -- Experimental, Nightly, Continuous") -parser.add_option("-u", "--update", action="store_true", dest="update", +parser.add_argument("-u", "--update", action="store_true", dest="update", help="Allow CTest to update repo. (WARNING: may overwrite\ changes that were not pushed.") -parser.add_option("-s", "--script", action="store_true", dest="script", +parser.add_argument("-s", "--script", action="store_true", dest="script", help="Activate CTest scripting mode for coverage, valgrind\ and dashboard capability.") -(options, args) = parser.parse_args() +args = parser.parse_args() # Default compiler paths FC='gfortran' @@ -173,7 +173,7 @@ class Test(object): # Sets the build name that will show up on the CDash def get_build_name(self): - self.build_name = options.project + '_' + self.name + self.build_name = args.project + '_' + self.name return self.build_name # Sets up build options for various tests. It is used both @@ -246,9 +246,9 @@ class Test(object): make_list = ['make','-s'] # Check for parallel - if options.n_procs is not None: + if args.n_procs is not None: make_list.append('-j') - make_list.append(options.n_procs) + make_list.append(args.n_procs) # Run make rc = call(make_list) @@ -265,14 +265,14 @@ class Test(object): ctest_list = ['ctest'] # Check for parallel - if options.n_procs is not None: + if args.n_procs is not None: ctest_list.append('-j') - ctest_list.append(options.n_procs) + ctest_list.append(args.n_procs) # Check for subset of tests - if options.regex_tests is not None: + if args.regex_tests is not None: ctest_list.append('-R') - ctest_list.append(options.regex_tests) + ctest_list.append(args.regex_tests) # Run ctests rc = call(ctest_list) @@ -308,7 +308,7 @@ add_test('hdf5-debug_valgrind', debug=True, valgrind=True) add_test('hdf5-debug_coverage', debug=True, coverage=True) # Check to see if we should just print build configuration information to user -if options.list_build_configs: +if args.list_build_configs: for key in tests: print('Configuration Name: {0}'.format(key)) print(' Debug Flags:..........{0}'.format(tests[key].debug)) @@ -320,10 +320,10 @@ if options.list_build_configs: exit() # Delete items of dictionary that don't match regular expression -if options.build_config is not None: +if args.build_config is not None: to_delete = [] for key in tests: - if not re.search(options.build_config, key): + if not re.search(args.build_config, key): to_delete.append(key) for key in to_delete: del tests[key] @@ -333,27 +333,21 @@ if options.build_config is not None: # Experimental, Nightly, Continuous. On the CDash end, these can be # reorganized into groups when a hostname, dashboard and build name # are matched. -if options.dash is None: +if args.dash is None: dash = 'Experimental' submit = '' else: - dash = options.dash + dash = args.dash submit = 'ctest_submit()' # Check for update command, which will run git fetch/merge and will delete # any changes to repo that were not pushed to remote origin -if options.update: - update = 'ctest_update()' -else: - update = '' +update = 'ctest_update()' if args.update else '' # Check for CTest scipts mode # Sets up whether we should use just the basic ctest command or use # CTest scripting to perform tests. -if not options.dash is None or options.script: - script_mode = True -else: - script_mode = False +script_mode = (args.dash is not None or args.script) # Setup CTest script vars. Not used in non-script mode pwd = os.getcwd() @@ -364,17 +358,17 @@ ctest_vars = { 'dashboard': dash, 'submit': submit, 'update': update, - 'n_procs': options.n_procs + 'n_procs': args.n_procs } # Check project name -subprop = """set_property(GLOBAL PROPERTY SubProject {0})""" -if options.project == "" : - ctest_vars.update({'subproject':''}) -elif options.project == 'develop': - ctest_vars.update({'subproject':''}) +subprop = "set_property(GLOBAL PROPERTY SubProject {0})" +if args.project == "" : + ctest_vars.update({'subproject': ''}) +elif args.project == 'develop': + ctest_vars.update({'subproject': ''}) else: - ctest_vars.update({'subproject':subprop.format(options.project)}) + ctest_vars.update({'subproject': subprop.format(args.project)}) # Set up default valgrind tests (subset of all tests) # Currently takes too long to run all the tests with valgrind @@ -396,8 +390,8 @@ if not script_mode: for key in to_delete: del tests[key] -# Check if tests empty -if len(list(tests.keys())) == 0: +# Check if tests is empty +if not tests: print('No tests to run.') exit() @@ -447,7 +441,7 @@ for key in iter(tests): # Check for user custom tests # INCLUDE is a CTest command that allows for a subset # of tests to be executed. Only used in script mode. - if options.regex_tests is None: + if args.regex_tests is None: ctest_vars.update({'tests' : ''}) # No user tests, use default valgrind tests @@ -456,7 +450,7 @@ for key in iter(tests): format(valgrind_default_tests)}) else: ctest_vars.update({'tests' : 'INCLUDE {0}'. - format(options.regex_tests)}) + format(args.regex_tests)}) # Main part of code that does the ctest execution. # It is broken up by two modes, script and non-script From 2673880a9c95f710d531a67598119280be2dbe0e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 29 Sep 2017 11:09:50 -0500 Subject: [PATCH 208/229] Move test_element_wo to unit tests --- tests/{test_element_wo => unit_tests}/test_element_wo.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename tests/{test_element_wo => unit_tests}/test_element_wo.py (92%) diff --git a/tests/test_element_wo/test_element_wo.py b/tests/unit_tests/test_element_wo.py similarity index 92% rename from tests/test_element_wo/test_element_wo.py rename to tests/unit_tests/test_element_wo.py index e2a5726f1..7b9487f73 100644 --- a/tests/test_element_wo/test_element_wo.py +++ b/tests/unit_tests/test_element_wo.py @@ -5,13 +5,11 @@ import sys import numpy as np -sys.path.insert(0, os.pardir) -sys.path.insert(0, os.path.join(os.pardir, os.pardir)) from openmc import Material from openmc.data import NATURAL_ABUNDANCE, atomic_mass -if __name__ == '__main__': +def test_element_wo(): # This test doesn't require an OpenMC run. We just need to make sure the # element.expand() method expands elements with the proper nuclide # compositions. From 232f40e1193c1e520025e30334f5ad3bc9cf30da Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 29 Sep 2017 11:11:18 -0500 Subject: [PATCH 209/229] Only install via setuptools --- setup.py | 65 +++++++++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/setup.py b/setup.py index 7ca824ab0..8d482b862 100755 --- a/setup.py +++ b/setup.py @@ -3,13 +3,8 @@ import glob import sys import numpy as np -try: - from setuptools import setup - have_setuptools = True -except ImportError: - from distutils.core import setup - have_setuptools = False +from setuptools import setup try: from Cython.Build import cythonize have_cython = True @@ -28,11 +23,12 @@ else: with open('openmc/__init__.py', 'r') as f: version = f.readlines()[-1].split()[-1].strip("'") -kwargs = {'name': 'openmc', - 'version': version, - 'packages': ['openmc', 'openmc.capi', 'openmc.data', 'openmc.mgxs', - 'openmc.model', 'openmc.stats'], - 'scripts': glob.glob('scripts/openmc-*'), +kwargs = { + 'name': 'openmc', + 'version': version, + 'packages': ['openmc', 'openmc.capi', 'openmc.data', 'openmc.mgxs', + 'openmc.model', 'openmc.stats'], + 'scripts': glob.glob('scripts/openmc-*'), # Data files and librarries 'package_data': { @@ -42,33 +38,30 @@ kwargs = {'name': 'openmc', # Metadata 'author': 'Will Boyd', - 'author_email': 'wbinventor@gmail.com', - 'description': 'OpenMC Python API', - 'url': 'https://github.com/mit-crpg/openmc', - 'classifiers': [ - 'Intended Audience :: Developers', - 'Intended Audience :: End Users/Desktop', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering' - ]} + 'author_email': 'wbinventor@gmail.com', + 'description': 'OpenMC Python API', + 'url': 'https://github.com/mit-crpg/openmc', + 'classifiers': [ + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering' + ], -if have_setuptools: - kwargs.update({ - # Required dependencies - 'install_requires': ['six', 'numpy>=1.9', 'h5py', 'scipy', 'pandas>=0.17.0'], + # Required dependencies + 'install_requires': ['six', 'numpy>=1.9', 'h5py', 'scipy', + 'pandas>=0.17.0', 'lxml'], - # Optional dependencies - 'extras_require': { - 'decay': ['uncertainties'], - 'plot': ['matplotlib', 'ipython'], - 'vtk': ['vtk', 'silomesh'], - 'validate': ['lxml'] - }, - - }) + # Optional dependencies + 'extras_require': { + 'decay': ['uncertainties'], + 'plot': ['matplotlib', 'ipython'], + 'vtk': ['vtk', 'silomesh'], + }, +} # If Cython is present, add resonance reconstruction capability if have_cython: From 819744bbcba2f53a15d4cdd257be3580f2ad0f12 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 29 Sep 2017 14:30:57 -0500 Subject: [PATCH 210/229] Add a MANIFEST.in and tox.ini file --- .gitignore | 4 ++++ MANIFEST.in | 2 ++ tox.ini | 9 +++++++++ 3 files changed, 15 insertions(+) create mode 100644 MANIFEST.in create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index a0cfd5c7f..35f45e747 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,7 @@ examples/jupyter/plots *.c *.html *.so + +.cache/ +.tox/ +.python-version diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..bd3bec568 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include readme.rst +include openmc/data/reconstruct.pyx diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..951bd8cd0 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist = py{34,36} +[testenv] +commands = pytest tests/unit_tests +deps = + pytest + numpy + cython +passenv = OPENMC_CROSS_SECTIONS From 12848904cb119e2c7b83eaffefa033b2424a58f8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 2 Oct 2017 14:01:51 -0500 Subject: [PATCH 211/229] Remove unused files at root --- CTestConfig.cmake | 25 ------------------------- Makefile | 14 -------------- 2 files changed, 39 deletions(-) delete mode 100644 CTestConfig.cmake delete mode 100644 Makefile diff --git a/CTestConfig.cmake b/CTestConfig.cmake deleted file mode 100644 index e127a8ddf..000000000 --- a/CTestConfig.cmake +++ /dev/null @@ -1,25 +0,0 @@ -## This file should be placed in the root directory of your project. -## Then modify the CMakeLists.txt file in the root directory of your -## project to incorporate the testing dashboard. -## # The following are required to uses Dart and the Cdash dashboard -## ENABLE_TESTING() -## INCLUDE(CTest) - -# Generic information about CDASH site -set(CTEST_PROJECT_NAME "OpenMC") -set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") -set(CTEST_DROP_METHOD "http") -set(CTEST_DROP_SITE "openmc.mit.edu") -set(CTEST_DROP_LOCATION "/cdash/submit.php?project=OpenMC") -set(CTEST_DROP_SITE_CDASH TRUE) - -# Set file size larger to see more output -set(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE "20000") -set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "20000") - -# User/password to CDASH site -# Please contact Nick Horelik or -# Bryan Herman if you want to push -# test suite information to our CDASH site. -set(CTEST_DROP_SITE_USER "") -set(CTEST_DROP_SITE_PASSWORD "") diff --git a/Makefile b/Makefile deleted file mode 100644 index 990f22d9d..000000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: - mkdir -p build - cmake -H. -Bbuild - make -s -C build -clean: - make -s -C build clean -distclean: - rm -fr build -test: - make -s -C build test -install: - make -s -C build install - -.PHONY: all clean distclean test install From d21d158a5bf3bd21ed49e37a5240e707b053d559 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 2 Oct 2017 14:06:14 -0500 Subject: [PATCH 212/229] Add MANIFEST.in and update setup.py --- MANIFEST.in | 36 +++++++++++++++++++++++++++++++++++- setup.py | 27 +++++++++++++++++---------- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index bd3bec568..04436bf1d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,36 @@ -include readme.rst +include CMakeLists.txt +include LICENSE +include schemas.xml +include tox.ini include openmc/data/reconstruct.pyx +include docs/source/_templates/layout.html +include docs/sphinxext/LICENSE +recursive-include . *.rst +recursive-include cmake *.cmake +recursive-include docs *.css +recursive-include docs *.dia +recursive-include docs *.png +recursive-include docs *.py +recursive-include docs *.svg +recursive-include docs *.tex +recursive-include docs *.txt +recursive-include docs Makefile +recursive-include examples *.h5 +recursive-include examples *.ipynb +recursive-include examples *.png +recursive-include examples *.py +recursive-include examples *.xml +recursive-include man *.1 +recursive-include src *.F90 +recursive-include src *.c +recursive-include src *.cc +recursive-include src *.cpp +recursive-include src *.h +recursive-include src *.hpp +recursive-include src *.rnc +recursive-include src *.rng +recursive-include tests *.dat +recursive-include tests *.h5 +recursive-include tests *.py +recursive-include tests *.xml +prune docs/build diff --git a/setup.py b/setup.py index 8d482b862..354098ea3 100755 --- a/setup.py +++ b/setup.py @@ -26,29 +26,36 @@ with open('openmc/__init__.py', 'r') as f: kwargs = { 'name': 'openmc', 'version': version, - 'packages': ['openmc', 'openmc.capi', 'openmc.data', 'openmc.mgxs', - 'openmc.model', 'openmc.stats'], + 'packages': find_packages(), 'scripts': glob.glob('scripts/openmc-*'), - # Data files and librarries - 'package_data': { - 'openmc.capi': ['libopenmc.{}'.format(suffix)], - 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] - }, + # Data files and librarries + 'package_data': { + 'openmc.capi': ['libopenmc.{}'.format(suffix)], + 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] + }, - # Metadata - 'author': 'Will Boyd', + # Metadata + 'author': 'Will Boyd', 'author_email': 'wbinventor@gmail.com', 'description': 'OpenMC Python API', 'url': 'https://github.com/mit-crpg/openmc', 'classifiers': [ + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', - 'Programming Language :: Python', 'Topic :: Scientific/Engineering' + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ], # Required dependencies From 00f6bbe26608e78b7de6447084f15abff76e3559 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 13 Oct 2017 16:21:34 -0500 Subject: [PATCH 213/229] Run unit tests on Travis --- .travis.yml | 6 ++++-- CMakeLists.txt | 5 +++++ setup.py | 17 +++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 64fbdc9df..bb2c500c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ before_install: - conda update -q conda - conda info -a - if [[ $OPENMC_CONFIG != "check_source" ]]; then - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION six numpy scipy h5py=2.5 pandas; + conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION pip numpy cython; source activate test-environment; sudo add-apt-repository ppa:nschloe/hdf5-backports -y; sudo apt-get update -q; @@ -52,7 +52,8 @@ before_install: export HDF5_DIR=/usr; fi -install: true +install: + - pip install -e .[test] before_script: - if [[ $OPENMC_CONFIG != "check_source" ]]; then @@ -73,4 +74,5 @@ script: else ./run_tests.py -C $OPENMC_CONFIG -j 2; fi + - pytest unit_tests/ - cd .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 905555a05..0b0bef14e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,6 +468,11 @@ file(GLOB_RECURSE TESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_*.py) # Loop through all the tests foreach(test ${TESTS}) + # Remove unit tests + if(test MATCHES ".*unit_tests.*") + continue() + endif() + # Get test information get_filename_component(TEST_NAME ${test} NAME) get_filename_component(TEST_PATH ${test} PATH) diff --git a/setup.py b/setup.py index 354098ea3..e064efa68 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import glob import sys import numpy as np -from setuptools import setup +from setuptools import setup, find_packages try: from Cython.Build import cythonize have_cython = True @@ -36,9 +36,9 @@ kwargs = { }, # Metadata - 'author': 'Will Boyd', - 'author_email': 'wbinventor@gmail.com', - 'description': 'OpenMC Python API', + 'author': 'The OpenMC Development Team', + 'author_email': 'openmc-dev@googlegroups.com', + 'description': 'OpenMC', 'url': 'https://github.com/mit-crpg/openmc', 'classifiers': [ 'Development Status :: 4 - Beta', @@ -59,13 +59,14 @@ kwargs = { ], # Required dependencies - 'install_requires': ['six', 'numpy>=1.9', 'h5py', 'scipy', - 'pandas>=0.17.0', 'lxml'], + 'install_requires': [ + 'six', 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', + 'pandas>=0.17.0', 'lxml', 'uncertainties' + ], # Optional dependencies 'extras_require': { - 'decay': ['uncertainties'], - 'plot': ['matplotlib', 'ipython'], + 'test': ['pytest'], 'vtk': ['vtk', 'silomesh'], }, } From 215220bb060def96323fc316b5c75749db323e6a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 14 Oct 2017 13:15:01 -0500 Subject: [PATCH 214/229] Don't pip install or run unit tests for check_source configuration --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb2c500c9..bb7a7da37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,9 @@ before_install: fi install: - - pip install -e .[test] + - if [[ $OPENMC_CONFIG != "check_source" ]]; then + pip install -e .[test]; + fi before_script: - if [[ $OPENMC_CONFIG != "check_source" ]]; then @@ -73,6 +75,6 @@ script: ./check_source.py; else ./run_tests.py -C $OPENMC_CONFIG -j 2; + pytest unit_tests/; fi - - pytest unit_tests/ - cd .. From ef7261cd713040780ddafc3b74cdf9c31e5945cd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 14 Oct 2017 14:06:24 -0500 Subject: [PATCH 215/229] Try using default pip/virtualenv on Travis instead of conda --- .travis.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb7a7da37..0de30b20a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,21 +28,7 @@ matrix: env: OPENMC_CONFIG="check_source" before_install: - # ============== Handle Python third-party packages ============== - - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then - wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; - else - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; - fi - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - - conda info -a - if [[ $OPENMC_CONFIG != "check_source" ]]; then - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION pip numpy cython; - source activate test-environment; sudo add-apt-repository ppa:nschloe/hdf5-backports -y; sudo apt-get update -q; sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y; @@ -54,6 +40,7 @@ before_install: install: - if [[ $OPENMC_CONFIG != "check_source" ]]; then + pip install numpy cython; pip install -e .[test]; fi From 3d32f57c6ff3157143a089de096a5ef7b237a706 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 17 Oct 2017 15:13:30 -0500 Subject: [PATCH 216/229] Add coverage to unit tests --- .travis.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0de30b20a..b4462ed0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,6 +62,6 @@ script: ./check_source.py; else ./run_tests.py -C $OPENMC_CONFIG -j 2; - pytest unit_tests/; + pytest --cov=../openmc unit_tests/; fi - cd .. diff --git a/setup.py b/setup.py index e064efa68..271fac0f0 100755 --- a/setup.py +++ b/setup.py @@ -66,7 +66,7 @@ kwargs = { # Optional dependencies 'extras_require': { - 'test': ['pytest'], + 'test': ['pytest', 'pytest-cov'], 'vtk': ['vtk', 'silomesh'], }, } From 3955e901b46781503cffc636eba15c54c1e55b09 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 18 Oct 2017 10:51:45 -0500 Subject: [PATCH 217/229] Remove tox.ini for now, update install instructions --- MANIFEST.in | 1 - docs/source/usersguide/install.rst | 17 ++++++++++------- tox.ini | 9 --------- 3 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 tox.ini diff --git a/MANIFEST.in b/MANIFEST.in index 04436bf1d..04348222f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include CMakeLists.txt include LICENSE include schemas.xml -include tox.ini include openmc/data/reconstruct.pyx include docs/source/_templates/layout.html include docs/sphinxext/LICENSE diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 497e09b4d..09fc4520c 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -414,16 +414,19 @@ distributions. various HDF5 files, h5py is needed to provide access to data within these files from Python. -.. admonition:: Optional - :class: note - `Matplotlib `_ Matplotlib is used to providing plotting functionality in the API like the :meth:`Universe.plot` method and the :func:`openmc.plot_xs` function. `uncertainties `_ - Uncertainties are optionally used for decay data in the :mod:`openmc.data` - module. + Uncertainties are used for decay data in the :mod:`openmc.data` module. + + `lxml `_ + lxml is used for the :ref:`scripts_validate` script and various other + parts of the Python API. + +.. admonition:: Optional + :class: note `Cython `_ Cython is used for resonance reconstruction for ENDF data converted to @@ -437,8 +440,8 @@ distributions. The silomesh package is needed to convert voxel and track files to SILO format. - `lxml `_ - lxml is used for the :ref:`scripts_validate` script. + `pytest `_ + The pytest framework is used for unit testing the Python API. .. _usersguide_nxml: diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 951bd8cd0..000000000 --- a/tox.ini +++ /dev/null @@ -1,9 +0,0 @@ -[tox] -envlist = py{34,36} -[testenv] -commands = pytest tests/unit_tests -deps = - pytest - numpy - cython -passenv = OPENMC_CROSS_SECTIONS From e510fc799213a226756f21a0760b8d1d486671e6 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 18 Oct 2017 11:23:10 -0500 Subject: [PATCH 218/229] Add license badge on readme.rst --- readme.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/readme.rst b/readme.rst index 34d2a5d09..75e4a1438 100644 --- a/readme.rst +++ b/readme.rst @@ -2,8 +2,7 @@ OpenMC Monte Carlo Particle Transport Code ========================================== -.. image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop - :target: https://travis-ci.org/mit-crpg/openmc +|licensebadge| |travisbadge| The OpenMC project aims to provide a fully-featured Monte Carlo particle transport code based on modern methods. It is a constructive solid geometry, @@ -55,3 +54,11 @@ OpenMC is distributed under the MIT/X license_. .. _Troubleshooting section: http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html .. _Issues: https://github.com/mit-crpg/openmc/issues .. _license: http://openmc.readthedocs.io/en/stable/license.html + +.. |licensebadge| image:: https://img.shields.io/github/license/mit-crpg/openmc.svg + :target: http://openmc.readthedocs.io/en/latest/license.html + :alt: License + +.. |travisbadge| image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop + :target: https://travis-ci.org/mit-crpg/openmc + :alt: Travis CI build status (Linux) From a701333eea6b39b57d9229050436c25876032fdb Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 19 Oct 2017 16:35:44 -0400 Subject: [PATCH 219/229] Add windowed multipole to the nuclear-data example --- examples/jupyter/nuclear-data.ipynb | 250 ++++++++++++++++++++++------ 1 file changed, 197 insertions(+), 53 deletions(-) diff --git a/examples/jupyter/nuclear-data.ipynb b/examples/jupyter/nuclear-data.ipynb index 4302e5295..7087681a0 100644 --- a/examples/jupyter/nuclear-data.ipynb +++ b/examples/jupyter/nuclear-data.ipynb @@ -205,7 +205,7 @@ { "data": { "text/plain": [ - "{'294K': }" + "{'294K': }" ] }, "execution_count": 8, @@ -315,7 +315,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 12, @@ -324,9 +324,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n1QAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -422,7 +422,7 @@ { "data": { "text/plain": [ - "{'294K': }" + "{'294K': }" ] }, "execution_count": 15, @@ -453,9 +453,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -510,7 +510,7 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, "execution_count": 18, @@ -540,36 +540,36 @@ { "data": { "text/plain": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" + "[,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ]" ] }, "execution_count": 19, @@ -598,9 +598,9 @@ "outputs": [ { "data": { - "image/png": "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\nRK5CYII=\n", + "image/png": "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\n2oFEPhuJq6XrnVymJEmSJN2xhk5Ad9scKZJutidsp/+a/vg4+hDxdMStg5YtW2DKFHj+eZg3r9rh\n/0tPZ8Dhw7yYkECz/ft5JymJnJKSfyqMGgXff1++vDR6NNYqU7aHbkdRFB5b9xiXCy430BVKkiRJ\n0v1BBi53aP2x9QwJH0J/z/5sD92OlbGV9op79kBQEDzxBHz2Gdxwh5FaCOacPcvk06eZ0rQpZ7t2\nZYyjIx+mpOC+bx+vJCSQXlRUXnnECPjxR9i2DZ58EhcjO7aHbq/KyltYWq/PspIkSZKk+4oMXO7A\nioMrCPkhhOD2wfww6gdMDEy0Vzx2DIYMgW7d4LvvNPK0FKnVhMbH82FKCp94efG5tzceJiZ85u1N\ncrduzHR15euMDDz272fyqVMkFhTA4MGwdWv5pt1hw2hj3pyfg38mKi2KhbsX3qWrlyRJ0s3q1atR\nqVRaX3p6ehw4cKBe+snMzGTy5Mm4urpiYmKCh4cHz2lZkq/JwoULUalU+PhoubkCiIyMpFevXpiZ\nmeHs7MyMGTPIy8ursd3k5OSq6160aJHWOqGhoahUKiwtLWs9bh8fH5o3b37bOj179sTZ2Rm1Wl3r\n9u8Xco+LDrRtzt15difTfpnGzK4z+WTgJ6iUW8SAKSnw6KPQrBn89FP5rc0VsktKGHHsGAevX+f7\ndu140t5e41R7Q0Pe8/TkVXd3vkxPZ0lqKl9nZDDawYHXe/bEZ9u28oBo8GC6b93KnF5zWPT3IkI6\nhMjNupIk3VcURWHBggVaf7G2aNHijts/f/48PXr0QKVSMXXqVFxcXEhPT691UJSWlsb777+Pubm5\n1uNxcXH079+ftm3bsnTpUs6fP8/ixYtJSEhg27ZtOvVhYmJCeHg4c+fO1SjPz89n69atmJjc4kNw\nDcaMGcOcOXPYs2cPvXr1qnY8OTmZ/fv3M336dFSqhpu3aOjNuQgh5OsWL8APEDExMeJms3+fLVw+\ncRFqtbrasSqFhUJ06iRE8+ZCpKdrHErMzxct9+8Xdnv2iMgrV7SefmXPFRE3IE4kvJYgSq6WiPzS\nUvHF+fOiWWSkICJCzE5IEOq//hLCzEyIwEBRcC1HeC/zFoHfBt5+XJIk3XdiYmLErX7eNHarVq0S\nKpWqQa/tscceE15eXuLy5ct31M7o0aNF//79RZ8+fUSHDh209uPi4iJyc3Oryr7++muhUqnE77//\nftu2k5KShKIoYuTIkUKlUokjR45oHF+3bp0wMjISw4YNExYWFrUee2pqqlCpVGLq1Klajy9atEio\nVCpx4MCBWretTU3fs5XHAT9Rj7+b5VJRHR1MP0hnl863f2bQG2+ULxP9+GN5Sv8KUdeu0S02FgHs\n69SJ7laa+2JKcko4NfEUh3odovhCMWmfpxHlHcXlby8yzakpZ7p25UNPTz5MTWWqkxNlO3bAwYMY\nT36eLx9fwe7k3ayKW9UwFy5JknSfOXXqFNu3b+e1117D2tqaoqIiSiuzkdfC7t27+fHHH/n000+1\nHr9+/To7d+5k7NixmJmZVZWPGzcOMzMzNm7cqFM/3bt3x8PDg7CwMI3ysLAwHn30UWxsbLSe9+uv\nvxIYGIi5uTmWlpYMHjyYEydOVB13dXUlMDCQTZs2UVZWVu388PBwvLy86Ny5s07jvF/JwKUO1EJN\nTHoMnZve5h9/5074+GNYtAg6daoq3nzpEn3j4mhpYkJkp060MDWtOiaE4MKaCxxodYDM7zPxXu5N\nwKEAupzqgk1/G05PPE1M5xjy9lzjNXd3vm3VipUZGYy1saFk9WoID+fhsH2M9RnLK7+/wqW8Sw35\nNkiSJNXK1atXyc7O1njl5ORo1Lly5Uq1OtpeBQUFVefs3LkTRVGwt7enX79+mJiYYGJiwqBBg0hO\nTtZpbGq1munTpzNx4kTatWuntc7Ro0cpLS2tdouvgYEBvr6+HDp0SOf3IigoiPXr11d9nZ2dzW+/\n/UZISIjW+t999x2DBw/GwsKCjz76iPnz5xMfH0/v3r1JSUmpqhcaGkp2djY7duzQOP/YsWMcO3aM\nMWPG6DzG+5UMXOogISeBq0VXCWgaoL1CVlZ5srj+/eGll6qKP01N5cnjxxlsa8vOjh2xMzSsOpZ/\nKp/D/Q9z8umT2PS3ocvJLrhMdUHRUzB2M6bturZ0iuyEoq8Q91Acx0cdZ3SRNRvbtWPTpUs80bo1\nBQsWwJtv8nl+H4QQvPr7qw39VkiSJOlECEG/fv2wt7fXeLm6auaf6tSpU7U6N78cHBxYvHhx1Tln\nzpxBCMGkSZMwNjZm48aNfPjhh+zZs4cBAwZQWFjz3ZYrVqwgJSWFBQsW3LJORkYGiqLgfMMMeiVn\nZ2fS09N1fj9CQkJITk4mMjISgA0bNmBiYsJQLUlJ8/LymDFjBpMmTWLbtm1MmzaNV155hf3796NW\nqzU2+o4cORJDQ8Nqsznr1q1DUZRbBkaNidycWwfR6dEA2gMXIcoTyxUVwerVULEBKvziRWYlJvKa\nmxvve3qiqlhiKissI+WDFFLeT8HI1QifHT40eaSJ1n6tulvht9+Pi2svcvb1sxxofYBOr7jxv0lt\nGZEUz+ODB7Pl1CmsJr7ANytf5onD7/F0x6fp69G3Yd4ISZLuifx8OHmy4ftp3RpumBS+I4qisHz5\ncry9vTXK9W64yxLKl0tunE25FU9Pz6q/5+bmAtC0aVONDbIuLi4EBwcTFhbGhAkTbtlWTk4Ob731\nFvPnz6dJE+0/f4GqcRkZGVU7ZmxsrNO4K7Vt2xYfHx/Cw8Pp0aMH4eHhDB8+HOMbbuCo9Pvvv3P1\n6lWCgoLIzs6uKlcUha5duxIREVFVZm1tzaBBg9i6dSsFBQVVG303bNhAQEBAvWyEvtdk4KKDm+8q\nOph2EE8bT5qYaPkGX7myPNHc5s3QtCkAV0tLeSkxkZH29nzo5VVV9fIflzk99TSFSYW4veZGs3nN\n0DPRq97mDRSVgtM4J+yesCPlgxRSP07F4r8GbH/TlaFtz9N/+nR+TUlh+OxvGfZyF6Zsm8KRKUcw\n0q/+H02SpMbp5Mnyh8c3tJiY8gfU15fOnTvXmIW8e/futW7XxMQERVF46qmnNMqfeuopxo4dS2Rk\n5G0Dl3nz5mFra8sLL7xQYz8ARZV5tW5QWFhY67uBQkJCWLJkCTNnziQyMpI33nhDa73KGaW+fat/\nCFUUBaub9kmGhoayefNmtmzZQlBQEHv37iUpKYlZs2bVanx1JVP+3wduTvl/MP2g9v0tJ0/CzJkw\naRIMH15VPP/cOa6XlrK0Imgpziwm8eVELq69iFWgFe23tMesjVn19m5D31wfz/c8cX7OmbOvneXS\ntBS2+pny4stFPPT++/w+cSJha/JxHJLIh3s/ZP5D8+t28ZIk3Xdaty4PKu5GP3dbVlaW1o2lNzM3\nN6/aINu04kOio6OjRh2VSoWtrS2XL986q3hCQgIrV67ks88+Iy0tDShf1iosLKSkpITk5GQsLS2x\nsbHB2dkZIQQZGRnV2snIyKgah66Cg4OZM2cOEydOxM7OjgEDBmitp1arURSFtWvXVrtGAH19zV/l\ngwcPxsrKirCwMIKCgggLC0NfX5/Ro0fXanx11dAp/2XgUkul6lIOXTjEiNYjNA8UFZU/R8jdHZYs\nqSqOu36dL9LS+NDTE1djY9Qlag71OkRJTgmt/tsKp/FOt78zqQYmzU1ot7EdV3Zf4fSU0yybKvhw\nvpreK1awc9w49uxpRReD9whqH0RL25Z17keSpPuHqWn9zoTcTzp37lzjhlpFUaqWdgD8/f0RQlQF\nHpVKSkrIysrC/qYcWTdKS0tDCMH06dN58cUXqx339PRkxowZLFmyhPbt26Ovr090dDQjR47U6Ccu\nLq7WgYGbmxs9e/Zk165dTJs27Za5Vby8vBBCYG9vz8MPP1xju4aGhowcOZLvvvuOzMxMNm3aRL9+\n/XBwuMXjaBoZGbjUUvylePJL8qvvb6m89TkqCio+BaiFYNqZM7QxNWVGxQa0C99eoCChgIC4AMx9\ntCc4qgvrQGv89vsRHxrPa69ls+EFfXp9/Q07JzzDBybmTG02lZ1jd95RkCRJktTQ6rLHpU+fPjg4\nOLBu3Trmzp2LYcWND99++y1qtZpHHnmkqm52djZZWVm4u7tjYmJC+/bt2bx5c7X2582bR25uLsuW\nLavqy9LSkv79+7N27VrefPPNqhmfNWvWkJeXx6hRo2p9vQsXLiQiIuK2Qc/AgQOxtLRk0aJF9OnT\np9oMS1ZWFnZ2dhploaGhfPPNN0yePJmsrCxCQ0NrPbb7lQxcaik6PRoFBT/nGz7uVN76vHixxq3P\nqy5cYN+1a/zl64uBSoW6SE3ye8nYj7Kv16Clkr6lPu1/as/ZuWcZ/VEqzRIN6bv8a357cTJ7f/6T\n9Z3WE9whuN77lSRJqokQgl9++YX4+Phqx3r06IGHhwdQtz0uhoaGLF68mPHjx9O7d2/Gjh1LcnIy\ny5YtIzAwkBEj/pkh//zzz3n33Xf566+/CAwMxNbWVuudPEuXLkVRFIYMGaJRvnDhQnr27ElgYCCT\nJk0iNTWVJUuWMHDgwFsu9dxO79696d27923rWFhYsGLFCsaNG4efnx9BQUHY29uTkpLCtm3b6NWr\nF8uWLdM456GHHsLV1ZUtW7Zgamqq8R40djJwqaWD6QdpbdcaCyOL8oLs7PJbn/v107j1ObukhNcS\nExnj6MhD1tYAZHydQVFaEc3fbt5g41P0FLw+9MKsvRnKxFM4phozYuFyNrz9PJ9vfF8GLpIk3ROV\nyzvafPvtt1WBS12NHTsWIyMjPvjgg6pEdFOnTmXhwoUaM82Koug886ytXqdOndi5cyezZ8/mpZde\nwsLCgokTJ97y2UPa2tSl/5vrBAcH4+LiwgcffMDHH39MUVERLi4u9O7dm2eeeUbr+cHBwXz88ccM\nHTpUI2FeY6eI8tT2khaKovgBMTExMVWbc7us7EIb+zasHr66/NbnJ56A3bvhyBFwcak6d/KpU2zI\nzORkly44GRlRVlBGlFcUNv1taLPm7jxH6FrUNY4MP8olUcr7r1/ng5XP47pxLS3b3T66lyTp7qvc\nyHjjzxtJup/V9D17w+ZcfyFEbH31K2dcdFB5O/RTo5/i8MXDjOs4rvxAYmL5gxO/+04jaIm6do2V\nGRksa9ECp4r7/dO/TKc4s5hm85vdtXFbdrUk4KA/cUOPsmCOYOmLXzBj+ku0/HUv3JD8TpIkSZLq\nS0PfDi0z5+pg6dKlbN26lTZ921BcVvzPxtzKHew3PPehTAimnT6Nr7k5UyuCmbK88iRzTuOdMG1R\nT9mcdGTsakznPX7YD7Hl5cUWbLZ7m/g5c+7qGCRJkqR/j+DgYLZu3crSpUsbpH0ZuNRCdHo0+ip9\nOjp2LC+4eLH8zxvuq/8yPZ3Y3FyWe3ujV7FGmfZFGqWXS2n+ZvM69SuEICfnd44cGcyePU04c2Y6\nBQXndD5fz1SPThvao37FkKc2mrElcgCnlv+3TmORJEmSpHtJBi61cDDtIO0d2mNiUJEd8cIFMDKC\niqyFF4uLmXf2LM85O9Otoqz0WikpH6Xg/Jwzxs2qp3K+nbKyfNLTV3LwYAeOHHmEoqLzODk9zcWL\nYURFteD48SCuX9ctC5WiKDy8uAf/NzUM3zhD9n3sxsnv/6rVeCRJkiTpXpOBSy1EZ0RrZsy9eLF8\ntqViZuXVxET0FYUPbsgvcP6z85TlldFsnu57W4qK0jh7di779rlx+vRkTE298fX9i4CAQ7RosZTu\n3VPw9v6c69cPEhMTQFzcw2Rn/4ouG627Pd2eWc/NxuK6ivjJZcRvPlHjOZIkSZJ0v5CBi47yS/I5\nnnlce+AC7L5yhe8uXuQDT09sDQwAKLlcQuonqTSd0hQjl5qfFXTtWhQnToSwf39z0tK+wMnpabp2\nTaB9+81YWz9UdXucnp4pLi7T6Nr1NG3bfk9ZWR5Hjw7i4MEOZGSsQq0uvmUfoR1COet4hHOfxXHZ\ntoyUoIscX6X7spMkSZIk3UsycNHRoYxDlIkyzYy5FYFLiVrNtNOn6WZpyYQbHnd+fsl5RLHA/XX3\nW7arVpeQmbmB2NjuxMZ249q1A3h5fUL37udp0WIJJiaetzxXUfRwcBiJn99+fH13YWLiyalTz7B/\nvwcpKR9RWlp9R7etqS1DWw1lzdXV9F9jx2G/Ai49k8zhdxJ0mrGRJEmSpHtJBi46ik6PxkjPiPYO\n7f8pvHABnJxYlpZGfH4+y729UVXMihRnFXP+0/O4vOCCkZP22ZZr16KIivLkxIkgVCpT2rffSteu\np3B1nY6+vqXOY1MUBWvrQDp02Ernzido0uQxzp17k3373EhIeJnCwlSN+hN8J3A08yiZzdQEv1rE\nlieucfnt80SPOY66SF37N0eSJEmS7hIZuOjoYPpBfJ18MdAz+KewYsZlcUoKzzk708nCoupQ6uLy\nYMHtNTet7QkhOHNmBvr6TQgIOIyv7x/Y2Q1BUfTuaJxmZm1o3fprunVLwsXlBS5c+C9RUZ7Ex48l\nN/cwAI94PUJTi6Z8e+hb3J4YwUudjrByajaXv7/E/r6xFF+69VKTJEmSJN1LMnDRUXT6TRtzhYCL\nFylxdORiSQldLf+ZISm+WEzaF2m4zHDB0E57orecnO1cvx6Fl9dizM196n28RkbOeHouolu3VLy8\nPubKlb+Jjvbl8OFHuHrlT57uOI6wY2EUlBTgNncuH1/exKdzMrl0MpeoLjHkncir9zFJkiRJ0p2S\ngYsOXpzxIqc+P0XpkdJ/Cq9cgeJispo2BcDe4J+ZmJQPUlAMFNxevvVsS1LSW1ha9sDGpvYP5aoN\nfX1zXF1n0LVrAm3ahFFSksWRI48wyGwLAZZX+Cl+E6hUOH/1Fd/+9imfzM/gnFJEdPdYcnbkNOjY\nJEmSpAdPeHg4Q4cOZdasWQ3SvgxcdDDutXEQAi8+++I/hRXJ5y5VPEq8MnApSisibUUabi+5YWBj\nUK0tgJycX7h+/SDNm7+j88O+7pRKpY+jYzD+/jF07LgTS9NmzGsDppmTSE1dQqmpguO6dfz42VyW\nv3GR6LZqjgw6Qtp/0u7K+CRJkqQHg8ycex84cekE5obmtLJt9U9hZeBiYwOAfcWzf5IXJaNnpofr\nTFetbZXPtryNlVUvbGz6NezAtVAUBRubfvj4/Eqq+TvszyokMXE2+/a5kSj+D4tvF/Pry1PY+FI2\nW59UOPPCGU6/cBp1idy0K0lS3axevRqVSqX1paenx4EDB+64j2vXrvHaa6/RsmVLTE1Nad68Oc89\n9xypqak1nrtr165ajS0yMpJevXphZmaGs7MzM2bMIC+v5uX15OTkqrZv9TTp0NBQVCoVlpa636BR\nycfHh+bNm9+2Ts+ePXF2dkatbrw/0+VDFnVw/NJx/Jz90FPdsHH2wgUALllaQk4ODgYGFCYXkrEy\ng+bvNkffUvtbm539M9evR9Ox4x93bbblVoZ3mMXU3z7C2mkKI5sqpKcv57xSiMOqTvw0P4SRH2wm\n1d2U5z9LJ/9EPm03tMXQXj6cUZKk2lMUhQULFmj9xdqiRYs7alsIQf/+/Tl58iTPP/883t7eJCQk\n8J///IfffvuN+Ph4zMzMamxn5syZBAQEaJTdPLa4uDj69+9P27ZtWbp0KefPn2fx4sUkJCSwbds2\nncZrYmJCeHg4c+fO1SjPz89n69atmJiY6NTOzcaMGcOcOXPYs2cPvXr1qnY8OTmZ/fv3M336dFSq\nxjtvIQMXHZy4dIKQTiGahRcvgpERl/T1MVIUzPX0OP1eIvrW+ri84KK1ncq9LVZWgVhb970LI789\nCyMLnmr3FF8d/pFXH0qgWbM3yMj4mrS0L7j4WRGfxg9m1eB5zHV/iEULcokJiKH9T+2x6GRRc+OS\nJEk3efTRR/Hz86v3dvfv3090dDTLly9nypQpVeUtW7bk2WefZefOnQwbNqzGdnr16sUTTzxx2zpz\n586lSZMm7Nq1qyoYatasGZMmTWLnzp3079+/xn4GDRrEjz/+yNGjR+nQoUNV+U8//URJSQmPPvoo\nf/75Z43t3CwkJIQ5c+YQFhamNXAJCwurqteYNd6Q6y7KuJ6hmXgOqm6Fziwpwd7QkMKzhWR8m4H7\n6+7om2uPB7OytpCbe+iu7m2pyQTfCZy7co7dybvR17fCze3l8my9rTdhYGzFUyxgjk8Qm1atotD1\nKod6HuJi2MV7PWxJkqQq165dA8DBwUGj3MnJCaBWMxi5ubmUlZVpPXb9+nV27tzJ2LFjNWZwxo0b\nh5mZGRs3btSpj+7du+Ph4VEVSFQKCwvj0UcfxaZiC8LNfv31VwIDAzE3N8fS0pLBgwdz4sQ/j21x\ndXUlMDCQTZs2ab2G8PBwvLy86Ny5c7VjjYkMXHSkcSs0VAUul4qLsTcwIGVxCoYOhjSd2lTr+UKo\nSUp6G2vrPtjY9Gn4Aeuol3svWjRpwX8P/fO0aEXRw87pSXyHJRDwlite+wTDzNZS8t5QSj/5hPj5\n/yPhlQTUpY13jVSSpLvv6tWrZGdna7xycjTvXrxy5Uq1OtpeBQUFVecEBARgZmbGm2++SUREBOnp\n6ezatYviVVK7AAAgAElEQVTZs2fTpUsXnWZBAJ555hksLS0xNjbm4YcfJiZG8yG2R48epbS0FH9/\nf41yAwMDfH19OXTokM7vRVBQEOvXr6/6Ojs7m99+++2WsyHfffcdgwcPxsLCgo8++oj58+cTHx9P\n7969SUlJqaoXGhpKdnY2O3bs0Dj/2LFjHDt2jDFjxug8xvuVDFx0YGFkgafNTan3K7LmXiopwd7A\ngLwjeTQZ2AQ9E+0J5LKyfiIv7zDNm79zF0asO0VReMb3GTad2MS1omuaB5s0wXzFDtq+X0z3/+vH\nQbPnyWq9H76eyHm3J4mZuZTirALtDUuSJN1ACEG/fv2wt7fXeLm6at7I0KlTp2p1bn45ODiwePHi\nqnNsbW3ZuHEjV65coV+/fri6utK3b19cXFz4448/atzPYWhoyMiRI/nss8/YunUrCxcu5NixYwQG\nBnL48OGqehkZGSiKgvMNj3ap5OzsTHp6us7vR0hICMnJyURGRgKwYcMGTExMGDp0aLW6eXl5zJgx\ng0mTJrFt2zamTZvGK6+8wv79+1Gr1RobfUeOHImhoWG12Zx169ahKEqjXyYCucdFJ23t21Zf2rl4\nEXx9uVRSgruREcWZBVj1ttJ6/j+zLQ9jbR14F0ZcO2N9xvLGn2/w/fHvedbvWc2DbdvC+vWYDx7M\nbA9fpoz5gzMXf+D1Nj9Dx1eI/OtjnF3H4tJ+HObm7bV3IElSvcovyedk1skG76e1XWtMDUzrpS1F\nUVi+fDne3t4a5Xp6mh/2wsLCNGZTbsXTU/PDpJ2dHX5+fvTq1Yu2bdsSFxfHhx9+yPjx42tcwune\nvTvdu3ev+nrw4ME8+eST+Pj4MGfOHH755ReAqnEZGVV/jIuxsbFO467Utm1bfHx8CA8Pp0ePHoSH\nhzN8+HCMjY2r1f3999+5evUqQUFBZGdnV5UrikLXrl2JiIioKrO2tmbQoEFs3bqVgoKCqmWyDRs2\nEBAQcMcboe8HMnDRQTv7dtULK5eKSkoIsLCgJLMEQwftd9xcuvQjeXlH8fX9u4FHWjduVm4M8BrA\nqsOrqgcuAIMGwUcfof/qq6xs04bZ3ccwKPUhlqquEnDmWzKMV5ARvRgzs/Y4OATj4BB024dDSpJ0\nZ05mncT///xrrniHYibF4Odcf5tpO3fuXOPm3BsDCF2dPXuWvn37snbtWoYPHw7AkCFDaNasGePH\nj2fHjh0MHDiwVm16eXkxbNgwNm/ejBACRVGqgoCioqJq9QsLC2t9N1BISAhLlixh5syZREZG8sYb\nb2itd+bMGYQQ9O1b/aYORVGwstL80BwaGsrmzZvZsmULQUFB7N27l6SkpAZLCHe3ycBFB23s22gW\nVKT7x8mJS8XFOJTpUXa9DAOH6gnnhFCTnPwONjYDsLauvsv7fjG+43hCfgzhTPYZvG29q1d4+WU4\nfhzl2Wf56M8/sfP0ZNbZs0x77AOmLi4k69wviBf3k1ywkHPn5mFh0aUiiBmFkZH2fT+SJNVNa7vW\nxEyKqbliPfRzt2VlZd1yc+yNzM3NqzbIrlq1iqKiIh5//HGNOpXLLnv37q114ALg5uZGcXExeXl5\nmJub4+zsjBCCjIyManUzMjJo2rR2P+uCg4OZM2cOEydOxM7OjgEDtGdSV6vVKIrC2rVrcXR0rHZc\nX1/zV/ngwYOxsrIiLCyMoKAgwsLC0NfXZ/To0bUa3/1KBi46qDbjUpHuv9TRkZzSUpyula+faptx\nuXRpE3l5x2jZ8v/uxlDrbHjr4VgZWbH68Gree/i96hUUBb76Cs6ehREjeC0qCttWrZh06hRZc+z4\n4JdQksf0wHrQXByWJpBdsImzZ2eTmPgS1tYP4eAQjL39kxgY2N79i5OkB4ypgWm9zoTcTzp37kxy\ncvJt6yiKwltvvcX8+fMByMzMRAhBWVkZBjc8fqWkpASA0tJSre3UJDExEWNjY8zNzQFo3749+vr6\nREdHM3LkSI1+4uLiah0YuLm50bNnT3bt2sW0adNuuRfHy8sLIQT29vY8/PDDNbZbuWfnu+++IzMz\nk02bNtGvX79qd101VjJw0YGD2U3/2BVZc7MdHBBCYFsRuNw84yJEGUlJ72BjMxArq9pPf95NJgYm\nBLUPYvXh1bzT5x3NZHuVDA3hhx+gWzcYPJhnIyNp0q4dQSdOcGVgGf/t0I6kcadJ6uNJ2/BVtO4h\nyMraTGZmOKdPT+XMmeexsXkEe/snsLUdjKFh9U8OkiT9u9Vlj0vLli1Rq9Vs3LiRcePGabSlKIrG\n8lR2djZZWVm4u7tXLe1kZWVhV/H4lkqHDx/mf//7n8YsjqWlJf3792ft2rW8+eabVTM+a9asIS8v\nj1GjRtX6ehcuXEhERMRtg56BAwdiaWnJokWL6NOnT7UZFm3jDw0N5ZtvvmHy5MlkZWURGhpa67Hd\nr2TgooNqG3Mrs+ba2cGlS9hcFpQCBvaagUtm5vfk55+gdev/0hiM9x3PVzFf8ee5PxngdYuHP9rZ\nwc8/Q/fuMHo0I37+me0+Pgw7downHUr56WBHMsadIa5PHB7veuD++jM4O0+gqOgCly5tIjNzPadO\nTQTAwqILdnZDsLUdgplZh/smt40kSfVPCMEvv/xCfHx8tWM9evTAw8MDqNsel/Hjx/Pxxx8zefJk\nYmNjadeuHTExMXzzzTe0b9++at8LwOeff867777LX3/9RWBg+c0So0ePxsTEhB49euDg4MDx48dZ\nuXIl5ubmvP/++xp9LVy4kJ49exIYGMikSZNITU1lyZIlDBw48JZLPbfTu3dvevfufds6FhYWrFix\ngnHjxuHn50dQUBD29vakpKSwbds2evXqxbJlyzTOeeihh3B1dWXLli2YmpoyYsSIWo/tviWEkK9b\nvAA/QAQGBoohQ4aIsLAwIYQQYv16IUD8mZoqiIgQh75KEhFEiLLCMlFJrS4VUVGtxeHDj4nGQq1W\ni9ZftBYhP4TUXHnnTiH09IR44QUhhBDR164Juz17RJuoKJFyPV+cfeOsiFAiRFz/OFF0oUjj1KKi\nTJGRsUocPfqE2L3bXEREICIj3cWpU8+L7OztoqyssCEuT5LuazExMQIQMTEx93oo9W7VqlVCpVLd\n8rV69eo77iM9PV0899xzwsvLSxgbGwsXFxcxZcoUkZ2drVHv7bffFiqVSuzatauq7PPPPxfdunUT\ndnZ2wtDQULi4uIinn35aJCYmau1r7969olevXsLU1FQ4OjqK6dOni9zc3BrHmJSUJFQqlViyZMlt\n640fP15YWlpWK9+1a5d47LHHhI2NjTA1NRXe3t5iwoQJIjY2Vms7r732mlCpVCI4OLjGsdXFrb5n\nw8LCxJAhQ0RgYKAABOAn6vN3c3029qC9KgOXaj9IPvtMCCMjseHCBUFEhDj1/lmx22q3RpULF9aK\niAjE1atRojH54O8PhPF7xuJyweWaK3/1Vfm30OefCyGEOJmXJ9wjI4V7ZKQ4ev26yP49W+xx3CP2\nOO4ROTtztDZRVlYosrO3i1OnnheRke4iIgKxe7e5OHr0CZGe/q0oKsqsz8uTpPvWgxy4SA+mmr5n\nK4/Xd+AiE9DVReWt0KWlGCgKqqwyjY25anUpSUnv0qTJ41hadrmHA629sR3HUlxWzMbjOqSunjQJ\nZs2CGTNg+3ZamZqyt1MnrPT16XHoEAc6CQLiAjBrZ8bhAYc599Y5RJnQaEKlMqJJk4G0bPkF3bol\nERBwGHf31ykqSuPUqQlERjoSG9uL1NQlFBSca6CrliRJkhoLGbjURWXW3Ip0/yVZJRobczMzwyko\nOE3z5m/fuzHWUVOLpgz0GsiquFW6nbB4cXmel1Gj4NgxXI2N2dupE4FWVjx+9Chfl2XR8beONH+3\nOcnvJRPXL46i9Oo5EKB8L5G5uQ/Nms3D338/PXpk0KrVSgwMbDh7di5RUZ4cPOhLUtI75OYerZwV\nkyRJkv5FZOBSFzc+YNHAoDz5nH35jItaXUpy8rvY2g7B0jKghobuT+N9x7Pv/D7dMnPq6UFYGHh4\nwJAhkJmJhb4+Wzp0YLqrKy+cOcP0swm4znXH909fCs4UEN0xmuzt2TU2bWjoiLPzs3To8D969rxE\n27YbMTNrS2rqJ0RH+xAV5U1i4qtcvRqJEPK5SZIkSf8GMnCpixuy5tobGlKcWVw145KZuY6CgoRG\nOdtSaWirodgY27A6brVuJ1hYwP/+BwUFMHw4FBSgpygsbdGCFd7erEhLY+ixY6h6mhMQF4BFgAVH\nHztK4muJqIt0Czj09S1wcHiKtm3D6NnzEh06/IKNzcNcuLCGQ4d6sm+fC6dPTyUn5zfU6pI7uHpJ\nkiTpfiYDl7q4eamoIt1/+d6WBdjaDsPCovEmhzLWNya4fTBrjqyhTF1zBksA3N1h61aIi4OnnwZ1\neUAyxcWFX318iLx6lR6xsaSbl9FhWwc8P/Lk/KfnifaP5nrM9VqNT6Uywtb2MVq1+j969EjH13c3\nDg7B5ORs58iRgezf34xz596isPB8bS9dkiRJus/JwKW2hIDMzH9mXPT1q2ZcMjPXU1iY2KhnWyo9\n0+kZ0q+n8/vZ33U/qUuX8mWjTZtgzpyq4gFNmrDPz498tZqusbHsv34N91fd8Y/xR2WoIqZrDOfe\nOoe6uPbLPYqih7V1b1q0WELXrmfx94/Bzm44588vYf/+5hw79iSXL/8h98NIkiQ9IGTgUlsV6f4r\nAxfnEgNEkcDQwZDr1w9gatoGCwvfez3KO+bv7E87+3a6b9KtNHw4LF0KH30EX35ZVdzGzIwoPz9a\nmprSNy6O8IsXMe9gjl+UH83eaEbKohRiu8aSezS3zmNWFAULCz9atlxO9+5peHsvIz//JIcP9+fA\ngTacP/8ZJSVX6ty+JEmSdO/JwKW2KtL9qx0dyS4pwfFqebZXAwcDiorSMDJyvZejqzeKojDedzw/\nnfyJywWXa3fyjBkwfTo8/zxUPA4ewN7QkJ0dOzLKwYGQ+HjeOncO9BU83vbAL8oPdYmaGP8Ykhcl\noy69s822+vqWuLhMo3PnY/j67sLcvCOJia+wb19TTp2ayPXrh+6ofUmSJOnekIFLbVWk+8+xt0cN\n2F6pCFzsDSguTsfQ8MF5EvIYnzGUqktZf2x97U9esgQGDy6/TfrQP0GCkUrF6tatWejhwYLkZAYd\nOUJWcTEWfhYExATg9rIb5948x6Geh8iLz7vja1AUBWvrQNq120C3bim4u88hO/tXYmL8iI3tzoUL\n31FWVnjH/UiSJEl3hwxcaqtixiXTxgYA64qVB0MHw4oZF5d7NbJ652TuxGPej/Ft3Le1P7nyNuk2\nbeDxxyElpeqQoijMbdaMHT4+xOTm0ikmhn1Xr6IyUuH5vied9nai9Gop0Z2iSf0ktVrSuroyMnKm\nefM36dYtiXbtfkRPz5yTJ8exb58riYmzZYI7SZKkRkAGLrV18SIYGXHJyAgAi8sCFNBvokdxccYD\nFbgABLUL4mD6QbLys2p/splZ+QMZjYzKg5erVzUOD2jShEP+/rgbGREYF8dn588jhMCqmxUBhwJw\nmeZC4quJHHroEPln8uvpikCl0sfefgQdO/5Oly4ncXIaS3r6V0RFeXHkyONkZ29DCB3vppIkSZLu\nKhm41FblrdAl5blCTHLUGNgZUKrOQojSB2qpCKCzS2cADmXUcU+Io2P5Ppfz52HkSCjRzLHiamzM\nX76+THdxYWZCAqNOnOBaaSl6Jnq0WNIC312+FGcUc7DDQZLeSaKssH4DClPTVrRosZQePdJo1Wol\nxcUZHD06mKioFqSkfEhx8aV67U+SJEm6MzJwqa0bks/pKwp6WWUVG3PTAR64GZcWTVpgYWhBbEZs\n3Rtp0wZ+/BF27YLJk8tvKb+BgUrFJy1a8EO7dvyWk0NATAxHcsvvLrLubU3no51xe8mN5PeSifaJ\nJmdnzp1cklZ6emY4Oz+Lv38Mfn77sbIK5Ny5t9i3z5X4+HFcvbpf3lItSXW0evVqVCqV1peenh4H\nDhy44z5WrFjBqFGjaNasGSqVigkTJmitd+HCBV5//XUefvhhLC0tUalU7N69u1Z9paenM2rUKGxs\nbLCysmL48OGcO6d9qfmbb76hbdu2mJiY0LJlS7744gud+rjxPYuMjNRax83NDZVKxdChQ2s1/kuX\nLmFgYMC4ceNuWSc3NxcTExNGjhxZq7bvBv17PYC7SVGUlsAGyp9WqQCtgCAhxFadG7khcLEzMKDk\nUnm6/6Ki8mRnRkYP1oyLSlHRybkTsRfuIHAB6NsXvvkGxo2D5s1h/vxqVZ6wt8fHzIyRx4/TNTaW\nFd7ejHd2Rs9UD89FnjiOceT0tNMcGXAEhyAHvJZ4YeRsdGfjuomiKFhadsXSsiteXp9w4cK3pKev\n4OLF7zA396Vp02k4Ooagp2dWr/1K0oNOURQWLFhA8+bNqx1r0aLFHbf/0UcfkZubS5cuXbhQcROF\nNqdOnWLx4sV4e3vj4+PDvn37atVPXl4effr04fr167zxxhvo6+uzZMkS+vTpQ1xcHDYV+x8Bvvrq\nK6ZOncpTTz3Fyy+/zN9//8306dMpKCjg1Vdf1ak/ExMTwsLC6NGjh0b5rl27SEtLw9jYuFbjB7C3\nt2fAgAFs2bKFwsJCrW388MMPFBcXM3bs2Fq33+Dq81HTjekFmAGZgMlt6vhx8yO7/f2FmDhRvHD6\ntOhw4IA41O+QODbqmEhL+0pERKhEWVmJ1sd7N2Yzf50pWixrUT+NLVggBAjx3//eskp+aal4Nj5e\nEBEhno2PF/mlpVXH1Gq1yFidIfbY7xG7LXeL1M9ThbpUXT9juwW1ukxkZf0ijhwZLCIiFPH33zYi\nMXGOKCxMb9B+pX+XmJgYUe3nzQNi1apVQqVSNei1paSkVP3d3NxcPPPMM1rr5ebmisuXLwshhNi0\naZNQqVRi165dOvfz4YcfVruWkydPCn19fTFv3ryqsoKCAmFnZyeGDh2qcf6YMWOEhYWFuHLlym37\nWbVqlVAURYwcOVI4ODiIsrIyjeOTJk0SnTt3Fh4eHmLIkCE6j7/S2rVrhUqlEhs2bNB6/JFHHhE2\nNjaiuLj4lm3U9D1beRzwE/X4+/vfvFQ0FPhDCFFQq7MqH7B4U7r/oqI0DA0dUakevEksP2c/EnIS\nuFp4tebKNZk3DyZNgokTYccOrVVM9PT4unVrvm3VirDMTPxjYoi5Xv5YAEVRcBrnRJeTXXAIdiDh\nxQRiusZwLfranY/tFhRFha3tY3To8D+6dk3EyWk8aWmfs39/M+Ljx5Obe7TB+pYkSTdubm461TMz\nM8Pa2rrO/fzwww907twZP79/HuvSqlUr+vXrx8aNG6vKIiIiyMnJYdq0aRrnP//88+Tm5rJt27Ya\n+1IUheDgYLKzs/n993+ymJeUlLBp0yZCQkK0LmELIfj0009p3749JiYmODk5MWXKFK5c+ScB54gR\nIzA1NSUsLKza+ZcuXeLPP//kqaeewsDAoMZx3m3/5sBlFOXLRrq7Od2/gUFVuv/i4vQHbn9LJT/n\n8v+gcRfi7rwxRYH//Acee6x8s27srZegxjs7E+Pvj4lKRbfYWN5LSqK04hlIBk0MaPVlKzrt64Qo\nFcR2ieX086cpudKwD1g0MfGgRYsldO9+Hg+PRVy58gfR0T4cPjyQnJzf5D4YSbqNq1evkp2drfHK\nydHcs3blypVqdbS9Cgpq95mzPgghOHLkCAEBAdWOdenShcTERPLyyvNPHarIX+Xv769Rz9/fH5VK\nVXW8Js2bN6dbt26Eh4dXlf3yyy9cu3aNoKAgredMmjSJ2bNn07t3b5YtW8aECRNYt24djz76KGVl\n5Tc4mJqaMmzYMHbs2KER0ACsX78etVpNaGioTmO82+7rwEVRlN6KomxVFCVNURS1oijVdiApivK8\noijnFEUpUBRlv6IonXVo1wLoDvxSU10Nlen+K+4qstc3oCTrxhmXB2t/S6VWdq0w0Te5sw26N9LX\nh/Xr/8nxkpR0y6ptzMzY5+fH6+7uvJWURO+4OM7k/3NrtFU3K/yj/fFa4sXFNRc50PoAF9ZcQKgb\nNoDQ17fC3f0VunY9S5s2aykpucSRIwOJju7IhQurUauLG7R/SWpshBD069cPe3t7jZerq2a28U6d\nOlWrc/PLwcGBxYsX3/VryMnJoaioCGdn52rHKsvS08tv1MjIyEBPTw87OzuNegYGBtja2lbV00VI\nSAg//fQTRUVFAISFhfHQQw/h5ORUre6ePXv45ptvWLNmDStWrGDixIksWrSIH3/8kQMHDvD9999X\n1Q0NDaWoqIhNmzZptBEWFoaLiwuBgYE6j/Fuut/XNcyAOOAb4MebDyqKMhr4BJgEHABmATsURWkp\nhMiqqDMNmEj5Olt3IUQRMAz4TQhRu98ulRu+HB25VFyMc74elJVnzS0qSsfKqsftz2+k9FX6dHTq\neOcbdG9UmeOle/fy2Ze9e6FJE61VDVUqFnh4MKhJE8adPIlvdDQfe3kxpWlTFEVBpa/CbaYbDk85\nkPBSAiefPknaF2m0+LQFVj2s6m/MWqhUBjg6huLgEMKVK3+RmvoJJ0+O5+zZObi4vEjTppMxMNB+\nXZJUZ/n5cPJkw/fTujWYmtZLU4qisHz5cry9vTXK9fT0NL4OCwvTaTbF09OzXsZVG5XjMjKqflNA\n5QbXyjoFBQUYGhpqbcfY2LhWM0ajRo1i5syZ/PzzzwwcOJCff/75lncnbdq0CWtra/r160d2dnZV\neadOnTA3NyciIqJqpuaRRx7B3t6esLAwnnvuOQCSkpKIioritdde03l8d9t9HbgIIbYD2wEURVG0\nVJkFfCWEWFNRZwrwODAB+KiijeXA8pvOGwV8VesBVT6nyMGBrIwMnK6WT1iVLxU9uDMuAH5OfvyV\n/Ff9NurgANu3Q48eMHQo7NwJt9kh393KiriAAF5JTGTamTNszc7mm1ataFrxQ8TIxYh2G9px5YUr\nJMxM4FDPQzgEOeD5gSfGzWq/8742FEXBxqYvNjZ9ycuL5/z5JSQlvUNy8ns4Oz+Lq+tMTEzu/g9a\n6QF18iTctATRIGJi4Ia9HHfq5r0h2nTv3r3e+qtvJiYmAFUzHzcqLCzUqGNiYkJxsfbPxoWFhVX1\ndGFnZ0f//v0JCwsjLy8PtVp9y9uUz5w5w5UrV3BwcKh2TFEUMjMzq77W09Nj9OjRrFixgoyMDJyd\nnVm3bh2KohASEqLz+O62+zpwuR1FUQwAf2BRZZkQQiiKspPyZaBbnWcJdAaeqHWnFYHLFTs7yjIy\nsK14wKK+vaAkI+uB3eMC5ftcvoz5krziPMwM6/FWYG/v8pmXvn1hzBjYuBFUt17BNNPTY0XLlgy1\ntWXCqVN0OHiQL1u25Kkb/pNa97bG/6A/F9Zc4NyccxxofQC3V9xwm+2GvnnDf8ubmbWhVauVeHi8\nR1ractLS/kNa2n+wt38SN7dXsLTs0uBjkB5wrVuXBxV3o5+7LCsrq2ofxu2Ym5tjZnZ30xI0adIE\nIyMjMjIyqh2rLGvatPwDrLOzM2VlZWRlZWksF5WUlJCdnV1VT1chISFMnDiRjIwMHnvsMSwsLLTW\nU6vVODo6EhYWpnXPnb29vcbXY8aM4YsvviA8PJyXXnqJ9evX07ZtW3x8fGo1vrup0QYugB2gB1y8\nqfwi5flZtBJCXAOqL1DexqxZs7CysoKzZ0GlInfcOPDzw9rrWQQgrLMg48HL4XIjP2c/1ELNkYtH\n6O5Wz5+IunYt3/MyYgS89BIsXVq+ifc2HrO15WhAAFPPnGHUiROEZmXxmbc3thU74BWVgvN4Z+xH\n2pPyQQopi1PI+CYDz/c9cRzriKK6ffv1wdDQEQ+Pd3B3n82FC6s5f34JsbFdsbLqjZvbq9jaPo6i\n3NfbzKT7lalpvc6E3E86d+5McnLybesoisJbb73FfC35oBqSoih06NCB6OjoaseioqLw9PSsCqZ8\nfX0RQhAdHc2jjz5aVe/gwYOo1Wp8fX1r1feIESOYPHkyUVFRbNhw6/tKvLy8+OOPP+jRo4fWJa2b\ndenSBS8vL8LCwujfvz/Hjx/n/fffr9XYAMLDwzU2EEP5ZuyG0JgDl7tm6dKl5dObc+dCbi5/r1tH\nRFwc5ocEuQYKZUblU2+Ghg/ujEs7h3YYqAyIzYit/8AFypeKvvgCpk0Dd/fyAKYGdoaGbGzblnUX\nL/JiQgK/HzjAMm9vRtnbU7myqG+uj+d7njg/58zZ189ycvxJzn9+nhaftsC6V91viawNPT1TXFym\n0rTpJLKytpKauphjx4ZiYtIKN7eXcXQci55ewy5lSVJjcT/tcUlNTSU/P59Wrf75LDxy5EjmzJlD\nbGxs1bLXqVOn+PPPPzX2hTz88MM0adKEFStWaAQuK1aswMzMjMcff7xWYzEzM+PLL78kKSmJIUOG\n3LLeqFGjWL58Oe+++y4LFy7UOFZWVkZubm75B/EbhIaG8u677/LWW2+hUqkIDg6u1dgAgoODq50X\nGxtb7a6q+tCYA5csoAxwvKncEbh12sQ7cUPWXADjnDKK7Mv3t8CDPeNiqGdIB8cO9XdnkTZTp5Y/\nRfqVV6BFi/JgpgaKojDGyYl+Nja8eOYMQSdOsM7WluXe3rjesF/GpLkJ7daX739JnJVIXO847EfZ\n4/mBJyYeuq813wlF0cPefgT29iO4ejWS1NSPOX16MufOvYGLy4u4uEzFwMD2roxFku42IQS//PIL\n8fHx1Y716NEDDw8PoO57XH7++WcOHz6MEIKSkhIOHz5c9Yt72LBhtG/fvqrue++9h6IoHD9+HCEE\na9as4e+//wZg3rx5VfXGjh3L7t27UVekYQCYNm0aK1euZNCgQbzyyivo6+uzdOlSnJ2deemGD1zG\nxsYsWLCAF154gVGjRjFw4EB2795NWFgYixYt0imXzM1LPbpksQ0MDGTy5Ml88MEHxMXF8cgjj2Bg\nYCwTMu4AACAASURBVMDp06fZtGkTy5Yt44knNHdKjBkzhnfffZctW7bQq1cv3N3da+znnqrPbHYN\n+QLUwNCbyvYDn93wtQKkAq/WU5+amXMHDRJi6FDxZVqaUEVEiJNTTomDvgdFauqnYtcuY6FWN2wG\n13vtuS3PiY4rOjZsJ2VlQjz5pBBmZkIcOlTr03/MzBTOe/cKi927xfLz50WZln8TdVl59t29TfeK\nvwz/EgmvJIjinFtnh2xIeXmnxalTU8WuXcZi1y4TcerU8yI/P+GejEW6t/4NmXNv9Vq9evUd9zF+\n/Hid21cURWs9PT09jXp9+vSpViaEEGlpaWLUqFHC2tpaWFpaimHDhonExESt4/r6669FmzZthLGx\nsfD29hbLli3T6Xp0zTbs4eFRLTtvZb+dO3cWZmZmwsrKSnTs2FHMmTNHXLhwQWs7Xbp0ESqVSnz1\n1Vc6jU+Ie5c5VxH/z96Zx1VdpX/8fe5luZd930FAQcSNRRCtzNK0ptQcV1D7lVOWU1lmU5OVmmVp\nOVmNo7ZY2iioqS1j20xu1SiiCO6ICyog+6IIynbP748LjAjIInCv+n2/Xt/X697zPd9zPhfuvd/n\nPuc5z2PECbOEEJZAN/QGyX7gBWA7UCilTBdCjAdWAU/xv+3QY4EgKeUNl/UVQoQBiYMGDcLW1pbo\nw4eJHjqUt2bP5u+ZmWxdYkt1STVWy9aSl7eZqKiTNzqlUbN873Jm/DSDkldK0Jh04NJGWRkMGqT3\ncCUkQCM5E65HcWUlL58+zSdZWdxpa8ungYEENRLEV11aTfr76ZxbdA6VuQrfOb54TPdAZdb5cScV\nFXmcP7+czMylVFYW4Oz8R7y9/6IE8t5G1LrVExMTm915o6BgDDT1nq2Nd7lw4UJtActwKWW7ueuN\nPTKwH5AEJKK32v6G3oB5A0BKuQF4EZhf068PMLw9jJarWbJkCd999x3RlZX1suZene7/Vl4mqiXM\nPYwqXRWHcw937EQWFvDdd/pMxaNGQSszZNqZmvJx9+7sCAkhp6KCvvv28daZM1Rc5e4FUFuq8X3d\nl/4n++M81pmTL5wkITiB3I25nZ4B18zMGV/fOURFnSUwcBmXLiWzf39/kpLuJj9/C1Lqmh9EQUFB\nwQiIjo7mu+++Y8mSJR0yvlEbLlLKnVJKlZRSfc0x9ao+y6SUvlJKrZRygJSyYbh3+4jRewBqs+aa\nmd0W6f6vpo9rH9RC3bFxLrV4eOiNlyNH4NFHQdf6G/fddnYc6NePWd7ezDtzhn6JiSRcbFjTyNzN\nnO4fdyfiYAQW3S04Ou4oSXckcWF3x0TEXw+1WouHx5NERqbQs+cmpKzg8OER7N3bm6ysL9DpGuaP\nUFBQULidMGrDxagoKoIaj0tdgcW8Wz/d/9VoTbX0cO7ROYYL6Ld7rlmjz+3yxhttGkKrVvO2vz/7\nwsMxE4Ko/ft5JjWVC1VVDfpa9rSkz/d96PtLX3SXdSQNTOLI+CNcPtX5NVH0gbx/JDR0FyEhv6HV\nduP48anEx/tx7twiKiuLmx9EQUFB4RZEMVxawMyZMxk5dixxULdU5IIJVYVVmDibUF5+e3hcAMLd\nwzvPcAF9bpd33oH586GRKqYtJcTamviwMJZ068bqnByCEhJYn9v4kpD9EHvCE8MJWh3EhV0XSOiR\nwMmZJ6ks7NgCjo0hhMDO7k569/6WiIhjODo+SFraHOLjvTl5chZXrqR3uiYFBQWF6xEXF8fIkSOZ\nOXNmh4yvGC4tYMmSJXw3Zw7RUGe4eFzS/+nULlfQ6UpvC48L6ONcDuYcpLK6E2/iL78MjzwCU6fC\n7t1tHsZEpeI5Ly+ORUQw0MaGiUeP8sDBg5xqJIZGqARuj7jRP7U/vvN8yfosiz1d95D+fjq6csPE\nm1haBtG9+6dERZ3F03MG2dmfs2ePP8eOTeHSpYMG0aSgoKBwLbd1jItRUVNgUbq6kl9ZicvFmsJg\nTvoiVreLxyXMPYzy6nKO5TfMxdBhCAGffAIREfDww9BMVs3m8NJo2NSrF//q1YtjZWX02ruXBWfP\nNgjeBVBbqOkyuwv9T/bHZaILp146RUKPBHI3dH4Aby3m5m74+y8gKiqdrl0XU1z8K/v29eXgwT9Q\nXLzTYLoUFBQUOgPFcGkpOTmg0XDBwoJKKXGqCTGQtvqsubfDriKAvq59EYjOXS4CMDeHr7/WV5V+\n6CFoJMi2tTzk5MTRyEhmeHoyNy2NkH372FnceOyImasZgcsDiTgYgWVPS45OOErSwCQu7Or8AN5a\nTEys8PJ6jv79TxIU9E/KyzNITh7M/v1R5OVtRsrm670oKCgo3GwohksLmDlzJiOXLiXOyqoua65d\nzf1NZ6HfeX27LBVZm1sT6BjY+YYLgJOTviBjejqMH68Plr5BLNVqFnXtSlK/ftiZmDA4OZnHUlLI\nb6Kqq2WwJb3/1Zu+W/uiK9eRdEcSR8YZJoC3FpXKFDe3yfTrd4DevX9ArbbgyJExJCQEc/78p1RX\nXzGYNgUFhdsPJcbFCFiyZAnfDRpEdNeudYaLZZFEZaGikixMTOxRqzsnbbwxEOYeZhjDBSA4GDZt\ngq1b9XWN2mlZpLeVFb+HhvJxYCDf5OcTlJDAF1lZTS672N9rT/i+mgDe3TUBvC8YJoC3FiEEjo4P\nEBKynbCweCwte5Ga+iR79vhx9uxCZSeSgoJCp6DEuBgL2dl1W6EBNAU6zFzMbpscLlcT5h5GcnYy\n1ToDLUUMGQKffaY/2lDFtClUQjDNw4OUyEjud3Bg6vHjDE5O5lhpaaP96wXwzvUl61PDB/DWYmPT\nn169NhEZmYKj4wjOnJlLfLwPp079hfLyTINqU1BQULgRFMOlpVxVYFEAJvnVmLqY3jY5XK4mzD2M\n0spSThSeMJyI//s/mDcPXn31hrZJN4armRlrgoP5T58+ZNVk3n09LY3L1Y0bamoLNV1evSqA9y+n\nSOiZQN7mPIMHylpYBNK9+ydERZ3B0/Npzp//hPh4P1JSplJammJQbQoKCgptQTFcWspVWXMdTEyo\nqks+d/t5XELdQgEMt1xUy5w5egPmscdg5852H36ogwMH+/XjFR8f3j13jt579/KfwsIm+18dwGsR\naMGRMUdIHpxMSWJJu2trLebm7vj7v8OAAen4+S2gsPAn9u4N5vDh0Vy4EG9oeQoKCgotRjFcWsDM\n559nZGYmcenp+uRzZmZU5lXWpPu//Twu9lp7/Oz8DG+41G6TvvNOfaK6lPb3IGjUat7w8+NgRATe\nGg3DDh4k5uhRssubTr1v2dOSPj/0oc9PfagsqCSxXyLH/u8YVzIMHyRrYmKDj89fiIpKo3v3Tykt\nPUpS0gCSkgZTUPCjwT1ECgoKNz9KcK4RsOSNN/hOSqIffJC8mnT/FbkVmDirKS/Puu08LqBfLkrM\nSjS0DDAz0wfrenjAAw/oPWMdQHcLC7b17cvqoCD+U1REUEICH58/j+46N3qH4Q70S+5H4MeBFP5U\nSEJgAmlz06i61LDcQGejUpnj7v4nIiOP0rPnJnS6yxw69Af27QshJycWnc7wGhVuHVavXo1KpWr0\nUKvVJCQk3PAcy5cvZ/z48XTp0gWVSsXUqVMb7ffbb78xatQofHx80Gq1uLu788ADD7Br164WzfPG\nG280+josLCwa7b9y5UqCg4PRarUEBgaydOnSFs1z9d+sKW3e3t6oVCpGjhzZojFrycvLw9TUlEce\neaTJPpcuXUKr1TJ27NhWjQ0dH5xr0iGj3mrULg/Uqwx9CbXHRaD6tsnhcjVh7mEs+u8idFKHShjY\n/rWzg++/h6goGDECtm/X53tpZ4QQPOLmxoOOjrx86hRPpaayJieHTwID6dHEfCoTFR7TPHCZ6MK5\nd85xbtE5sj7Nwm+BH27/54ZQiXbX2RpqayI5OY2muHgn584t5NixSaSlvYqX1yzc3aeiVjf+hayg\n0BqEELz55pv4+vo2ONetW7cbHv/dd9/l0qVLREZGkl2TMLQxUlNTUavVTJ8+HTc3N4qKilizZg2D\nBg3ihx9+YNiwYc3OJYRgxYoVWF71uVer1Q36ffzxx0yfPp1x48Yxa9YsfvvtN2bMmMHly5f5y1/+\n0qLXpdVqiY2NZeDAgfXad+7cSWZmJhqNpkXjXI2zszP33Xcf3377LVeuXGl0jE2bNlFRUcGUKVNa\nPX6HI6VUjiYOIAyQiStWSAlSpqbKkL175dPJx+R2tsu0dT/L7duRFy7slbcbP574UTIPebLgpKGl\n/I/ERCktLaUcNUrKqqoOn25HUZEMiI+XZjt2yPlpabK8urrZa8rSyuSRiUfkdrbLvaF7ZeG2wg7X\n2VouXkySR45Ey+3bVfL3351kWtp8WVGRb2hZtzyJiYkSkImJiYaW0u6sWrVKqlSqDn1t586dq3ts\nZWUlH3vssRZfW1ZWJt3c3OQDDzzQbN958+ZJlUolCwoKrtvv8uXL0snJSY4cObJe++TJk6W1tbUs\nLi6+7vWrVq2SQgg5duxY6eLiIquv+X6ZNm2ajIiIkH5+fnLEiBHN6r6WNWvWSJVKJdevX9/o+WHD\nhkl7e3tZUVHR5BjNvWdrzwNhsh3vzcpSUUu42uNSUYFHSY1l7ZAP3D7p/q/GaAJ0ryYsDNavh3/9\nC154ocOnu9vOjoP9+vGitzfzz54lbN8+dl+4fiZdra+W4LhgQneFojJXceDeAxwaeYjSlMa3XBsC\na+sQgoNj6d//JM7OEzh37m127/bhxInnuHz5jKHlKSg0ire3d5uv1Wq1ODs7U9xE5uzG0Ol0lJQ0\nHXi/fft2CgsL+fOf/1yv/emnn+bSpUt8//33zc4hhCA6OpqCggL+85//1LVXVlayceNGYmJiGo1L\nk1LywQcf0KtXL7RaLW5ubjz11FP1Xt/o0aOxsLAgtpFdmXl5eWzbto1x48ZhamrarM7ORjFcWkJB\nAWg0yJrMuS7Feve+ziYPUGNm5mJYfQbA1coVT2tP4zJcAB58EP7xD/joI/jwww6fTqNWs8Dfn8Tw\ncCzUau5ISmLGiROUVF0/RsR2gC2hu0IJXhdM6aFS9vbaS+rTqVTkNZ6x1xBotX4EBi4lKuoc3t4v\nkpOzhj17unH06CRKSpINLU/hJuTChQsUFBTUOwqv2alXXFzcoE9jx+VGiqO2hpKSEgoKCjh+/Diz\nZ8/myJEjDB06tEXXSinx9/fH1tYWa2trpkyZQm5ubr0+SUlJAISHh9drDw8PR6VS1Z1vDl9fX6Ki\nooiLi6tr++GHH7h48SITJ05s9Jpp06bx8ssvc9ddd/HRRx8xdepU1q5dy/333091TVoHCwsLRo0a\nxc8//9zAYFu3bh06nY5Jkya1SGNno8S4tICZGzZgKwQPx8ZS4eWF40W94VKtzcGs2g0hGq5t3g6E\nuYexP9vIDBeAp56CU6dg5kzw9YVRozp8yj5WVuwOC+PvGRm8mpbGN/n5LAsI4CEnpyavEULgMsEF\nx1GOZC7N5OxbZ8lZk0OX2V3wfM4TtcY43ldmZs74+b2Bj89LZGV9TkbG+yQmhmJvfx/e3i9hbz8E\nIQwbq6Ng/EgpGTJkSIN2jUZDWVlZ3fPQ0FDONlNIVQjB3LlzmTNnTpv1jB8/np9//hkAMzMznnzy\nSV577bVmr7O3t+fZZ59lwIABmJub89tvv7F06VL27t3Lvn37sLKyAiArKwu1Wo3TNd8BpqamODo6\ncv78+RZrjYmJYfbs2ZSXl2Nubk5sbCx33303bm5uDfr+/vvvrFy5kri4OCZMmFDXfs899zB8+HC+\n+uqrOoNn0qRJxMbGsnHjRh5//PG6vrGxsXh6ejJo0KAWa7yauLg44uLiuNCMB7qtKIZLC1gSEkJY\nbi6nxoyBPXuwLdK3V5vk3JaBubWEu4ezdO9SpJTGd+NatAjS0iA6Wp/jJSKiw6dUC8Hz3t487OTE\nU6mpjDh8mAnOznwYEICrmVnT12nU+Lzog9ujbpx98yxpr6WRuSwT/3f8cZnoYvAA3lrUaku8vJ7F\nw2M6eXkbSU9/l4MH78PKKhRv77/g7DwOlUr5SukMyqqrSbnqZt9RBFlYYNFI0GlbEEKwbNkyAgIC\n6rVfG9QaGxvbIm+Kv7//DelZtGgRL774Iunp6axevZqKigoqKysxu85nFWDGjBn1no8ePZqIiAgm\nTZrEsmXLeOmllwC4fPlyk2NpNJpWeYzGjx/P888/z5YtWxg+fDhbtmxpcnfSxo0bsbOzY8iQIRQU\nFNS1h4aGYmVlxfbt2+sMl2HDhuHs7ExsbGyd4XLmzBn27NlT9zraQnR0NNHR0ezfv7+Bx6k9UL5l\nWkJhYV18C4BVoY4KOxMqqm6/5HNXE+YeRn5ZPhkXM/C2bfv6coegUsE//wn33quvJh0fD35+nTK1\nr1bLj336EJuby3MnThCckMDSgAAmurhc18AzczIj4MMAPJ/x5PTLpzk26RgZH2TQdXFX7AbZdYr2\nlqBSmeDqOhEXlwkUF2/j3Ll3OXYshrS02Xh5vVCzE6n9d3Up/I+UsjLCEzs+HUFieDhh1tbtNl5E\nRARhYWHX7TNgwIB2m+969OnTp+7xpEmTCAsL47HHHmPDhg2tHis6OppZs2bxyy+/1N3wtVotFU0U\na71y5Qpabcvr2zk5OTF06FBiY2MpLS1Fp9M1uU35xIkTFBcX4+LSMIRBCFFvSUutVjNhwgSWL19O\nVlYW7u7urF27FiEEMTExLdbX2SiGS0soLISePesKLGoKdciadP+2tncZWJzhCHYOBuB4wXHjM1wA\ntFr47jv9NukHH4T//hfs7TtlaiEEk1xdGWZvzzMnThBz7Bhf5eWxPDDwut4XAIsAC3pt7kXxb8Wc\nmnWK5LuTcXrYCf9F/lgEGs/WZCEE9vZDsLcfQklJMunpizl5ciZnzszDw2M6np7PYG7e0JWtcOME\nWViQ2AG/ZBubp7PJz8+vi8O4HlZWVvW2I98IpqamjBw5kkWLFtUtx7QWb2/vevE67u7uVFdXk5+f\nX2+5qLKykoKCAjw8Wuetj4mJ4YknniArK4sHHngA6yYMSp1Oh6urK7GxsY0G7jo7O9d7PnnyZJYu\nXUpcXBwvvPAC69atIzg4uJ5hZ2wohktLyM/XF1isMVzU+dWYuZhRehum+78aJwv9h7HocpGBlVwH\nZ2f48UcYMADGjIGfftInreus6c3MWN+zJ+Nyc/lzK7wvAHZ32REWH0bu+lxOv3KahOAEPJ7woMuc\nLpi7t/6LtSPR70Rag7//AjIyPiAz80PS09/D1TUGL68XsLLqbWiJtxQWanW7ekKMiYiIiE6JcbmW\nsrIypJSUlJS0yXA5c+ZMPW9SSEgIUkr27dvH/fffX9e+d+9edDodISEhrRp/9OjRPPnkk+zZs4f1\n69c32a9r165s3bqVgQMHtuh1REZG0rVrV2JjYxk6dChHjhzhnXYsXtsRKIZLSygqqlsqsjcxoTq/\nChN3HVVVBbdduv+rsTG3QS3UFF5uun6PURAYCN98A0OHwhNPwKpV+nIBnchYFxfutrPj6Rrvy8a8\nPJa1wPsiVALXaFecRjtx/h/nObvgLNlfZuP1vBfef/HG1M64tipqNF3o1m0Jvr7zOH/+UzIzPyQ7\nexX29vfh5fUCDg7DjS8eSsGo6OgYl7y8vAZeh+LiYjZt2oSPj08970h6ejplZWV07969ru1aDwrA\nsmXLyMvL44EHHqhru/fee3FwcGD58uX1DJfly5djaWnJgw8+2CrdlpaWrFixgjNnzjBixIgm+40f\nP55ly5Yxf/58FixYUO9cdXU1ly5dwtbWtl77pEmTmD9/PnPnzkWlUhEdHd0qbZ2NYri0hKqqellz\nK3Ir0Abro6VvZ4+LEAJ7rb3xGy4Ad92lN1hiYsDfH+bO7XQJzmZmbOjZk69qvC89ExL4R2Ag452d\nm72ZqzVqvGd54/YnN9LfTSdjSQbnV5zH5xUfPJ8xnh1ItZiY2OLj8yJeXs/VBPL+jUOHHsDCIhhv\n7xdwcZmEWt36jJ8KNy9SSn744QeOHTvW4NzAgQPxq4lBa2uMy5YtWzhw4ABSSiorKzlw4EDdjXvk\nyJH07q33+j3wwAN4eXnRv39/XFxcOHv2LKtWrSIrK6tBfMuUKVP49ddf0el0dW1dunRhwoQJ9O7d\nG41Gw2+//cb69esJCwtj2rRpdf00Gg1vvvkmzzzzDOPHj2f48OH8+uuvxMbG8vbbb2Nn13zc2rVL\nPS3JYjto0CCefPJJFi5cSHJyMsOGDcPU1JTU1FQ2btzIRx99xB//+Md610yePJn58+fz7bffcued\nd+Lj49PsPAalPbPZ3WoHtZlzQcrffpNTjh6Vd+7fL3d57ZJHF6+X27cjL1063GjGwNuFwL8Hyhd/\nftHQMlrOggX6LMirVhlURm55uRx3+LBk+3Y55tAhmVNe3qrrr2RekSlPpsjt6u1yl9cueX7leVld\n2XzmXkOh0+lkUdGv8uDBUXL7diF//91ZpqXNk+XluYaWZjTcDplzmzpWr159w3M8+uijLRp/2bJl\nctCgQdLFxUWamZlJV1dX+fDDD8v//ve/DcYcPHiwVKvV9dqmTZsme/XqJW1tbaW5ubkMDAyUs2fP\nlpcuXWpU12effSZ79OghNRqNDAgIkB999FGLXk9Lsw37+fk1yM5bO29ERIS0tLSUtra2sm/fvvKV\nV16R2dnZjY4TGRkpVSqV/Pjjj1ukT0rDZc4VspHgHQU9QogwIHEQYHvvvZwdNoyuf/gDz/UrxOXT\no+T4/Jk77ijC1NR4dnx0NgNWDqCHUw8+H/W5oaW0DCn1y0WrV+trGt15p0HlbMjN5ekTJ5BS8nH3\n7oy5xoXdHGWpZaS9nkbehjwseljg97YfTqOcjHo5pqzsBBkZH5Kd/QVSVuPm9gheXs9hadnT0NIM\nSu3W0cTExGZ33igoGANNvWevzuPy66+/AoRLKdst6VerMucKITYKIe4Xxvyt2AEsAb77+mtMhwzB\no9wEWSHBPg+VSouJiW2z19/KOGgdbo6lolqEgOXL4Y47YOxYyMw0qJzxLi4ciYhgkJ0dY48c4U8p\nKVxqJuvu1VgEWtBzfU/C9oZh7mnOkdFHSLojieKdLU9d3tlYWAQQGLiUAQPS8fWdS0HBFvbu7cWB\nA/eRn/8vpGx+R4mCgoLx0tHVoVub8t8e+B44J4SYL4S4sQxANwvm5mBtTV5lJe4X9X8ynXUe5uae\nRv3LtjO46QwXAFNTfU0jU1P9TqPycoPKcTEzY1PPnqzs3p31ubmE7NvHnosXWzWGTT8b+v6nL33+\n0wddhY7kwckkD0mm+FfjNWBMTR3o0uUVoqLO0KNHLFVVJRw+PJI9ewJJT/+AqqqOybqpoKBwc9Mq\nw0VKOQTwB1YCk4ETQohtQogYIYRx7c9sTxwckEBuZSUuNYZLtXnObb2jqBYHzU1ouAC4usKmTZCU\nBNdkwjQEQgimuruT3K8fjqam3LF/P2+eOUPVVUGBLcFhqAPhCeH0/LonlQWVJN9t/AaMSmWGq2s0\n4eHxhIXFY2MzgNOnX2LXLk9SU5+hrOy4oSUqKCgYEa0usiilPCulnCel9AfuA84DnwJZQoh/CCE6\nPitSZ+PoSGl1NVd0OhxrCixWqXNu6x1FtdyUHpdaIiP1y0affKI/jIBuFhb8HhrK7C5dmHfmDIOT\nk0lrZTE5oRI4P+xMv/39bioDBsDGpj/BwWuIijqLt/cs8vK+IiEhiIMHH6Cg4EekbJ0hp6CgcOtx\nQ9WhpZTbpJSTATfgFWAisKc9hBkVjo51WXNtiySooFJ3eyefq6XWcLlpg7ynToXp0+GZZ/RlAYwA\nU5WK+X5+7AwJIbOigr779rEmO7vVf+Ob2YAxN3fHz+8NBgw4R1DQaioqcjl06A8kJPQgI2MpVVUl\nhpaooKBgIG7IcAEQQvgBLwKzAVvglxsd0+i4ynCxLJKYOJlQXnFeWSpCb7iUV5dzuerGSswblA8+\n0BdhHDMGsrMNraaOO+3sSO7Xj4ednJiSkkLMsWMU17wPW8PNbMCoVOa4uT1CePg+QkN/x8oqhJMn\nn2f3bg9SU5+mtPSIoSUqKCh0Mm0yXIQQGiHEZCHENuAE8Aj6uBc/KeX917/6JsTB4X91igp0mHWp\nQKcrUzwu6A0X4OZdLgJ9CYCNG/VbpceNgyYKoxkCWxMTvuzRg7gePfixoIA++/YR38ZS8U0ZMEmD\nkyj4ocCovWZCCGxt76Bnz/VERZ3By2smeXmb2Lu3F0lJg8nN3YBOZzz/NwUFhY6jtduhI4UQK4As\n9HEt2cD9gL+Ucr6UMr0DNBoeR8e6ytAmBdWoffW1eRSPyy1iuAC4u+uNlz17YNYsQ6tpwERXVw5G\nROBlbs6g5GT+npHRZkPjWgNGd1nHoQcPsbf3XrJXZ6OrMO44Eo3GCz+/+QwYcI7g4HWA5OjRCcTH\ndyEtbQ5XrmQYWqKCgkIH0lqPSzzQH3gd8JBSxkgpf5HG/FOtPXB0JLeyElu1mqq8SlQ++pu04nG5\nhQwXgIED4aOPYOlSfXkAI8NHo2FnSAhPe3oy4+RJYo4da1XOl2upNWDC4sMI2RmC1k9LyqMpxPvH\nc27xOaoutn3szkClMsPFZQKhoTvp1+8QTk6jychYQny8L4cPj6GoaKtRe5EUFBTaRmtrFfVrz+x3\nNwsz164l86ef0AweTGXu/Zi66W/SZmbuBlZmeG4pwwXgySdh3z546ino2VMf+2JEmKpULOnWjQE2\nNvzp+HEi9+9nU8+e9LC0bPOYQgjsBtlhN8iO0qOlpC9OJ212GmffPIvHUx54PeeFuYdxZzuwsupF\nYOAy/P0XkpPzTzIzl3HgwFC02u54ev4ZV9dHbusM1woKncnVmXM7gtbmcakzWoQQdwkh1gghdgsh\nPGvapgghDJtDvQNYMm8edy5dStcHH6QitwKc8jExcVSKxAF2Gv3N4JYxXITQe1xCQ2HYMPj9VZAA\nsgAAIABJREFUd0MrapTxLi7sDQtDABGJiazLyWmXcS2DLQn6PIiotCg8nvLg/IrzxPvGkzI1hdKj\npe0yR0diYmKDp+fTREQcJiRkB1ZWfTh1aha7d3tw7NijXLiwS/HCKCh0MMaWORcAIcQY4GfgMhAK\n1P4cs0W/u+jWomZXkbPahMr8SqRdPubmSnwLgFqlxk5jd+sYLgAaDfz0E4SEwH33wb/+ZWhFjRJk\nacmesDBGOTkRfewYM06coKKVCeuawtzTnK6LujIgfQB+b/tR+O9C9vbcy8E/HKTg+wKkzrhv/kII\n7OzupmfPDURFnaNLl9e4cOFXkpLuYO/eXmRkfEhl5S30nlVQuI1o63bo14CnpJRPAFfvz/wv+orK\ntxYWFuRVVuJ12RR0oLNQks9djaPW8dYyXABsbeHHH+HBB2H0aPjcOItIWpmYsKZHD5YFBLDi/Hnu\nTk4m/cqVdhvfxMYEnxd9iDodRdDqICpyKzj00CH2BOwh/W/pVBa2fnt2Z2Nu7k6XLrPp3/8kffr8\nG0vLYE6depFduzw4enQyxcW/Kl6YDmb16tWoVKpGD7VaTUJCwg3PsXz5csaPH0+XLl1QqVRMnTr1\nuv1/+eUXhgwZgp2dHTY2NvTr14+vvvqqRXOlpKRw//33Y21tjaOjI4888gj5+fkN+kkpeffdd/H3\n90er1dK3b1/WrVvXojneeOONur9PZiM11UpKStBqtahUKma0Mvt3UlISKpWKOXPmNNnn5MmTqFQq\nXnzxxVaN3Rm0Nsallu7Ar420XwBuvYVkIcirqMD9Qm26/1wszfoaWJTxcFNnz70eGo2+ptEzz8Cf\n/gQ5OfDXv+qXk4wIIQTTPT0Jt7Zm3JEjhCUmEtejB0MdHNptDpWZCrdH3HCd4kpJQgmZSzM5Pfs0\naa+l4TLJBc+nPbEOtW63+ToCIVQ4ONyHg8N9VFTkkJ29mqysT0lOXotW2x0Pjydwdf0/zMycDC31\nlkQIwZtvvomvr2+Dc926dbvh8d99910uXbpEZGQk2c3kY/riiy94/PHHGTZsGO+88w5qtZrjx4+T\nnt78xtjMzEzuuusu7O3tWbhwISUlJbz33nscPnyYhIQETEz+d1udPXs2ixYt4sknn6Rfv358++23\nxMTEoFKpGD9+fItel0ajIS4uroEBsXnzZoQQbaqXFxoaSlBQEHFxccyfP7/RPmvXrkUIwZQpU1o9\nfocjpWz1AZwGhtY8LkG/HRr0+VyOtmVMYzzQe49kYmKitNy5U36y/rjcznb5+04Pefr061JBz/B/\nDpdj1o8xtIyOQ6eTct48KUHK556Tsrra0IqaJL+iQg5PTpaq7dvlh+npUqfTddhc5Tnl8syCM3KX\n9y65ne0ycWCizF6bLavLjffvcy06XbUsLNwqjxyZKHfsMJM7dpjJw4cnyIKCf0udrqpTtSQmJsra\n75tbjVWrVkmVStWhr+3cuXN1j62srORjjz3WaL8zZ85ICwsLOXPmzDbNM336dGlpaSkzMjLq2n75\n5RcphJCffvppXVtmZqY0MzOTM2bMqHf9oEGDpI+PT7OfzXnz5kmVSiXHjh0rw8LCGpwfNmyYHDdu\nnBRCyGeffbbVr+Ott96SKpVK7tmzp9HzQUFBMjg4+LpjNPeerT0PhMl2vDe3danoU+BDIUT/GlEe\nQohJwGJgeVuNKGPlcnU1pTodDsWAqppKnVJg8WpuWY9LLULA3Ln6ukYffQSTJxtVkrqrcTQ15fs+\nfZjp5cVzJ0/yVGoqle0U93ItZi5mdJndhf6n+9Nzc09UWhXHJh1jt89u0l5P40p6+y1ZdRRCqLC3\nv5fg4DgGDMjE3/8dLl1K5uDBYeze3YVTp/5KaelRQ8tUaAHe3t4t6rd8+XJ0Oh1vvPEGAKWlrQs6\n37x5Mw899BCenv8LFxgyZAiBgYFs2LChru2bb76hqqqK6dOn17t++vTpZGRksHv37hbNFxMTQ1JS\nEqmpqXVtOTk5bNu2jZiYmEavqaioYO7cuQQEBKDRaPDx8eHll1+m4qrvrUmTJiGlJDY2tsH1+/fv\n5/jx40yePLlFGjubthouC4FYYCtghX7Z6DPgYynl39tJm9FQXJMrw6YIcLkAVCsxLldxyxsutTz1\nFGzYoK8q/dBDUGKc9XLUQrC4WzdWdu/OF9nZDDt4kII2lApoKSoTFc6jnQn5JYSIIxE4j3Um44MM\n4rvEc/APB8nbnIeu0riT2gGYmTnh7f0CkZHHCAuLx8lpFFlZn7B3b0/27etHRsZHVFTkGVrmTc2F\nCxcoKCiodxQW1v/uKC4ubtCnseNyK4uP1rJ161aCgoL4/vvv8fb2rotTmTNnTrOxTufPnyc3N5d+\n/fo1OBcZGUlSUlLd8+TkZCwtLQkKCmrQT0pZr+/1GDRoEF5eXvUMjHXr1mFtbc2DDz7YoL+UkhEj\nRvD+++8zatQoli5dyujRo1myZAkTJ06s6+fr68vAgQPZsGFDg9ddu0wUHR3dIo2dTZsMlxov0ALA\nAegFRAHOUsrX21OcsVBU86VvVSgxDdDXdlF2Ff2P28ZwARg7Vr/jKD4ehgwxWuMFYKq7O1v79uVw\naSn9ExM51spflm3BMtiSwKWBDDg/gO6fdqeysJIjY46w22s3p14+RVlqWYdruFGEENjY9Ccw8B8M\nHJhFz56b0Wi8OXXqRXbv9uDQoZHk5m5Epys3tNSbCiklQ4YMwdnZud7h5eVVr19oaGiDPtceLi4u\nvPfee23SceLECc6dO8fUqVN5/PHH2bRpE3/4wx946623eO211657bVZWFgDu7g1zeLm7u1NYWEhl\nzf0iKysLV1fXRvuB3ghqCUIIJk6cSFxcXF1bbGwsY8aMwdTUtEH/tWvXsm3bNv7973+zePFiHn/8\ncT788EOWLl3Kt99+S/xVxWQnTZpETk4OW7durWuTUrJhwwYGDBjQaDySMdCq4FwhxDngu5pjm5Sy\nArjl/ahFVVWgUmFeVE1FlyIqATMzxeNSy21luADccw/s3Al33w2PPqovFWBkAbu13GVnR0JYGCMO\nHSJq/37WBwdzv6Njh89rYm2C+5/ccf+TO5cOXSJrZRZZn2aR/m46tnfb4v64O85jnFFr1R2u5UZQ\nqcxxdh6Ns/NoKiryyctbT3b2lxw9Og4TEztcXCbi6voINjZRbQqSbCvVZdWUpXS8EWgRZIHaon3+\nR0IIli1bRkBAQL12tbr++LGxsS3ypvj7+7dJx6VLl5BSsmjRorqA19GjR1NQUMCHH37I7NmzsWwi\noWOtLnPzhgkZNRpNXR9TU1MuX77cbL+WEhMTw+LFi0lMTMTOzo69e/eycOHCRvtu3LiRHj16EBgY\nSEFBQV37Pffcg5SS7du3ExUVBcCECRN4/vnniY2NZejQoQDs2LGDzMxMXn311Rbr62xau6toCjAS\n+AfgLIT4Gb0R872U0rjLzN4ARVVVYGaGSb6Oqu6FgBozMxdDyzIaHLQOlFaWUl5VjrmJcWdYbTdC\nQ+HLL/VbpRcuhFdeMbSiJvHTatkVFkbM0aM8eOgQ73frxgxPz0670Vr1tiLggwD8F/qT/3U+WZ9l\nkTIlhZPPnsR1sivuj7tj1deqU7TcCGZmTnh6Po2n59OUlqaQk/NPcnL+yfnzK9Bo/HBy+iPOzmOw\nsemPEG1dhW8ZZSllJIYndugcAOGJ4ViHtd9usYiICMLCrp8xY8CAAe02X2NotVrKysrqLZuAPmna\nzz//TFJSEnfe2XgeVa1WC0B5eUNv25WaNAS1fbRabYv6tYSQkBCCgoKIjY3F1tYWd3d37rnnnkb7\nnjhxgpSUFJydnRucE0KQm5tb99zBwYHhw4fz9ddfs2LFCszMzIiNjcXU1JRx48a1WF9n0yrDRUq5\nE9gJzBJC9ERvxDwLrBRC7KLGGyOlPN3uSg1IUVUV1lot1XmViEGFmJu7d/gX081Ebdr/oitFuFm5\nGVhNJ/Lww/D66/Dqq3pD5n7jLYxuY2LCt71789fTp3n+5EmOlJayNCAAM1XnvY/VGjWu0a64Rrty\n+dRlslZmkf1FNplLM7EKt8J9qjsu0S6Y2jd0fxsblpZB+PsvwM/vTYqLd5CX9xU5OWvIyPgbZmYe\nODmNxtl5DLa2d6FStTXrRNNYBFkQnhje7uM2Nk9nk5+fT3V1dbP9rKysmvSMXA8PDw9OnjzZYBnH\nxcUFKSVFRUVNXlu7zFO7ZHQ1WVlZODg41C3fuLu7s2PHjkb71epoDTExMSxfvhxra2smTJjQZD+d\nTkfv3r1ZsmRJozE71wYxT548mS1btrBlyxZGjBjB5s2bGT58OI6d4JltK23+REkpjwBHgHeEEG7A\nCPSGzNtCiNPAy1LK79tHpmEprKzE2dSUitwKhEOeskx0DVfXK7qtDBeAefNg/36IjtbXOOra1dCK\nmkQtBO917UqwhQVPpqaSWlbGpl69cGxknbyj0XbV4v+2P77zfSn8oZCsz7M4MeMEJ184ifNoZ9ym\numE/xB6hMs4luFpqdyXZ299LQMBSLlzYRV7eJvLzN3P+/D8wNXXCyelhnJz+iL39EFQqs3aZV22h\nbldPiDERERHB2bNnr9tHCMHcuXOvm0CtKcLDwzl58iSZmZn1YjgyMzMRQjTqqajFw8MDZ2dn9u3b\n1+BcQkICISEhdc9DQkJYuXIlKSkp9QJ04+PjEULU69sSYmJimDNnDtnZ2U3uJgLo2rUrBw8ebNIj\ncy0jR47E2tqa2NhYTExMKCoqYtKkSa3S1tm0y08BKWU2+i3SnwohLIDhwC0TufbzW29RrtXyY8a9\nPGCjpPu/lluu0GJrUKlgzRqIjNR7YHbvBivjXvZ4zN2dAK2W0UeOcMf+/fzUpw++rXBbtycqExVO\nI51wGulEeXY5OWtyyP48m4PDDmLuY47bo264PeqG1s8w+lqDEGrs7O7Czu4uunVbQknJXvLyNpOf\nv4msrM9Qq21xchqBk9MYHByGoVZ3vjfjZqCjY1wmTJjAunXrWLlyJW+++SagD0j94osvcHBwIDz8\nf56s06dPN5hrzJgxfPnll2RmZtZtid66dSupqanMmjWrrt+oUaOYOXMmy5Yt46OPPqprX7FiBZ6e\nngwcOLBVuv39/fnwww+5fPlyo7uaahk/fjw//PADn376KU888US9c1euXEGn02Fh8b/3nkajYfTo\n0axfv57S0lKsrKwYOXJkq7RdS0cXWWyT4SKE2AmsBL6SUtZ7h0kpy4Cv20Gb0RD44os4BPRgcHgh\n1RbrMTfvbWhJRsVtbbgA2NnBN99A//76DLvr1hltsG4td9rZsTs0lOEHDzIgKYkfevcm1Nqwv+DN\n3czxedEH71neXNxzkezPs8lYksHZ+Wexu8cOt6luOP/Rud2CRTsS/c6kSGxsIvH3f4fS0kN1npic\nnDUIYY6t7Z04ONyHvf19WFm17tf3zYiUkh9++IFjx441ODdw4ED8/PyAtse4bNmyhQMHDiClpLKy\nkgMHDrBgwQJAb0T06tWr7vGQIUN45513yMvLo2/fvnz99dfs2rWLTz75pN5OnXvvvReVSlVnwIA+\nG+7GjRsZPHgwzz33HCUlJSxevJi+ffvy6KOP1vXz9PTk+eefZ/HixVRUVBAREcHXX3/Nf//7X2Jj\nY9sUY/bss88222fKlCls2LCB6dOns337du644w6qq6s5duwYX331Ff/+978bxBlNnjyZL7/8kp9/\n/pnJkye3Kv6mMaKjo4mOjmb//v31DMF2oy1Z64APgFz0Kf4/BaLaMyuesRzUZM7ttWaNfHrnYbmd\n7fLXbfbyzJm3pcL/qKiqkMxDfpH0haGlGJZNm/TZdRctMrSSFpNdXi777dsnrX/9Vf6noMDQchpQ\ndalKZn2ZJZMGJ+k/fza/yuN/Pi4vJl00tLQ2U1qaIs+de18eOPCA3LnTQm7fjvz9dye5YcN9t3zm\n3KaO1atX3/Acjz76aIvHLy0tlTNnzpQeHh5So9HIvn37yri4uAZj+vr6Sn9//wbtR48elffff7+0\nsrKSDg4O8pFHHpG5ubmN6lq4cKH08/OTGo1G9u7du9F5GqM2c25BM59LlUrVIDtvVVWVfO+992Tv\n3r2lVquVjo6OMiIiQr711luypKSkwRjV1dXSw8NDqtVq+dNPP7VIn5SGy5wrZDMJd5pCCGGCPqbl\n/4AHgJPA58A/pZQ5N2JMGQtCiDAg0XPVKqY7RHLH2HPw8/0EBa3Gze0RQ8szKmzesWHe4Hm8MOAF\nQ0sxLK++qt9l9OOPMGyYodW0iEtVVYw7epStRUV8ERTEpEZyTxgDl09dJuvzLLI/z6YiuwLrCGvc\np7njMtEFE6v2D4DtDHS6ci5c2E1R0X/YvfsbJk8+SmJiYrM7bxQUjIFaj0pT79mrPC7hUsr97TVv\nm7cUSCmrpJSbpZSjAC/0mXTfBNKFEN8IIe5tL5GGpqiyEueLKnDU74lX0v035LbL5dIU8+frDZaJ\nE+H0zbG5zsrEhO969SLGxYXJx47x3rlzzWYQNQTarlr8F/gTdS6Knl/3xNTJlNRpqex2383xp45T\nst94kwE2hUpljr39YPz9F9Cjxz8NLUdB4abghvdCCiEigTeAWeiXj94B8oEtQojFNzq+MVCm0+FQ\nBDjpy5Yr6f4bohguNajVEBsL9vb6HC+dkK22PTBVqfgiKIjZPj68dPo0M0+eRGeExguAylSF88PO\n9PmhD1FpUXi94EXBlgISwxPZ128f5z85T1VJlaFlKigodBBtMlyEEC5CiFlCiMPAb4AzEA34Sinn\nSikfB4YBT7WfVMNiUwzCU39jVnYVNUQxXK7C3l4frHvqFDzxBBipAXAtQggW+Pvzj4AAPsrMJPro\nUa60IJ+GIdF00eD3hh9RZ6Lo9V0vzN3NSZ2eyi73XRyfdpxLhy4ZWqKCgkI701aPSwbwOLAa8JJS\njpVS/iTr+5cPAntvVKCxYFUkUXcpQqWyRK22MbQco8NB60DB5YLmO94u9O4NX3wBcXGwZImh1bSK\nP3t6sqlnT77Nz+f+gwcp7sACje2FykSF0wgnev+rN1Fno/B5yYeCHwrY12cfyUOSyf8uH1l9cxiQ\nCgoK16ethssQKWUPKeV7UspGy6VKKS9KKVuWAecmwLygGuFRiLm5R6fWJLlZUDwujTBuHLz8Mvzl\nL3BVEbObgdHOzvzSty8HS0u5KzmZszVpym8GNF4afOf4EpUWRfC6YHSXdRwedZg9gXtI/yCdqovK\nMpKCws1MWw2XN4QQdtc2CiFshBDbblCTUaLOr0a45CvxLU2gGC5NsGABDB0KEybAmTOGVtMq7rSz\n4/fQUC5VVxOZmEh8ByWT6ihUpipcJrgQtiuMsD1h2ETZcPovp9nttZsTz52g7KTxV6pWUFBoSFsN\nl7uBxnJXa4C72i7HONGoVFTnVSLt85UdRU2gGC5NoFbrl4tsbPTBumU3180y2NKSPWFhBGi1DE5O\nJjbn5sx0YBNpQ/DaYKLORuE5w5Pc2FwSAhM4NOIQhb8UGuUuKgUFhcZpleEihOgjhOgDCCC49nnN\nEQr8CcjsCKGGxN7UlMrcSqR1ruJxaQIHrQMXyy9SWW388RCdjoMDfP01HD8O06bdNMG6tbiYmbE1\nJIQJLi5MOnaMOWlpRrvjqDnMPczxf0u/pbr7Z925cu4KB+87yL6++8iJzUFXpTO0RAUFhWZobdam\nZPRZ8CTQ2JLQZfTVom8p7E1MKM8rB41iuDRFbdr/4ivFOFs2XaTstqVvX1i5EmJiICICnnvO0Ipa\nhblKxaqgIHpYWPBKWhopZWWsCgrCQm386fcbQ61V4z7VHbfH3CjeWUz6u+kcm3SMtDlp+PzVB7dH\n3FCZKRXgFRSMkdZ+Mv2Arug9LpE1z2sPT8BGSvl5uyo0Apyr1EhxEam6oiwVNcFtX6+oJURHw6xZ\n+qORcvfGjhCCv3bpwuaePfm+oIC7k5M5X35z11IVQmA/2J4+P/QhPDEcqxArUqelsqfrHjI+yqC6\nzLi3gyso3I60ynCRUp6VUp6RUqqklPtqntceWVLKW/JT7npZpSSfawbFcGkhCxfC4MEwfjycO2do\nNW1itLMzv4eGkl1RQURiIvtLbr6MtY1hHWZNr429iDgSgd09dpx84STxvvGcXXhW2YmkoGBEtNhw\nEUKMFEKYXvW4yaPj5BoGp0v/M1wUj0vjOGodAcVwaRYTE331aAsL+OMf4fLl5q8xQkKtrUkIC8PT\n3Jw7k5LYlNdoVoSbEsselvT4sgf9U/vj9Ecnzsw9Q3yXeNLmpFFZoMRwKSgYmtZ4XL4B7K963NTx\ndXsKbG+EEDOFEIdrjg9aco39JXGVx8W9Q/XdrNhr9W8NxXBpAU5O+mDdI0fgz382tJo2425uzs6Q\nEEY4OjL2yBEWnD17S+3O0fpr6b6iO1Gno3B7zI30v6Wzu8tuTr10ispCxYBpDatXr0alUjV6qNVq\nEhISbniO5cuXM378eLp06YJKpWLq1KlN9k1MTOShhx7C3d0da2tr+vbty9///nd0uuaDsx977LFG\nX0dwcHCDvlJK3n33Xfz9/dFqtfTt25d169a16PW88cYbdX+fzMyGe15KSkrQarWoVCpmzJjRojFr\nSUpKQqVSMWfOnCb7nDx5EpVKxYsvvtiqsTuDFgfnSilVjT2+mRBCOAFPAz2AKuA3IUR/KeWe611n\nUwI4FmBq4oRKZd4JSm8+NCYaLEwtFMOlpYSGwrJlMHUqPPII3HNz5mrUqtWsCw6mx5kzvJaWxpHS\nUlZ27472Jg3abQxzT3O6vd8Nn1d8yPggg8yPMjn/yXl8/uqD1wwv1Ba3zmvtSIQQvPnmm/j6+jY4\n161btxse/9133+XSpUtERkaSnZ3dZL/9+/dzxx13EBgYyF//+lcsLCz48ccfee655zh9+jRLWpDp\nWqPRsHLlynqGuq2tbYN+s2fPZtGiRTz55JP069ePb7/9lpiYGFQqFePHj2/R69JoNMTFxTUwIDZv\n3owQok0JUUNDQwkKCiIuLo758+c32mft2rUIIZgyZUqrx+9wpJS3zQE4AWmALfqcM/GA33X6hwFy\n6RMb5Y6XH5YJCX2lQtN4ve8l52ybY2gZNw86nZSRkVKGh0tZXW1oNTfM+pwcqd25U0bs2yczr1wx\ntJwOozynXKY+myp3mO6Q//X4r8z8OFNWV974/y8xMVECMjExsR1UGherVq2SKpWqQ1/buXPn6h5b\nWVnJxx57rNF+TzzxhNRoNLK4uLhe+9133y3t7OyanefRRx+V1tbWzfbLzMyUZmZmcsaMGfXaBw0a\nJH18fKROp7vu9fPmzZMqlUqOHTtWhoWFNTg/bNgwOW7cOCmEkM8++2yzeq7lrbfekiqVSu7Zs6fR\n80FBQTI4OPi6YzT3nq09D4TJdryXtybGZUZLj/Y1rdoPKWU+8DfgHPp6S79IKdOau05zQSLcCpXi\nis2gJKFrJULA4sWQmKiPe7nJGe/iwm+hoZwvLyciMZF9Fy8aWlKHYOZiRsBHAUSmRGI32I7UJ1PZ\n23MvuRtzb6mlspsNb2/vFvUrKSlBo9E08JC4ubmh1WpbPJ9Op6PkOoHp33zzDVVVVUyfPr1e+/Tp\n08nIyGD37t0tmicmJoakpCRSU1Pr2nJycti2bRsxMTGNXlNRUcHcuXMJCAhAo9Hg4+PDyy+/TEVF\nRV2fSZMmIaUkNja2wfX79+/n+PHjTJ48uUUaO5vWLPnMbOHxfHuJE0LcJYT4TgiRKYTQNRb4K4R4\nWgiRJoS4LISIF0JEXGc8O+AhwAf99u07hBB3NqfD7EI1wllJ998cDloHCq8ohkuruOsuGDUKZs+G\nm3xrMUC4tTV7w8PxMjfnruRk1ufmGlpSh6H11xK8NpjwpHC0/lqOjjvK/v77KdpeZGhpRsuFCxco\nKCiodxQW1v/OKC4ubtCnseNyGwPbBw8ezMWLF5k2bRopKSmcO3eOFStW8M033zB79uwWjVFWVoaN\njQ22trY4OjryzDPPUFpaWq9PcnIylpaWBAUF1WuPjIxESklSUlKL5ho0aBBeXl71DIx169ZhbW3N\ngw8+2KC/lJIRI0bw/vvvM2rUKJYuXcro0aNZsmQJEydOrOvn6+vLwIED2bBhQwODu3aZKDo6ukUa\nO5vWxLj4daSQJrBEn/RuJbD52pNCiAnoPSjTgAT0htPPQojAGu8KQog/A0+gd1e9D5yQUl6oOfc9\nEAX8fj0RqmId0lZJ998ciseljSxcCL16wT/+AS+8YGg1N4y7uTk7QkJ44vhxJh49ypHSUub5+qK6\nRYuTWodY0+fHPhRtL+L0X09z4N4D2A+3x/8df6xDrQ0tz2iQUjJkyJAG7RqNhrKrSmGEhoZy9uzZ\n644lhGDu3LnXDS5tiieeeIIjR47w8ccf89lnnwFgYmLC0qVLmTZtWrPXe3h48NJLLxEWFoZOp+On\nn35i2bJlHDx4kB07dqBS6f0BWVlZuLq6Nrje3V2/weP8+fMt0iuEYOLEicTFxTFv3jwAYmNjGTNm\nDKampg36r127lm3btvHrr78yYMCAuvaePXsyffp04uPjiYqKAvRel2eeeYatW7cydOhQQP9/2rBh\nAwMGDGg0HskYaG3m3E5FSvkT8BOAaDwCaSbwsZTyy5o+TwEPAlOBd2vGWAYsqznfH5gphDADqoHB\nwMfN6dBdqEBnoXhcmsNB40DGxQxDy7j5CAqCJ56At96Cxx4De/vmrzFytGo1/+zRg16WlsyuCdr9\nskcPLG+hoN1rsb/HnrD4MPI353N69mkSwxJxneKK/7v+mLu1b1B/dXUZZWUp7TpmY1hYBKFWW7TL\nWEIIli1bRkBAQL129TXvidjY2BZ5U/z9/dukQ6VS0bVrV+6//37Gjx+Pubk5cXFxPPPMM7i5uTFy\n5PUzeixYsKDe8/HjxxMQEMBrr73Gxo0b64JuL1++jLl5w/+7RqOpO99SYmJiWLx4MYnKX1gLAAAg\nAElEQVSJidjZ2bF3714WLlzYaN+NGzfSo0cPAgMDKSgoqGu/5557kFKyffv2OsNlwoQJPP/888TG\nxtYZLjt27CAzM5NXX321xfo6mxYbLkKI94HXpZSlNY+bRErZ4T8ba3LKhANvXzWvFEL8Agxo7Bop\n5R4hxA/ovTjV6GNc/tXcXJUVBaDSKR6XZlA8LjfA3Lnwz3/C22/De+8ZWk27UJtpt4elJZOOHuXO\npCS+7dULn5ov7lsRIQTOY5xxHOVI9sps0l5LI//bfPzm++HxtAcqk/bZkFlWlkJiYni7jHU9wsMT\nsbYOa7fxIiIiCAu7/nhXewk6goULF/L3v/+dEydOYGGhN8rGjh3Lvffey9NPP81DDz1U5zVpKTNn\nzuT111/nl19+qTNctFot5Y0s/165cqXufEsJCQkhKCiI2NhYbG1tcXd3554mdiKeOHGClJQUnJ0b\nll4RQpB71fKtg4MDw4cP5+uvv2bFihWYmZkRGxuLqakp48aNa7G+zqY1HpdQwPSqx03RWdFpToAa\nuLZcbQ7QvamLpJSvA6+3ZqIPs1dg9SrY2r6HicknAERHRxvt+p+hUAyXG8DNDV56CRYsgKefBiN1\n0baFUU5O7AoLY+ShQ0QkJvJ97970s7ExtKwORWWiwuNJD5zHOZP2WhonZ54ka2UWAf8IwO4uuxse\n38IiiPDwxHZQ2vw8nU1+fj7V1c0nYbeyssLS0rLV4y9fvpx77723zmipZeTIkcyaNYszZ8602puj\n0WhwdHSsF6/j7u7OjkZKe2RlZQH6JafWEBMTw/Lly7G2tmbChAlN9tPpdPTu3ZslS5Y0Gix+bRDz\n5MmT2bJlC1u2bGHEiBFs3ryZ4cOH4+jo2Cp9cXFxxMXF1Wu7cOFCq8ZoKa2Jcbmnsce3A08HDCVw\nwQkGDtyAmVnDNUsFPQ5aB4ouF6GTOlTipkz1Y1heeAGWL4fXXoM1awytpl3pY2XF3vBwRh4+zNAD\nB/ilb99b3ngBMHUwJXBZIO5/cif16VSSByW3y/KRWm3Rrp4QYyIiIqJDY1xycnIaNYwqK/VJBauq\nWl/e4dKlS+Tn59fzcoSEhLBy5UpSUlLqBejGx8cjhCAkJKRVc8TExDBnzhyys7Ob3E0E0LVrVw4e\nPNikR+ZaRo4cibW1NbGxsZiYmFBUVMSkSZNapQ0a/zG/f/9+wsPb3zN4wzEuQghvACll+o3LaRX5\n6Jd7rrUkXPn/9u48zqq6/uP46zMbszLMsC/CDDvKIozgmpoIKiWllUnimkuR+pO0tEXNUnNLUn9q\nappSidovLTMF3CpTERlgEAVk30GEYR9glu/vj3MGL8MAcy/3zrnL+/l4nAdzzz3L5xzuzP2c7woH\nHn0oEq02Y2SSmalZjw+mOKcYh2PLri17R9KVMOTnwy9/CVdeCePHQwx+4YPUNiuLKQMHcsacOYyY\nM4c3Bw1iSEFqNF4tKCtgyHtDWPeHdSy+cbFXffSrUjqNi171UbKIdRuX3r178/rrr1NZWUmR356s\nrq6O559/noKCAnr06LF32yVLluxzrt27d1NdXU1+fv4+x6wfxO2ss87au+5rX/sa48eP55FHHuHB\nBx/cu/53v/sdnTt35oQTTggr7u7du/PAAw9QVVXFMcccc8DtzjvvPF599VWeeOIJrrjiin3e27Vr\nF3V1dfuUNmVnZ3POOefw/PPPs2PHDvLz8w/ZzidoESUuZpYB3ApcC+T767YDDwG3OediPh62c67a\nzMqB4cDLfgzmv37wYPuG6+H5b1Lws3R+cPXzqh46iNCJFpW4ROjSS2HCBPjRj+DNN72xXpJIy4wM\nJg8cyMiKCk6vqODNQYMYnCLJi6UZHb/bkTbntGHpz5ay6LqQ6qOTDr/6KN4553j11VeZN2/efu+d\ncMIJlJZ6HVcjbePyyiuvUFFRgXOO6upqKioq9jakHT16NAMGDADgpptu4sILL2TYsGFceeWV5OTk\n8OyzzzJr1izuuOOOfRoLn3baaaSlpe1NYNatW8fgwYMZM2bM3lKUyZMn89prrzFq1Kh9vvA7d+7M\nddddx3333ceePXsYOnQoL730Eu+++y7PPvtsRCPeXnPNNYfc5sILL+SFF17g+9//Pm+//TYnnngi\ntbW1zJs3j7/85S9MnTp1v3ZGY8eOZeLEiUyZMoWxY8eG1f6mMfXVRrGqKop0BNpH8dqSXAUM9Jer\ngLXAo9EaHQ+vO/Qg4GigDm+MmEHAEf775wE7gYuAvng9hDYCbaN0/iGAe+yi492H045tdGRA+cLs\ntbMdv8BNXzU96FAS2z/+4Rw4989/Bh1JzFTu2eOGzpjhit95x83aujXocAKx5cMtbsawGe5t3naf\nXPSJm/b6tKQfOfdAyzPPPHPY57jkkkuafPypU6e6L3/5y65du3YuOzvbDRo0yD3xxBP7HbOkpMR1\n79597+vNmze7iy66yPXu3dvl5+e7nJwcN2DAAHf33Xe7mpqaRuO66667XGlpqcvOznYDBgxwkyZN\natL11I+cu3HjxoNul5aWtt/ovDU1Ne7ee+91AwYMcDk5Oa5169Zu6NCh7vbbb3fbtm3b7xi1tbWu\nU6dOLj093U2ePLlJ8TkX3Mi55iIY6dHMtgDnO+dea7B+FDDJObf/pA0RMLNTgLfZv8HvM865y/xt\nxgE/xqsimg1c45ybEaXzDwHKH7u2HydccST9+/9fNA6btFZuWUnX33Zl8gWTOaPnGUGHk7ic8+Yu\n+vxzqKiAJO1CvLm6mhFz5rCkqoq3jj6aQQ2K31OBq3OsfWotS25awqe1n/Ldzd+lvLz8kD1vROJB\nfRuWA31mQ9q4lDnnZkbrvJFWru4GljWyfimwp5H1EXHO/ds5l+acS2+wXBayzSPOuRLnXI5z7vho\nJS37aLNFw/03QWhVkRwGM69L9Mcfw9NPBx1NzLTKzGTqwIGUZGczfPZs5mzfHnRIzc7SjE6Xd2LY\nvGHkD069xE0kEpEmLv8L3Gxme5vF+z//zH8vqTz8/HrGjXtjv65esq/czFyy0rOUuETD0KFw/vlw\nyy3QYCjxZFKUmcnrgwZxRHY2wysqmJuCyQtAVtssetzb49AbiiSASZMmMXr0aMaPHx+T44czyeKL\n9Qtem5OvAqvM7A1/0LdVwNl4bVCSyg+ureWPf/yJGuYegplpLJdouvNO2LABnnwy6EhiqjgzkzcG\nDaJzVhanVVTwcRInagcTSWNNkXg0ZswYXn75ZSZMmBCT44dT4rKlwfJX4BVgpb+8gjefUIyaEQdL\nw/03jRKXKCotheHD4R+HHNw54bX2k5cOWVmcNns2n6Ro8iIihxbOAHSXxjKQeKfh/ptGM0RH2ahR\ncP31sH27N85LEmuTlcWbgwZxWkUFp86ezX09ejC2ffuknZxRRCKjkY+aSCUuTaMSlyg76yyorvbG\ndEkBbbOyeGvQIL5UWMjF8+czZMYMpm7S50lEvhBx4mJm3zSzF8xsmpnNDF2iGWA8ePh/0zj33AvU\nOLcJlLhEWc+e0Ls3vPpq0JE0m7ZZWfy1f3/eGzyY/PR0zpgzh5EVFczeti3o0ESkCeKmcW4oM7sW\n+APeIHSDgel4A791B147yK4J6bpxnXj55ZfVOLcJirOVuETdqFFe4hLBmEuJ7PjCQt4ZPJiXjjqK\nFbt2MaS8nIvmzWO5P7uuiMSneGqcG2occKVz7hq8cVvucc6NwBtqPyqDz8WTzHTNUdRUxTnFbNy5\nMegwksuoUbBqFcydG3Qkzc7M+HrbtswdOpRHe/dm6qZN9PngA360eDGV1TGfWURE4lCkkyx2Bd7z\nf64C6icb+SMwDbj6MOOKK5ktlLg0VX1VkXNO3Tuj5eSTITfXK3Xx51tJNRlpaVzVqRMXtGvHb1at\n4t4VK3hy7Vp+3q0bV3fuTFZa8jTXa2wuH5F4FNRnNdLEZR1QDCwHVgDHARVAKZB031Yt8hpOQC0H\n0jq3NbWulm17ttGyRcugw0kOLVrA6ad7icuNNwYdTaDyMzK4taSEqzp25Lbly/nR4sU8vmYNE3r2\n5KzWrYMO77C0adOG3Nxcxo4dG3QoIk2Wm5tLmzZtmvWckSYubwGjgVl4bV0mmNk3gWPwxnJJKr++\n512eemY0Y8aMUTuXQwgd9l+JSxSNGgU/+AFs3gytkn8m4UPp0KIFj/buzbhOnfifRYsY9dFHjCou\nZkLPnvTOzQ06vIh07dqVefPm8fnnn4e9766Vu1h681J2zN1Bx8s70vHyjqRlJE8pVDxzzlFZ+Sar\nVt1PdfVG2re/iI4dLyM9/fBmWE4Ubdq0oWvXrvusi/Xs0JFOspgGpDnnavzX5wMnAAuBx5xzUZuv\nKEj1kyy+/vrdnH76j4MOJyHMXDuTssfLKL+ynCEdNVFc1KxYAd26wQsvwLe+FXQ0ccU5x4uff871\nixaxZs8eru3cmZtLSijMiPS5LDHV1dSx4tcrWHbbMgrKCuj3p37k9krMJC4R1dbuZMWKu1ix4h6y\nstrRq9dDtGnztaDDClRcTbLonKurT1r818855651zj2ULElLqMzMdkGHkDA00WKMdO0K/funVLfo\npjIzvtG2LfOGDeOWbt14dM0aen/wAU+uXUtdCvXESstIo+TmEoa8N4SaTTXMOHoGax5fQyQPpxK+\n9PRcSkt/ybBhn5CXN5C5c7/OggXfo7Z2Z9ChJZ3DGcelyMxuMLMn/eV6MyuOZnDxIitLjXObSolL\nDI0aBa+9BnV1QUcSl3LS0/l5SQkLhg3j9KIiLl+wgGHl5bwbo+LqeNVyWEvKZpXRfmx7Pr3qU+Zd\n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\nNnoOAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -660,7 +660,7 @@ { "data": { "text/plain": [ - "{'294K': }" + "{'294K': }" ] }, "execution_count": 22, @@ -691,7 +691,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 23, @@ -700,9 +700,9 @@ }, { "data": { - "image/png": "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\nYII=\n", + "image/png": "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\nln8MOElr/feVGtxCwDAMrr76atatW8f73/9+fve73/H5z3+eN73pTfj9fiYmJrj88st59NFHue++\n+zJapBfCunXr2LdvH5OTkzniZzEwPT1NIBDIKPfu7OxkdHR0/nk0Gs0QKdX2pOSb9ThdpBSa7ikm\nklLN6p56iJR6yaKAMjl1yVLOXLoUgH3RKPcMDvKHgQG+/fJL3BR/jhbTxyldvWzsWsLGrl5eEWms\nz2AorDjxlAjxuPtVTMQ1wwN2TtVQtSq2o3sm+OnRWwlmtepvP6KbM267sKRjBkwwwLUAuiVs0xJ2\n/1wbpvv10YZCZ8VMFDplVnHFqbdKOtJnpTBKeRu+Bvisw/I7SU462LRUorrHjXe84x1s3LiRD3/4\nw2zatIn29nZWrlzJSy+9RCKR4Ac/+AEnnXRS0cdNTUL4l7/8hRNOOKGiY24GotFoRhQFoKurK0Ok\nuEVSapXuyY6kJBKJ+fF4iZTsEmmnY2cvr3Z1T6Ole6rpb7UTiskRY76wo40Wzmtt4bzWlViv0Dw3\nM869w/3cMzzAF557krjWLA2EOKm9h9UznRzr72aJGfY+SQ0IhgyCHrMHzMY04yM6p2ooWfGmMYzM\n5bbtXvBSKNO7JpjeldmqX0/G0LOJkjrZRnyKsw/xMeuQYRmJabbvLTH1EtSO6sfyFVLW7M1C6LPS\nUNU9abTiXGocx3teqYanUtU9bqxdu5Y77riDxx9/nDvuuIP+/n6WL1/O29/+9vmeJ6UcExavSJme\nns7p7tvZ2ZlhJs4WKW6RlGqle5wiKam+Ll7N3CqV7imGQiMp9eiX4nRTNBS0thuO6YxwK5Bnajml\n5la7XCptK8dVhlIc097JMe2dvGfVOqatBI+MDnP/yAD3Dw/y86k9aOAgI8KxgW6O83dzjL+bbrN5\n/CyJBLz0fAwzS7wEggqfL+AoEE0fdPSUdudO9E/Q9w+3YbQnhV3cF+SQz70J31xaKNY3jd1qYQSd\nUygRnyLicEcrpM+Kz6cxlMbO6jWjwgr/2QY66443GzPYu7MF06HznC9msWTfZM5yJ/bsyb25N1Ma\nqNGqe1L8GXgr8Lms5W8DdpQ9okXA+vXrWb9+fUWO1d3dTU9PD88++2xFjtdsOEVSstM9hXpSap3u\nAfdIimEYJRtns89XDU9KLSMpSs3NeWMoWlpNZ/+E0w3TANOvPSfKCYZhxSEBxzb1fo+usNnWyYjp\n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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -990,7 +990,7 @@ { "data": { "text/plain": [ - "{'0K': }" + "{'0K': }" ] }, "execution_count": 31, @@ -1048,8 +1048,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 33, @@ -1107,7 +1107,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 35, @@ -1116,9 +1116,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiYAAAGBCAYAAABSP3qNAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3WmYHGX19/HvyWQShiQkhEDYFQQhRogkhLAF5I+AoIwg\n6zzsixACAqOAyqqIqCxOAAmCLAGBgaCoQTYFEUQ2SVhkFQQkskSWZIAkkGXu58Xd5dT09D5VXdXd\nv8919dXd1dVVpzJJ6sy5N3POISIiIpIGA5IOQERERCSgxERERERSQ4mJiIiIpIYSExEREUkNJSYi\nIiKSGkpMREREJDWUmIiIiEhqKDERERGR1FBiIiIiIqmhxERERERSQ4mJiIiIpEbdJSZm1mJmr5nZ\neUnHIiIiIuWpu8QEOA14OOkgREREpHx1lZiY2QbARsCdScciIiIi5aurxAS4APgeYEkHIiIiIuVL\nRWJiZpPNbJaZvWFm3WbWmmOfY83sVTNbbGaPmNnErM9bgRedcy8Hm6oRu4iIiEQnFYkJMAR4EpgK\nuOwPzWw/4ELgLGAz4CngbjMbFdptS2B/M3sFXzk50sxOjztwERERiY451ycPSJSZdQN7OOdmhbY9\nAjzqnDsh896AucDFzrk+o2/M7BBgrHPulDznWAXYBXgN+DjyixAREalfKwCfBu52zr0X9cEHRn3A\nqJlZMzABODfY5pxzZnYPsFWFh90FuCGC8ERERBrVAcCNUR809YkJMApoAuZlbZ+HH4HTh3Pu2iLH\nfA3g+uuvZ8yYMf0Krr29nY6Ojqodo9C++T6rdoxRHEfXqevUdcYTYxTHKLZfrs91nfHEGNUxyvm7\n+/zzz3PggQdC5l4atVpITOLwMcCYMWMYP358vw40fPjwqh6j0L75Pqt2jFEcR9ep69R1xhNjFMco\ntl+uz3Wd8cQY1TEq+btLTF0haiExeRdYDozO2j4aeLs/B25vb2f48OG0tbXR1tZW0TEq/V6lxyi0\nbxSxxH3sUo+j69R1RqFRrjOq40dxnVHFEuexdZ3l7Rt81tnZSWdnJ11dXf2OrSDnXKoeQDfQmrXt\nEeCi0Pug8+vJFZ5jPOBmz57tGsHuu++edAhVoeusL7rO+qLrrB+zZ892+BG0410MeUAqKiZmNgTY\ngJ65R9Y3s3HA+865ucDPgBlmNht4DGgHVgRmJBCuiIiIxCQViQmwOXAfPgNz+DlLAK4FDnfOzczM\nWXI2vgnnSWAX59w7SQRba+IuIaeFrrO+6Drri65TSpW6eUyqwczGA7O32267fvcxERERaQThPiYP\nPPAAwATn3Jyoz9PQicns2bMj6T0tIiLSKObMmcOECRMgpsQkLVPSi4iIiCgxERERkfRQYiIiIiKp\nkZZROYmIYoI1ERGRRlCtCdbU+VWdX0VEREqmzq8iIiLSMJSYiIiISGooMREREZHUUOdXdX4VEREp\nSp1fY6TOryIiIpVR51cRERFpGEpMREREJDWUmIiIiEhqKDERERGR1NCoHI3KERERKUqjcmKkUTki\nIiKV0agcERERaRhKTERERCQ1lJiIiIhIaigxERERkdRQYiIiIiKpocREREREUkPzmGgeExERkaI0\nj0mMNI+JiIhIZTSPiYiIiDQMJSYiIiKSGkpMREREJDWUmIiIiEhqKDERERGR1FBiIiIiIqmhxERE\nRERSQxOsaYI1ERGRojTBWow0wZqIiEhlNMGaiIiINAwlJiIiIpIaSkxEREQkNZSYiIiISGooMRER\nEZHUUGIiIiIiqaHERERERFJDiYmIiIikhhITERERSQ0lJiIiIpIaSkxEREQkNZSYiIiISGpodWGt\nLiwiIlKUVheOkVYXFhERqYxWFxYREZGGocREREREUkOJiYiIiKSGEhMRERFJDSUmIiIikhpKTERE\nRGLy2GNw881JR1FbGnoeExERkThNmuSf99sv2ThqiSomIiIikhpKTERERCQ1lJiIiIhIaigxERER\nkdRQYiIiIiKpocREREREUkOJiYiISBW9+WbSEaRb3SQmZjbczP5uZnPM7GkzOzLpmERERML++EdY\nay14/PGkI0mvuklMgA+Ayc658cAk4FQzWznhmERERP7n2Wf986uvJhtHmtXNzK/OOQd8nHnbknm2\nhMIRERHJy7mkI0iveqqYBM05TwKvA+c7595POiYREREpXSoSEzObbGazzOwNM+s2s9Yc+xxrZq+a\n2WIze8TMJmbv45zrcs59AVgPOMDMVq1G/CIiIuUw1fPzSkViAgwBngSmAn0KXGa2H3AhcBawGfAU\ncLeZjcp1MOfcO5l9JscVsEijcA4WLYIPPvAPlaBFJE6p6GPinLsLuAvALGce2Q5c7py7LrPPFOAr\nwOHAeZltqwGLnHMfmdlwYDtgehXCF6kL8+fD7Nm+c96zz8Jzz8Ebb8Dbb8PHH/fs19wMo0fDmDEw\n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\nRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1336,8 +1336,8 @@ { "data": { "text/plain": [ - "{'0K': ,\n", - " '294K': }" + "{'0K': ,\n", + " '294K': }" ] }, "execution_count": 38, @@ -1448,12 +1448,156 @@ "source": [ "Note that 0 K elastic scattering data is automatically added when using `from_njoy()` so that resonance elastic scattering treatments can be used." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Windowed multipole\n", + "\n", + "OpenMC can also be used with an experimental format called windowed multipole. Windowed multipole allows for analytic on-the-fly Doppler broadening of the resolved resonance range. Windowed multipole data can be downloaded with the `openmc-get-multipole-data` script. This data can be used in the transport solver, but it can also be used directly in the Python API." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "url = 'https://anl.box.com/shared/static/ulhcoohm12gduwdalknmf8dpnepzkxj0.h5'\n", + "filename, headers = urllib.request.urlretrieve(url, '092238.h5')" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "u238_multipole = openmc.data.WindowedMultipole.from_hdf5('092238.h5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `WindowedMultipole` object can be called with energy and temperature values. Calling the object gives a tuple of 3 cross sections: total, radiative capture, and fission." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(array(9.638243132516015),\n", + " array(0.5053244245010787),\n", + " array(2.931753364280356e-06))" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u238_multipole(1.0, 294)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An array can be passed for the energy argument." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "E = np.linspace(5, 25, 1000)\n", + "plt.semilogy(E, u238_multipole(E, 293.606)[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The real advantage to multipole is that it can be used to generate cross sections at any temperature. For example, this plot shows the Doppler broadening of the 6.67 eV resonance between 0 K and 900 K." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "E = np.linspace(6.1, 7.1, 1000)\n", + "plt.semilogy(E, u238_multipole(E, 0)[1])\n", + "plt.semilogy(E, u238_multipole(E, 900)[1])" + ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [default]", + "display_name": "Python 3", "language": "python", "name": "python3" }, From 27b1e7d22876f362a34dd552d975a107fb071db8 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 24 Oct 2017 02:03:12 -0400 Subject: [PATCH 220/229] Make sure autogenerated filter IDs are unique --- openmc/capi/filter.py | 10 ++++++++++ src/api.F90 | 1 + src/cmfd_input.F90 | 15 ++++++++++----- src/input_xml.F90 | 7 +++++-- src/tallies/tally_filter_header.F90 | 15 +++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 1b52af6db..f5066767d 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -45,6 +45,8 @@ _dll.openmc_filter_set_type.errcheck = _error_handler _dll.openmc_get_filter_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_filter_index.restype = c_int _dll.openmc_get_filter_index.errcheck = _error_handler +_dll.openmc_get_free_filter_id.argtypes = [POINTER(c_int32)] +_dll.openmc_get_free_filter_id.restype = None _dll.openmc_material_filter_get_bins.argtypes = [ c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_material_filter_get_bins.restype = c_int @@ -253,4 +255,12 @@ class _FilterMapping(Mapping): def __repr__(self): return repr(dict(self)) + filters = _FilterMapping() + + +def get_free_filter_id(): + """Returns an ID number that has not been used by any other filters.""" + id_ = c_int32() + _dll.openmc_get_free_filter_id(id_) + return id_.value diff --git a/src/api.F90 b/src/api.F90 index 4410f2fe4..ea33b40c7 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -51,6 +51,7 @@ module openmc_api public :: openmc_get_cell_index public :: openmc_get_keff public :: openmc_get_filter_index + public :: openmc_get_free_filter_id public :: openmc_get_material_index public :: openmc_get_nuclide_index public :: openmc_get_tally_index diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 65190fb51..eec0f3ceb 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -261,7 +261,8 @@ contains integer :: i_filt_start, i_filt_end integer(C_INT32_T), allocatable :: filter_indices(:) integer(C_INT) :: err - integer :: i_filt ! index in filters array + integer :: i_filt ! index in filters array + integer :: filt_id integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array real(C_DOUBLE), allocatable :: energies(:) @@ -381,14 +382,16 @@ contains ! Set up mesh filter i_filt = i_filt_start err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) - err = openmc_filter_set_id(i_filt, i_filt) + call openmc_get_free_filter_id(filt_id) + err = openmc_filter_set_id(i_filt, filt_id) err = openmc_mesh_filter_set_mesh(i_filt, i_start) if (energy_filters) then ! Read and set incoming energy mesh filter i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'energy' // C_NULL_CHAR) - err = openmc_filter_set_id(i_filt, i_filt) + call openmc_get_free_filter_id(filt_id) + err = openmc_filter_set_id(i_filt, filt_id) ! Get energies and set bins ng = node_word_count(node_mesh, "energy") @@ -399,7 +402,8 @@ contains ! Read and set outgoing energy mesh filter i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'energyout' // C_NULL_CHAR) - err = openmc_filter_set_id(i_filt, i_filt) + call openmc_get_free_filter_id(filt_id) + err = openmc_filter_set_id(i_filt, filt_id) err = openmc_energy_filter_set_bins(i_filt, ng, energies) end if @@ -407,7 +411,8 @@ contains ! tallies use this filter and we need to change the dimension i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) - err = openmc_filter_set_id(i_filt, i_filt) + call openmc_get_free_filter_id(filt_id) + err = openmc_filter_set_id(i_filt, filt_id) err = openmc_mesh_filter_set_mesh(i_filt, i_start) ! We need to increase the dimension by one since we also need diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e1fd21cb0..862ec4a82 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3146,7 +3146,9 @@ contains filters(i_filt_start) % obj % n_bins = product(m % dimension + 1) ! Set ID - err = openmc_filter_set_id(i_filt_start, i_filt_start) + call openmc_get_free_filter_id(filter_id) + err = openmc_filter_set_id(i_filt_start, filter_id) + ! Add surface filter allocate(SurfaceFilter :: filters(i_filt_end) % obj) @@ -3167,7 +3169,8 @@ contains filt % current = .true. ! Set ID - err = openmc_filter_set_id(i_filt_end, i_filt_end) + call openmc_get_free_filter_id(filter_id) + err = openmc_filter_set_id(i_filt_end, filter_id) end select ! Copy filter indices to resized array diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index c9ce22fea..76d90324a 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -19,6 +19,7 @@ module tally_filter_header public :: openmc_filter_get_id public :: openmc_filter_set_id public :: openmc_get_filter_index + public :: openmc_get_free_filter_id !=============================================================================== ! TALLYFILTERMATCH stores every valid bin and weight for a filter @@ -122,6 +123,10 @@ module tally_filter_header ! Dictionary that maps user IDs to indices in 'filters' type(DictIntInt), public :: filter_dict + ! The largest filter ID that has been specified in the system. This is useful + ! in case the code needs to find an ID for a new filter. + integer :: largest_filter_id + contains !=============================================================================== @@ -140,6 +145,7 @@ contains n_filters = 0 if (allocated(filters)) deallocate(filters) call filter_dict % clear() + largest_filter_id = 0 end subroutine free_memory_tally_filter !=============================================================================== @@ -205,6 +211,7 @@ contains if (allocated(filters(index) % obj)) then filters(index) % obj % id = id call filter_dict % set(id, index) + if (id > largest_filter_id) largest_filter_id = id err = 0 else @@ -238,4 +245,12 @@ contains end if end function openmc_get_filter_index + + subroutine openmc_get_free_filter_id(id) bind(C) + ! Returns an ID number that has not been used by any other filters. + integer(C_INT32_T), intent(out) :: id + + id = largest_filter_id + 1 + end subroutine openmc_get_free_filter_id + end module tally_filter_header From b0cc6a320fc7a415e4cf6b6949025ddb472b47ae Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Tue, 24 Oct 2017 09:01:50 -0600 Subject: [PATCH 221/229] Remove troublesome mesh_id assignment. Closes #924 --- examples/python/pincell/build-xml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index 4d41a3126..a9e6a5a74 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -119,7 +119,7 @@ settings_file.export_to_xml() ############################################################################### # Instantiate a tally mesh -mesh = openmc.Mesh(mesh_id=1) +mesh = openmc.Mesh() mesh.type = 'regular' mesh.dimension = [100, 100, 1] mesh.lower_left = [-0.62992, -0.62992, -1.e50] From 5a4b04a10f0353e433c0271b6b6471f8a20ca051 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 24 Oct 2017 11:17:49 -0500 Subject: [PATCH 222/229] Use in XML pincell example --- examples/xml/pincell/settings.xml | 5 +++-- examples/xml/pincell/tallies.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/xml/pincell/settings.xml b/examples/xml/pincell/settings.xml index 733de1926..5845898c8 100644 --- a/examples/xml/pincell/settings.xml +++ b/examples/xml/pincell/settings.xml @@ -22,10 +22,11 @@ - + -0.39218 -0.39218 -1.e50 0.39218 0.39218 1.e50 10 10 1 - + + 1 diff --git a/examples/xml/pincell/tallies.xml b/examples/xml/pincell/tallies.xml index 642bdd7cd..0ae36eced 100644 --- a/examples/xml/pincell/tallies.xml +++ b/examples/xml/pincell/tallies.xml @@ -1,7 +1,7 @@ - + 100 100 1 -0.62992 -0.62992 -1.e50 0.62992 0.62992 1.e50 From 64be3267d0094d4a224ba4e765216e8c1b353163 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 24 Oct 2017 13:19:57 -0400 Subject: [PATCH 223/229] Address #925 comments --- openmc/capi/filter.py | 10 ---------- src/api.F90 | 2 +- src/cmfd_input.F90 | 8 ++++---- src/input_xml.F90 | 4 ++-- src/tallies/tally_filter_header.F90 | 6 +++--- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index f5066767d..1b52af6db 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -45,8 +45,6 @@ _dll.openmc_filter_set_type.errcheck = _error_handler _dll.openmc_get_filter_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_filter_index.restype = c_int _dll.openmc_get_filter_index.errcheck = _error_handler -_dll.openmc_get_free_filter_id.argtypes = [POINTER(c_int32)] -_dll.openmc_get_free_filter_id.restype = None _dll.openmc_material_filter_get_bins.argtypes = [ c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_material_filter_get_bins.restype = c_int @@ -255,12 +253,4 @@ class _FilterMapping(Mapping): def __repr__(self): return repr(dict(self)) - filters = _FilterMapping() - - -def get_free_filter_id(): - """Returns an ID number that has not been used by any other filters.""" - id_ = c_int32() - _dll.openmc_get_free_filter_id(id_) - return id_.value diff --git a/src/api.F90 b/src/api.F90 index ea33b40c7..f5b27e718 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -51,7 +51,7 @@ module openmc_api public :: openmc_get_cell_index public :: openmc_get_keff public :: openmc_get_filter_index - public :: openmc_get_free_filter_id + public :: openmc_get_filter_next_id public :: openmc_get_material_index public :: openmc_get_nuclide_index public :: openmc_get_tally_index diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index eec0f3ceb..a1827febd 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -382,7 +382,7 @@ contains ! Set up mesh filter i_filt = i_filt_start err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) - call openmc_get_free_filter_id(filt_id) + call openmc_get_filter_next_id(filt_id) err = openmc_filter_set_id(i_filt, filt_id) err = openmc_mesh_filter_set_mesh(i_filt, i_start) @@ -390,7 +390,7 @@ contains ! Read and set incoming energy mesh filter i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'energy' // C_NULL_CHAR) - call openmc_get_free_filter_id(filt_id) + call openmc_get_filter_next_id(filt_id) err = openmc_filter_set_id(i_filt, filt_id) ! Get energies and set bins @@ -402,7 +402,7 @@ contains ! Read and set outgoing energy mesh filter i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'energyout' // C_NULL_CHAR) - call openmc_get_free_filter_id(filt_id) + call openmc_get_filter_next_id(filt_id) err = openmc_filter_set_id(i_filt, filt_id) err = openmc_energy_filter_set_bins(i_filt, ng, energies) end if @@ -411,7 +411,7 @@ contains ! tallies use this filter and we need to change the dimension i_filt = i_filt + 1 err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR) - call openmc_get_free_filter_id(filt_id) + call openmc_get_filter_next_id(filt_id) err = openmc_filter_set_id(i_filt, filt_id) err = openmc_mesh_filter_set_mesh(i_filt, i_start) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 862ec4a82..71ebe3ae6 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3146,7 +3146,7 @@ contains filters(i_filt_start) % obj % n_bins = product(m % dimension + 1) ! Set ID - call openmc_get_free_filter_id(filter_id) + call openmc_get_filter_next_id(filter_id) err = openmc_filter_set_id(i_filt_start, filter_id) @@ -3169,7 +3169,7 @@ contains filt % current = .true. ! Set ID - call openmc_get_free_filter_id(filter_id) + call openmc_get_filter_next_id(filter_id) err = openmc_filter_set_id(i_filt_end, filter_id) end select diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index 76d90324a..34ad75388 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -19,7 +19,7 @@ module tally_filter_header public :: openmc_filter_get_id public :: openmc_filter_set_id public :: openmc_get_filter_index - public :: openmc_get_free_filter_id + public :: openmc_get_filter_next_id !=============================================================================== ! TALLYFILTERMATCH stores every valid bin and weight for a filter @@ -246,11 +246,11 @@ contains end function openmc_get_filter_index - subroutine openmc_get_free_filter_id(id) bind(C) + subroutine openmc_get_filter_next_id(id) bind(C) ! Returns an ID number that has not been used by any other filters. integer(C_INT32_T), intent(out) :: id id = largest_filter_id + 1 - end subroutine openmc_get_free_filter_id + end subroutine openmc_get_filter_next_id end module tally_filter_header From fbab98f3ca95fd3e35bf74c7be51dbac1cd63353 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 24 Oct 2017 13:34:27 -0500 Subject: [PATCH 224/229] Fix bug in displaying leakage fraction --- src/output.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.F90 b/src/output.F90 index 34134168b..f820ce4b9 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -652,7 +652,7 @@ contains t_n3 * k_combined(2) end if end if - x(:) = mean_stdev(global_tallies(:, LEAKAGE), n) + x(:) = mean_stdev(r(:, LEAKAGE), n) write(ou,102) "Leakage Fraction", x(1), t_n1 * x(2) end associate else From b334ade165192b364e0c35581af8c975fdb9a3bf Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 24 Oct 2017 13:36:17 -0500 Subject: [PATCH 225/229] Update tally arithmetic notebook --- examples/jupyter/tally-arithmetic.ipynb | 472 +++++++++++++++--------- 1 file changed, 299 insertions(+), 173 deletions(-) diff --git a/examples/jupyter/tally-arithmetic.ipynb b/examples/jupyter/tally-arithmetic.ipynb index 70cabc7ef..de5917d7b 100644 --- a/examples/jupyter/tally-arithmetic.ipynb +++ b/examples/jupyter/tally-arithmetic.ipynb @@ -11,7 +11,7 @@ "cell_type": "code", "execution_count": 1, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -19,7 +19,6 @@ "\n", "from IPython.display import Image\n", "import numpy as np\n", - "\n", "import openmc" ] }, @@ -65,7 +64,7 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -100,7 +99,7 @@ "cell_type": "code", "execution_count": 4, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -122,7 +121,7 @@ "cell_type": "code", "execution_count": 5, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -151,7 +150,7 @@ "cell_type": "code", "execution_count": 6, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -188,7 +187,7 @@ "cell_type": "code", "execution_count": 7, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -215,7 +214,7 @@ "cell_type": "code", "execution_count": 8, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -228,7 +227,7 @@ "cell_type": "code", "execution_count": 9, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -283,7 +282,7 @@ "cell_type": "code", "execution_count": 11, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -310,9 +309,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -333,13 +330,11 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX////pgJFyEhJNv8RV\nUZDeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUZLksd2dYAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMDQtMTNUMTc6MjU6\nNDUtMDQ6MDCJ1tNgAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTA0LTEzVDE3OjI1OjQ1LTA0OjAw\n+Itr3AAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EKGA0jE/weoLoAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMTAtMjRUMTM6MzU6\nMTktMDU6MDCdcfAWAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTEwLTI0VDEzOjM1OjE5LTA1OjAw\n7CxIqgAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] @@ -368,7 +363,7 @@ "cell_type": "code", "execution_count": 14, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -380,7 +375,7 @@ "cell_type": "code", "execution_count": 15, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -457,7 +452,7 @@ "cell_type": "code", "execution_count": 17, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -472,7 +467,7 @@ "cell_type": "code", "execution_count": 18, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -522,10 +517,25 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, - "outputs": [], + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=1.\n", + " warn(msg, IDWarning)\n", + "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another MeshFilter instance already exists with id=5.\n", + " warn(msg, IDWarning)\n", + "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=6.\n", + " warn(msg, IDWarning)\n", + "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n", + " warn(msg, IDWarning)\n", + "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=2.\n", + " warn(msg, IDWarning)\n" + ] + } + ], "source": [ "# Export to \"tallies.xml\"\n", "tallies_file.export_to_xml()" @@ -542,7 +552,6 @@ "cell_type": "code", "execution_count": 22, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -578,25 +587,24 @@ " | The OpenMC Monte Carlo Code\n", " Copyright | 2011-2017 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.8.0\n", - " Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n", - " Date/Time | 2017-04-13 17:26:05\n", - " MPI Processes | 1\n", - " OpenMP Threads | 1\n", + " Version | 0.9.0\n", + " Git SHA1 | 5ca1d06b0c6ac3b56060ef289b7e5215210e7332\n", + " Date/Time | 2017-10-24 13:35:19\n", + " OpenMP Threads | 4\n", "\n", " Reading settings XML file...\n", - " Reading geometry XML file...\n", " Reading materials XML file...\n", " Reading cross sections XML file...\n", - " Reading U235 from /home/smharper/openmc/data/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/smharper/openmc/data/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/smharper/openmc/data/nndc_hdf5/O16.h5\n", - " Reading H1 from /home/smharper/openmc/data/nndc_hdf5/H1.h5\n", - " Reading B10 from /home/smharper/openmc/data/nndc_hdf5/B10.h5\n", - " Reading Zr90 from /home/smharper/openmc/data/nndc_hdf5/Zr90.h5\n", + " Reading geometry XML file...\n", + " Building neighboring cells lists for each surface...\n", + " Reading U235 from /home/romano/openmc/scripts/nndc_hdf5/U235.h5\n", + " Reading U238 from /home/romano/openmc/scripts/nndc_hdf5/U238.h5\n", + " Reading O16 from /home/romano/openmc/scripts/nndc_hdf5/O16.h5\n", + " Reading H1 from /home/romano/openmc/scripts/nndc_hdf5/H1.h5\n", + " Reading B10 from /home/romano/openmc/scripts/nndc_hdf5/B10.h5\n", + " Reading Zr90 from /home/romano/openmc/scripts/nndc_hdf5/Zr90.h5\n", " Maximum neutron transport energy: 2.00000E+07 eV for U235\n", " Reading tallies XML file...\n", - " Building neighboring cells lists for each surface...\n", " Initializing source particles...\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", @@ -627,20 +635,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 2.2576E-01 seconds\n", - " Reading cross sections = 1.8005E-01 seconds\n", - " Total time in simulation = 9.6105E+00 seconds\n", - " Time in transport only = 9.5952E+00 seconds\n", - " Time in inactive batches = 1.4678E+00 seconds\n", - " Time in active batches = 8.1427E+00 seconds\n", - " Time synchronizing fission bank = 2.6325E-03 seconds\n", - " Sampling source sites = 1.5038E-03 seconds\n", - " SEND/RECV source sites = 8.8069E-04 seconds\n", - " Time accumulating tallies = 2.0568E-04 seconds\n", - " Total time for finalization = 1.5435E-03 seconds\n", - " Total time elapsed = 9.8506E+00 seconds\n", - " Calculation Rate (inactive) = 8516.30 neutrons/second\n", - " Calculation Rate (active) = 4605.35 neutrons/second\n", + " Total time for initialization = 4.1497E-01 seconds\n", + " Reading cross sections = 3.6232E-01 seconds\n", + " Total time in simulation = 3.6447E+00 seconds\n", + " Time in transport only = 3.5939E+00 seconds\n", + " Time in inactive batches = 4.4241E-01 seconds\n", + " Time in active batches = 3.2022E+00 seconds\n", + " Time synchronizing fission bank = 2.7734E-03 seconds\n", + " Sampling source sites = 1.1981E-03 seconds\n", + " SEND/RECV source sites = 1.5506E-03 seconds\n", + " Time accumulating tallies = 1.2237E-04 seconds\n", + " Total time for finalization = 1.4924E-03 seconds\n", + " Total time elapsed = 4.0823E+00 seconds\n", + " Calculation Rate (inactive) = 28254.0 neutrons/second\n", + " Calculation Rate (active) = 11710.5 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -689,7 +697,7 @@ "cell_type": "code", "execution_count": 23, "metadata": { - "collapsed": false, + "collapsed": true, "scrolled": true }, "outputs": [], @@ -710,14 +718,25 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "\n", " \n", " \n", @@ -777,14 +796,25 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -803,7 +833,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -812,11 +842,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 0.00e+00 6.25e-01 total (absorption + current) 6.94e-01 \n", + " energy low [eV] energy high [eV] nuclide \\\n", + "0 0.00e+00 6.25e-01 total \n", "\n", - " std. dev. \n", - "0 4.61e-03 " + " score mean std. dev. \n", + "0 ((absorption + current) / (absorption + current)) 6.94e-01 4.61e-03 " ] }, "execution_count": 25, @@ -845,14 +875,25 @@ { "cell_type": "code", "execution_count": 26, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
0.00.625total(absorption + current)((absorption + current) / (absorption + current))0.6943680.004606
\n", " \n", " \n", @@ -871,7 +912,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -880,8 +921,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] nuclide score mean std. dev.\n", - "0 0.00e+00 6.25e-01 total nu-fission 1.20e+00 9.61e-03" + " energy low [eV] energy high [eV] nuclide score \\\n", + "0 0.00e+00 6.25e-01 total (nu-fission / nu-fission) \n", + "\n", + " mean std. dev. \n", + "0 1.20e+00 9.61e-03 " ] }, "execution_count": 26, @@ -908,14 +952,25 @@ { "cell_type": "code", "execution_count": 27, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
0.00.625totalnu-fission(nu-fission / nu-fission)1.2030990.009615
\n", " \n", " \n", @@ -934,9 +989,9 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -945,11 +1000,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide score mean \\\n", - "0 0.00e+00 6.25e-01 10000 total absorption 7.49e-01 \n", + " energy low [eV] energy high [eV] cell nuclide score \\\n", + "0 0.00e+00 6.25e-01 1 total (absorption / absorption) \n", "\n", - " std. dev. \n", - "0 6.09e-03 " + " mean std. dev. \n", + "0 7.49e-01 6.09e-03 " ] }, "execution_count": 27, @@ -974,14 +1029,25 @@ { "cell_type": "code", "execution_count": 28, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
00.00.625100001totalabsorption(absorption / absorption)0.7494230.006089
\n", " \n", " \n", @@ -1000,7 +1066,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1011,11 +1077,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide \\\n", - "0 0.00e+00 6.25e-01 10000 total \n", + " energy low [eV] energy high [eV] cell nuclide score \\\n", + "0 0.00e+00 6.25e-01 1 total (nu-fission / absorption) \n", "\n", - " score mean std. dev. \n", - "0 (nu-fission / absorption) 1.66e+00 1.44e-02 " + " mean std. dev. \n", + "0 1.66e+00 1.44e-02 " ] }, "execution_count": 28, @@ -1039,14 +1105,25 @@ { "cell_type": "code", "execution_count": 29, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
00.00.625100001total(nu-fission / absorption)1.663727
\n", " \n", " \n", @@ -1065,7 +1142,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1074,11 +1151,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 0.00e+00 6.25e-01 total (absorption + current) 9.85e-01 \n", + " energy low [eV] energy high [eV] nuclide \\\n", + "0 0.00e+00 6.25e-01 total \n", "\n", - " std. dev. \n", - "0 5.51e-03 " + " score mean std. dev. \n", + "0 ((absorption + current) / (absorption + current)) 9.85e-01 5.51e-03 " ] }, "execution_count": 29, @@ -1101,14 +1178,25 @@ { "cell_type": "code", "execution_count": 30, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
0.00.625total(absorption + current)((absorption + current) / (absorption + current))0.9846680.005509
\n", " \n", " \n", @@ -1163,14 +1251,25 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
\n", " \n", " \n", @@ -1189,9 +1288,9 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1200,11 +1299,11 @@ "" ], "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide \\\n", - "0 0.00e+00 6.25e-01 10000 total \n", + " energy low [eV] energy high [eV] cell nuclide \\\n", + "0 0.00e+00 6.25e-01 1 total \n", "\n", " score mean std. dev. \n", - "0 ((((((absorption + current) * nu-fission) * ab... 1.02e+00 1.88e-02 " + "0 (((((((absorption + current) / (absorption + c... 1.02e+00 1.88e-02 " ] }, "execution_count": 31, @@ -1230,7 +1329,7 @@ "cell_type": "code", "execution_count": 32, "metadata": { - "collapsed": false, + "collapsed": true, "scrolled": true }, "outputs": [], @@ -1245,14 +1344,25 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
00.00.625100001total((((((absorption + current) * nu-fission) * ab...(((((((absorption + current) / (absorption + c...1.0230020.018791
\n", " \n", " \n", @@ -1269,7 +1379,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1279,7 +1389,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1289,7 +1399,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1299,7 +1409,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1309,7 +1419,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1319,7 +1429,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1329,7 +1439,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1339,7 +1449,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1352,15 +1462,15 @@ "" ], "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 10000 0.00e+00 6.25e-01 (U238 / total) \n", - "1 10000 0.00e+00 6.25e-01 (U238 / total) \n", - "2 10000 0.00e+00 6.25e-01 (U235 / total) \n", - "3 10000 0.00e+00 6.25e-01 (U235 / total) \n", - "4 10000 6.25e-01 2.00e+07 (U238 / total) \n", - "5 10000 6.25e-01 2.00e+07 (U238 / total) \n", - "6 10000 6.25e-01 2.00e+07 (U235 / total) \n", - "7 10000 6.25e-01 2.00e+07 (U235 / total) \n", + " cell energy low [eV] energy high [eV] nuclide \\\n", + "0 1 0.00e+00 6.25e-01 (U238 / total) \n", + "1 1 0.00e+00 6.25e-01 (U238 / total) \n", + "2 1 0.00e+00 6.25e-01 (U235 / total) \n", + "3 1 0.00e+00 6.25e-01 (U235 / total) \n", + "4 1 6.25e-01 2.00e+07 (U238 / total) \n", + "5 1 6.25e-01 2.00e+07 (U238 / total) \n", + "6 1 6.25e-01 2.00e+07 (U235 / total) \n", + "7 1 6.25e-01 2.00e+07 (U235 / total) \n", "\n", " score mean std. dev. \n", "0 (nu-fission / flux) 6.66e-07 5.63e-09 \n", @@ -1393,9 +1503,7 @@ { "cell_type": "code", "execution_count": 34, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1425,9 +1533,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1449,9 +1555,7 @@ { "cell_type": "code", "execution_count": 36, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1480,14 +1584,25 @@ { "cell_type": "code", "execution_count": 37, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
01000010.0006.250000e-01(U238 / total)
11000010.0006.250000e-01(U238 / total)
21000010.0006.250000e-01(U235 / total)
31000010.0006.250000e-01(U235 / total)
41000010.6252.000000e+07(U238 / total)
51000010.6252.000000e+07(U238 / total)
61000010.6252.000000e+07(U235 / total)
71000010.6252.000000e+07(U235 / total)
\n", " \n", " \n", @@ -1504,7 +1619,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1514,7 +1629,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1524,7 +1639,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1534,7 +1649,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1547,11 +1662,11 @@ "" ], "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 10000 0.00e+00 6.25e-01 U238 nu-fission 1.60e-06 \n", - "1 10000 0.00e+00 6.25e-01 U235 nu-fission 8.55e-01 \n", - "2 10000 6.25e-01 2.00e+07 U238 nu-fission 8.30e-02 \n", - "3 10000 6.25e-01 2.00e+07 U235 nu-fission 9.06e-02 \n", + " cell energy low [eV] energy high [eV] nuclide score mean \\\n", + "0 1 0.00e+00 6.25e-01 U238 nu-fission 1.60e-06 \n", + "1 1 0.00e+00 6.25e-01 U235 nu-fission 8.55e-01 \n", + "2 1 6.25e-01 2.00e+07 U238 nu-fission 8.30e-02 \n", + "3 1 6.25e-01 2.00e+07 U235 nu-fission 9.06e-02 \n", "\n", " std. dev. \n", "0 9.68e-09 \n", @@ -1574,14 +1689,25 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", + "\n", "
01000010.0006.250000e-01U238
11000010.0006.250000e-01U235
21000010.6252.000000e+07U238
31000010.6252.000000e+07U235
\n", " \n", " \n", @@ -1598,7 +1724,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1608,7 +1734,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1618,7 +1744,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1628,7 +1754,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1638,7 +1764,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1648,7 +1774,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1658,7 +1784,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1668,7 +1794,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1678,7 +1804,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1691,16 +1817,16 @@ "" ], "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 10002 1.00e-02 1.08e-01 H1 scatter 4.54e+00 \n", - "1 10002 1.08e-01 1.17e+00 H1 scatter 2.00e+00 \n", - "2 10002 1.17e+00 1.26e+01 H1 scatter 1.64e+00 \n", - "3 10002 1.26e+01 1.36e+02 H1 scatter 1.82e+00 \n", - "4 10002 1.36e+02 1.47e+03 H1 scatter 2.03e+00 \n", - "5 10002 1.47e+03 1.59e+04 H1 scatter 2.12e+00 \n", - "6 10002 1.59e+04 1.71e+05 H1 scatter 2.18e+00 \n", - "7 10002 1.71e+05 1.85e+06 H1 scatter 2.01e+00 \n", - "8 10002 1.85e+06 2.00e+07 H1 scatter 3.73e-01 \n", + " cell energy low [eV] energy high [eV] nuclide score mean \\\n", + "0 3 1.00e-02 1.08e-01 H1 scatter 4.54e+00 \n", + "1 3 1.08e-01 1.17e+00 H1 scatter 2.00e+00 \n", + "2 3 1.17e+00 1.26e+01 H1 scatter 1.64e+00 \n", + "3 3 1.26e+01 1.36e+02 H1 scatter 1.82e+00 \n", + "4 3 1.36e+02 1.47e+03 H1 scatter 2.03e+00 \n", + "5 3 1.47e+03 1.59e+04 H1 scatter 2.12e+00 \n", + "6 3 1.59e+04 1.71e+05 H1 scatter 2.18e+00 \n", + "7 3 1.71e+05 1.85e+06 H1 scatter 2.01e+00 \n", + "8 3 1.85e+06 2.00e+07 H1 scatter 3.73e-01 \n", "\n", " std. dev. \n", "0 2.52e-02 \n", @@ -1744,9 +1870,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.6.1" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } From 1c8fbf536747971af6f6b4a9a50755378fb2e24c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 7 Nov 2017 08:28:29 -0600 Subject: [PATCH 226/229] PEP8 fixes in run_tests.py --- tests/run_tests.py | 61 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/tests/run_tests.py b/tests/run_tests.py index a3320823a..6e6b886a5 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -15,38 +15,38 @@ from argparse import ArgumentParser # Command line parsing parser = ArgumentParser() parser.add_argument('-j', '--parallel', dest='n_procs', default='1', - help="Number of parallel jobs.") + help="Number of parallel jobs.") parser.add_argument('-R', '--tests-regex', dest='regex_tests', - help="Run tests matching regular expression. \ - Test names are the directories present in tests folder.\ - This uses standard regex syntax to select tests.") + help="Run tests matching regular expression. \ + Test names are the directories present in tests folder.\ + This uses standard regex syntax to select tests.") parser.add_argument('-C', '--build-config', dest='build_config', - help="Build configurations matching regular expression. \ - Specific build configurations can be printed out with \ - optional argument -p, --print. This uses standard \ - regex syntax to select build configurations.") + help="Build configurations matching regular expression. \ + Specific build configurations can be printed out with \ + optional argument -p, --print. This uses standard \ + regex syntax to select build configurations.") parser.add_argument('-l', '--list', action="store_true", - dest="list_build_configs", default=False, - help="List out build configurations.") + dest="list_build_configs", default=False, + help="List out build configurations.") parser.add_argument("-p", "--project", dest="project", default="", - help="project name for build") + help="project name for build") parser.add_argument("-D", "--dashboard", dest="dash", - help="Dash name -- Experimental, Nightly, Continuous") + help="Dash name -- Experimental, Nightly, Continuous") parser.add_argument("-u", "--update", action="store_true", dest="update", - help="Allow CTest to update repo. (WARNING: may overwrite\ - changes that were not pushed.") + help="Allow CTest to update repo. (WARNING: may overwrite\ + changes that were not pushed.") parser.add_argument("-s", "--script", action="store_true", dest="script", - help="Activate CTest scripting mode for coverage, valgrind\ - and dashboard capability.") + help="Activate CTest scripting mode for coverage, valgrind\ + and dashboard capability.") args = parser.parse_args() # Default compiler paths -FC='gfortran' -CC='gcc' -CXX='g++' -MPI_DIR='/opt/mpich/3.2-gnu' -HDF5_DIR='/opt/hdf5/1.8.16-gnu' -PHDF5_DIR='/opt/phdf5/1.8.16-gnu' +FC = 'gfortran' +CC = 'gcc' +CXX = 'g++' +MPI_DIR = '/opt/mpich/3.2-gnu' +HDF5_DIR = '/opt/hdf5/1.8.16-gnu' +PHDF5_DIR = '/opt/phdf5/1.8.16-gnu' # Script mode for extra capability script_mode = False @@ -115,6 +115,7 @@ endif() # Define test data structure tests = OrderedDict() + def cleanup(path): """Remove generated output files.""" for dirpath, dirnames, filenames in os.walk(path): @@ -173,7 +174,7 @@ class Test(object): # Sets the build name that will show up on the CDash def get_build_name(self): - self.build_name = args.project + '_' + self.name + self.build_name = args.project + '_' + self.name return self.build_name # Sets up build options for various tests. It is used both @@ -211,7 +212,7 @@ class Test(object): os.environ['HDF5_ROOT'] = PHDF5_DIR else: os.environ['HDF5_ROOT'] = HDF5_DIR - rc = call(['ctest', '-S', 'ctestscript.run','-V']) + rc = call(['ctest', '-S', 'ctestscript.run', '-V']) if rc != 0: self.success = False self.msg = 'Failed on ctest script.' @@ -243,7 +244,7 @@ class Test(object): return # Default make string - make_list = ['make','-s'] + make_list = ['make', '-s'] # Check for parallel if args.n_procs is not None: @@ -282,7 +283,7 @@ class Test(object): # Simple function to add a test to the global tests dictionary -def add_test(name, debug=False, optimize=False, mpi=False, openmp=False,\ +def add_test(name, debug=False, optimize=False, mpi=False, openmp=False, phdf5=False, valgrind=False, coverage=False): tests.update({name: Test(name, debug, optimize, mpi, openmp, phdf5, valgrind, coverage)}) @@ -363,7 +364,7 @@ ctest_vars = { # Check project name subprop = "set_property(GLOBAL PROPERTY SubProject {0})" -if args.project == "" : +if args.project == "": ctest_vars.update({'subproject': ''}) elif args.project == 'develop': ctest_vars.update({'subproject': ''}) @@ -442,14 +443,14 @@ for key in iter(tests): # INCLUDE is a CTest command that allows for a subset # of tests to be executed. Only used in script mode. if args.regex_tests is None: - ctest_vars.update({'tests' : ''}) + ctest_vars.update({'tests': ''}) # No user tests, use default valgrind tests if test.valgrind: - ctest_vars.update({'tests' : 'INCLUDE {0}'. + ctest_vars.update({'tests': 'INCLUDE {0}'. format(valgrind_default_tests)}) else: - ctest_vars.update({'tests' : 'INCLUDE {0}'. + ctest_vars.update({'tests': 'INCLUDE {0}'. format(args.regex_tests)}) # Main part of code that does the ctest execution. From 05250cdc17c3d99aa175760270b4aeabd1c626f3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Nov 2017 06:39:47 -0600 Subject: [PATCH 227/229] Make sure Travis checks results of regression and unit tests --- .travis.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4462ed0e..19bb96040 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ script: - if [[ $OPENMC_CONFIG == "check_source" ]]; then ./check_source.py; else - ./run_tests.py -C $OPENMC_CONFIG -j 2; + ./run_tests.py -C $OPENMC_CONFIG -j 2 && pytest --cov=../openmc unit_tests/; fi - cd .. diff --git a/setup.py b/setup.py index 271fac0f0..2f85bc3a3 100755 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ kwargs = { # Required dependencies 'install_requires': [ 'six', 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', - 'pandas>=0.17.0', 'lxml', 'uncertainties' + 'pandas<0.21.0', 'lxml', 'uncertainties' ], # Optional dependencies From abe0584c041265a24cab6c093ce0b25b745ed861 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 8 Nov 2017 10:24:22 -0600 Subject: [PATCH 228/229] Fix pandas issue related to MultiIndex conversion --- openmc/tallies.py | 6 ++++-- setup.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 76c6fa714..977aed5e5 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -1664,8 +1664,10 @@ class Tally(IDManagerMixin): new_column.extend(['']*delta_len) columns[i] = tuple(new_column) - # Create and set a MultiIndex for the DataFrame's columns - df.columns = pd.MultiIndex.from_tuples(columns) + # Create and set a MultiIndex for the DataFrame's columns, but only + # if any column actually is multi-level (e.g., a mesh filter) + if any(len(c) > 1 for c in columns): + df.columns = pd.MultiIndex.from_tuples(columns) # Modify the df.to_string method so that it prints formatted strings. # Credit to http://stackoverflow.com/users/3657742/chrisb for this trick diff --git a/setup.py b/setup.py index 2f85bc3a3..338fe5fec 100755 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ kwargs = { # Required dependencies 'install_requires': [ 'six', 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', - 'pandas<0.21.0', 'lxml', 'uncertainties' + 'pandas', 'lxml', 'uncertainties' ], # Optional dependencies From 13758d0e362a3a8ea5886cec52b91862bf93dd29 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 9 Nov 2017 23:19:09 -0500 Subject: [PATCH 229/229] Remove false warnings when a Filter is reused --- openmc/tallies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 76c6fa714..a4c57e1f1 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -3514,7 +3514,7 @@ class Tallies(cv.CheckedList): if f not in already_written: root_element.append(f.to_xml_element()) already_written[f] = f.id - else: + elif f.id != already_written[f]: # Set the IDs of identical filters with different # user-defined IDs to the same value f.id = already_written[f]
01000231.000000e-021.080060e-01H1
11000231.080060e-011.166529e+00H1
21000231.166529e+001.259921e+01H1
31000231.259921e+011.360790e+02H1
41000231.360790e+021.469734e+03H1
51000231.469734e+031.587401e+04H1
61000231.587401e+041.714488e+05H1
71000231.714488e+051.851749e+06H1
81000231.851749e+062.000000e+07H1