diff --git a/CMakeLists.txt b/CMakeLists.txt index 250d5aa..c205b64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,12 @@ if( NDItk.python ) pybind11_add_module( NDItk.python python/src/NDItk.python.cpp python/src/MultigroupTable.python.cpp + python/src/depletion.python.cpp + python/src/depletion/ReactionMultiplicityType.python.cpp + python/src/depletion/Multiplicities.python.cpp + python/src/depletion/ReactionMultiplicities.python.cpp python/src/multigroup.python.cpp + python/src/multigroup/FissionType.python.cpp python/src/multigroup/Metadata.python.cpp python/src/multigroup/CrossSection.python.cpp python/src/multigroup/FluxWeights.python.cpp diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index 0129499..bb33417 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -35,6 +35,9 @@ add_subdirectory( src/NDItk/base/RealListRecord/test ) add_subdirectory( src/NDItk/base/StringListRecord/test ) add_subdirectory( src/NDItk/base/InformationRecord/test ) +add_subdirectory( src/NDItk/depletion/Multiplicities/test ) +add_subdirectory( src/NDItk/depletion/ReactionMultiplicities/test ) + add_subdirectory( src/NDItk/multigroup/Metadata/test ) add_subdirectory( src/NDItk/multigroup/EnergyGroupStructure/test ) add_subdirectory( src/NDItk/multigroup/FluxWeights/test ) diff --git a/cmake/unit_testing_python.cmake b/cmake/unit_testing_python.cmake index 1c88d6e..1d09388 100644 --- a/cmake/unit_testing_python.cmake +++ b/cmake/unit_testing_python.cmake @@ -22,6 +22,9 @@ endfunction() message( STATUS "Adding NDItk Python unit testing" ) +add_python_test( depletion.Multiplicities depletion/Test_NDItk_depletion_Multiplicities.py ) +add_python_test( depletion.ReactionMultiplicities depletion/Test_NDItk_depletion_ReactionMultiplicities.py ) + add_python_test( multigroup.Metadata multigroup/Test_NDItk_multigroup_Metadata.py ) add_python_test( multigroup.CrossSection multigroup/Test_NDItk_multigroup_CrossSection.py ) add_python_test( multigroup.FluxWeights multigroup/Test_NDItk_multigroup_FluxWeights.py ) diff --git a/python/src/NDItk.python.cpp b/python/src/NDItk.python.cpp index 9621c4d..d79ab73 100644 --- a/python/src/NDItk.python.cpp +++ b/python/src/NDItk.python.cpp @@ -10,6 +10,7 @@ namespace python = pybind11; // declarations // declarations - record and subrecord subpackages +void wrapDepletion( python::module&, python::module& ); void wrapMultigroup( python::module&, python::module& ); // declarations - NDI table types @@ -33,6 +34,7 @@ PYBIND11_MODULE( NDItk, module ) { ); // record and subrecord subpackages + wrapDepletion( module, viewmodule ); wrapMultigroup( module, viewmodule ); // wrap ACE table types diff --git a/python/src/depletion.python.cpp b/python/src/depletion.python.cpp new file mode 100644 index 0000000..dbc5c25 --- /dev/null +++ b/python/src/depletion.python.cpp @@ -0,0 +1,32 @@ +// system includes +#include +#include + +// local includes + +// namespace aliases +namespace python = pybind11; + +namespace depletion { + + // declarations - NDI enumerators + void wrapReactionMultiplicityType( python::module&, python::module& ); + + // declarations - NDI records and subrecords + void wrapMultiplicities( python::module&, python::module& ); + void wrapReactionMultiplicities( python::module&, python::module& ); +} + +void wrapDepletion( python::module& module, python::module& viewmodule ) { + + // create the submodule + python::module submodule = module.def_submodule( + + "depletion", + "Depeltion NDI records and subrecords" + ); + + depletion::wrapReactionMultiplicityType( submodule, viewmodule ); + depletion::wrapMultiplicities( submodule, viewmodule ); + depletion::wrapReactionMultiplicities( submodule, viewmodule ); +} diff --git a/python/src/depletion/Multiplicities.python.cpp b/python/src/depletion/Multiplicities.python.cpp new file mode 100644 index 0000000..9af72c9 --- /dev/null +++ b/python/src/depletion/Multiplicities.python.cpp @@ -0,0 +1,75 @@ +// system includes +#include +#include + +// local includes +#include "NDItk/depletion/Multiplicities.hpp" +#include "tools/views/views-python.hpp" +#include "definitions.hpp" + +// namespace aliases +namespace python = pybind11; + +namespace depletion { + +void wrapMultiplicities( python::module& module, python::module& ) { + + // type aliases + using Record = njoy::NDItk::depletion::Multiplicities; + + // wrap views created by this record + + // create the record + python::class_< Record > record( + + module, + "Multiplicities", + "A reaction product multiplicity subrecord for depletion data" + ); + + // wrap the record + record + .def( + + python::init< int, std::vector< int >, std::vector< int > >(), + python::arg( "reaction" ), python::arg( "products" ), + python::arg( "multiplicities" ), + "Initialise the subrecord\n\n" + "Arguments:\n" + " self the record\n" + " reaction the reaction number\n" + " products the reaction product identifiers\n" + " multiplicities the multiplicity values" + ) + .def_property_readonly( + + "identifier", + &Record::identifier, + "The reaction identifier" + ) + .def_property_readonly( + + "number_reaction_products", + &Record::numberReactionProducts, + "The number of reaction products" + ) + .def_property_readonly( + + "reaction_products", + [] ( const Record& self ) -> IntRange + { return self.reactionProducts(); }, + "The reaction product identifiers" + ) + .def_property_readonly( + + "multiplicities", + [] ( const Record& self ) -> IntRange + { return self.multiplicities(); }, + "The reaction product multiplicities" + ); + + // add standard record definitions + addStandardSubrecordDefinitions< Record, IntRange >( record ); +} + +} // depletion namespace diff --git a/python/src/depletion/ReactionMultiplicities.python.cpp b/python/src/depletion/ReactionMultiplicities.python.cpp new file mode 100644 index 0000000..c271f68 --- /dev/null +++ b/python/src/depletion/ReactionMultiplicities.python.cpp @@ -0,0 +1,103 @@ +// system includes +#include +#include + +// local includes +#include "NDItk/depletion/ReactionMultiplicities.hpp" +#include "tools/views/views-python.hpp" +#include "definitions.hpp" +#include "read.hpp" + +// namespace aliases +namespace python = pybind11; + +namespace depletion { + +void wrapReactionMultiplicities( python::module& module, python::module& ) { + + // type aliases + using Record = njoy::NDItk::depletion::ReactionMultiplicities; + using Multiplicities = njoy::NDItk::depletion::Multiplicities; + using ReactionMultiplicityType = njoy::NDItk::depletion::ReactionMultiplicityType; + + // wrap views created by this record + + // create the record + python::class_< Record > record( + + module, + "ReactionMultiplicities", + "A reaction product multiplicity record for depletion data" + ); + + // wrap the record + record + .def( + + python::init< std::vector< Multiplicities > >(), + python::arg( "multiplicities" ), + "Initialise the record\n\n" + "Arguments:\n" + " self the record\n" + " multiplicities the multiplicity data" + ) + .def( + + python::init< const ReactionMultiplicityType&, + std::vector< Multiplicities > >(), + python::arg( "type" ),python::arg( "multiplicities" ), + "Initialise the record\n\n" + "Arguments:\n" + " self the record\n" + " type the multiplicity type (all, few or rmo)\n" + " multiplicities the multiplicity data" + ) + .def_property_readonly( + + "number_reactions", + &Record::numberReactions, + "The number of reactions defined by this record" + ) + .def_property_readonly( + + "reactions", + &Record::reactions, + "The multiplicity data for all reactions" + ) + .def( + + "has_reaction", + &Record::hasReaction, + python::arg( "reaction" ), + "Return whether or not a given reaction is present\n\n" + " self the record\n" + " reaction the reaction to look for" + ) + .def( + + "reaction", + &Record::reaction, + python::arg( "reaction" ), + "Return the multiplicity data for a given reaction\n\n" + " self the record\n" + " reaction the reaction to look for" + ) + .def_static( + + "from_string", + [] ( const std::string& string, unsigned int reactions ) -> Record + { return readWithMultiplicitySubtype< Record >( string, reactions ); }, + python::arg( "string" ), python::arg( "reactions" ), + "Read the record from a string\n\n" + "An exception is raised if something goes wrong while reading the\n" + "record\n\n" + "Arguments:\n" + " string the string representing the record\n" + " reactions the number of reactions to be read" + ); + + // add standard record definitions + addStandardRecordDefinitions< Record, DoubleRange >( record ); +} + +} // depletion namespace diff --git a/python/src/depletion/ReactionMultiplicityType.python.cpp b/python/src/depletion/ReactionMultiplicityType.python.cpp new file mode 100644 index 0000000..3284800 --- /dev/null +++ b/python/src/depletion/ReactionMultiplicityType.python.cpp @@ -0,0 +1,36 @@ +// system includes +#include +#include + +// local includes +#include "NDItk/depletion/ReactionMultiplicityType.hpp" + +// namespace aliases +namespace python = pybind11; + +namespace depletion { + +void wrapReactionMultiplicityType( python::module& module, python::module& ) { + + // type aliases + using Component = njoy::NDItk::depletion::ReactionMultiplicityType; + + // wrap views created by this component + + // create the component + python::enum_< Component > component( + + module, + "ReactionMultiplicityType", + "The reaction multiplicity types", + python::arithmetic() + ); + + // wrap the component + component + .value( "All", Component::All ) + .value( "Few", Component::Few ) + .value( "RMO", Component::RMO ); +} + +} // namespace depletion \ No newline at end of file diff --git a/python/src/multigroup.python.cpp b/python/src/multigroup.python.cpp index d54e26b..7cbf996 100644 --- a/python/src/multigroup.python.cpp +++ b/python/src/multigroup.python.cpp @@ -10,6 +10,7 @@ namespace python = pybind11; namespace multigroup { // declarations - NDI records and subrecords + void wrapFissionType( python::module&, python::module& ); void wrapMetadata( python::module&, python::module& ); void wrapCrossSection( python::module&, python::module& ); void wrapFluxWeights( python::module&, python::module& ); @@ -35,6 +36,7 @@ void wrapMultigroup( python::module& module, python::module& viewmodule ) { "Multigroup neutron and photon NDI records and subrecords" ); + multigroup::wrapFissionType( submodule, viewmodule ); multigroup::wrapMetadata( submodule, viewmodule ); multigroup::wrapCrossSection( submodule, viewmodule ); multigroup::wrapFluxWeights( submodule, viewmodule ); diff --git a/python/src/multigroup/EnergyGroupStructure.python.cpp b/python/src/multigroup/EnergyGroupStructure.python.cpp index f50f7e6..a9b5c45 100644 --- a/python/src/multigroup/EnergyGroupStructure.python.cpp +++ b/python/src/multigroup/EnergyGroupStructure.python.cpp @@ -65,7 +65,7 @@ void wrapEnergyGroupStructure( python::module& module, python::module& ) { "from_string", [] ( const std::string& string, unsigned int number ) -> Record - { return readWithSubtype< Record >( string, number ); }, + { return readWithParticleSubtype< Record >( string, number ); }, python::arg( "string" ), python::arg( "number" ), "Read the record from a string\n\n" "An exception is raised if something goes wrong while reading the\n" diff --git a/python/src/multigroup/FissionType.python.cpp b/python/src/multigroup/FissionType.python.cpp new file mode 100644 index 0000000..ee14acb --- /dev/null +++ b/python/src/multigroup/FissionType.python.cpp @@ -0,0 +1,36 @@ +// system includes +#include +#include + +// local includes +#include "NDItk/multigroup/FissionType.hpp" + +// namespace aliases +namespace python = pybind11; + +namespace multigroup { + +void wrapFissionType( python::module& module, python::module& ) { + + // type aliases + using Component = njoy::NDItk::multigroup::FissionType; + + // wrap views created by this component + + // create the component + python::enum_< Component > component( + + module, + "FissionType", + "The fission data types", + python::arithmetic() + ); + + // wrap the component + component + .value( "Prompt", Component::Prompt ) + .value( "Delayed", Component::Delayed ) + .value( "Total", Component::Total ); +} + +} // namespace multigroup \ No newline at end of file diff --git a/python/src/multigroup/HeatingNumbers.python.cpp b/python/src/multigroup/HeatingNumbers.python.cpp index eb7389d..5753ec8 100644 --- a/python/src/multigroup/HeatingNumbers.python.cpp +++ b/python/src/multigroup/HeatingNumbers.python.cpp @@ -65,7 +65,7 @@ void wrapHeatingNumbers( python::module& module, python::module& ) { "from_string", [] ( const std::string& string, unsigned int number ) -> Record - { return readWithSubtype< Record >( string, number ); }, + { return readWithParticleSubtype< Record >( string, number ); }, python::arg( "string" ), python::arg( "number" ), "Read the record from a string\n\n" "An exception is raised if something goes wrong while reading the\n" diff --git a/python/src/multigroup/Kerma.python.cpp b/python/src/multigroup/Kerma.python.cpp index 6c7780f..2128387 100644 --- a/python/src/multigroup/Kerma.python.cpp +++ b/python/src/multigroup/Kerma.python.cpp @@ -65,7 +65,7 @@ void wrapKerma( python::module& module, python::module& ) { "from_string", [] ( const std::string& string, unsigned int number ) -> Record - { return readWithSubtype< Record >( string, number ); }, + { return readWithParticleSubtype< Record >( string, number ); }, python::arg( "string" ), python::arg( "number" ), "Read the record from a string\n\n" "An exception is raised if something goes wrong while reading the\n" diff --git a/python/src/multigroup/ScatteringMatrix.python.cpp b/python/src/multigroup/ScatteringMatrix.python.cpp index 37c3a31..6d7fd6b 100644 --- a/python/src/multigroup/ScatteringMatrix.python.cpp +++ b/python/src/multigroup/ScatteringMatrix.python.cpp @@ -103,7 +103,7 @@ void wrapScatteringMatrix( python::module& module, python::module& ) { "from_string", [] ( const std::string& string, unsigned int incident, unsigned int number ) -> Record - { return readWithSubtype< Record >( string, incident, number ); }, + { return readWithParticleSubtype< Record >( string, incident, number ); }, python::arg( "string" ), python::arg( "incident" ), python::arg( "number" ), "Read the record from a string\n\n" @@ -119,7 +119,7 @@ void wrapScatteringMatrix( python::module& module, python::module& ) { "from_string", [] ( const std::string& string, unsigned int incident, unsigned int outgoing, unsigned int number ) -> Record - { return readWithSubtype< Record >( string, incident, outgoing, number ); }, + { return readWithParticleSubtype< Record >( string, incident, outgoing, number ); }, python::arg( "string" ), python::arg( "incident" ), python::arg( "outgoing" ), python::arg( "number" ), "Read the record from a string\n\n" diff --git a/python/src/read.hpp b/python/src/read.hpp index 224b059..68b7960 100644 --- a/python/src/read.hpp +++ b/python/src/read.hpp @@ -41,12 +41,12 @@ Record read( const std::string& string, Arguments... arguments ) { } /** - * @brief Read a record from a string (subtype record) + * @brief Read a record from a string (particle subtype record) * * @param[in] string the string to read from */ template < typename Record, typename... Arguments > -Record readWithSubtype( const std::string& string, Arguments... arguments ) { +Record readWithParticleSubtype( const std::string& string, Arguments... arguments ) { using namespace njoy::tools; using namespace njoy::NDItk; @@ -75,4 +75,77 @@ Record readWithSubtype( const std::string& string, Arguments... arguments ) { throw std::exception(); } } + +/** + * @brief Read a record from a string (multiplicity subtype record) + * + * @param[in] string the string to read from + */ +template < typename Record, typename... Arguments > +Record readWithMultiplicitySubtype( const std::string& string, Arguments... arguments ) { + + using namespace njoy::tools; + using namespace njoy::NDItk; + + Record record; + auto iter = string.begin(); + auto end = string.end(); + + base::Keyword key( disco::FreeFormatCharacter::read< std::string >( iter, end ) ); + if ( key.multiplicityType().has_value() ) { + + record = Record( key.multiplicityType().value() ); + } + if ( key.keyword() == record.keyword() ) { + + record.read( iter, end, arguments... ); + + //! @todo verify the string is now empty + return record; + } + else { + + Log::error( "The record keyword is not the one expected" ); + Log::info( "Expected: \'{}\'", record.keyword() ); + Log::info( "Found: \'{}\'", key.keyword() ); + throw std::exception(); + } +} + +/** + * @brief Read a record from a string (fission subtype record) + * + * @param[in] string the string to read from + */ +template < typename Record, typename... Arguments > +Record readWithFissionSubtype( const std::string& string, Arguments... arguments ) { + + using namespace njoy::tools; + using namespace njoy::NDItk; + + Record record; + auto iter = string.begin(); + auto end = string.end(); + + base::Keyword key( disco::FreeFormatCharacter::read< std::string >( iter, end ) ); + if ( key.fissionType().has_value() ) { + + record = Record( key.fissionType().value() ); + } + if ( key.keyword() == record.keyword() ) { + + record.read( iter, end, arguments... ); + + //! @todo verify the string is now empty + return record; + } + else { + + Log::error( "The record keyword is not the one expected" ); + Log::info( "Expected: \'{}\'", record.keyword() ); + Log::info( "Found: \'{}\'", key.keyword() ); + throw std::exception(); + } +} + #endif diff --git a/python/test/Test_NDItk_MultigroupTable.py b/python/test/Test_NDItk_MultigroupTable.py index 57034e3..93150f1 100644 --- a/python/test/Test_NDItk_MultigroupTable.py +++ b/python/test/Test_NDItk_MultigroupTable.py @@ -149,6 +149,8 @@ def verify_chunk( self, chunk ) : self.assertEqual( 7, matrix.number_outgoing_groups ) self.assertEqual( 2, matrix.number_legendre_moments ) moment = matrix.moment( 0 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 7, len( moment.matrix[0] ) ) self.assertEqual( 0, moment.order ) self.assertAlmostEqual( 1, moment.matrix[0][0] ) self.assertAlmostEqual( 0, moment.matrix[0][1] ) @@ -200,6 +202,8 @@ def verify_chunk( self, chunk ) : self.assertAlmostEqual( 0, moment.matrix[6][5] ) self.assertAlmostEqual( 1, moment.matrix[6][6] ) moment = matrix.moment( 1 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 7, len( moment.matrix[0] ) ) self.assertEqual( 1, moment.order ) self.assertAlmostEqual( 0, moment.matrix[0][0] ) self.assertAlmostEqual( 0, moment.matrix[0][1] ) @@ -293,6 +297,8 @@ def verify_chunk( self, chunk ) : self.assertEqual( 3, matrix.number_outgoing_groups ) self.assertEqual( 2, matrix.number_legendre_moments ) moment = matrix.moment( 0 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 3, len( moment.matrix[0] ) ) self.assertEqual( 0, moment.order ) self.assertAlmostEqual( 1, moment.matrix[0][0] ) self.assertAlmostEqual( 0, moment.matrix[0][1] ) @@ -316,6 +322,8 @@ def verify_chunk( self, chunk ) : self.assertAlmostEqual( 0, moment.matrix[6][1] ) self.assertAlmostEqual( 1, moment.matrix[6][2] ) moment = matrix.moment( 1 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 3, len( moment.matrix[0] ) ) self.assertEqual( 1, moment.order ) self.assertAlmostEqual( 0, moment.matrix[0][0] ) self.assertAlmostEqual( 0, moment.matrix[0][1] ) @@ -349,6 +357,8 @@ def verify_chunk( self, chunk ) : self.assertEqual( 2, matrix.number_outgoing_groups ) self.assertEqual( 2, matrix.number_legendre_moments ) moment = matrix.moment( 0 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 2, len( moment.matrix[0] ) ) self.assertEqual( 0, moment.order ) self.assertAlmostEqual( 1, moment.matrix[0][0] ) self.assertAlmostEqual( 0, moment.matrix[0][1] ) @@ -365,6 +375,8 @@ def verify_chunk( self, chunk ) : self.assertAlmostEqual( 1, moment.matrix[6][0] ) self.assertAlmostEqual( 0, moment.matrix[6][1] ) moment = matrix.moment( 1 ) + self.assertEqual( 7, len( moment.matrix ) ) + self.assertEqual( 2, len( moment.matrix[0] ) ) self.assertEqual( 1, moment.order ) self.assertAlmostEqual( 0, moment.matrix[0][0] ) self.assertAlmostEqual( 1, moment.matrix[0][1] ) diff --git a/python/test/depletion/Test_NDItk_depletion_Multiplicities.py b/python/test/depletion/Test_NDItk_depletion_Multiplicities.py new file mode 100644 index 0000000..7a6f859 --- /dev/null +++ b/python/test/depletion/Test_NDItk_depletion_Multiplicities.py @@ -0,0 +1,51 @@ +# standard imports +import unittest + +# third party imports + +# local imports +from NDItk.depletion import Multiplicities + +class Test_NDItk_depletion_Multiplicities( unittest.TestCase ) : + """Unit test for the Multiplicities class.""" + + chunk_values = [ 16, 2, 1, 2, 92234, 1 ] + chunk_string = ( ' 16\n' + ' 2\n' + ' 1 2\n' + ' 92234 1\n' ) + + def test_component( self ) : + + def verify_chunk( self, chunk ) : + + # verify content + self.assertEqual( 2, chunk.number_reaction_products ) + self.assertEqual( 2, len( chunk.reaction_products ) ) + self.assertEqual( 2, len( chunk.multiplicities ) ) + self.assertEqual( 16, chunk.identifier ) + self.assertEqual( 1, chunk.reaction_products[0] ) + self.assertEqual( 92234, chunk.reaction_products[1] ) + self.assertEqual( 2, chunk.multiplicities[0] ) + self.assertEqual( 1, chunk.multiplicities[1] ) + + self.assertEqual( self.chunk_string, chunk.to_string() ) + + # verify the record + self.assertEqual( False, chunk.empty ) + self.assertEqual( 6, chunk.size ) + + values = chunk.values + for index in range( chunk.size ) : + + self.assertAlmostEqual( self.chunk_values[index], values[index] ) + + # the data is given explicitly + chunk = Multiplicities( reaction = 16, products = [ 1, 92234 ], + multiplicities = [ 2, 1 ] ) + + verify_chunk( self, chunk ) + +if __name__ == '__main__' : + + unittest.main() diff --git a/python/test/depletion/Test_NDItk_depletion_ReactionMultiplicities.py b/python/test/depletion/Test_NDItk_depletion_ReactionMultiplicities.py new file mode 100644 index 0000000..b377732 --- /dev/null +++ b/python/test/depletion/Test_NDItk_depletion_ReactionMultiplicities.py @@ -0,0 +1,180 @@ +# standard imports +import unittest + +# third party imports + +# local imports +from NDItk.depletion import ReactionMultiplicities +from NDItk.depletion import Multiplicities +from NDItk.depletion import ReactionMultiplicityType + +class Test_NDItk_depletion_ReactionMultiplicities( unittest.TestCase ) : + """Unit test for the ReactionMultiplicities class.""" + + chunk_values = [ 2, 2, 1, 1, 92235, 1, 16, 2, 1, 2, 92234, 1 ] + chunk_string = ( 'rprod\n' + ' 2\n' + ' 2\n' + ' 1 1\n' + ' 92235 1\n' + ' 16\n' + ' 2\n' + ' 1 2\n' + ' 92234 1\n' ) + + chunk_typed_string = ( 'rprod_all\n' + ' 2\n' + ' 2\n' + ' 1 1\n' + ' 92235 1\n' + ' 16\n' + ' 2\n' + ' 1 2\n' + ' 92234 1\n' ) + + def test_component( self ) : + + def verify_chunk( self, chunk ) : + + # verify content + self.assertEqual( 2, chunk.number_reactions ) + + self.assertEqual( True, chunk.has_reaction( 2 ) ) + self.assertEqual( True, chunk.has_reaction( 16 ) ) + self.assertEqual( False, chunk.has_reaction( 102 ) ) + + self.assertEqual( 2, chunk.reactions[0].identifier ) + self.assertEqual( 2, chunk.reactions[0].number_reaction_products ) + self.assertEqual( 2, len( chunk.reactions[0].reaction_products ) ) + self.assertEqual( 2, len( chunk.reactions[0].multiplicities ) ) + self.assertEqual( 1, chunk.reactions[0].reaction_products[0] ) + self.assertEqual( 92235, chunk.reactions[0].reaction_products[1] ) + self.assertEqual( 1, chunk.reactions[0].multiplicities[0] ) + self.assertEqual( 1, chunk.reactions[0].multiplicities[1] ) + + self.assertEqual( 16, chunk.reactions[1].identifier ) + self.assertEqual( 2, chunk.reactions[1].number_reaction_products ) + self.assertEqual( 2, len( chunk.reactions[1].reaction_products ) ) + self.assertEqual( 2, len( chunk.reactions[1].multiplicities ) ) + self.assertEqual( 1, chunk.reactions[1].reaction_products[0] ) + self.assertEqual( 92234, chunk.reactions[1].reaction_products[1] ) + self.assertEqual( 2, chunk.reactions[1].multiplicities[0] ) + self.assertEqual( 1, chunk.reactions[1].multiplicities[1] ) + + multiplicities = chunk.reaction( 2 ) + self.assertEqual( 2, multiplicities.identifier ) + self.assertEqual( 2, multiplicities.number_reaction_products ) + self.assertEqual( 2, len( multiplicities.reaction_products ) ) + self.assertEqual( 2, len( multiplicities.multiplicities ) ) + self.assertEqual( 1, multiplicities.reaction_products[0] ) + self.assertEqual( 92235, multiplicities.reaction_products[1] ) + self.assertEqual( 1, multiplicities.multiplicities[0] ) + self.assertEqual( 1, multiplicities.multiplicities[1] ) + + multiplicities = chunk.reaction( 16 ) + self.assertEqual( 2, multiplicities.number_reaction_products ) + self.assertEqual( 2, len( multiplicities.reaction_products ) ) + self.assertEqual( 2, len( multiplicities.multiplicities ) ) + self.assertEqual( 1, multiplicities.reaction_products[0] ) + self.assertEqual( 92234, multiplicities.reaction_products[1] ) + self.assertEqual( 2, multiplicities.multiplicities[0] ) + self.assertEqual( 1, multiplicities.multiplicities[1] ) + + self.assertEqual( self.chunk_string, chunk.to_string() ) + + # verify the record + self.assertEqual( 'rprod', chunk.keyword ) + self.assertEqual( False, chunk.empty ) + self.assertEqual( 12, chunk.size ) + + values = chunk.values + for index in range( chunk.size ) : + + self.assertAlmostEqual( self.chunk_values[index], values[index] ) + + def verify_chunk_typed( self, chunk ) : + + # verify content + self.assertEqual( 2, chunk.number_reactions ) + + self.assertEqual( True, chunk.has_reaction( 2 ) ) + self.assertEqual( True, chunk.has_reaction( 16 ) ) + self.assertEqual( False, chunk.has_reaction( 102 ) ) + + self.assertEqual( 2, chunk.reactions[0].identifier ) + self.assertEqual( 2, chunk.reactions[0].number_reaction_products ) + self.assertEqual( 2, len( chunk.reactions[0].reaction_products ) ) + self.assertEqual( 2, len( chunk.reactions[0].multiplicities ) ) + self.assertEqual( 1, chunk.reactions[0].reaction_products[0] ) + self.assertEqual( 92235, chunk.reactions[0].reaction_products[1] ) + self.assertEqual( 1, chunk.reactions[0].multiplicities[0] ) + self.assertEqual( 1, chunk.reactions[0].multiplicities[1] ) + + self.assertEqual( 16, chunk.reactions[1].identifier ) + self.assertEqual( 2, chunk.reactions[1].number_reaction_products ) + self.assertEqual( 2, len( chunk.reactions[1].reaction_products ) ) + self.assertEqual( 2, len( chunk.reactions[1].multiplicities ) ) + self.assertEqual( 1, chunk.reactions[1].reaction_products[0] ) + self.assertEqual( 92234, chunk.reactions[1].reaction_products[1] ) + self.assertEqual( 2, chunk.reactions[1].multiplicities[0] ) + self.assertEqual( 1, chunk.reactions[1].multiplicities[1] ) + + multiplicities = chunk.reaction( 2 ) + self.assertEqual( 2, multiplicities.identifier ) + self.assertEqual( 2, multiplicities.number_reaction_products ) + self.assertEqual( 2, len( multiplicities.reaction_products ) ) + self.assertEqual( 2, len( multiplicities.multiplicities ) ) + self.assertEqual( 1, multiplicities.reaction_products[0] ) + self.assertEqual( 92235, multiplicities.reaction_products[1] ) + self.assertEqual( 1, multiplicities.multiplicities[0] ) + self.assertEqual( 1, multiplicities.multiplicities[1] ) + + multiplicities = chunk.reaction( 16 ) + self.assertEqual( 2, multiplicities.number_reaction_products ) + self.assertEqual( 2, len( multiplicities.reaction_products ) ) + self.assertEqual( 2, len( multiplicities.multiplicities ) ) + self.assertEqual( 1, multiplicities.reaction_products[0] ) + self.assertEqual( 92234, multiplicities.reaction_products[1] ) + self.assertEqual( 2, multiplicities.multiplicities[0] ) + self.assertEqual( 1, multiplicities.multiplicities[1] ) + + self.assertEqual( self.chunk_typed_string, chunk.to_string() ) + + # verify the record + self.assertEqual( 'rprod_all', chunk.keyword ) + self.assertEqual( False, chunk.empty ) + self.assertEqual( 12, chunk.size ) + + values = chunk.values + for index in range( chunk.size ) : + + self.assertAlmostEqual( self.chunk_values[index], values[index] ) + + # the data is given explicitly + chunk = ReactionMultiplicities( + multiplicities = [ Multiplicities( 2, [ 1, 92235 ], [ 1, 1 ] ), + Multiplicities( 16, [ 1, 92234 ], [ 2, 1 ] ) ] ) + + verify_chunk( self, chunk ) + + # the data is read from a string + chunk = ReactionMultiplicities.from_string( self.chunk_string, 2 ) + + verify_chunk( self, chunk ) + + # the data is given explicitly with a multiplicty type + chunk = ReactionMultiplicities( + type = ReactionMultiplicityType.All, + multiplicities = [ Multiplicities( 2, [ 1, 92235 ], [ 1, 1 ] ), + Multiplicities( 16, [ 1, 92234 ], [ 2, 1 ] ) ] ) + + verify_chunk_typed( self, chunk ) + + # the data is read from a string + chunk = ReactionMultiplicities.from_string( self.chunk_typed_string, 2 ) + + verify_chunk_typed( self, chunk ) + +if __name__ == '__main__' : + + unittest.main() diff --git a/python/test/depletion/__init__.py b/python/test/depletion/__init__.py new file mode 100644 index 0000000..5eeec73 --- /dev/null +++ b/python/test/depletion/__init__.py @@ -0,0 +1 @@ +# empty __init__.py diff --git a/src/NDItk/MultigroupTable.hpp b/src/NDItk/MultigroupTable.hpp index 254162c..29ea86c 100644 --- a/src/NDItk/MultigroupTable.hpp +++ b/src/NDItk/MultigroupTable.hpp @@ -5,6 +5,7 @@ // other includes #include "tools/Log.hpp" +#include "NDItk/depletion/ReactionMultiplicities.hpp" #include "NDItk/multigroup/Metadata.hpp" #include "NDItk/multigroup/EnergyGroupStructure.hpp" #include "NDItk/multigroup/Velocities.hpp" @@ -38,6 +39,9 @@ class MultigroupTable { multigroup::AverageFissionEnergyRelease release_; multigroup::HeatingNumbers primary_heating_; multigroup::Kerma primary_kerma_; + depletion::ReactionMultiplicities product_multiplicities_all_; + depletion::ReactionMultiplicities product_multiplicities_few_; + depletion::ReactionMultiplicities product_multiplicities_rmo_; multigroup::OutgoingParticleTypes outgoing_particles_; multigroup::OutgoingParticleTransportData outgoing_zaids_; std::vector< multigroup::EnergyGroupStructure > outgoing_structure_; @@ -276,6 +280,9 @@ class MultigroupTable { this->release_.print( iter ); this->primary_heating_.print( iter ); this->primary_kerma_.print( iter ); + this->product_multiplicities_all_.print( iter ); + this->product_multiplicities_few_.print( iter ); + this->product_multiplicities_rmo_.print( iter ); this->outgoing_particles_.print( iter ); this->outgoing_zaids_.print( iter ); for ( const auto& entry : this->outgoing_structure_ ) { entry.print( iter ); } diff --git a/src/NDItk/MultigroupTable/src/ctor.hpp b/src/NDItk/MultigroupTable/src/ctor.hpp index a439abe..d754ffd 100644 --- a/src/NDItk/MultigroupTable/src/ctor.hpp +++ b/src/NDItk/MultigroupTable/src/ctor.hpp @@ -5,6 +5,9 @@ MultigroupTable() : metadata_(), primary_structure_(), velocities_(), weights_(), total_(), xs_(), scattering_(), release_(), primary_heating_(), primary_kerma_(), + product_multiplicities_all_( depletion::ReactionMultiplicityType::All ), + product_multiplicities_few_( depletion::ReactionMultiplicityType::Few ), + product_multiplicities_rmo_( depletion::ReactionMultiplicityType::RMO ), outgoing_particles_(), outgoing_zaids_(), outgoing_structure_(), outgoing_production_(), outgoing_heating_(), outgoing_kerma_() {} diff --git a/src/NDItk/MultigroupTable/src/read.hpp b/src/NDItk/MultigroupTable/src/read.hpp index 77714b7..7766c9c 100644 --- a/src/NDItk/MultigroupTable/src/read.hpp +++ b/src/NDItk/MultigroupTable/src/read.hpp @@ -182,6 +182,51 @@ void read( Iterator& iter, const Iterator& end ) { readOutgoingProductionMatrix( keyword, iter, end ); } + // reaction product multiplicities: all + else if ( keyword == this->product_multiplicities_all_.keyword() ) { + + if ( this->metadata_.numberReactions().has_value() ) { + + readRecord( this->product_multiplicities_all_, iter, end, + this->metadata_.numberReactions().value() ); + } + else { + + Log::error( "Metadata required for the \'\' record was not found", keyword ); + Log::info( "Required metadata is missing: number of reactions" ); + throw std::exception(); + } + } + // reaction product multiplicities: few + else if ( keyword == this->product_multiplicities_few_.keyword() ) { + + if ( this->metadata_.numberReactions().has_value() ) { + + readRecord( this->product_multiplicities_few_, iter, end, + this->metadata_.numberReactions().value() ); + } + else { + + Log::error( "Metadata required for the \'\' record was not found", keyword ); + Log::info( "Required metadata is missing: number of reactions" ); + throw std::exception(); + } + } + // reaction product multiplicities: rmo + else if ( keyword == this->product_multiplicities_rmo_.keyword() ) { + + if ( this->metadata_.numberReactions().has_value() ) { + + readRecord( this->product_multiplicities_rmo_, iter, end, + this->metadata_.numberReactions().value() ); + } + else { + + Log::error( "Metadata required for the \'\' record was not found", keyword ); + Log::info( "Required metadata is missing: number of reactions" ); + throw std::exception(); + } + } // unknown or end keyword else { diff --git a/src/NDItk/MultigroupTable/test/MultigroupTable.test.cpp b/src/NDItk/MultigroupTable/test/MultigroupTable.test.cpp index ec45e04..5332d4a 100644 --- a/src/NDItk/MultigroupTable/test/MultigroupTable.test.cpp +++ b/src/NDItk/MultigroupTable/test/MultigroupTable.test.cpp @@ -544,6 +544,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK( 7 == chunk.scatteringMatrix().numberOutgoingGroups() ); CHECK( 2 == chunk.scatteringMatrix().numberLegendreMoments() ); auto moment = chunk.scatteringMatrix().moment( 0 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 7 == moment.matrix()[0].size() ); CHECK( 0 == moment.order() ); CHECK_THAT( 1, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][1] ) ); @@ -595,6 +597,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK_THAT( 0, WithinRel( moment.matrix()[6][5] ) ); CHECK_THAT( 1, WithinRel( moment.matrix()[6][6] ) ); moment = chunk.scatteringMatrix().moment( 1 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 7 == moment.matrix()[0].size() ); CHECK( 1 == moment.order() ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][1] ) ); @@ -744,6 +748,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK( 3 == production.numberOutgoingGroups() ); CHECK( 2 == production.numberLegendreMoments() ); moment = production.moment( 0 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 3 == moment.matrix()[0].size() ); CHECK( 0 == moment.order() ); CHECK_THAT( 1, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][1] ) ); @@ -767,6 +773,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK_THAT( 0, WithinRel( moment.matrix()[6][1] ) ); CHECK_THAT( 1, WithinRel( moment.matrix()[6][2] ) ); moment = production.moment( 1 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 3 == moment.matrix()[0].size() ); CHECK( 1 == moment.order() ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][1] ) ); @@ -800,6 +808,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK( 2 == production.numberOutgoingGroups() ); CHECK( 2 == production.numberLegendreMoments() ); moment = production.moment( 0 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 2 == moment.matrix()[0].size() ); CHECK( 0 == moment.order() ); CHECK_THAT( 1, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][1] ) ); @@ -816,6 +826,8 @@ void verifyChunk( const MultigroupTable& chunk ) { CHECK_THAT( 1, WithinRel( moment.matrix()[6][0] ) ); CHECK_THAT( 0, WithinRel( moment.matrix()[6][1] ) ); moment = production.moment( 1 ); + CHECK( 7 == moment.matrix().size() ); + CHECK( 2 == moment.matrix()[0].size() ); CHECK( 1 == moment.order() ); CHECK_THAT( 0, WithinRel( moment.matrix()[0][0] ) ); CHECK_THAT( 1, WithinRel( moment.matrix()[0][1] ) ); diff --git a/src/NDItk/base/Keyword.hpp b/src/NDItk/base/Keyword.hpp index ecc3587..b78ff07 100644 --- a/src/NDItk/base/Keyword.hpp +++ b/src/NDItk/base/Keyword.hpp @@ -9,6 +9,8 @@ // other includes #include "tools/Log.hpp" +#include "NDItk/multigroup/FissionType.hpp" +#include "NDItk/depletion/ReactionMultiplicityType.hpp" namespace njoy { namespace NDItk { @@ -25,6 +27,8 @@ class Keyword { std::string keyword_; std::optional< std::string > subtype_ = std::nullopt; std::optional< unsigned int > particle_ = std::nullopt; + std::optional< depletion::ReactionMultiplicityType > multiplicity_ = std::nullopt; + std::optional< multigroup::FissionType > fission_ = std::nullopt; /* auxilairy functions */ #include "NDItk/base/Keyword/src/splitKeyword.hpp" @@ -55,6 +59,22 @@ class Keyword { */ const std::optional< unsigned int >& particle() const { return this->particle_; } + /** + * @brief Return the multiplicity type (if any) + */ + const std::optional< depletion::ReactionMultiplicityType >& multiplicityType() const { + + return this->multiplicity_; + } + + /** + * @brief Return the fission type (if any) + */ + const std::optional< multigroup::FissionType >& fissionType() const { + + return this->fission_; + } + /** * @brief Print the record keyword * diff --git a/src/NDItk/base/Keyword/src/ctor.hpp b/src/NDItk/base/Keyword/src/ctor.hpp index 08f17dd..0b1ac95 100644 --- a/src/NDItk/base/Keyword/src/ctor.hpp +++ b/src/NDItk/base/Keyword/src/ctor.hpp @@ -7,10 +7,14 @@ */ Keyword( std::tuple< std::string, std::optional< std::string >, - std::optional< int > > tuple ) : + std::optional< int >, + std::optional< depletion::ReactionMultiplicityType >, + std::optional< multigroup::FissionType > > tuple ) : keyword_( std::move( std::get< 0 >( tuple ) ) ), subtype_( std::move( std::get< 1 >( tuple ) ) ), - particle_( std::move( std::get< 2 >( tuple ) ) ) {} + particle_( std::move( std::get< 2 >( tuple ) ) ), + multiplicity_( std::move( std::get< 3 >( tuple ) ) ), + fission_( std::move( std::get< 4 >( tuple ) ) ) {} public: diff --git a/src/NDItk/base/Keyword/src/splitKeyword.hpp b/src/NDItk/base/Keyword/src/splitKeyword.hpp index 28f6b0e..b082f45 100644 --- a/src/NDItk/base/Keyword/src/splitKeyword.hpp +++ b/src/NDItk/base/Keyword/src/splitKeyword.hpp @@ -8,13 +8,17 @@ * * @param[in] keyword the keyword */ -static std::tuple< std::string, std::optional< std::string >, std::optional< int > > +static std::tuple< std::string, + std::optional< std::string >, + std::optional< int >, + std::optional< depletion::ReactionMultiplicityType >, + std::optional< multigroup::FissionType > > splitKeyword( std::string keyword ) { // special cases: sig_0 if ( "sig_0" == keyword ) { - return { std::move( keyword ), std::nullopt, std::nullopt }; + return { std::move( keyword ), std::nullopt, std::nullopt, std::nullopt, std::nullopt }; } else { @@ -22,21 +26,42 @@ splitKeyword( std::string keyword ) { // A key is basically xxx_yyy with an optional particle type at the end (the // full keyword would be xxx_yyy_0 for the xxx_yyy subtype keyword for gammas). // "([a-z]+(?:_[a-z]+)*)" captures the subtype part of the key, i.e. 'xxx_yyy' - // and "([0-9]+)" captures an optional particle type. - const std::regex key{ "^([a-z]+(?:_[a-z]+)*)(?:_([0-9]+))?" }; + // and "([0-9]+)" captures an optional particle type that must end the string. + const std::regex key{ "^([a-z]+(?:_[a-z]+)*)(?:_([0-9]+))?$" }; std::smatch match; if ( std::regex_match( keyword, match, key ) ) { if ( match[1] == keyword ) { - return { std::move( keyword ), std::nullopt, std::nullopt }; + const std::array< std::string, 6 > suffixes = { "_all", "_few", "_rmo", "_pr", "_del", "_tot" }; + for ( unsigned int i = 0; i < suffixes.size(); ++i ) { + + if ( keyword.size() >= suffixes[i].size() && + keyword.compare( keyword.size() - suffixes[i].size(), suffixes[i].size(), suffixes[i] ) == 0 ) { + + std::string subtype = keyword.substr( 0, keyword.size() - suffixes[i].size() ); + switch ( i ) { + + case 0 : return { std::move( keyword ), std::move( subtype ), std::nullopt, depletion::ReactionMultiplicityType::All, std::nullopt }; + case 1 : return { std::move( keyword ), std::move( subtype ), std::nullopt, depletion::ReactionMultiplicityType::Few, std::nullopt }; + case 2 : return { std::move( keyword ), std::move( subtype ), std::nullopt, depletion::ReactionMultiplicityType::RMO, std::nullopt }; + case 3 : return { std::move( keyword ), std::move( subtype ), std::nullopt, std::nullopt, multigroup::FissionType::Prompt }; + case 4 : return { std::move( keyword ), std::move( subtype ), std::nullopt, std::nullopt, multigroup::FissionType::Delayed }; + case 5 : return { std::move( keyword ), std::move( subtype ), std::nullopt, std::nullopt, multigroup::FissionType::Total }; + } + } + } + + return { std::move( keyword ), std::nullopt, std::nullopt, std::nullopt, std::nullopt }; } else { return { std::move( keyword ), std::make_optional( std::string( match[1] ) ), - std::make_optional( std::stoi( match[2] ) ) }; + std::make_optional( std::stoi( match[2] ) ), + std::nullopt , + std::nullopt}; } } diff --git a/src/NDItk/base/Keyword/test/Keyword.test.cpp b/src/NDItk/base/Keyword/test/Keyword.test.cpp index 93961c4..eea2837 100644 --- a/src/NDItk/base/Keyword/test/Keyword.test.cpp +++ b/src/NDItk/base/Keyword/test/Keyword.test.cpp @@ -18,42 +18,112 @@ SCENARIO( "Keyword" ) { CHECK( "num_grps" == result.keyword() ); CHECK( std::nullopt == result.subtype() ); CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( false == result.hasSubtype() ); result = Keyword( "num_grps_0" ); CHECK( "num_grps_0" == result.keyword() ); CHECK( "num_grps" == result.subtype() ); CHECK( 0 == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( true == result.hasSubtype() ); result = Keyword( "num_grps", 0 ); CHECK( "num_grps_0" == result.keyword() ); CHECK( "num_grps" == result.subtype() ); CHECK( 0 == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( true == result.hasSubtype() ); result = Keyword( "e_bounds_1001" ); CHECK( "e_bounds_1001" == result.keyword() ); CHECK( "e_bounds" == result.subtype() ); CHECK( 1001 == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( true == result.hasSubtype() ); result = Keyword( "e_bounds", 1001 ); CHECK( "e_bounds_1001" == result.keyword() ); CHECK( "e_bounds" == result.subtype() ); CHECK( 1001 == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( true == result.hasSubtype() ); result = Keyword( "sig_0" ); CHECK( "sig_0" == result.keyword() ); CHECK( std::nullopt == result.subtype() ); CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( false == result.hasSubtype() ); + result = Keyword( "rprod" ); + CHECK( "rprod" == result.keyword() ); + CHECK( std::nullopt == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); + CHECK( false == result.hasSubtype() ); + + result = Keyword( "rprod_all" ); + CHECK( "rprod_all" == result.keyword() ); + CHECK( "rprod" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( depletion::ReactionMultiplicityType::All == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + + result = Keyword( "rprod_few" ); + CHECK( "rprod_few" == result.keyword() ); + CHECK( "rprod" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( depletion::ReactionMultiplicityType::Few == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + + result = Keyword( "rprod_rmo" ); + CHECK( "rprod_rmo" == result.keyword() ); + CHECK( "rprod" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( depletion::ReactionMultiplicityType::RMO == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + + result = Keyword( "nu_pr" ); + CHECK( "nu_pr" == result.keyword() ); + CHECK( "nu" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( multigroup::FissionType::Prompt == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + + result = Keyword( "nu_del" ); + CHECK( "nu_del" == result.keyword() ); + CHECK( "nu" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( multigroup::FissionType::Delayed == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + + result = Keyword( "nu_tot" ); + CHECK( "nu_tot" == result.keyword() ); + CHECK( "nu" == result.subtype() ); + CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( multigroup::FissionType::Total == result.fissionType() ); + CHECK( true == result.hasSubtype() ); + result = Keyword( "num_sec_parts" ); CHECK( "num_sec_parts" == result.keyword() ); CHECK( std::nullopt == result.subtype() ); CHECK( std::nullopt == result.particle() ); + CHECK( std::nullopt == result.multiplicityType() ); + CHECK( std::nullopt == result.fissionType() ); CHECK( false == result.hasSubtype() ); CHECK_THROWS( Keyword( "NuM_GrPs" ) ); diff --git a/src/NDItk/depletion/Multiplicities.hpp b/src/NDItk/depletion/Multiplicities.hpp new file mode 100644 index 0000000..22b3c5c --- /dev/null +++ b/src/NDItk/depletion/Multiplicities.hpp @@ -0,0 +1,80 @@ +#ifndef NJOY_NDITK_DEPLETION_MULTIPLICITIES +#define NJOY_NDITK_DEPLETION_MULTIPLICITIES + +// system includes +#include +#include + +// other includes +#include "tools/std23/views.hpp" +#include "NDItk/base/SubListRecord.hpp" + +namespace njoy { +namespace NDItk { +namespace depletion { + +/** + * @brief A reaction product multiplicity subrecord for depletion data + */ +class Multiplicities : protected base::SubListRecord< Multiplicities, int > { + + friend class base::SubListRecord< Multiplicities, int >; + using Parent = base::SubListRecord< Multiplicities, int >; + + /* auxiliary functions */ + + #include "NDItk/depletion/Multiplicities/src/verify.hpp" + #include "NDItk/depletion/Multiplicities/src/generateData.hpp" + #include "NDItk/depletion/Multiplicities/src/write.hpp" + +public: + + /* constructor */ + + #include "NDItk/depletion/Multiplicities/src/ctor.hpp" + + /* methods */ + + /** + * @brief Return the reaction identifier + */ + int identifier() const { return this->value( 0 ); } + + /** + * @brief Return the number of reaction products + */ + int numberReactionProducts() const { return this->value( 1 ); } + + /** + * @brief Return the reaction product identifiers + */ + auto reactionProducts() const { + + using namespace njoy::tools; + return this->values( 2, 2 * this->numberReactionProducts() ) + | std23::views::stride( 2 ); + } + + /** + * @brief Return the reaction product multiplicities + */ + auto multiplicities() const { + + using namespace njoy::tools; + return this->values( 3, 2 * this->numberReactionProducts() ) + | std23::views::stride( 2 ); + } + + using Parent::values; + using Parent::size; + using Parent::empty; + using Parent::begin; + using Parent::end; + using Parent::print; +}; + +} // depletion namespace +} // NDItk namespace +} // njoy namespace + +#endif diff --git a/src/NDItk/depletion/Multiplicities/src/ctor.hpp b/src/NDItk/depletion/Multiplicities/src/ctor.hpp new file mode 100644 index 0000000..462d973 --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/src/ctor.hpp @@ -0,0 +1,25 @@ +/** + * @brief Constructor + * + * @param[in] reaction the reaction number + * @param[in] products the reaction product identifiers + * @param[in] multiplicities the multiplicity values + */ +Multiplicities( int reaction, std::vector< int > products, + std::vector< int > multiplicities ) : + Parent( generateData( reaction, std::move( products ), std::move( multiplicities ) ) ) { + + verify( this->values() ); +} + +/** + * @brief Constructor + * + * @param[in] begin the begin iterator of the cross section + * @param[in] end the end iterator of the cross section + */ +Multiplicities( Iterator begin, Iterator end ) : + Parent( begin, end ) { + + verify( this->values() ); +} diff --git a/src/NDItk/depletion/Multiplicities/src/generateData.hpp b/src/NDItk/depletion/Multiplicities/src/generateData.hpp new file mode 100644 index 0000000..ff7203e --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/src/generateData.hpp @@ -0,0 +1,28 @@ +/** + * @brief Generate the subrecord's data vector + * + * @param[in] reaction the reaction number + * @param[in] products the reaction product identifiers + * @param[in] multiplicities the multiplicity values + */ +static std::vector< int > +generateData( int reaction, std::vector< int > products, + std::vector< int > multiplicities ) { + + auto size = products.size(); + if ( multiplicities.size() != size ) { + + Log::error( "The number of reaction product identifiers and multiplicities " + "is inconsistent" ); + Log::info( "Found {} reaction product identifiers", products.size() ); + Log::info( "Found {} multiplicity values", multiplicities.size() ); + throw std::exception(); + } + std::vector< int > data = { reaction, static_cast< int >( size ) }; + for ( unsigned int i = 0; i < size; ++i ) { + + data.push_back( products[i] ); + data.push_back( multiplicities[i] ); + } + return data; +} diff --git a/src/NDItk/depletion/Multiplicities/src/verify.hpp b/src/NDItk/depletion/Multiplicities/src/verify.hpp new file mode 100644 index 0000000..a6eb854 --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/src/verify.hpp @@ -0,0 +1,38 @@ +/** + * @brief Verify the cross section data values + * + * The following verification tests are performed: + * - there are at least three values + * - the reaction identifier looks to be an integer + * + * @param[in] data the data values in the cross section subrecord + */ +template < typename Range > +static void verify( const Range& data ) { + + if ( data.size() < 2 ) { + + Log::error( "Expected at least 2 data values consisting of a reaction identifier,\n" + "and the number of reaction products" ); + Log::info( "Found {} data values", data.size() ); + throw std::exception(); + } + + if ( data[1] < 0 ) { + + Log::error( "The number of reaction products cannot be less than zero" ); + Log::info( "Found {} as the number of reaction products", data[1] ); + throw std::exception(); + } + + + if ( data.size() != 2 + 2 * data[1] ) { + + Log::error( "Expected at least {} data values consisting of a reaction identifier,\n" + "the number of reaction products (in this case equal to {}) followed\n" + "by {} reaction product identifier and multiplicity value pairs", + 2 + 2 * data[1], data[1], data[1] ); + Log::info( "Found {} data values", data.size() ); + throw std::exception(); + } +} diff --git a/src/NDItk/depletion/Multiplicities/src/write.hpp b/src/NDItk/depletion/Multiplicities/src/write.hpp new file mode 100644 index 0000000..39144bd --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/src/write.hpp @@ -0,0 +1,27 @@ +/** + * @brief Write the record data + * + * This assumes that the record is not empty. + * + * @param[in] iter the current position in the output + */ +template< typename OutputIterator > +void write( OutputIterator& iter ) const { + + std::ostringstream buffer; + + auto x = this->begin(); + buffer << " " << x[0] << '\n' + << " " << x[1] << '\n'; + x += 2; + + auto lines = this->numberReactionProducts(); + + while ( lines-- ) { + + buffer << " " << x[0] << ' ' << x[1] << '\n'; + x += 2; + } + + for ( auto c : buffer.str() ) { *iter++ = c; } +}; diff --git a/src/NDItk/depletion/Multiplicities/test/CMakeLists.txt b/src/NDItk/depletion/Multiplicities/test/CMakeLists.txt new file mode 100644 index 0000000..aa7bb3e --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/test/CMakeLists.txt @@ -0,0 +1 @@ +add_cpp_test( depletion.Multiplicities Multiplicities.test.cpp ) \ No newline at end of file diff --git a/src/NDItk/depletion/Multiplicities/test/Multiplicities.test.cpp b/src/NDItk/depletion/Multiplicities/test/Multiplicities.test.cpp new file mode 100644 index 0000000..c3555d4 --- /dev/null +++ b/src/NDItk/depletion/Multiplicities/test/Multiplicities.test.cpp @@ -0,0 +1,140 @@ +// include Catch2 +#include +#include +using Catch::Matchers::WithinRel; + +// what we are testing +#include "NDItk/depletion/Multiplicities.hpp" + +// other includes + +// convenience typedefs +using namespace njoy::NDItk; +using Multiplicities = depletion::Multiplicities; + +std::string chunk(); +std::vector< int > data(); +void verifyChunk( const Multiplicities& ); +std::vector< int > dataWithInsufficientLength(); + +SCENARIO( "Multiplicities" ) { + + GIVEN( "valid data for a Multiplicities instance" ) { + + std::string record = chunk(); + + WHEN( "the data is given explicitly" ) { + + int reaction = 16; + std::vector< int > products = { 1, 92234 }; + std::vector< int > multiplicities = { 2, 1 }; + + Multiplicities chunk( reaction, std::move( products ), std::move( multiplicities ) ); + + THEN( "a Multiplicities can be constructed and members can " + "be tested" ) { + + verifyChunk( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + + WHEN( "the data is defined using iterators" ) { + + std::vector< int > values = data(); + auto begin = values.begin(); + auto end = values.end(); + + Multiplicities chunk( begin, end ); + + THEN( "a Multiplicities can be constructed and members can " + "be tested" ) { + + verifyChunk( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "invalid data for a Multiplicities instance" ) { + + WHEN( "the number of reaction products and multiplcities is insufficient" ) { + + THEN( "an exception is thrown" ) { + + CHECK_THROWS( Multiplicities( 16, { 1, 92233 }, { 1 } ) ); + } // THEN + } // WHEN + + WHEN( "using iterators and the number of cross section values is " + "insufficient" ) { + + std::vector< int > values = dataWithInsufficientLength(); + auto begin = values.begin(); + auto end = values.end(); + + THEN( "an exception is thrown" ) { + + CHECK_THROWS( Multiplicities( begin, end ) ); + } // THEN + } // WHEN + } // GIVEN +} // SCENARIO + +std::string chunk() { + + return " 16\n" + " 2\n" + " 1 2\n" + " 92234 1\n"; +} + +std::vector< int > data() { + + return { 16, + 2, + 1, 2, 92234, 1 }; +} + +void verifyChunk( const Multiplicities& chunk ) { + + CHECK( 16 == chunk.values()[0] ); + CHECK( 2 == chunk.values()[1] ); + CHECK( 1 == chunk.values()[2] ); + CHECK( 2 == chunk.values()[3] ); + CHECK( 92234 == chunk.values()[4] ); + CHECK( 1 == chunk.values()[5] ); + + CHECK( false == chunk.empty() ); + CHECK( 6 == chunk.size() ); + + CHECK( 2 == chunk.numberReactionProducts() ); + CHECK( 2 == chunk.reactionProducts().size() ); + CHECK( 2 == chunk.multiplicities().size() ); + CHECK( 16 == chunk.identifier() ); + CHECK( 1 == chunk.reactionProducts()[0] ); + CHECK( 92234 == chunk.reactionProducts()[1] ); + CHECK( 2 == chunk.multiplicities()[0] ); + CHECK( 1 == chunk.multiplicities()[1] ); +} + +std::vector< int > dataWithInsufficientLength() { + + return { 16 }; +} diff --git a/src/NDItk/depletion/ReactionMultiplicities.hpp b/src/NDItk/depletion/ReactionMultiplicities.hpp new file mode 100644 index 0000000..9faaece --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities.hpp @@ -0,0 +1,112 @@ +#ifndef NJOY_NDITK_DEPLETION_REACTIONPRODUCTMULTIPLICITIES +#define NJOY_NDITK_DEPLETION_REACTIONPRODUCTMULTIPLICITIES + +// system includes +#include +#include + +// other includes +#include "tools/Log.hpp" +#include "NDItk/base/IntegerListRecord.hpp" +#include "NDItk/depletion/ReactionMultiplicityType.hpp" +#include "NDItk/depletion/Multiplicities.hpp" + +namespace njoy { +namespace NDItk { +namespace depletion { + +/** + * @brief A reaction product multiplicity record for depletion data + */ +class ReactionMultiplicities : protected base::IntegerListRecord { + + /* fields */ + + std::vector< Multiplicities > multiplicities_; + unsigned int reactions_; + + /* auxiliary functions */ + + #include "NDItk/depletion/ReactionMultiplicities/src/getPostFix.hpp" + #include "NDItk/depletion/ReactionMultiplicities/src/verify.hpp" + #include "NDItk/depletion/ReactionMultiplicities/src/generateData.hpp" + #include "NDItk/depletion/ReactionMultiplicities/src/generateBlocks.hpp" + + using base::IntegerListRecord::key; + +public: + + /* constructor */ + + #include "NDItk/depletion/ReactionMultiplicities/src/ctor.hpp" + + /* methods */ + + /** + * @brief Return the number of reactions defined in this record + */ + std::size_t numberReactions() const { + + return this->reactions_; + } + + /** + * @brief Return the multiplicity data for all reactions + */ + const std::vector< Multiplicities >& reactions() const { + + return this->multiplicities_; + } + + /** + * @brief Verify whether or not a given reaction is present + * + * @param[in] reaction the reaction to look for + */ + bool hasReaction( int reaction ) const { + + auto iter = std::find_if( this->reactions().begin(), this->reactions().end(), + [reaction] ( const auto& entry ) { + + return entry.identifier() == reaction; } ); + return iter != this->reactions().end(); + } + + /** + * @brief Return the cross section data for a given reaction + * + * @param[in] reaction the reaction to look for + */ + const Multiplicities& reaction( int reaction ) const { + + auto iter = std::find_if( this->reactions().begin(), this->reactions().end(), + [reaction] ( const auto& entry ) { + + return entry.identifier() == reaction; } ); + if ( iter != this->reactions().end() ){ + + return *iter; + } + else { + + Log::error( "Reaction with identifier \'{}\' is not present", reaction ); + throw std::exception(); + } + } + + using base::IntegerListRecord::keyword; + using base::IntegerListRecord::values; + using base::IntegerListRecord::size; + using base::IntegerListRecord::empty; + using base::IntegerListRecord::begin; + using base::IntegerListRecord::end; + + #include "NDItk/depletion/ReactionMultiplicities/src/read.hpp" + #include "NDItk/depletion/ReactionMultiplicities/src/print.hpp" +}; + +} // depletion namespace +} // NDItk namespace +} // njoy namespace + +#endif diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/ctor.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/ctor.hpp new file mode 100644 index 0000000..7b0e054 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/ctor.hpp @@ -0,0 +1,95 @@ +private: + +/** + * @brief Private intermediate constructor + */ +ReactionMultiplicities( std::string postfix ) : + IntegerListRecord( base::Keyword( postfix.size() > 1 + ? std::string( "rprod_" ) + postfix + : std::string( "rprod" ) ) ) { +} + +/** + * @brief Private intermediate constructor + */ +ReactionMultiplicities( std::string postfix, + std::vector< Multiplicities >&& multiplicities, + std::size_t reactions ) : + IntegerListRecord( base::Keyword( postfix.size() > 1 + ? std::string( "rprod_" ) + postfix + : std::string( "rprod" ) ), + generateData( std::move( multiplicities ) ) ), + reactions_( reactions ) { + + this->generateBlocks(); +} + +public: + +/** + * @brief Default constructor + */ +ReactionMultiplicities() : ReactionMultiplicities( "" ) {} + +/** + * @brief Default constructor + */ +ReactionMultiplicities( const ReactionMultiplicityType& type ) : + ReactionMultiplicities( getPostFix( type ) ) {} + +/** + * @brief Constructor + * + * @param[in] multiplicities the multiplicity data + */ +ReactionMultiplicities( std::vector< Multiplicities > multiplicities ) : + ReactionMultiplicities( "", std::move( multiplicities ), + multiplicities.size() ) {} + +/** + * @brief Constructor + * + * @param[in] type the multiplicity type (all, few or rmo) + * @param[in] multiplicities the multiplicity data + */ +ReactionMultiplicities( const ReactionMultiplicityType& type, + std::vector< Multiplicities > multiplicities ) : + ReactionMultiplicities( getPostFix( type ), + std::move( multiplicities ), + multiplicities.size() ) {} + +/** + * @brief Copy constructor + */ +ReactionMultiplicities( const ReactionMultiplicities& base ) : + IntegerListRecord( base ), reactions_( base.reactions_ ) { + + this->generateBlocks(); +} + +/** + * @brief Move constructor + */ +ReactionMultiplicities( ReactionMultiplicities&& base ) : + IntegerListRecord( std::move( base ) ), reactions_( base.reactions_ ) { + + this->generateBlocks(); +} + +/** + * @brief Copy assignment + */ +ReactionMultiplicities& operator=( const ReactionMultiplicities& base ) { + + new (this) ReactionMultiplicities( base ); + return *this; +} + +/** + * @brief Move assignment + */ +ReactionMultiplicities& operator=( ReactionMultiplicities&& base ) { + + new (this) ReactionMultiplicities( std::move( base ) ); + return *this; +} diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/generateBlocks.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/generateBlocks.hpp new file mode 100644 index 0000000..22cf418 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/generateBlocks.hpp @@ -0,0 +1,18 @@ +/** + * @brief Generate the subrecords for this record + */ +void generateBlocks() { + + if ( ! this->empty() ) { + + this->multiplicities_.clear(); + auto left = this->values().begin(); + for ( unsigned int index = 0; index < this->numberReactions(); ++index ) { + + auto number = *( left + 1 ); + const auto right = left + 2 + 2 * number; + this->multiplicities_.emplace_back( left, right ); + left = right; + } + } +} diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/generateData.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/generateData.hpp new file mode 100644 index 0000000..adea1d3 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/generateData.hpp @@ -0,0 +1,18 @@ +/** + * @brief Generate the record's data vector + * + * @param[in] xs the cross section data + */ +static std::vector< int > generateData( std::vector< Multiplicities > multiplicities ) { + + // verify the data + verify( multiplicities ); + + // generate the data vector + std::vector< int > data; + for ( unsigned int i = 0; i < multiplicities.size(); ++i ) { + + data.insert( data.end(), multiplicities[i].begin(), multiplicities[i].end() ); + } + return data; +} diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/getPostFix.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/getPostFix.hpp new file mode 100644 index 0000000..9789d5f --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/getPostFix.hpp @@ -0,0 +1,8 @@ +static std::string getPostFix( const ReactionMultiplicityType& type ) { + + return type == ReactionMultiplicityType::All + ? std::string( "all" ) + : type == ReactionMultiplicityType::Few + ? std::string( "few" ) + : std::string( "rmo" ); +} diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/print.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/print.hpp new file mode 100644 index 0000000..b410e6a --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/print.hpp @@ -0,0 +1,17 @@ +/** + * @brief Print the record (if it is not empty) + * + * @param[in] iter the current position in the output + */ +template< typename OutputIterator > +void print( OutputIterator& iter ) const { + + if ( ! this->empty() ) { + + this->key().print( iter ); + for ( const auto& entry : this->multiplicities_ ) { + + entry.print( iter ); + } + } +}; diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/read.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/read.hpp new file mode 100644 index 0000000..9afd585 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/read.hpp @@ -0,0 +1,39 @@ + /** + * @brief Read the record data + * + * @param[in,out] iter an iterator to the current position in the input + * @param[in,out] end an iterator to the end of the input + * @param[in,out] reactions the number of reactions + */ + template< typename Iterator > + void read( Iterator& iter, const Iterator& end, std::size_t reactions ) { + + // read in the data + this->reactions_ = reactions; + std::vector< int > data; + while ( reactions-- ) { + + data.push_back( njoy::tools::disco::FreeFormatInteger::read< int >( iter, end ) ); + data.push_back( njoy::tools::disco::FreeFormatInteger::read< int >( iter, end ) ); + int number = data.back(); + if ( number < 0 ) { + + Log::error( "The number of reaction products cannot be less than zero" ); + Log::info( "Found {} as the number of reaction products", data[1] ); + throw std::exception(); + } + else { + + number *= 2; + while ( number-- ) { + + data.push_back( njoy::tools::disco::FreeFormatInteger::read< int >( iter, end ) ); + } + } + } + this->data() = data; + this->generateBlocks(); + + // verify + verify( this->reactions() ); + }; diff --git a/src/NDItk/depletion/ReactionMultiplicities/src/verify.hpp b/src/NDItk/depletion/ReactionMultiplicities/src/verify.hpp new file mode 100644 index 0000000..5a37db0 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/src/verify.hpp @@ -0,0 +1,18 @@ +/** + * @brief Verify the reaction cross section information + * + * The following verification tests are performed: + * - there is at least one reaction + * - the number of groups for each reaction is the same + * + * @param[in] reactions the reactions to be verified + */ +template < typename Range > +static void verify( const Range& reactions ) { + + if ( reactions.size() < 1 ) { + + Log::error( "Expected at least one reaction, found {}", reactions.size() ); + throw std::exception(); + } +} diff --git a/src/NDItk/depletion/ReactionMultiplicities/test/CMakeLists.txt b/src/NDItk/depletion/ReactionMultiplicities/test/CMakeLists.txt new file mode 100644 index 0000000..5c8f53e --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/test/CMakeLists.txt @@ -0,0 +1 @@ +add_cpp_test( depletion.ReactionMultiplicities ReactionMultiplicities.test.cpp ) \ No newline at end of file diff --git a/src/NDItk/depletion/ReactionMultiplicities/test/ReactionMultiplicities.test.cpp b/src/NDItk/depletion/ReactionMultiplicities/test/ReactionMultiplicities.test.cpp new file mode 100644 index 0000000..86dd793 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicities/test/ReactionMultiplicities.test.cpp @@ -0,0 +1,302 @@ +// include Catch2 +#include +#include +using Catch::Matchers::WithinRel; + +// what we are testing +#include "NDItk/depletion/ReactionMultiplicities.hpp" + +// other includes + +// convenience typedefs +using namespace njoy::NDItk; +using Multiplicities = depletion::Multiplicities; +using ReactionMultiplicities = depletion::ReactionMultiplicities; + +std::string chunk(); +void verifyChunk( const ReactionMultiplicities& ); +std::string chunkWithMultiplicityType(); +void verifyChunkWithMultiplicityType( const ReactionMultiplicities& ); +std::string chunkWithInsufficientNumberReactions(); + +SCENARIO( "ReactionMultiplicities" ) { + + GIVEN( "valid data for a ReactionMultiplicities instance" ) { + + std::string record = chunk(); + + WHEN( "the data is given explicitly" ) { + + std::vector< Multiplicities > multiplicities = { + + { 2, { 1, 92235 }, { 1, 1 } }, + { 16, { 1, 92234 }, { 2, 1 } } + }; + + ReactionMultiplicities chunk( std::move( multiplicities ) ); + + THEN( "a ReactionMultiplicities can be constructed and members can " + "be tested" ) { + + verifyChunk( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + + WHEN( "the data is defined using iterators" ) { + + auto iter = record.begin() + 5; + auto end = record.end(); + + ReactionMultiplicities chunk; + chunk.read( iter, end, 2 ); + + THEN( "a ReactionMultiplicities can be constructed and members can " + "be tested" ) { + + verifyChunk( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "valid data for a ReactionMultiplicities instance with a multiplicity type" ) { + + std::string record = chunkWithMultiplicityType(); + + WHEN( "the data is given explicitly" ) { + + std::vector< Multiplicities > multiplicities = { + + { 2, { 1, 92235 }, { 1, 1 } }, + { 16, { 1, 92234 }, { 2, 1 } } + }; + + ReactionMultiplicities chunk( depletion::ReactionMultiplicityType::All, + std::move( multiplicities ) ); + + THEN( "a ReactionMultiplicities can be constructed and members can " + "be tested" ) { + + verifyChunkWithMultiplicityType( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + + WHEN( "the data is defined using iterators" ) { + + auto iter = record.begin() + 9; + auto end = record.end(); + + ReactionMultiplicities chunk( depletion::ReactionMultiplicityType::All ); + chunk.read( iter, end, 2 ); + + THEN( "a ReactionMultiplicities can be constructed and members can " + "be tested" ) { + + verifyChunkWithMultiplicityType( chunk ); + } // THEN + + THEN( "the record can be printed" ) { + + std::string buffer; + auto output = std::back_inserter( buffer ); + chunk.print( output ); + + CHECK( buffer == record ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "invalid data for a ReactionMultiplicities instance" ) { + + WHEN( "the number of reactions is insufficient" ) { + + std::vector< Multiplicities > multiplicities = {}; + + THEN( "an exception is thrown" ) { + + CHECK_THROWS( ReactionMultiplicities( std::move( multiplicities ) ) ); + } // THEN + } // WHEN + + WHEN( "reading the data of the record and the number of reactions " + "values is insufficient" ) { + + std::string record = chunkWithInsufficientNumberReactions(); + auto iter = record.begin() + 5; + auto end = record.end(); + ReactionMultiplicities chunk; + + THEN( "an exception is thrown" ) { + + CHECK_THROWS( chunk.read( iter, end, 0 ) ); + } // THEN + } // WHEN + } // GIVEN +} // SCENARIO + +std::string chunk() { + + return "rprod\n" + " 2\n" + " 2\n" + " 1 1\n" + " 92235 1\n" + " 16\n" + " 2\n" + " 1 2\n" + " 92234 1\n"; +} + +void verifyChunk( const ReactionMultiplicities& chunk ) { + + CHECK( "rprod" == chunk.keyword() ); + CHECK( 2 == chunk.values()[0] ); + CHECK( 2 == chunk.values()[1] ); + CHECK( 1 == chunk.values()[2] ); + CHECK( 1 == chunk.values()[3] ); + CHECK( 92235 == chunk.values()[4] ); + CHECK( 1 == chunk.values()[5] ); + CHECK( 16 == chunk.values()[6] ); + CHECK( 2 == chunk.values()[7] ); + CHECK( 1 == chunk.values()[8] ); + CHECK( 2 == chunk.values()[9] ); + CHECK( 92234 == chunk.values()[10] ); + CHECK( 1 == chunk.values()[11] ); + + CHECK( false == chunk.empty() ); + CHECK( 12 == chunk.size() ); + + CHECK( 2 == chunk.numberReactions() ); + + CHECK( true == chunk.hasReaction( 2 ) ); + CHECK( true == chunk.hasReaction( 16 ) ); + CHECK( false == chunk.hasReaction( 102 ) ); + + CHECK( 2 == chunk.reactions()[0].identifier() ); + CHECK( 2 == chunk.reactions()[0].numberReactionProducts() ); + CHECK( 1 == chunk.reactions()[0].reactionProducts()[0] ); + CHECK( 92235 == chunk.reactions()[0].reactionProducts()[1] ); + CHECK( 1 == chunk.reactions()[0].multiplicities()[0] ); + CHECK( 1 == chunk.reactions()[0].multiplicities()[1] ); + + CHECK( 16 == chunk.reactions()[1].identifier() ); + CHECK( 2 == chunk.reactions()[1].numberReactionProducts() ); + CHECK( 1 == chunk.reactions()[1].reactionProducts()[0] ); + CHECK( 92234 == chunk.reactions()[1].reactionProducts()[1] ); + CHECK( 2 == chunk.reactions()[1].multiplicities()[0] ); + CHECK( 1 == chunk.reactions()[1].multiplicities()[1] ); + + auto multiplicities = chunk.reaction( 2 ); + CHECK( 2 == chunk.reaction( 2 ).identifier() ); + CHECK( 2 == chunk.reaction( 2 ).numberReactionProducts() ); + CHECK( 1 == chunk.reaction( 2 ).reactionProducts()[0] ); + CHECK( 92235 == chunk.reaction( 2 ).reactionProducts()[1] ); + CHECK( 1 == chunk.reaction( 2 ).multiplicities()[0] ); + CHECK( 1 == chunk.reaction( 2 ).multiplicities()[1] ); + + CHECK( 16 == chunk.reaction( 16 ).identifier() ); + CHECK( 2 == chunk.reaction( 16 ).numberReactionProducts() ); + CHECK( 1 == chunk.reaction( 16 ).reactionProducts()[0] ); + CHECK( 92234 == chunk.reaction( 16 ).reactionProducts()[1] ); + CHECK( 2 == chunk.reaction( 16 ).multiplicities()[0] ); + CHECK( 1 == chunk.reaction( 16 ).multiplicities()[1] ); +} + +std::string chunkWithMultiplicityType() { + + return "rprod_all\n" + " 2\n" + " 2\n" + " 1 1\n" + " 92235 1\n" + " 16\n" + " 2\n" + " 1 2\n" + " 92234 1\n"; +} + +void verifyChunkWithMultiplicityType( const ReactionMultiplicities& chunk ) { + + CHECK( "rprod_all" == chunk.keyword() ); + CHECK( 2 == chunk.values()[0] ); + CHECK( 2 == chunk.values()[1] ); + CHECK( 1 == chunk.values()[2] ); + CHECK( 1 == chunk.values()[3] ); + CHECK( 92235 == chunk.values()[4] ); + CHECK( 1 == chunk.values()[5] ); + CHECK( 16 == chunk.values()[6] ); + CHECK( 2 == chunk.values()[7] ); + CHECK( 1 == chunk.values()[8] ); + CHECK( 2 == chunk.values()[9] ); + CHECK( 92234 == chunk.values()[10] ); + CHECK( 1 == chunk.values()[11] ); + + CHECK( false == chunk.empty() ); + CHECK( 12 == chunk.size() ); + + CHECK( 2 == chunk.numberReactions() ); + + CHECK( true == chunk.hasReaction( 2 ) ); + CHECK( true == chunk.hasReaction( 16 ) ); + CHECK( false == chunk.hasReaction( 102 ) ); + + CHECK( 2 == chunk.reactions()[0].identifier() ); + CHECK( 2 == chunk.reactions()[0].numberReactionProducts() ); + CHECK( 1 == chunk.reactions()[0].reactionProducts()[0] ); + CHECK( 92235 == chunk.reactions()[0].reactionProducts()[1] ); + CHECK( 1 == chunk.reactions()[0].multiplicities()[0] ); + CHECK( 1 == chunk.reactions()[0].multiplicities()[1] ); + + CHECK( 16 == chunk.reactions()[1].identifier() ); + CHECK( 2 == chunk.reactions()[1].numberReactionProducts() ); + CHECK( 1 == chunk.reactions()[1].reactionProducts()[0] ); + CHECK( 92234 == chunk.reactions()[1].reactionProducts()[1] ); + CHECK( 2 == chunk.reactions()[1].multiplicities()[0] ); + CHECK( 1 == chunk.reactions()[1].multiplicities()[1] ); + + auto multiplicities = chunk.reaction( 2 ); + CHECK( 2 == chunk.reaction( 2 ).identifier() ); + CHECK( 2 == chunk.reaction( 2 ).numberReactionProducts() ); + CHECK( 1 == chunk.reaction( 2 ).reactionProducts()[0] ); + CHECK( 92235 == chunk.reaction( 2 ).reactionProducts()[1] ); + CHECK( 1 == chunk.reaction( 2 ).multiplicities()[0] ); + CHECK( 1 == chunk.reaction( 2 ).multiplicities()[1] ); + + CHECK( 16 == chunk.reaction( 16 ).identifier() ); + CHECK( 2 == chunk.reaction( 16 ).numberReactionProducts() ); + CHECK( 1 == chunk.reaction( 16 ).reactionProducts()[0] ); + CHECK( 92234 == chunk.reaction( 16 ).reactionProducts()[1] ); + CHECK( 2 == chunk.reaction( 16 ).multiplicities()[0] ); + CHECK( 1 == chunk.reaction( 16 ).multiplicities()[1] ); +} + +std::string chunkWithInsufficientNumberReactions() { + + return "rprod\n"; +} diff --git a/src/NDItk/depletion/ReactionMultiplicityType.hpp b/src/NDItk/depletion/ReactionMultiplicityType.hpp new file mode 100644 index 0000000..25b1dd1 --- /dev/null +++ b/src/NDItk/depletion/ReactionMultiplicityType.hpp @@ -0,0 +1,23 @@ +#ifndef NJOY_NDITK_DEPLETION_REACTIONMULTIPLICITYTYPE +#define NJOY_NDITK_DEPLETION_REACTIONMULTIPLICITYTYPE + +// system includes + +// other includes + +namespace njoy { +namespace NDItk { +namespace depletion { + +enum class ReactionMultiplicityType : short { + + All = 1, + Few = 2, + RMO = 3 //! @todo change this name to be more understandable +}; + +} // depletion namespace +} // NDItk namespace +} // njoy namespace + +#endif diff --git a/src/NDItk/multigroup/FissionType.hpp b/src/NDItk/multigroup/FissionType.hpp new file mode 100644 index 0000000..0d4e477 --- /dev/null +++ b/src/NDItk/multigroup/FissionType.hpp @@ -0,0 +1,23 @@ +#ifndef NJOY_NDITK_MULTIGROUP_FISSIONTYPE +#define NJOY_NDITK_MULTIGROUP_FISSIONTYPE + +// system includes + +// other includes + +namespace njoy { +namespace NDItk { +namespace multigroup { + +enum class FissionType : short { + + Prompt = 1, + Delayed = 2, + Total = 3 +}; + +} // depletion namespace +} // NDItk namespace +} // njoy namespace + +#endif