Line data Source code
1 : /********************************************************************/ 2 : /* SOFTWARE COPYRIGHT NOTIFICATION */ 3 : /* Cardinal */ 4 : /* */ 5 : /* (c) 2021 UChicago Argonne, LLC */ 6 : /* ALL RIGHTS RESERVED */ 7 : /* */ 8 : /* Prepared by UChicago Argonne, LLC */ 9 : /* Under Contract No. DE-AC02-06CH11357 */ 10 : /* With the U. S. Department of Energy */ 11 : /* */ 12 : /* Prepared by Battelle Energy Alliance, LLC */ 13 : /* Under Contract No. DE-AC07-05ID14517 */ 14 : /* With the U. S. Department of Energy */ 15 : /* */ 16 : /* See LICENSE for full restrictions */ 17 : /********************************************************************/ 18 : 19 : #ifdef ENABLE_OPENMC_COUPLING 20 : #include "CellTally.h" 21 : 22 : registerMooseObject("CardinalApp", CellTally); 23 : 24 : InputParameters 25 3748 : CellTally::validParams() 26 : { 27 3748 : auto params = TallyBase::validParams(); 28 3748 : params.addClassDescription("A class which implements distributed cell tallies."); 29 : 30 7496 : params.addParam<bool>( 31 : "check_equal_mapped_tally_volumes", 32 7496 : false, 33 : "Whether to check if the tallied cells map to regions in the mesh of equal volume. " 34 : "This can be helpful to ensure that the volume normalization of OpenMC's tallies doesn't " 35 : "introduce any unintentional distortion just because the mapped volumes are different. " 36 : "You should only set this to true if your OpenMC tally cells are all the same volume!"); 37 11244 : params.addRangeCheckedParam<Real>("equal_tally_volume_abs_tol", 38 7496 : 1e-8, 39 : "equal_tally_volume_abs_tol > 0", 40 : "Absolute tolerance for comparing tally volumes"); 41 : 42 3748 : return params; 43 0 : } 44 : 45 1841 : CellTally::CellTally(const InputParameters & parameters) 46 : : TallyBase(parameters), 47 3618 : _check_equal_mapped_tally_volumes(getParam<bool>("check_equal_mapped_tally_volumes")), 48 5459 : _equal_tally_volume_abs_tol(getParam<Real>("equal_tally_volume_abs_tol")) 49 : { 50 1809 : } 51 : 52 : std::pair<unsigned int, openmc::Filter *> 53 1799 : CellTally::spatialFilter() 54 : { 55 : // Check to make sure we can map tallies to the mesh subdomains requested in tally_blocks. 56 1799 : checkCellMappedSubdomains(); 57 : 58 1797 : if (_openmc_problem.cellToElem().size() == 0) 59 0 : mooseError("Did not find any overlap between MOOSE elements and OpenMC cells for " 60 : "the specified blocks!"); 61 : 62 1797 : auto tally_cells = getTallyCells(); 63 : std::vector<openmc::CellInstance> cells; 64 65275 : for (const auto & c : tally_cells) 65 63480 : cells.push_back({c.first, c.second}); 66 : 67 1795 : _cell_filter = dynamic_cast<openmc::CellInstanceFilter *>(openmc::Filter::create("cellinstance")); 68 1795 : _cell_filter->set_cell_instances(cells); 69 : 70 3590 : return std::make_pair(openmc::model::tally_filters.size() - 1, _cell_filter); 71 1795 : } 72 : 73 : Real 74 2615 : CellTally::storeResultsInner(const std::vector<unsigned int> & var_numbers, 75 : unsigned int local_score, 76 : unsigned int global_score, 77 : std::vector<xt::xtensor<double, 1>> tally_vals, 78 : bool norm_by_src_rate) 79 : { 80 : Real total = 0.0; 81 : 82 6384 : for (unsigned int ext_bin = 0; ext_bin < _num_ext_filter_bins; ++ext_bin) 83 : { 84 : int i = 0; 85 240199 : for (const auto & c : _openmc_problem.cellToElem()) 86 : { 87 236430 : auto cell_info = c.first; 88 : 89 : // if this cell doesn't have any tallies, skip it 90 236430 : if (!_cell_has_tally[cell_info]) 91 30688 : continue; 92 : 93 205742 : Real unnormalized_tally = tally_vals[local_score](ext_bin * _cell_filter->n_bins() + i++); 94 : 95 : // divide each tally value by the volume that it corresponds to in MOOSE 96 : // because we will apply it as a volumetric tally 97 205742 : Real volumetric_tally = unnormalized_tally; 98 411452 : volumetric_tally *= norm_by_src_rate ? _openmc_problem.tallyMultiplier(global_score) / 99 205710 : _openmc_problem.cellMappedVolume(cell_info) 100 : : 1.0; 101 205742 : total += _ext_bins_to_skip[ext_bin] ? 0.0 : unnormalized_tally; 102 : 103 205742 : auto var = var_numbers[_num_ext_filter_bins * local_score + ext_bin]; 104 205742 : fillElementalAuxVariable(var, c.second, volumetric_tally); 105 : } 106 : } 107 : 108 2615 : return total; 109 : } 110 : 111 : void 112 1799 : CellTally::checkCellMappedSubdomains() 113 : { 114 : _cell_has_tally.clear(); 115 : 116 : // If the OpenMC cell maps to multiple subdomains that _also_ have different 117 : // tally settings, we need to error because we are unsure of whether to add tallies or not; 118 : // both of these need to be true to error 119 76727 : for (const auto & c : _openmc_problem.cellToElem()) 120 : { 121 : bool at_least_one_in_tallies = false; 122 : bool at_least_one_not_in_tallies = false; 123 : int block_in_tallies, block_not_in_tallies; 124 : 125 74930 : auto cell_info = c.first; 126 74930 : auto cell_subdomains = _openmc_problem.getCellToElementSub(cell_info); 127 179760 : for (const auto & s : cell_subdomains) 128 : { 129 104832 : if (!at_least_one_in_tallies) 130 : { 131 74956 : at_least_one_in_tallies = _tally_blocks.count(s) != 0; 132 74956 : block_in_tallies = s; 133 : } 134 : 135 104832 : if (!at_least_one_not_in_tallies) 136 : { 137 104806 : at_least_one_not_in_tallies = _tally_blocks.count(s) == 0; 138 104806 : block_not_in_tallies = s; 139 : } 140 : 141 : // can cut the search early if we've already hit multiple tally settings 142 104832 : if (at_least_one_in_tallies && at_least_one_not_in_tallies) 143 : break; 144 : } 145 : 146 74930 : if (at_least_one_in_tallies && at_least_one_not_in_tallies) 147 6 : mooseError("cell " + _openmc_problem.printCell(cell_info) + 148 : " maps to blocks with different tally settings!\n" 149 2 : "Block " + 150 0 : Moose::stringify(block_in_tallies) + 151 : " is in 'block', but " 152 2 : "block " + 153 0 : Moose::stringify(block_not_in_tallies) + " is not."); 154 : 155 74928 : _cell_has_tally[cell_info] = at_least_one_in_tallies; 156 : } 157 1797 : } 158 : 159 : std::vector<OpenMCCellAverageProblem::cellInfo> 160 1797 : CellTally::getTallyCells() const 161 : { 162 : bool is_first_tally_cell = true; 163 1797 : OpenMCCellAverageProblem::cellInfo first_tally_cell; 164 : Real mapped_tally_volume; 165 : 166 : std::vector<OpenMCCellAverageProblem::cellInfo> tally_cells; 167 : 168 76715 : for (const auto & c : _openmc_problem.cellToElem()) 169 : { 170 74920 : auto cell_info = c.first; 171 : 172 74920 : if (_cell_has_tally.at(cell_info)) 173 : { 174 63484 : tally_cells.push_back(cell_info); 175 : 176 63484 : if (is_first_tally_cell) 177 : { 178 : is_first_tally_cell = false; 179 : first_tally_cell = cell_info; 180 1797 : mapped_tally_volume = _openmc_problem.cellMappedVolume(first_tally_cell); 181 : } 182 : 183 63484 : if (_check_equal_mapped_tally_volumes) 184 : { 185 6270 : Real diff = std::abs(mapped_tally_volume - _openmc_problem.cellMappedVolume(cell_info)); 186 6270 : bool absolute_diff = diff > _equal_tally_volume_abs_tol; 187 6270 : bool relative_diff = diff / mapped_tally_volume > 1e-3; 188 6270 : if (absolute_diff && relative_diff) 189 : { 190 2 : std::stringstream msg; 191 : msg << "Detected un-equal mapped tally volumes!\n cell " 192 2 : << _openmc_problem.printCell(first_tally_cell) << " maps to a volume of " 193 4 : << Moose::stringify(_openmc_problem.cellMappedVolume(first_tally_cell)) 194 4 : << " (cm3)\n cell " << _openmc_problem.printCell(cell_info) << " maps to a volume of " 195 4 : << Moose::stringify(_openmc_problem.cellMappedVolume(cell_info)) 196 : << " (cm3).\n\n" 197 : "If the tallied cells in your OpenMC model are of identical volumes, this means " 198 : "that you can get\n" 199 : "distortion of the volumetric tally output. For instance, suppose you have " 200 : "two equal-size OpenMC\n" 201 : "cells which have the same volume - but each OpenMC cell maps to a MOOSE region " 202 : "of different volume\n" 203 : "just due to the nature of the centroid mapping scheme. Even if those two tallies " 204 : "do actually have the\n" 205 : "same value, the volumetric tally will be different because you'll be " 206 : "dividing each tally by a\n" 207 10 : "different mapped MOOSE volume.\n\n"; 208 : 209 2 : if (_openmc_problem.hasPointTransformations()) 210 : msg << "NOTE: You have imposed symmetry, which means that you'll hit this error if any " 211 : "of your tally\n" 212 : "cells are cut by symmetry planes. If your tally cells would otherwise be the " 213 : "same volume if NOT\n" 214 : "imposing symmetry, or if your tally cells are not the same volume regardless, " 215 : "you need to set\n" 216 0 : "'check_equal_mapped_tally_volumes = false'."; 217 : else 218 : msg << "We recommend re-creating the mesh mirror to have an equal volume mapping of " 219 : "MOOSE elements to each\n" 220 : "OpenMC cell. Or, you can disable this check by setting " 221 2 : "'check_equal_mapped_tally_volumes = false'."; 222 : 223 2 : mooseError(msg.str()); 224 0 : } 225 : } 226 : } 227 : } 228 : 229 1795 : return tally_cells; 230 0 : } 231 : #endif