diff --git a/doc/content/news.md b/doc/content/news.md index e349bbf87..12bcc1bdf 100644 --- a/doc/content/news.md +++ b/doc/content/news.md @@ -5,6 +5,7 @@ significant changes to report. ### 2024 +- [October 2024](news/october2024.md) - [July 2024](news/july2024.md) - [March 2024](news/march2024.md) diff --git a/doc/content/news/october2024.md b/doc/content/news/october2024.md new file mode 100644 index 000000000..57c06a752 --- /dev/null +++ b/doc/content/news/october2024.md @@ -0,0 +1,11 @@ +# October 2024 News + +- We have enabled Adaptive Mesh Refinement (AMR) on the OpenMC mesh mirror for simulations using an [OpenMCCellAverageProblem](/problems/OpenMCCellAverageProblem.md) + + - All AMR capabilities included in MOOSE are now natively supported for temperature/density feedback and tallies + - Mesh tallies will automatically use the adapted mesh when tallying on the mesh mirror + +- There are a few limitations to [MeshTally](/tallies/MeshTally.md) AMR, namely: + + - Only replicated meshes are supported + - The mesh mirror must be tallied on directly when AMR is active and a mesh tally is included in the input file diff --git a/include/base/OpenMCCellAverageProblem.h b/include/base/OpenMCCellAverageProblem.h index 0ff964dee..d5f90f187 100644 --- a/include/base/OpenMCCellAverageProblem.h +++ b/include/base/OpenMCCellAverageProblem.h @@ -345,6 +345,12 @@ class OpenMCCellAverageProblem : public OpenMCProblemBase int fixedPointIteration() const { return _fixed_point_iteration; } + /** + * Checks if the problem uses adaptivity or not. + * @return if the problem uses adaptivity. + */ + bool hasAdaptivity() const { return _has_adaptivity; } + /// Constant flag to indicate that a cell/element was unmapped static constexpr int32_t UNMAPPED{-1}; @@ -707,7 +713,7 @@ class OpenMCCellAverageProblem : public OpenMCProblemBase void compareContainedCells(std::map & reference, std::map & compare) const; - std::unique_ptr> _serialized_solution; + NumericVector & _serialized_solution; /** * Whether to automatically compute the mapping of OpenMC cell IDs and @@ -769,12 +775,16 @@ class OpenMCCellAverageProblem : public OpenMCProblemBase const bool _normalize_by_global; /** - * If 'fixed_mesh' is false, this indicates that the [Mesh] is changing during - * the simulation (either from adaptive refinement or from deformation). - * When the mesh changes during the simulation, the mapping from OpenMC cells to - * the [Mesh] must be re-established after each OpenMC run. + * Whether or not the problem contains mesh adaptivity. + */ + bool _has_adaptivity; + + /** + * When the mesh changes during the simulation (either from adaptive mesh refinement + * or deformation), the mapping from OpenMC cells to the [Mesh] must be re-established + * after each OpenMC run. */ - const bool _need_to_reinit_coupling; + bool _need_to_reinit_coupling; /** * Whether to check the tallies against the global tally; diff --git a/include/tallies/MeshTally.h b/include/tallies/MeshTally.h index 9dc79152b..4ff805682 100644 --- a/include/tallies/MeshTally.h +++ b/include/tallies/MeshTally.h @@ -23,6 +23,11 @@ #include "openmc/tallies/filter_mesh.h" +namespace libMesh +{ +class ReplicatedMesh; +} + class MeshTally : public TallyBase { public: @@ -82,7 +87,7 @@ class MeshTally : public TallyBase Point _mesh_translation; /// The index into an array of mesh translations. - unsigned int _instance; + const unsigned int _instance; /// The index of the mesh added by this tally. unsigned int _mesh_index; @@ -91,5 +96,24 @@ class MeshTally : public TallyBase openmc::MeshFilter * _mesh_filter; /// OpenMC unstructured mesh instance for use with mesh tallies - const openmc::LibMesh * _mesh_template; + openmc::LibMesh * _mesh_template; + + /// Blocks for which to add mesh tallies. + std::set _tally_blocks; + + /// Whether we're using an indirection layer to map between the OpenMC mesh tally and the MOOSE mesh. + const bool _use_dof_map; + + /** + * For use with AMR only. A copy of the mesh which only contains active elements. + * This removes the link between the MooseMesh that has an auxvariable equation system and the + * OpenMC mesh which has an equation system that is tallied on. The OpenMC equation system throws + * errors when attempting to project solution vectors as it has not been initialized with + * the data structures required for adaptivity. + * TODO: Fix this in OpenMC (enable adaptivity in the equation systems added by openmc::LibMesh + * meshes). + */ + std::unique_ptr _libmesh_mesh_copy; + /// A mapping between the elements in '_libmesh_mesh_copy' and the elements in the MooseMesh. + std::vector _active_to_total_mapping; }; diff --git a/include/tallies/TallyBase.h b/include/tallies/TallyBase.h index a72129b86..439596ae2 100644 --- a/include/tallies/TallyBase.h +++ b/include/tallies/TallyBase.h @@ -304,6 +304,9 @@ class TallyBase : public MooseObject /// Suffixes to apply to 'tally_name' in order to name the fields in the 'output'. std::vector _output_name; + /// Whether the problem uses adaptive mesh refinement or not. + const bool _is_adaptive; + /// Tolerance for setting zero tally static constexpr Real ZERO_TALLY_THRESHOLD = 1e-12; }; diff --git a/src/base/OpenMCCellAverageProblem.C b/src/base/OpenMCCellAverageProblem.C index d01ab71a0..f0d7d1a4f 100644 --- a/src/base/OpenMCCellAverageProblem.C +++ b/src/base/OpenMCCellAverageProblem.C @@ -23,6 +23,7 @@ #include "TallyBase.h" #include "CellTally.h" #include "AddTallyAction.h" +#include "CreateDisplacedProblemAction.h" #include "openmc/constants.h" #include "openmc/cross_sections.h" @@ -84,13 +85,6 @@ OpenMCCellAverageProblem::validParams() "filled into more than one cell). If your OpenMC model has a unique material " "in every cell you want to receive density feedback, these two options are IDENTICAL"); - // TODO: would be nice to auto-detect this - params.addParam("fixed_mesh", true, - "Whether the MooseMesh is unchanging during the simulation (true), or whether there is mesh " - "movement and/or adaptivity that is changing the mesh in time (false). When the mesh changes " - "during the simulation, the mapping from OpenMC's cells to the mesh must be re-evaluated after " - "each OpenMC run."); - MooseEnum scores_heat( "heating heating_local kappa_fission fission_q_prompt fission_q_recoverable"); params.addParam( @@ -184,7 +178,7 @@ OpenMCCellAverageProblem::validParams() OpenMCCellAverageProblem::OpenMCCellAverageProblem(const InputParameters & params) : OpenMCProblemBase(params), - _serialized_solution(NumericVector::build(_communicator).release()), + _serialized_solution(_aux->serializedSolution()), _output_cell_mapping(getParam("output_cell_mapping")), _initial_condition( getParam("initial_properties").getEnum()), @@ -194,7 +188,8 @@ OpenMCCellAverageProblem::OpenMCCellAverageProblem(const InputParameters & param _normalize_by_global(_run_mode == openmc::RunMode::FIXED_SOURCE ? false : getParam("normalize_by_global_tally")), - _need_to_reinit_coupling(!getParam("fixed_mesh")), + _has_adaptivity(getMooseApp().actionWarehouse().hasActions("set_adaptivity_options")), + _need_to_reinit_coupling(_has_adaptivity), _check_tally_sum( isParamValid("check_tally_sum") ? getParam("check_tally_sum") @@ -213,12 +208,26 @@ OpenMCCellAverageProblem::OpenMCCellAverageProblem(const InputParameters & param _initial_num_openmc_surfaces(openmc::model::surfaces.size()), _using_skinner(isParamValid("skinner")) { + // Check to see if a displaced problem is being initialized. + // TODO: this also needs to include a "use_displaced_mesh" parameter, alongside the ability to + // actually use the displaced mesh. See https://github.com/neams-th-coe/cardinal/pull/907 for more + // information. + const auto & dis_actions = + getMooseApp().actionWarehouse().getActions(); + for (const auto & act : dis_actions) + { + auto has_displaced = + act->isParamValid("displacements") && act->getParam("use_displaced_mesh"); + _need_to_reinit_coupling |= has_displaced; + // Switch the above with: _need_to_reinit_coupling |= (has_displaced && _use_displaced_mesh); + } + // Look through the list of AddTallyActions to see if we have a CellTally. If so, we need to map // cells. const auto & actions = getMooseApp().actionWarehouse().getActions(); for (const auto & act : actions) - _has_cell_tallies = act->getMooseObjectType() == "CellTally" || _has_cell_tallies; - _needs_to_map_cells = _needs_to_map_cells || _has_cell_tallies; + _has_cell_tallies |= act->getMooseObjectType() == "CellTally"; + _needs_to_map_cells |= _has_cell_tallies; if (!_needs_to_map_cells) checkUnusedParam(params, @@ -246,11 +255,13 @@ OpenMCCellAverageProblem::OpenMCCellAverageProblem(const InputParameters & param // the same number of bins or to exactly the same regions of space, so we must // disable relaxation. if (_need_to_reinit_coupling && _relaxation != relaxation::none) - mooseError("When 'fixed_mesh' is false, the mapping from the OpenMC model to the [Mesh] may " - "vary in time. This means that we have no guarantee that the number of tally bins (or even " - "the regions of space corresponding to each bin) are fixed. Therefore, it is not " - "possible to apply relaxation to the OpenMC tallies because you might end up trying to add vectors " - "of different length (and possibly spatial mapping)."); + mooseError( + "When adaptivity is requested or a displaced problem is used, the mapping from the " + "OpenMC model to the [Mesh] may vary in time. This means that we have no guarantee that " + "the " + "number of tally bins (or even the regions of space corresponding to each bin) are fixed. " + "Therefore, it is not possible to apply relaxation to the OpenMC tallies because you might " + "end up trying to add vectors of different length (and possibly spatial mapping)."); if (_run_mode == openmc::RunMode::FIXED_SOURCE) checkUnusedParam(params, "normalize_by_global_tally", "running OpenMC in fixed source mode"); @@ -494,9 +505,6 @@ OpenMCCellAverageProblem::initialSetup() "OpenMCVolumeCalculation!"); } - if (_adaptivity.isOn() && !_need_to_reinit_coupling) - mooseError("When using mesh adaptivity, 'fixed_mesh' must be false!"); - if (isParamValid("symmetry_mapper")) { const auto & name = getParam("symmetry_mapper"); @@ -636,7 +644,7 @@ OpenMCCellAverageProblem::setupProblem() for (unsigned int e = 0; e < _mesh.nElem(); ++e) { const auto * elem = _mesh.queryElemPtr(e); - if (!isLocalElem(elem)) + if (!isLocalElem(elem) || !elem->active()) continue; _local_to_global_elem.push_back(e); @@ -830,8 +838,8 @@ OpenMCCellAverageProblem::storeElementPhase() for (const auto & s : excl_density_blocks) _n_moose_density_elems += numElemsInSubdomain(s); - _n_moose_none_elems = - _mesh.nElem() - _n_moose_temp_density_elems - _n_moose_temp_elems - _n_moose_density_elems; + _n_moose_none_elems = _mesh.getMesh().n_active_elem() - _n_moose_temp_density_elems - + _n_moose_temp_elems - _n_moose_density_elems; } void @@ -1413,9 +1421,10 @@ OpenMCCellAverageProblem::initializeElementToCellMapping() mooseError("Did not find any overlap between MOOSE elements and OpenMC cells for " "the specified blocks!"); - _console << "\nMapping between " + Moose::stringify(_mesh.nElem()) + " MOOSE elements and " + - Moose::stringify(_n_openmc_cells) + " OpenMC cells (on " + - Moose::stringify(openmc::model::n_coord_levels) + " coordinate levels):" + _console << "\nMapping between " + Moose::stringify(_mesh.getMesh().n_active_elem()) + + " MOOSE elements and " + Moose::stringify(_n_openmc_cells) + + " OpenMC cells (on " + Moose::stringify(openmc::model::n_coord_levels) + + " coordinate levels):" << std::endl; VariadicTable vt( @@ -1729,7 +1738,7 @@ OpenMCCellAverageProblem::mapElemsToCells() { const auto * elem = _mesh.queryElemPtr(e); - if (!isLocalElem(elem)) + if (!isLocalElem(elem) || !elem->active()) continue; local_elem++; @@ -1862,10 +1871,9 @@ OpenMCCellAverageProblem::mapElemsToCells() gatherCellVector(elems, n_elems, _cell_to_elem); // fill out the elem_to_cell structure - _elem_to_cell.resize(_mesh.nElem()); - for (unsigned int e = 0; e < _mesh.nElem(); ++e) - _elem_to_cell[e] = {UNMAPPED, UNMAPPED}; - + // TODO: figure out how to shrink this so we only store the mapping for active + // elements as opposed to the entire element hierarchy. + _elem_to_cell.resize(_mesh.nElem(), {UNMAPPED, UNMAPPED}); for (const auto & c : _cell_to_elem) { for (const auto & e : c.second) @@ -2150,7 +2158,7 @@ OpenMCCellAverageProblem::computeVolumeWeightedCellInput( const auto * elem = _mesh.queryElemPtr(globalElemID(e)); auto v = var_num.at(elem->subdomain_id()).first; auto dof_idx = elem->dof_number(sys_number, v, 0); - product += (*_serialized_solution)(dof_idx) * elem->volume(); + product += _serialized_solution(dof_idx) * elem->volume(); } volume_product.push_back(product); @@ -2403,12 +2411,7 @@ OpenMCCellAverageProblem::checkNormalization(const Real & sum, unsigned int glob void OpenMCCellAverageProblem::syncSolutions(ExternalProblem::Direction direction) { - auto & solution = _aux->solution(); - - if (_first_transfer) - _serialized_solution->init(_aux->sys().n_dofs(), false, SERIAL); - - solution.localize(*_serialized_solution); + _aux->serializeSolution(); switch (direction) { @@ -2595,7 +2598,7 @@ OpenMCCellAverageProblem::syncSolutions(ExternalProblem::Direction direction) } _first_transfer = false; - solution.close(); + _aux->solution().close(); _aux->system().update(); } diff --git a/src/base/OpenMCProblemBase.C b/src/base/OpenMCProblemBase.C index e17143f84..e3eba5d11 100644 --- a/src/base/OpenMCProblemBase.C +++ b/src/base/OpenMCProblemBase.C @@ -346,7 +346,7 @@ OpenMCProblemBase::numElemsInSubdomain(const SubdomainID & id) const { const auto * elem = _mesh.queryElemPtr(e); - if (!isLocalElem(elem)) + if (!isLocalElem(elem) || !elem->active()) continue; const auto subdomain_id = elem->subdomain_id(); diff --git a/src/tallies/MeshTally.C b/src/tallies/MeshTally.C index 9d397a4e8..b1c18f984 100644 --- a/src/tallies/MeshTally.C +++ b/src/tallies/MeshTally.C @@ -19,6 +19,8 @@ #ifdef ENABLE_OPENMC_COUPLING #include "MeshTally.h" +#include "libmesh/replicated_mesh.h" + registerMooseObject("CardinalApp", MeshTally); InputParameters @@ -34,6 +36,10 @@ MeshTally::validParams() params.addParam("mesh_translation", "Coordinate to which this mesh should be " "translated. Units must match those used to define the [Mesh]."); + params.addParam>( + "blocks", + "Subdomains for which to add tallies in OpenMC. If not provided, this mesh " + "tally will be applied over the entire mesh."); // The index of this tally into an array of mesh translations. Defaults to zero. params.addPrivateParam("instance", 0); @@ -45,7 +51,8 @@ MeshTally::MeshTally(const InputParameters & parameters) : TallyBase(parameters), _mesh_translation(isParamValid("mesh_translation") ? getParam("mesh_translation") : Point(0.0, 0.0, 0.0)), - _instance(getParam("instance")) + _instance(getParam("instance")), + _use_dof_map(_is_adaptive || isParamValid("blocks")) { // Error check the estimators. if (isParamValid("estimator")) @@ -62,7 +69,16 @@ MeshTally::MeshTally(const InputParameters & parameters) "Mesh tallies currently require 'allow_renumbering = false' to be set in the [Mesh]!"); if (isParamValid("mesh_template")) + { + if (_is_adaptive) + mooseError("Adaptivity is only supported when tallying on the mesh in the [Mesh] block!"); + + if (isParamValid("blocks")) + mooseError("Block restriction is currently not supported for mesh tallies which load a " + "mesh from a file!"); + _mesh_template_filename = &getParam("mesh_template"); + } else { if (std::abs(_openmc_problem.scaling() - 1.0) > 1e-6) @@ -82,6 +98,30 @@ MeshTally::MeshTally(const InputParameters & parameters) if (isParamValid("mesh_translation")) mooseError("The mesh filter cannot be translated if directly tallying on the mesh " "provided in the [Mesh] block!"); + + // Fetch subdomain IDs for block restrictions. + if (isParamValid("blocks")) + { + auto block_names = getParam>("blocks"); + if (block_names.empty()) + mooseError("Subdomain names must be provided if using 'blocks'!"); + + auto block_ids = _mesh.getSubdomainIDs(block_names); + std::copy( + block_ids.begin(), block_ids.end(), std::inserter(_tally_blocks, _tally_blocks.end())); + + // Check to make sure all of the blocks are in the mesh. + const auto & subdomains = _mesh.meshSubdomains(); + for (std::size_t b = 0; b < block_names.size(); ++b) + if (subdomains.find(block_ids[b]) == subdomains.end()) + mooseError("Block '" + block_names[b] + "' specified in 'blocks' not found in mesh!"); + } + else + { + // Tally over all mesh blocks if no blocks are provided. + for (const auto & s : _mesh.meshSubdomains()) + _tally_blocks.insert(s); + } } /** @@ -97,21 +137,53 @@ std::pair MeshTally::spatialFilter() { // Create the OpenMC mesh which will be tallied on. - std::unique_ptr tally_mesh; if (!_mesh_template_filename) - tally_mesh = std::make_unique(_mesh.getMesh(), _openmc_problem.scaling()); + { + if (_use_dof_map) + { + /** + * Need to create a copy of the mesh which only contains active elements. If this isn't + * done, the equation system added by the OpenMC mesh object will throw an error during + * the refinement / coarsening process as it has no idea that AMR is required. + */ + _libmesh_mesh_copy = + std::make_unique(_openmc_problem.comm(), _mesh.dimension()); + + auto msh = dynamic_cast(_mesh.getMeshPtr()); + if (!msh) + mooseError("Internal error: The mesh is not a replicated mesh."); + + msh->create_submesh(*_libmesh_mesh_copy.get(), + msh->active_subdomain_set_elements_begin(_tally_blocks), + msh->active_subdomain_set_elements_end(_tally_blocks)); + _libmesh_mesh_copy->allow_find_neighbors(true); + _libmesh_mesh_copy->allow_renumbering(false); + _libmesh_mesh_copy->prepare_for_use(); + + _active_to_total_mapping.clear(); + _active_to_total_mapping.reserve(_libmesh_mesh_copy->n_active_elem()); + for (const auto & old_elem : + libMesh::as_range(msh->active_subdomain_set_elements_begin(_tally_blocks), + msh->active_subdomain_set_elements_end(_tally_blocks))) + _active_to_total_mapping.push_back(old_elem->id()); + + openmc::model::meshes.emplace_back( + std::make_unique(*_libmesh_mesh_copy.get(), _openmc_problem.scaling())); + } + else + openmc::model::meshes.emplace_back( + std::make_unique(_mesh.getMesh(), _openmc_problem.scaling())); + } else - tally_mesh = - std::make_unique(*_mesh_template_filename, _openmc_problem.scaling()); + openmc::model::meshes.emplace_back( + std::make_unique(*_mesh_template_filename, _openmc_problem.scaling())); - // by setting the ID to -1, OpenMC will automatically detect the next available ID - tally_mesh->set_id(-1); - tally_mesh->output_ = false; - _mesh_template = tally_mesh.get(); + _mesh_index = openmc::model::meshes.size() - 1; + _mesh_template = dynamic_cast(openmc::model::meshes[_mesh_index].get()); - // Create the mesh filter itself. - _mesh_index = openmc::model::meshes.size(); - openmc::model::meshes.push_back(std::move(tally_mesh)); + // by setting the ID to -1, OpenMC will automatically detect the next available ID + _mesh_template->set_id(-1); + _mesh_template->output_ = false; _mesh_filter = dynamic_cast(openmc::Filter::create("mesh")); _mesh_filter->set_mesh(_mesh_index); @@ -160,9 +232,9 @@ MeshTally::storeResultsInner(const std::vector & var_numbers, : 1.0; total += power_fraction; - std::vector elem_ids = {mesh_offset + e}; auto var = var_numbers[_num_ext_filter_bins * local_score + ext_bin]; - fillElementalAuxVariable(var, elem_ids, volumetric_power); + auto elem_id = _use_dof_map ? _active_to_total_mapping[e] : mesh_offset + e; + fillElementalAuxVariable(var, {elem_id}, volumetric_power); } } @@ -180,7 +252,8 @@ MeshTally::checkMeshTemplateAndTranslations() const unsigned int mesh_offset = _instance * _mesh_filter->n_bins(); for (int e = 0; e < _mesh_filter->n_bins(); ++e) { - auto elem_ptr = _mesh.queryElemPtr(mesh_offset + e); + auto elem_id = _use_dof_map ? _active_to_total_mapping[e] : mesh_offset + e; + auto elem_ptr = _mesh.queryElemPtr(elem_id); // if element is not on this part of the distributed mesh, skip it if (!elem_ptr) @@ -227,7 +300,7 @@ MeshTally::checkMeshTemplateAndTranslations() const if (different_centroids) mooseError( - "Centroid for element " + Moose::stringify(mesh_offset + e) + " in the [Mesh] (cm): " + + "Centroid for element " + Moose::stringify(elem_id) + " in the [Mesh] (cm): " + _openmc_problem.printPoint(centroid_mesh) + "\ndoes not match centroid for element " + Moose::stringify(e) + " in the 'mesh_template' with instance " + Moose::stringify(_instance) + " (cm): " + _openmc_problem.printPoint(centroid_template) + diff --git a/src/tallies/TallyBase.C b/src/tallies/TallyBase.C index 52ed2b69b..aab04eca8 100644 --- a/src/tallies/TallyBase.C +++ b/src/tallies/TallyBase.C @@ -89,7 +89,8 @@ TallyBase::TallyBase(const InputParameters & parameters) _tally_trigger(isParamValid("trigger") ? &getParam("trigger") : nullptr), _trigger_ignore_zeros(getParam>("trigger_ignore_zeros")), _renames_tally_vars(isParamValid("name")), - _has_outputs(isParamValid("output")) + _has_outputs(isParamValid("output")), + _is_adaptive(_openmc_problem.hasAdaptivity()) { if (isParamValid("score")) { diff --git a/test/tests/openmc_errors/adaptivity/fixed_mesh.i b/test/tests/neutronics/adaptivity/cell.i similarity index 59% rename from test/tests/openmc_errors/adaptivity/fixed_mesh.i rename to test/tests/neutronics/adaptivity/cell.i index 3f22fbea7..c85fb006e 100644 --- a/test/tests/openmc_errors/adaptivity/fixed_mesh.i +++ b/test/tests/neutronics/adaptivity/cell.i @@ -1,8 +1,7 @@ [Mesh] [sphere] - # Mesh of a single pebble with outer radius of 1.5 (cm) type = FileMeshGenerator - file = ../../neutronics/meshes/sphere.e + file = ../meshes/sphere.e [] [solid] type = CombinerGenerator @@ -16,35 +15,41 @@ [] [] +[Adaptivity] + steps = 1 + marker = uniform + + [Markers/uniform] + type = UniformMarker + mark = refine + [] +[] + [Problem] type = OpenMCCellAverageProblem - power = 70.0 + verbose = true + power = 1e4 temperature_blocks = '100' cell_level = 0 - fixed_mesh = true + initial_properties = xml + + normalize_by_global_tally = false [Tallies] [Cell] type = CellTally + score = kappa_fission blocks = '100' [] [] [] [Executioner] - type = Transient - num_steps = 1 -[] - -[Adaptivity] - [Markers] - [error_tol_marker] - type = UniformMarker - mark = refine - [] - [] + type = Steady [] [Outputs] exodus = true + execute_on = timestep_end + hide = 'temp cell_instance' [] diff --git a/test/tests/openmc_errors/adaptivity/geometry.xml b/test/tests/neutronics/adaptivity/geometry.xml similarity index 100% rename from test/tests/openmc_errors/adaptivity/geometry.xml rename to test/tests/neutronics/adaptivity/geometry.xml diff --git a/test/tests/neutronics/adaptivity/gold/cell_out.e b/test/tests/neutronics/adaptivity/gold/cell_out.e new file mode 100644 index 000000000..dc201b3be Binary files /dev/null and b/test/tests/neutronics/adaptivity/gold/cell_out.e differ diff --git a/test/tests/neutronics/adaptivity/gold/cell_out.e-s002 b/test/tests/neutronics/adaptivity/gold/cell_out.e-s002 new file mode 100644 index 000000000..91830b0bd Binary files /dev/null and b/test/tests/neutronics/adaptivity/gold/cell_out.e-s002 differ diff --git a/test/tests/neutronics/adaptivity/gold/mesh_out.e b/test/tests/neutronics/adaptivity/gold/mesh_out.e new file mode 100644 index 000000000..9a85ec8bd Binary files /dev/null and b/test/tests/neutronics/adaptivity/gold/mesh_out.e differ diff --git a/test/tests/neutronics/adaptivity/gold/mesh_out.e-s002 b/test/tests/neutronics/adaptivity/gold/mesh_out.e-s002 new file mode 100644 index 000000000..d6a2016d0 Binary files /dev/null and b/test/tests/neutronics/adaptivity/gold/mesh_out.e-s002 differ diff --git a/test/tests/openmc_errors/adaptivity/materials.xml b/test/tests/neutronics/adaptivity/materials.xml similarity index 89% rename from test/tests/openmc_errors/adaptivity/materials.xml rename to test/tests/neutronics/adaptivity/materials.xml index 7cfcd0a5c..54d5c6a86 100644 --- a/test/tests/openmc_errors/adaptivity/materials.xml +++ b/test/tests/neutronics/adaptivity/materials.xml @@ -1,7 +1,7 @@ - + @@ -10,7 +10,7 @@ - + @@ -19,7 +19,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/test/tests/neutronics/adaptivity/mesh.i b/test/tests/neutronics/adaptivity/mesh.i new file mode 100644 index 000000000..efeedc25a --- /dev/null +++ b/test/tests/neutronics/adaptivity/mesh.i @@ -0,0 +1,58 @@ +[Mesh] + [sphere] + type = FileMeshGenerator + file = ../meshes/sphere.e + [] + [solid_ids] + type = SubdomainIDGenerator + input = sphere + subdomain_id = '100' + [] + [solid] + type = CombinerGenerator + inputs = solid_ids + positions = '0 0 0' + avoid_merging_subdomains = true + [] + + allow_renumbering = false +[] + +[Adaptivity] + steps = 1 + marker = uniform + + [Markers/uniform] + type = UniformMarker + mark = refine + [] +[] + +[Problem] + type = OpenMCCellAverageProblem + verbose = true + power = 1e4 + temperature_blocks = '100' + cell_level = 0 + initial_properties = xml + + # The global tally check is disabled because we have a loosely fitting unstructured mesh tally. + normalize_by_global_tally = false + + [Tallies] + [Mesh] + type = MeshTally + score = kappa_fission + [] + [] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = true + execute_on = timestep_end + hide = 'temp cell_instance' +[] diff --git a/test/tests/openmc_errors/adaptivity/settings.xml b/test/tests/neutronics/adaptivity/settings.xml similarity index 79% rename from test/tests/openmc_errors/adaptivity/settings.xml rename to test/tests/neutronics/adaptivity/settings.xml index de9ecca58..2206cb140 100644 --- a/test/tests/openmc_errors/adaptivity/settings.xml +++ b/test/tests/neutronics/adaptivity/settings.xml @@ -2,15 +2,15 @@ eigenvalue 100 - 50 10 + 50 -5.0 -5.0 0 5.0 5.0 12.0 - 294.0 - interpolation + 600.0 + nearest false 294.0 1600.0 diff --git a/test/tests/neutronics/adaptivity/tests b/test/tests/neutronics/adaptivity/tests new file mode 100644 index 000000000..df4301c5f --- /dev/null +++ b/test/tests/neutronics/adaptivity/tests @@ -0,0 +1,36 @@ +[Tests] + [adaptive_cell] + type = Exodiff + input = cell.i + exodiff = cell_out.e + requirement = "The system shall allow problems which contain adaptivity on the mesh mirror for cell tallies." + required_objects = 'OpenMCCellAverageProblem' + [] + [adaptive_mesh] + type = Exodiff + input = mesh.i + exodiff = mesh_out.e + mesh_mode = 'replicated' + requirement = "The system shall allow problems which contain adaptivity on the mesh mirror for mesh tallies." + required_objects = 'OpenMCCellAverageProblem' + [] + [adaptive_mesh_template] + type = RunException + input = mesh.i + cli_args = "Problem/Tallies/Mesh/mesh_template='../meshes/sphere.e'" + mesh_mode = 'replicated' + expect_err = "Adaptivity is only supported when tallying on the mesh in the \[Mesh\] block!" + requirement = "The system shall error if adaptivity is active and tallying on a mesh template instead of the" + " mesh block." + required_objects = 'OpenMCCellAverageProblem' + [] + [adaptive_relaxation] + type = RunException + input = cell.i + cli_args = "Problem/relaxation='constant'" + expect_err = "When adaptivity is requested or a displaced problem is used, the mapping from the " + "OpenMC model to the \[Mesh\] may vary in time." + requirement = "The system shall error if adaptivity is active and a relaxation scheme is requested." + required_objects = 'OpenMCCellAverageProblem' + [] +[] diff --git a/test/tests/neutronics/mesh_tally/block_restrict.i b/test/tests/neutronics/mesh_tally/block_restrict.i new file mode 100644 index 000000000..3a70c67fc --- /dev/null +++ b/test/tests/neutronics/mesh_tally/block_restrict.i @@ -0,0 +1,70 @@ +[Mesh] + [sphere] + type = FileMeshGenerator + file = ../meshes/sphere.e + [] + [solid1] + type = SubdomainIDGenerator + input = sphere + subdomain_id = '100' + [] + [sphereb] + type = FileMeshGenerator + file = ../meshes/sphere.e + [] + [solid2] + type = SubdomainIDGenerator + input = sphereb + subdomain_id = '200' + [] + [spherec] + type = FileMeshGenerator + file = ../meshes/sphere.e + [] + [solid3] + type = SubdomainIDGenerator + input = spherec + subdomain_id = '300' + [] + [combine] + type = CombinerGenerator + inputs = 'solid1 solid2 solid3' + positions_file = pebble_centers.txt + [] + [delete_solid3] + type = BlockDeletionGenerator + input = combine + block = 300 + [] + + allow_renumbering = false + parallel_type = replicated +[] + +[Problem] + type = OpenMCCellAverageProblem + temperature_blocks = '100 200' + initial_properties = xml + verbose = true + cell_level = 0 + normalize_by_global_tally = false + + power = 100.0 + + [Tallies] + [Mesh] + type = MeshTally + blocks = '200' + [] + [] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + execute_on = final + exodus = true + hide = 'temp cell_instance cell_id' +[] diff --git a/test/tests/neutronics/mesh_tally/gold/block_restrict_out.e b/test/tests/neutronics/mesh_tally/gold/block_restrict_out.e new file mode 100644 index 000000000..9537708fa Binary files /dev/null and b/test/tests/neutronics/mesh_tally/gold/block_restrict_out.e differ diff --git a/test/tests/neutronics/mesh_tally/tests b/test/tests/neutronics/mesh_tally/tests index 6f265808e..54fa4fd52 100644 --- a/test/tests/neutronics/mesh_tally/tests +++ b/test/tests/neutronics/mesh_tally/tests @@ -63,6 +63,16 @@ "approaches the value of a cell tally as the difference in volume decreases." required_objects = 'OpenMCCellAverageProblem' [] + [block_restrict] + type = Exodiff + input = block_restrict.i + exodiff = block_restrict_out.e + # This test has very few particles, and OpenMC will error if there aren't any particles + # on a particular process + max_parallel = 32 + requirement = "Mesh tallies shall allow for block restrictions to be applied." + required_objects = 'OpenMCCellAverageProblem' + [] [multiple_meshes] type = Exodiff input = multiple_meshes.i @@ -130,4 +140,20 @@ requirement = "Mesh tallies shall temporarily require disabled renumbering until capability is available" required_objects = 'OpenMCCellAverageProblem' [] + [file_mesh_block_restrict] + type = RunException + input = one_mesh.i + cli_args = 'Problem/Tallies/Mesh/blocks=100' + expect_err = "Block restriction is currently not supported for mesh tallies which load a mesh from a file!" + requirement = "Mesh tallies shall error if the user attempts to apply a block restriction when using a mesh template." + required_objects = 'OpenMCCellAverageProblem' + [] + [block_restrict_no_blocks] + type = RunException + input = one_mesh_no_input_file.i + cli_args = "Problem/Tallies/Mesh/blocks='' Mesh/parallel_type=replicated" + expect_err = "Subdomain names must be provided if using 'blocks'!" + requirement = "Mesh tallies shall error if the user attempts to apply a block restriction with no blocks." + required_objects = 'OpenMCCellAverageProblem' + [] [] diff --git a/test/tests/neutronics/relaxation/cell_tallies/openmc_adapt.i b/test/tests/neutronics/relaxation/cell_tallies/openmc_adapt.i new file mode 100644 index 000000000..d20901da9 --- /dev/null +++ b/test/tests/neutronics/relaxation/cell_tallies/openmc_adapt.i @@ -0,0 +1,68 @@ +[Mesh] + [pebble] + type = FileMeshGenerator + file = ../../meshes/sphere_in_m.e + [] + [repeat] + type = CombinerGenerator + inputs = pebble + positions = '0 0 0.02 + 0 0 0.06 + 0 0 0.10' + [] + [set_block_ids] + type = SubdomainIDGenerator + input = repeat + subdomain_id = 0 + [] +[] + +[AuxKernels] + [temp] + type = FunctionAux + variable = temp + function = axial + execute_on = initial + [] +[] + +[Functions] + [axial] + type = ParsedFunction + expression = '500 + z / 0.10 * 100' + [] +[] + +[Adaptivity] + [Markers/uniform] + type = UniformMarker + mark = refine + [] +[] + +[Problem] + type = OpenMCCellAverageProblem + verbose = true + power = 100.0 + temperature_blocks = '0' + cell_level = 1 + scaling = 100.0 + + relaxation = robbins_monro + + [Tallies] + [Cell] + type = CellTally + blocks = '0' + [] + [] +[] + +[Executioner] + type = Transient + num_steps = 3 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/neutronics/relaxation/cell_tallies/tests b/test/tests/neutronics/relaxation/cell_tallies/tests index 1f41b29b9..2da1b9625 100644 --- a/test/tests/neutronics/relaxation/cell_tallies/tests +++ b/test/tests/neutronics/relaxation/cell_tallies/tests @@ -134,10 +134,8 @@ [] [no_relax_with_fixed_mesh] type = RunException - input = openmc.i - cli_args = "Problem/relaxation=robbins_monro Problem/fixed_mesh=false" - expect_err = "When 'fixed_mesh' is false, the mapping from the OpenMC model to the \[Mesh\] may " - "vary in time." + input = openmc_adapt.i + expect_err = "When adaptivity is requested or a displaced problem is used, the mapping from the OpenMC model to the \[Mesh\] may vary in time." requirement = "The system shall correctly error if trying to use relaxation with a time-varying mesh." required_objects = 'OpenMCCellAverageProblem' [] diff --git a/test/tests/openmc_errors/adaptivity/tests b/test/tests/openmc_errors/adaptivity/tests deleted file mode 100644 index 92b67200e..000000000 --- a/test/tests/openmc_errors/adaptivity/tests +++ /dev/null @@ -1,9 +0,0 @@ -[Tests] - [fixed_mesh] - type = RunException - input = fixed_mesh.i - expect_err = "When using mesh adaptivity, 'fixed_mesh' must be false!" - requirement = "The system shall error if user incorrectly specifies a fixed mesh when adaptivity is turned on." - required_objects = 'OpenMCCellAverageProblem' - [] -[]